All of lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH 052/165] drm/radeon/cik: Add support for compute queues (v2)
  2013-06-26 13:22 ` [PATCH 052/165] drm/radeon/cik: Add support for compute queues (v2) alexdeucher
@ 2013-06-26 10:08   ` Jerome Glisse
  0 siblings, 0 replies; 142+ messages in thread
From: Jerome Glisse @ 2013-06-26 10:08 UTC (permalink / raw)
  To: alexdeucher; +Cc: Alex Deucher, dri-devel

On Wed, Jun 26, 2013 at 09:22:12AM -0400, alexdeucher@gmail.com wrote:
> From: Alex Deucher <alexander.deucher@amd.com>
> 
> On CIK, the compute rings work slightly differently than
> on previous asics, however the basic concepts are the same.
> 
> The main differences:
> - New MEC engines for compute queues
> - Multiple queues per MEC:
>   - CI/KB: 1 MEC, 4 pipes per MEC, 8 queues per pipe = 32 queues
>   -    KV: 2 MEC, 4 pipes per MEC, 8 queues per pipe = 64 queues
> - Queues can be allocated and scheduled by another queue
> - New doorbell aperture allows you to assign space in the aperture
>   for the wptr which allows for userspace access to queues
> 
> v2: add wptr shadow, fix eop setup
> 
> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>

Minor nitpick below otherwise

Reviewed-by: Jerome Glisse <jglisse@redhat.com>

> ---
>  drivers/gpu/drm/radeon/cik.c       |  528 +++++++++++++++++++++++++++++++++++-
>  drivers/gpu/drm/radeon/cikd.h      |   62 +++++
>  drivers/gpu/drm/radeon/radeon.h    |   19 ++
>  drivers/gpu/drm/radeon/radeon_cs.c |    4 +-
>  4 files changed, 601 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
> index 5c28fa5..9d2d6bb 100644
> --- a/drivers/gpu/drm/radeon/cik.c
> +++ b/drivers/gpu/drm/radeon/cik.c
> @@ -1687,6 +1687,7 @@ int cik_ring_test(struct radeon_device *rdev, struct radeon_ring *ring)
>  	radeon_ring_write(ring, ((scratch - PACKET3_SET_UCONFIG_REG_START) >> 2));
>  	radeon_ring_write(ring, 0xDEADBEEF);
>  	radeon_ring_unlock_commit(rdev, ring);
> +
>  	for (i = 0; i < rdev->usec_timeout; i++) {
>  		tmp = RREG32(scratch);
>  		if (tmp == 0xDEADBEEF)
> @@ -2112,6 +2113,51 @@ static int cik_cp_gfx_resume(struct radeon_device *rdev)
>  	return 0;
>  }
>  
> +static u32 cik_compute_ring_get_rptr(struct radeon_device *rdev,
> +				     struct radeon_ring *ring)
> +{
> +	u32 rptr;
> +
> +
> +
> +	if (rdev->wb.enabled) {
> +		rptr = le32_to_cpu(rdev->wb.wb[ring->rptr_offs/4]);
> +	} else {
> +		cik_srbm_select(rdev, ring->me, ring->pipe, ring->queue, 0);
> +		rptr = RREG32(CP_HQD_PQ_RPTR);
> +		cik_srbm_select(rdev, 0, 0, 0, 0);
> +	}
> +	rptr = (rptr & ring->ptr_reg_mask) >> ring->ptr_reg_shift;
> +
> +	return rptr;
> +}
> +
> +static u32 cik_compute_ring_get_wptr(struct radeon_device *rdev,
> +				     struct radeon_ring *ring)
> +{
> +	u32 wptr;
> +
> +	if (rdev->wb.enabled) {
> +		wptr = le32_to_cpu(rdev->wb.wb[ring->wptr_offs/4]);
> +	} else {
> +		cik_srbm_select(rdev, ring->me, ring->pipe, ring->queue, 0);
> +		wptr = RREG32(CP_HQD_PQ_WPTR);
> +		cik_srbm_select(rdev, 0, 0, 0, 0);
> +	}
> +	wptr = (wptr & ring->ptr_reg_mask) >> ring->ptr_reg_shift;
> +
> +	return wptr;
> +}
> +
> +static void cik_compute_ring_set_wptr(struct radeon_device *rdev,
> +				      struct radeon_ring *ring)
> +{
> +	u32 wptr = (ring->wptr << ring->ptr_reg_shift) & ring->ptr_reg_mask;
> +
> +	rdev->wb.wb[ring->wptr_offs/4] = cpu_to_le32(wptr);
> +	WDOORBELL32(ring->doorbell_offset, wptr);
> +}
> +
>  /**
>   * cik_cp_compute_enable - enable/disable the compute CP MEs
>   *
> @@ -2176,7 +2222,8 @@ static int cik_cp_compute_load_microcode(struct radeon_device *rdev)
>   */
>  static int cik_cp_compute_start(struct radeon_device *rdev)
>  {
> -	//todo
> +	cik_cp_compute_enable(rdev, true);
> +
>  	return 0;
>  }
>  
> @@ -2190,10 +2237,171 @@ static int cik_cp_compute_start(struct radeon_device *rdev)
>   */
>  static void cik_cp_compute_fini(struct radeon_device *rdev)
>  {
> +	int i, idx, r;
> +
>  	cik_cp_compute_enable(rdev, false);
> -	//todo
> +
> +	for (i = 0; i < 2; i++) {
> +		if (i == 0)
> +			idx = CAYMAN_RING_TYPE_CP1_INDEX;
> +		else
> +			idx = CAYMAN_RING_TYPE_CP2_INDEX;
> +
> +		if (rdev->ring[idx].mqd_obj) {
> +			r = radeon_bo_reserve(rdev->ring[idx].mqd_obj, false);
> +			if (unlikely(r != 0))
> +				dev_warn(rdev->dev, "(%d) reserve MQD bo failed\n", r);
> +
> +			radeon_bo_unpin(rdev->ring[idx].mqd_obj);
> +			radeon_bo_unreserve(rdev->ring[idx].mqd_obj);
> +
> +			radeon_bo_unref(&rdev->ring[idx].mqd_obj);
> +			rdev->ring[idx].mqd_obj = NULL;
> +		}
> +	}
> +}
> +
> +static void cik_mec_fini(struct radeon_device *rdev)
> +{
> +	int r;
> +
> +	if (rdev->mec.hpd_eop_obj) {
> +		r = radeon_bo_reserve(rdev->mec.hpd_eop_obj, false);
> +		if (unlikely(r != 0))
> +			dev_warn(rdev->dev, "(%d) reserve HPD EOP bo failed\n", r);
> +		radeon_bo_unpin(rdev->mec.hpd_eop_obj);
> +		radeon_bo_unreserve(rdev->mec.hpd_eop_obj);
> +
> +		radeon_bo_unref(&rdev->mec.hpd_eop_obj);
> +		rdev->mec.hpd_eop_obj = NULL;
> +	}
> +}
> +
> +#define MEC_HPD_SIZE 2048
> +
> +static int cik_mec_init(struct radeon_device *rdev)
> +{
> +	int r;
> +	u32 *hpd;
> +
> +	/*
> +	 * KV:    2 MEC, 4 Pipes/MEC, 8 Queues/Pipe - 64 Queues total
> +	 * CI/KB: 1 MEC, 4 Pipes/MEC, 8 Queues/Pipe - 32 Queues total
> +	 */
> +	if (rdev->family == CHIP_KAVERI)
> +		rdev->mec.num_mec = 2;
> +	else
> +		rdev->mec.num_mec = 1;
> +	rdev->mec.num_pipe = 4;
> +	rdev->mec.num_queue = rdev->mec.num_mec * rdev->mec.num_pipe * 8;
> +
> +	if (rdev->mec.hpd_eop_obj == NULL) {
> +		r = radeon_bo_create(rdev,
> +				     rdev->mec.num_mec *rdev->mec.num_pipe * MEC_HPD_SIZE * 2,
> +				     PAGE_SIZE, true,
> +				     RADEON_GEM_DOMAIN_GTT, NULL,
> +				     &rdev->mec.hpd_eop_obj);
> +		if (r) {
> +			dev_warn(rdev->dev, "(%d) create HDP EOP bo failed\n", r);
> +			return r;
> +		}
> +	}
> +
> +	r = radeon_bo_reserve(rdev->mec.hpd_eop_obj, false);
> +	if (unlikely(r != 0)) {
> +		cik_mec_fini(rdev);
> +		return r;
> +	}
> +	r = radeon_bo_pin(rdev->mec.hpd_eop_obj, RADEON_GEM_DOMAIN_GTT,
> +			  &rdev->mec.hpd_eop_gpu_addr);
> +	if (r) {
> +		dev_warn(rdev->dev, "(%d) pin HDP EOP bo failed\n", r);
> +		cik_mec_fini(rdev);
> +		return r;
> +	}
> +	r = radeon_bo_kmap(rdev->mec.hpd_eop_obj, (void **)&hpd);
> +	if (r) {
> +		dev_warn(rdev->dev, "(%d) map HDP EOP bo failed\n", r);
> +		cik_mec_fini(rdev);
> +		return r;
> +	}
> +
> +	/* clear memory.  Not sure if this is required or not */
> +	memset(hpd, 0, rdev->mec.num_mec *rdev->mec.num_pipe * MEC_HPD_SIZE * 2);
> +
> +	radeon_bo_kunmap(rdev->mec.hpd_eop_obj);
> +	radeon_bo_unreserve(rdev->mec.hpd_eop_obj);
> +
> +	return 0;
>  }
>  
> +struct hqd_registers
> +{
> +	u32 cp_mqd_base_addr;
> +	u32 cp_mqd_base_addr_hi;
> +	u32 cp_hqd_active;
> +	u32 cp_hqd_vmid;
> +	u32 cp_hqd_persistent_state;
> +	u32 cp_hqd_pipe_priority;
> +	u32 cp_hqd_queue_priority;
> +	u32 cp_hqd_quantum;
> +	u32 cp_hqd_pq_base;
> +	u32 cp_hqd_pq_base_hi;
> +	u32 cp_hqd_pq_rptr;
> +	u32 cp_hqd_pq_rptr_report_addr;
> +	u32 cp_hqd_pq_rptr_report_addr_hi;
> +	u32 cp_hqd_pq_wptr_poll_addr;
> +	u32 cp_hqd_pq_wptr_poll_addr_hi;
> +	u32 cp_hqd_pq_doorbell_control;
> +	u32 cp_hqd_pq_wptr;
> +	u32 cp_hqd_pq_control;
> +	u32 cp_hqd_ib_base_addr;
> +	u32 cp_hqd_ib_base_addr_hi;
> +	u32 cp_hqd_ib_rptr;
> +	u32 cp_hqd_ib_control;
> +	u32 cp_hqd_iq_timer;
> +	u32 cp_hqd_iq_rptr;
> +	u32 cp_hqd_dequeue_request;
> +	u32 cp_hqd_dma_offload;
> +	u32 cp_hqd_sema_cmd;
> +	u32 cp_hqd_msg_type;
> +	u32 cp_hqd_atomic0_preop_lo;
> +	u32 cp_hqd_atomic0_preop_hi;
> +	u32 cp_hqd_atomic1_preop_lo;
> +	u32 cp_hqd_atomic1_preop_hi;
> +	u32 cp_hqd_hq_scheduler0;
> +	u32 cp_hqd_hq_scheduler1;
> +	u32 cp_mqd_control;
> +};
> +
> +struct bonaire_mqd
> +{
> +	u32 header;
> +	u32 dispatch_initiator;
> +	u32 dimensions[3];
> +	u32 start_idx[3];
> +	u32 num_threads[3];
> +	u32 pipeline_stat_enable;
> +	u32 perf_counter_enable;
> +	u32 pgm[2];
> +	u32 tba[2];
> +	u32 tma[2];
> +	u32 pgm_rsrc[2];
> +	u32 vmid;
> +	u32 resource_limits;
> +	u32 static_thread_mgmt01[2];
> +	u32 tmp_ring_size;
> +	u32 static_thread_mgmt23[2];
> +	u32 restart[3];
> +	u32 thread_trace_enable;
> +	u32 reserved1;
> +	u32 user_data[16];
> +	u32 vgtcs_invoke_count[2];
> +	struct hqd_registers queue_state;
> +	u32 dequeue_cntr;
> +	u32 interrupt_queue[64];
> +};
> +
>  /**
>   * cik_cp_compute_resume - setup the compute queue registers
>   *
> @@ -2205,24 +2413,247 @@ static void cik_cp_compute_fini(struct radeon_device *rdev)
>   */
>  static int cik_cp_compute_resume(struct radeon_device *rdev)
>  {
> -	int r;
> +	int r, i, idx;
> +	u32 tmp;
> +	bool use_doorbell = true;
> +	u64 hqd_gpu_addr;
> +	u64 mqd_gpu_addr;
> +	u64 eop_gpu_addr;
> +	u64 wb_gpu_addr;
> +	u32 *buf;
> +	struct bonaire_mqd *mqd;
>  
> -	//todo
>  	r = cik_cp_compute_start(rdev);
>  	if (r)
>  		return r;
> +
> +	/* fix up chicken bits */
> +	tmp = RREG32(CP_CPF_DEBUG);
> +	tmp |= (1 << 23);

What is this chicken bit ? Is it tasty ?

> +	WREG32(CP_CPF_DEBUG, tmp);
> +
> +	/* init the pipes */
> +	for (i = 0; i < (rdev->mec.num_pipe * rdev->mec.num_mec); i++) {
> +		int me = (i < 4) ? 1 : 2;
> +		int pipe = (i < 4) ? i : (i - 4);
> +
> +		eop_gpu_addr = rdev->mec.hpd_eop_gpu_addr + (i * MEC_HPD_SIZE * 2);
> +
> +		cik_srbm_select(rdev, me, pipe, 0, 0);
> +
> +		/* write the EOP addr */
> +		WREG32(CP_HPD_EOP_BASE_ADDR, eop_gpu_addr >> 8);
> +		WREG32(CP_HPD_EOP_BASE_ADDR_HI, upper_32_bits(eop_gpu_addr) >> 8);
> +
> +		/* set the VMID assigned */
> +		WREG32(CP_HPD_EOP_VMID, 0);
> +
> +		/* set the EOP size, register value is 2^(EOP_SIZE+1) dwords */
> +		tmp = RREG32(CP_HPD_EOP_CONTROL);
> +		tmp &= ~EOP_SIZE_MASK;
> +		tmp |= drm_order(MEC_HPD_SIZE / 8);
> +		WREG32(CP_HPD_EOP_CONTROL, tmp);
> +	}
> +	cik_srbm_select(rdev, 0, 0, 0, 0);
> +
> +	/* init the queues.  Just two for now. */
> +	for (i = 0; i < 2; i++) {
> +		if (i == 0)
> +			idx = CAYMAN_RING_TYPE_CP1_INDEX;
> +		else
> +			idx = CAYMAN_RING_TYPE_CP2_INDEX;
> +
> +		if (rdev->ring[idx].mqd_obj == NULL) {
> +			r = radeon_bo_create(rdev,
> +					     sizeof(struct bonaire_mqd),
> +					     PAGE_SIZE, true,
> +					     RADEON_GEM_DOMAIN_GTT, NULL,
> +					     &rdev->ring[idx].mqd_obj);
> +			if (r) {
> +				dev_warn(rdev->dev, "(%d) create MQD bo failed\n", r);
> +				return r;
> +			}
> +		}
> +
> +		r = radeon_bo_reserve(rdev->ring[idx].mqd_obj, false);
> +		if (unlikely(r != 0)) {
> +			cik_cp_compute_fini(rdev);
> +			return r;
> +		}
> +		r = radeon_bo_pin(rdev->ring[idx].mqd_obj, RADEON_GEM_DOMAIN_GTT,
> +				  &mqd_gpu_addr);
> +		if (r) {
> +			dev_warn(rdev->dev, "(%d) pin MQD bo failed\n", r);
> +			cik_cp_compute_fini(rdev);
> +			return r;
> +		}
> +		r = radeon_bo_kmap(rdev->ring[idx].mqd_obj, (void **)&buf);
> +		if (r) {
> +			dev_warn(rdev->dev, "(%d) map MQD bo failed\n", r);
> +			cik_cp_compute_fini(rdev);
> +			return r;
> +		}
> +
> +		/* doorbell offset */
> +		rdev->ring[idx].doorbell_offset =
> +			(rdev->ring[idx].doorbell_page_num * PAGE_SIZE) + 0;
> +
> +		/* init the mqd struct */
> +		memset(buf, 0, sizeof(struct bonaire_mqd));
> +
> +		mqd = (struct bonaire_mqd *)buf;
> +		mqd->header = 0xC0310800;
> +		mqd->static_thread_mgmt01[0] = 0xffffffff;
> +		mqd->static_thread_mgmt01[1] = 0xffffffff;
> +		mqd->static_thread_mgmt23[0] = 0xffffffff;
> +		mqd->static_thread_mgmt23[1] = 0xffffffff;
> +
> +		cik_srbm_select(rdev, rdev->ring[idx].me,
> +				rdev->ring[idx].pipe,
> +				rdev->ring[idx].queue, 0);
> +
> +		/* disable wptr polling */
> +		tmp = RREG32(CP_PQ_WPTR_POLL_CNTL);
> +		tmp &= ~WPTR_POLL_EN;
> +		WREG32(CP_PQ_WPTR_POLL_CNTL, tmp);
> +
> +		/* enable doorbell? */
> +		mqd->queue_state.cp_hqd_pq_doorbell_control =
> +			RREG32(CP_HQD_PQ_DOORBELL_CONTROL);
> +		if (use_doorbell)
> +			mqd->queue_state.cp_hqd_pq_doorbell_control |= DOORBELL_EN;
> +		else
> +			mqd->queue_state.cp_hqd_pq_doorbell_control &= ~DOORBELL_EN;
> +		WREG32(CP_HQD_PQ_DOORBELL_CONTROL,
> +		       mqd->queue_state.cp_hqd_pq_doorbell_control);
> +
> +		/* disable the queue if it's active */
> +		mqd->queue_state.cp_hqd_dequeue_request = 0;
> +		mqd->queue_state.cp_hqd_pq_rptr = 0;
> +		mqd->queue_state.cp_hqd_pq_wptr= 0;
> +		if (RREG32(CP_HQD_ACTIVE) & 1) {
> +			WREG32(CP_HQD_DEQUEUE_REQUEST, 1);
> +			for (i = 0; i < rdev->usec_timeout; i++) {
> +				if (!(RREG32(CP_HQD_ACTIVE) & 1))
> +					break;
> +				udelay(1);
> +			}
> +			WREG32(CP_HQD_DEQUEUE_REQUEST, mqd->queue_state.cp_hqd_dequeue_request);
> +			WREG32(CP_HQD_PQ_RPTR, mqd->queue_state.cp_hqd_pq_rptr);
> +			WREG32(CP_HQD_PQ_WPTR, mqd->queue_state.cp_hqd_pq_wptr);
> +		}
> +
> +		/* set the pointer to the MQD */
> +		mqd->queue_state.cp_mqd_base_addr = mqd_gpu_addr & 0xfffffffc;
> +		mqd->queue_state.cp_mqd_base_addr_hi = upper_32_bits(mqd_gpu_addr);
> +		WREG32(CP_MQD_BASE_ADDR, mqd->queue_state.cp_mqd_base_addr);
> +		WREG32(CP_MQD_BASE_ADDR_HI, mqd->queue_state.cp_mqd_base_addr_hi);
> +		/* set MQD vmid to 0 */
> +		mqd->queue_state.cp_mqd_control = RREG32(CP_MQD_CONTROL);
> +		mqd->queue_state.cp_mqd_control &= ~MQD_VMID_MASK;
> +		WREG32(CP_MQD_CONTROL, mqd->queue_state.cp_mqd_control);
> +
> +		/* set the pointer to the HQD, this is similar CP_RB0_BASE/_HI */
> +		hqd_gpu_addr = rdev->ring[idx].gpu_addr >> 8;
> +		mqd->queue_state.cp_hqd_pq_base = hqd_gpu_addr;
> +		mqd->queue_state.cp_hqd_pq_base_hi = upper_32_bits(hqd_gpu_addr);
> +		WREG32(CP_HQD_PQ_BASE, mqd->queue_state.cp_hqd_pq_base);
> +		WREG32(CP_HQD_PQ_BASE_HI, mqd->queue_state.cp_hqd_pq_base_hi);
> +
> +		/* set up the HQD, this is similar to CP_RB0_CNTL */
> +		mqd->queue_state.cp_hqd_pq_control = RREG32(CP_HQD_PQ_CONTROL);
> +		mqd->queue_state.cp_hqd_pq_control &=
> +			~(QUEUE_SIZE_MASK | RPTR_BLOCK_SIZE_MASK);
> +
> +		mqd->queue_state.cp_hqd_pq_control |=
> +			drm_order(rdev->ring[idx].ring_size / 8);
> +		mqd->queue_state.cp_hqd_pq_control |=
> +			(drm_order(RADEON_GPU_PAGE_SIZE/8) << 8);
> +#ifdef __BIG_ENDIAN
> +		mqd->queue_state.cp_hqd_pq_control |= BUF_SWAP_32BIT;
> +#endif
> +		mqd->queue_state.cp_hqd_pq_control &=
> +			~(UNORD_DISPATCH | ROQ_PQ_IB_FLIP | PQ_VOLATILE);
> +		mqd->queue_state.cp_hqd_pq_control |=
> +			PRIV_STATE | KMD_QUEUE; /* assuming kernel queue control */
> +		WREG32(CP_HQD_PQ_CONTROL, mqd->queue_state.cp_hqd_pq_control);
> +
> +		/* only used if CP_PQ_WPTR_POLL_CNTL.WPTR_POLL_EN=1 */
> +		if (i == 0)
> +			wb_gpu_addr = rdev->wb.gpu_addr + CIK_WB_CP1_WPTR_OFFSET;
> +		else
> +			wb_gpu_addr = rdev->wb.gpu_addr + CIK_WB_CP2_WPTR_OFFSET;
> +		mqd->queue_state.cp_hqd_pq_wptr_poll_addr = wb_gpu_addr & 0xfffffffc;
> +		mqd->queue_state.cp_hqd_pq_wptr_poll_addr_hi = upper_32_bits(wb_gpu_addr) & 0xffff;
> +		WREG32(CP_HQD_PQ_WPTR_POLL_ADDR, mqd->queue_state.cp_hqd_pq_wptr_poll_addr);
> +		WREG32(CP_HQD_PQ_WPTR_POLL_ADDR_HI,
> +		       mqd->queue_state.cp_hqd_pq_wptr_poll_addr_hi);
> +
> +		/* set the wb address wether it's enabled or not */
> +		if (i == 0)
> +			wb_gpu_addr = rdev->wb.gpu_addr + RADEON_WB_CP1_RPTR_OFFSET;
> +		else
> +			wb_gpu_addr = rdev->wb.gpu_addr + RADEON_WB_CP2_RPTR_OFFSET;
> +		mqd->queue_state.cp_hqd_pq_rptr_report_addr = wb_gpu_addr & 0xfffffffc;
> +		mqd->queue_state.cp_hqd_pq_rptr_report_addr_hi =
> +			upper_32_bits(wb_gpu_addr) & 0xffff;
> +		WREG32(CP_HQD_PQ_RPTR_REPORT_ADDR,
> +		       mqd->queue_state.cp_hqd_pq_rptr_report_addr);
> +		WREG32(CP_HQD_PQ_RPTR_REPORT_ADDR_HI,
> +		       mqd->queue_state.cp_hqd_pq_rptr_report_addr_hi);
> +
> +		/* enable the doorbell if requested */
> +		if (use_doorbell) {
> +			mqd->queue_state.cp_hqd_pq_doorbell_control =
> +				RREG32(CP_HQD_PQ_DOORBELL_CONTROL);
> +			mqd->queue_state.cp_hqd_pq_doorbell_control &= ~DOORBELL_OFFSET_MASK;
> +			mqd->queue_state.cp_hqd_pq_doorbell_control |=
> +				DOORBELL_OFFSET(rdev->ring[idx].doorbell_offset / 4);
> +			mqd->queue_state.cp_hqd_pq_doorbell_control |= DOORBELL_EN;
> +			mqd->queue_state.cp_hqd_pq_doorbell_control &=
> +				~(DOORBELL_SOURCE | DOORBELL_HIT);
> +
> +		} else {
> +			mqd->queue_state.cp_hqd_pq_doorbell_control = 0;
> +		}
> +		WREG32(CP_HQD_PQ_DOORBELL_CONTROL,
> +		       mqd->queue_state.cp_hqd_pq_doorbell_control);
> +
> +		/* read and write pointers, similar to CP_RB0_WPTR/_RPTR */
> +		rdev->ring[idx].wptr = 0;
> +		mqd->queue_state.cp_hqd_pq_wptr = rdev->ring[idx].wptr;
> +		WREG32(CP_HQD_PQ_WPTR, mqd->queue_state.cp_hqd_pq_wptr);
> +		rdev->ring[idx].rptr = RREG32(CP_HQD_PQ_RPTR);
> +		mqd->queue_state.cp_hqd_pq_rptr = rdev->ring[idx].rptr;
> +
> +		/* set the vmid for the queue */
> +		mqd->queue_state.cp_hqd_vmid = 0;
> +		WREG32(CP_HQD_VMID, mqd->queue_state.cp_hqd_vmid);
> +
> +		/* activate the queue */
> +		mqd->queue_state.cp_hqd_active = 1;
> +		WREG32(CP_HQD_ACTIVE, mqd->queue_state.cp_hqd_active);
> +
> +		cik_srbm_select(rdev, 0, 0, 0, 0);
> +
> +		radeon_bo_kunmap(rdev->ring[idx].mqd_obj);
> +		radeon_bo_unreserve(rdev->ring[idx].mqd_obj);
> +
> +		rdev->ring[idx].ready = true;
> +		r = radeon_ring_test(rdev, idx, &rdev->ring[idx]);
> +		if (r)
> +			rdev->ring[idx].ready = false;
> +	}
> +
>  	return 0;
>  }
>  
> -/* XXX temporary wrappers to handle both compute and gfx */
> -/* XXX */
>  static void cik_cp_enable(struct radeon_device *rdev, bool enable)
>  {
>  	cik_cp_gfx_enable(rdev, enable);
>  	cik_cp_compute_enable(rdev, enable);
>  }
>  
> -/* XXX */
>  static int cik_cp_load_microcode(struct radeon_device *rdev)
>  {
>  	int r;
> @@ -2237,14 +2668,12 @@ static int cik_cp_load_microcode(struct radeon_device *rdev)
>  	return 0;
>  }
>  
> -/* XXX */
>  static void cik_cp_fini(struct radeon_device *rdev)
>  {
>  	cik_cp_gfx_fini(rdev);
>  	cik_cp_compute_fini(rdev);
>  }
>  
> -/* XXX */
>  static int cik_cp_resume(struct radeon_device *rdev)
>  {
>  	int r;
> @@ -2865,6 +3294,22 @@ static void cik_print_gpu_status_regs(struct radeon_device *rdev)
>  		RREG32(SDMA0_STATUS_REG + SDMA0_REGISTER_OFFSET));
>  	dev_info(rdev->dev, "  SDMA1_STATUS_REG   = 0x%08X\n",
>  		 RREG32(SDMA0_STATUS_REG + SDMA1_REGISTER_OFFSET));
> +	dev_info(rdev->dev, "  CP_STAT = 0x%08x\n", RREG32(CP_STAT));
> +	dev_info(rdev->dev, "  CP_STALLED_STAT1 = 0x%08x\n",
> +		 RREG32(CP_STALLED_STAT1));
> +	dev_info(rdev->dev, "  CP_STALLED_STAT2 = 0x%08x\n",
> +		 RREG32(CP_STALLED_STAT2));
> +	dev_info(rdev->dev, "  CP_STALLED_STAT3 = 0x%08x\n",
> +		 RREG32(CP_STALLED_STAT3));
> +	dev_info(rdev->dev, "  CP_CPF_BUSY_STAT = 0x%08x\n",
> +		 RREG32(CP_CPF_BUSY_STAT));
> +	dev_info(rdev->dev, "  CP_CPF_STALLED_STAT1 = 0x%08x\n",
> +		 RREG32(CP_CPF_STALLED_STAT1));
> +	dev_info(rdev->dev, "  CP_CPF_STATUS = 0x%08x\n", RREG32(CP_CPF_STATUS));
> +	dev_info(rdev->dev, "  CP_CPC_BUSY_STAT = 0x%08x\n", RREG32(CP_CPC_BUSY_STAT));
> +	dev_info(rdev->dev, "  CP_CPC_STALLED_STAT1 = 0x%08x\n",
> +		 RREG32(CP_CPC_STALLED_STAT1));
> +	dev_info(rdev->dev, "  CP_CPC_STATUS = 0x%08x\n", RREG32(CP_CPC_STATUS));
>  }
>  
>  /**
> @@ -4952,12 +5397,31 @@ static int cik_startup(struct radeon_device *rdev)
>  	if (r)
>  		return r;
>  
> +	/* allocate rlc buffers */

Init mec not allocate rlc ...

> +	r = cik_mec_init(rdev);
> +	if (r) {
> +		DRM_ERROR("Failed to init MEC BOs!\n");
> +		return r;
> +	}
> +
>  	r = radeon_fence_driver_start_ring(rdev, RADEON_RING_TYPE_GFX_INDEX);
>  	if (r) {
>  		dev_err(rdev->dev, "failed initializing CP fences (%d).\n", r);
>  		return r;
>  	}
>  
> +	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);
> +		return r;
> +	}
> +
> +	r = radeon_fence_driver_start_ring(rdev, CAYMAN_RING_TYPE_CP2_INDEX);
> +	if (r) {
> +		dev_err(rdev->dev, "failed initializing CP fences (%d).\n", r);
> +		return r;
> +	}
> +
>  	r = radeon_fence_driver_start_ring(rdev, R600_RING_TYPE_DMA_INDEX);
>  	if (r) {
>  		dev_err(rdev->dev, "failed initializing DMA fences (%d).\n", r);
> @@ -5002,6 +5466,36 @@ static int cik_startup(struct radeon_device *rdev)
>  	if (r)
>  		return r;
>  
> +	/* set up the compute queues */
> +	ring = &rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX];
> +	r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP1_RPTR_OFFSET,
> +			     CP_HQD_PQ_RPTR, CP_HQD_PQ_WPTR,
> +			     0, 0xfffff, RADEON_CP_PACKET2);
> +	if (r)
> +		return r;
> +	ring->me = 1; /* first MEC */
> +	ring->pipe = 0; /* first pipe */
> +	ring->queue = 0; /* first queue */
> +	ring->wptr_offs = CIK_WB_CP1_WPTR_OFFSET;
> +	ring->funcs.get_rptr = &cik_compute_ring_get_rptr;
> +	ring->funcs.get_wptr = &cik_compute_ring_get_wptr;
> +	ring->funcs.set_wptr = &cik_compute_ring_set_wptr;
> +
> +	ring = &rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX];
> +	r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP2_RPTR_OFFSET,
> +			     CP_HQD_PQ_RPTR, CP_HQD_PQ_WPTR,
> +			     0, 0xffffffff, RADEON_CP_PACKET2);
> +	if (r)
> +		return r;
> +	/* dGPU only have 1 MEC */
> +	ring->me = 1; /* first MEC */
> +	ring->pipe = 0; /* first pipe */
> +	ring->queue = 1; /* second queue */
> +	ring->wptr_offs = CIK_WB_CP2_WPTR_OFFSET;
> +	ring->funcs.get_rptr = &cik_compute_ring_get_rptr;
> +	ring->funcs.get_wptr = &cik_compute_ring_get_wptr;
> +	ring->funcs.set_wptr = &cik_compute_ring_set_wptr;
> +
>  	ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX];
>  	r = radeon_ring_init(rdev, ring, ring->ring_size, R600_WB_DMA_RPTR_OFFSET,
>  			     SDMA0_GFX_RB_RPTR + SDMA0_REGISTER_OFFSET,
> @@ -5176,6 +5670,20 @@ int cik_init(struct radeon_device *rdev)
>  	ring->ring_obj = NULL;
>  	r600_ring_init(rdev, ring, 1024 * 1024);
>  
> +	ring = &rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX];
> +	ring->ring_obj = NULL;
> +	r600_ring_init(rdev, ring, 1024 * 1024);
> +	r = radeon_doorbell_get(rdev, &ring->doorbell_page_num);
> +	if (r)
> +		return r;
> +
> +	ring = &rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX];
> +	ring->ring_obj = NULL;
> +	r600_ring_init(rdev, ring, 1024 * 1024);
> +	r = radeon_doorbell_get(rdev, &ring->doorbell_page_num);
> +	if (r)
> +		return r;
> +
>  	ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX];
>  	ring->ring_obj = NULL;
>  	r600_ring_init(rdev, ring, 256 * 1024);
> @@ -5206,6 +5714,7 @@ int cik_init(struct radeon_device *rdev)
>  		cik_sdma_fini(rdev);
>  		cik_irq_fini(rdev);
>  		si_rlc_fini(rdev);
> +		cik_mec_fini(rdev);
>  		radeon_wb_fini(rdev);
>  		radeon_ib_pool_fini(rdev);
>  		radeon_vm_manager_fini(rdev);
> @@ -5241,6 +5750,7 @@ void cik_fini(struct radeon_device *rdev)
>  	cik_sdma_fini(rdev);
>  	cik_irq_fini(rdev);
>  	si_rlc_fini(rdev);
> +	cik_mec_fini(rdev);
>  	radeon_wb_fini(rdev);
>  	radeon_vm_manager_fini(rdev);
>  	radeon_ib_pool_fini(rdev);
> diff --git a/drivers/gpu/drm/radeon/cikd.h b/drivers/gpu/drm/radeon/cikd.h
> index 79be39e..63514b9 100644
> --- a/drivers/gpu/drm/radeon/cikd.h
> +++ b/drivers/gpu/drm/radeon/cikd.h
> @@ -460,6 +460,13 @@
>  #       define RDERR_INT_ENABLE                         (1 << 0)
>  #       define GUI_IDLE_INT_ENABLE                      (1 << 19)
>  
> +#define CP_CPC_STATUS					0x8210
> +#define CP_CPC_BUSY_STAT				0x8214
> +#define CP_CPC_STALLED_STAT1				0x8218
> +#define CP_CPF_STATUS					0x821c
> +#define CP_CPF_BUSY_STAT				0x8220
> +#define CP_CPF_STALLED_STAT1				0x8224
> +
>  #define CP_MEC_CNTL					0x8234
>  #define		MEC_ME2_HALT					(1 << 28)
>  #define		MEC_ME1_HALT					(1 << 30)
> @@ -468,6 +475,12 @@
>  #define		MEC_ME2_HALT					(1 << 28)
>  #define		MEC_ME1_HALT					(1 << 30)
>  
> +#define CP_STALLED_STAT3				0x8670
> +#define CP_STALLED_STAT1				0x8674
> +#define CP_STALLED_STAT2				0x8678
> +
> +#define CP_STAT						0x8680
> +
>  #define CP_ME_CNTL					0x86D8
>  #define		CP_CE_HALT					(1 << 24)
>  #define		CP_PFP_HALT					(1 << 26)
> @@ -701,6 +714,11 @@
>  #       define CP_RINGID1_INT_STAT                      (1 << 30)
>  #       define CP_RINGID0_INT_STAT                      (1 << 31)
>  
> +#define CP_CPF_DEBUG                                    0xC200
> +
> +#define CP_PQ_WPTR_POLL_CNTL                            0xC20C
> +#define		WPTR_POLL_EN      			(1 << 31)
> +
>  #define CP_ME1_PIPE0_INT_CNTL                           0xC214
>  #define CP_ME1_PIPE1_INT_CNTL                           0xC218
>  #define CP_ME1_PIPE2_INT_CNTL                           0xC21C
> @@ -773,6 +791,50 @@
>  #define RLC_GPM_SCRATCH_ADDR                              0xC4B0
>  #define RLC_GPM_SCRATCH_DATA                              0xC4B4
>  
> +#define CP_HPD_EOP_BASE_ADDR                              0xC904
> +#define CP_HPD_EOP_BASE_ADDR_HI                           0xC908
> +#define CP_HPD_EOP_VMID                                   0xC90C
> +#define CP_HPD_EOP_CONTROL                                0xC910
> +#define		EOP_SIZE(x)				((x) << 0)
> +#define		EOP_SIZE_MASK      			(0x3f << 0)
> +#define CP_MQD_BASE_ADDR                                  0xC914
> +#define CP_MQD_BASE_ADDR_HI                               0xC918
> +#define CP_HQD_ACTIVE                                     0xC91C
> +#define CP_HQD_VMID                                       0xC920
> +
> +#define CP_HQD_PQ_BASE                                    0xC934
> +#define CP_HQD_PQ_BASE_HI                                 0xC938
> +#define CP_HQD_PQ_RPTR                                    0xC93C
> +#define CP_HQD_PQ_RPTR_REPORT_ADDR                        0xC940
> +#define CP_HQD_PQ_RPTR_REPORT_ADDR_HI                     0xC944
> +#define CP_HQD_PQ_WPTR_POLL_ADDR                          0xC948
> +#define CP_HQD_PQ_WPTR_POLL_ADDR_HI                       0xC94C
> +#define CP_HQD_PQ_DOORBELL_CONTROL                        0xC950
> +#define		DOORBELL_OFFSET(x)			((x) << 2)
> +#define		DOORBELL_OFFSET_MASK			(0x1fffff << 2)
> +#define		DOORBELL_SOURCE      			(1 << 28)
> +#define		DOORBELL_SCHD_HIT      			(1 << 29)
> +#define		DOORBELL_EN      			(1 << 30)
> +#define		DOORBELL_HIT      			(1 << 31)
> +#define CP_HQD_PQ_WPTR                                    0xC954
> +#define CP_HQD_PQ_CONTROL                                 0xC958
> +#define		QUEUE_SIZE(x)				((x) << 0)
> +#define		QUEUE_SIZE_MASK      			(0x3f << 0)
> +#define		RPTR_BLOCK_SIZE(x)			((x) << 8)
> +#define		RPTR_BLOCK_SIZE_MASK			(0x3f << 8)
> +#define		PQ_VOLATILE      			(1 << 26)
> +#define		NO_UPDATE_RPTR      			(1 << 27)
> +#define		UNORD_DISPATCH      			(1 << 28)
> +#define		ROQ_PQ_IB_FLIP      			(1 << 29)
> +#define		PRIV_STATE      			(1 << 30)
> +#define		KMD_QUEUE      				(1 << 31)
> +
> +#define CP_HQD_DEQUEUE_REQUEST                          0xC974
> +
> +#define CP_MQD_CONTROL                                  0xC99C
> +#define		MQD_VMID(x)				((x) << 0)
> +#define		MQD_VMID_MASK      			(0xf << 0)
> +
>  #define PA_SC_RASTER_CONFIG                             0x28350
>  #       define RASTER_CONFIG_RB_MAP_0                   0
>  #       define RASTER_CONFIG_RB_MAP_1                   1
> diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
> index a2a3430..d40d506 100644
> --- a/drivers/gpu/drm/radeon/radeon.h
> +++ b/drivers/gpu/drm/radeon/radeon.h
> @@ -714,6 +714,22 @@ struct radeon_ring {
>  		u32			(*get_wptr)(struct radeon_device *rdev, struct radeon_ring *ring);
>  		void			(*set_wptr)(struct radeon_device *rdev, struct radeon_ring *ring);
>  	} funcs;
> +	/* for CIK queues */
> +	u32 me;
> +	u32 pipe;
> +	u32 queue;
> +	struct radeon_bo	*mqd_obj;
> +	u32 doorbell_page_num;
> +	u32 doorbell_offset;
> +	unsigned		wptr_offs;
> +};
> +
> +struct radeon_mec {
> +	struct radeon_bo	*hpd_eop_obj;
> +	u64			hpd_eop_gpu_addr;
> +	u32 num_pipe;
> +	u32 num_mec;
> +	u32 num_queue;
>  };
>  
>  /*
> @@ -971,6 +987,8 @@ struct radeon_wb {
>  #define CAYMAN_WB_DMA1_RPTR_OFFSET   2304
>  #define R600_WB_UVD_RPTR_OFFSET  2560
>  #define R600_WB_EVENT_OFFSET     3072
> +#define CIK_WB_CP1_WPTR_OFFSET     3328
> +#define CIK_WB_CP2_WPTR_OFFSET     3584
>  
>  /**
>   * struct radeon_pm - power management datas
> @@ -1760,6 +1778,7 @@ struct radeon_device {
>  	int msi_enabled; /* msi enabled */
>  	struct r600_ih ih; /* r6/700 interrupt ring */
>  	struct si_rlc rlc;
> +	struct radeon_mec mec;
>  	struct work_struct hotplug_work;
>  	struct work_struct audio_work;
>  	struct work_struct reset_work;
> diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c
> index cf71734..7e265a5 100644
> --- a/drivers/gpu/drm/radeon/radeon_cs.c
> +++ b/drivers/gpu/drm/radeon/radeon_cs.c
> @@ -121,9 +121,7 @@ static int radeon_cs_get_ring(struct radeon_cs_parser *p, u32 ring, s32 priority
>  		p->ring = RADEON_RING_TYPE_GFX_INDEX;
>  		break;
>  	case RADEON_CS_RING_COMPUTE:
> -		if (p->rdev->family >= CHIP_BONAIRE)
> -			p->ring = RADEON_RING_TYPE_GFX_INDEX;
> -		else if (p->rdev->family >= CHIP_TAHITI) {
> +		if (p->rdev->family >= CHIP_TAHITI) {
>  			if (p->priority > 0)
>  				p->ring = CAYMAN_RING_TYPE_CP1_INDEX;
>  			else
> -- 
> 1.7.7.5
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 053/165] drm/radeon/cik: switch to type3 nop packet for compute rings
  2013-06-26 13:22 ` [PATCH 053/165] drm/radeon/cik: switch to type3 nop packet for compute rings alexdeucher
@ 2013-06-26 10:10   ` Jerome Glisse
  0 siblings, 0 replies; 142+ messages in thread
From: Jerome Glisse @ 2013-06-26 10:10 UTC (permalink / raw)
  To: alexdeucher; +Cc: Alex Deucher, dri-devel

On Wed, Jun 26, 2013 at 09:22:13AM -0400, alexdeucher@gmail.com wrote:
> From: Alex Deucher <alexander.deucher@amd.com>
> 
> Type 2 packets are deprecated on CIK MEC and we should use
> type 3 nop packets.  Setting the count field to the max value
> (0x3fff) indicates that only one dword should be skipped
> like a type 2 packet.
> 
> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>

What about adding same comment in the code and not only in git commit
message.

Reviewed-by: Jerome Glisse <jglisse@redhat.com>

> ---
>  drivers/gpu/drm/radeon/cik.c |    4 ++--
>  1 files changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
> index 9d2d6bb..08dc4c2 100644
> --- a/drivers/gpu/drm/radeon/cik.c
> +++ b/drivers/gpu/drm/radeon/cik.c
> @@ -5470,7 +5470,7 @@ static int cik_startup(struct radeon_device *rdev)
>  	ring = &rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX];
>  	r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP1_RPTR_OFFSET,
>  			     CP_HQD_PQ_RPTR, CP_HQD_PQ_WPTR,
> -			     0, 0xfffff, RADEON_CP_PACKET2);
> +			     0, 0xfffff, PACKET3(PACKET3_NOP, 0x3FFF));
>  	if (r)
>  		return r;
>  	ring->me = 1; /* first MEC */
> @@ -5484,7 +5484,7 @@ static int cik_startup(struct radeon_device *rdev)
>  	ring = &rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX];
>  	r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP2_RPTR_OFFSET,
>  			     CP_HQD_PQ_RPTR, CP_HQD_PQ_WPTR,
> -			     0, 0xffffffff, RADEON_CP_PACKET2);
> +			     0, 0xffffffff, PACKET3(PACKET3_NOP, 0x3FFF));
>  	if (r)
>  		return r;
>  	/* dGPU only have 1 MEC */
> -- 
> 1.7.7.5
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 069/165] drm/radeon/kms: add common dpm infrastructure
  2013-06-26 13:22 ` [PATCH 069/165] drm/radeon/kms: add common dpm infrastructure alexdeucher
@ 2013-06-26 10:27   ` Jerome Glisse
  2013-06-27 13:52   ` K. Schnass
  1 sibling, 0 replies; 142+ messages in thread
From: Jerome Glisse @ 2013-06-26 10:27 UTC (permalink / raw)
  To: alexdeucher; +Cc: Alex Deucher, dri-devel

On Wed, Jun 26, 2013 at 09:22:29AM -0400, alexdeucher@gmail.com wrote:
> From: Alex Deucher <alexander.deucher@amd.com>
> 
> This adds the common dpm (dynamic power management)
> infrastructure:
> - dpm callbacks
> - dpm init/fini/suspend/resume
> - dpm power state selection
> 
> No device specific code is enabled yet.
> 
> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>

Reviewed-by: Jerome Glisse <jglisse@redhat.com>

> ---
>  drivers/gpu/drm/radeon/radeon.h     |  100 +++++++-
>  drivers/gpu/drm/radeon/radeon_drv.c |    4 +
>  drivers/gpu/drm/radeon/radeon_pm.c  |  496 ++++++++++++++++++++++++++++++++++-
>  3 files changed, 591 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
> index 6c445f5..c43673c 100644
> --- a/drivers/gpu/drm/radeon/radeon.h
> +++ b/drivers/gpu/drm/radeon/radeon.h
> @@ -96,6 +96,7 @@ extern int radeon_pcie_gen2;
>  extern int radeon_msi;
>  extern int radeon_lockup_timeout;
>  extern int radeon_fastfb;
> +extern int radeon_dpm;
>  
>  /*
>   * Copy from radeon_drv.h so we don't have to include both and have conflicting
> @@ -1048,6 +1049,7 @@ struct radeon_wb {
>  enum radeon_pm_method {
>  	PM_METHOD_PROFILE,
>  	PM_METHOD_DYNPM,
> +	PM_METHOD_DPM,
>  };
>  
>  enum radeon_dynpm_state {
> @@ -1073,11 +1075,23 @@ enum radeon_voltage_type {
>  };
>  
>  enum radeon_pm_state_type {
> +	/* not used for dpm */
>  	POWER_STATE_TYPE_DEFAULT,
>  	POWER_STATE_TYPE_POWERSAVE,
> +	/* user selectable states */
>  	POWER_STATE_TYPE_BATTERY,
>  	POWER_STATE_TYPE_BALANCED,
>  	POWER_STATE_TYPE_PERFORMANCE,
> +	/* internal states */
> +	POWER_STATE_TYPE_INTERNAL_UVD,
> +	POWER_STATE_TYPE_INTERNAL_UVD_SD,
> +	POWER_STATE_TYPE_INTERNAL_UVD_HD,
> +	POWER_STATE_TYPE_INTERNAL_UVD_HD2,
> +	POWER_STATE_TYPE_INTERNAL_UVD_MVC,
> +	POWER_STATE_TYPE_INTERNAL_BOOT,
> +	POWER_STATE_TYPE_INTERNAL_THERMAL,
> +	POWER_STATE_TYPE_INTERNAL_ACPI,
> +	POWER_STATE_TYPE_INTERNAL_ULV,
>  };
>  
>  enum radeon_pm_profile_type {
> @@ -1106,12 +1120,16 @@ struct radeon_pm_profile {
>  
>  enum radeon_int_thermal_type {
>  	THERMAL_TYPE_NONE,
> +	THERMAL_TYPE_EXTERNAL,
> +	THERMAL_TYPE_EXTERNAL_GPIO,
>  	THERMAL_TYPE_RV6XX,
>  	THERMAL_TYPE_RV770,
> +	THERMAL_TYPE_ADT7473_WITH_INTERNAL,
>  	THERMAL_TYPE_EVERGREEN,
>  	THERMAL_TYPE_SUMO,
>  	THERMAL_TYPE_NI,
>  	THERMAL_TYPE_SI,
> +	THERMAL_TYPE_EMC2103_WITH_INTERNAL,
>  	THERMAL_TYPE_CI,
>  };
>  
> @@ -1166,6 +1184,60 @@ struct radeon_power_state {
>   */
>  #define RADEON_MODE_OVERCLOCK_MARGIN 500 /* 5 MHz */
>  
> +struct radeon_ps {
> +	u32 caps; /* vbios flags */
> +	u32 class; /* vbios flags */
> +	u32 class2; /* vbios flags */
> +	/* UVD clocks */
> +	u32 vclk;
> +	u32 dclk;
> +	/* asic priv */
> +	void *ps_priv;
> +};
> +
> +struct radeon_dpm_thermal {
> +	/* thermal interrupt work */
> +	struct work_struct work;
> +	/* low temperature threshold */
> +	int                min_temp;
> +	/* high temperature threshold */
> +	int                max_temp;
> +	/* was interrupt low to high or high to low */
> +	bool               high_to_low;
> +};
> +
> +struct radeon_dpm {
> +	struct radeon_ps        *ps;
> +	/* number of valid power states */
> +	int                     num_ps;
> +	/* current power state that is active */
> +	struct radeon_ps        *current_ps;
> +	/* requested power state */
> +	struct radeon_ps        *requested_ps;
> +	/* boot up power state */
> +	struct radeon_ps        *boot_ps;
> +	/* default uvd power state */
> +	struct radeon_ps        *uvd_ps;
> +	enum radeon_pm_state_type state;
> +	enum radeon_pm_state_type user_state;
> +	u32                     platform_caps;
> +	u32                     voltage_response_time;
> +	u32                     backbias_response_time;
> +	void                    *priv;

Just nitpick all of the above have broken indentation space instead of tab.

> +	u32			new_active_crtcs;
> +	int			new_active_crtc_count;
> +	u32			current_active_crtcs;
> +	int			current_active_crtc_count;
> +	/* special states active */
> +	bool                    thermal_active;
> +	/* thermal handling */
> +	struct radeon_dpm_thermal thermal;
> +};
> +
> +void radeon_dpm_enable_power_state(struct radeon_device *rdev,
> +				    enum radeon_pm_state_type dpm_state);
> +
> +
>  struct radeon_pm {
>  	struct mutex		mutex;
>  	/* write locked while reprogramming mclk */
> @@ -1219,6 +1291,9 @@ struct radeon_pm {
>  	/* internal thermal controller on rv6xx+ */
>  	enum radeon_int_thermal_type int_thermal_type;
>  	struct device	        *int_hwmon_dev;
> +	/* dpm */
> +	bool                    dpm_enabled;
> +	struct radeon_dpm       dpm;
>  };
>  
>  int radeon_pm_get_type_index(struct radeon_device *rdev,
> @@ -1416,7 +1491,7 @@ struct radeon_asic {
>  		bool (*sense)(struct radeon_device *rdev, enum radeon_hpd_id hpd);
>  		void (*set_polarity)(struct radeon_device *rdev, enum radeon_hpd_id hpd);
>  	} hpd;
> -	/* power management */
> +	/* static power management */
>  	struct {
>  		void (*misc)(struct radeon_device *rdev);
>  		void (*prepare)(struct radeon_device *rdev);
> @@ -1433,6 +1508,19 @@ struct radeon_asic {
>  		int (*set_uvd_clocks)(struct radeon_device *rdev, u32 vclk, u32 dclk);
>  		int (*get_temperature)(struct radeon_device *rdev);
>  	} pm;
> +	/* dynamic power management */
> +	struct {
> +		int (*init)(struct radeon_device *rdev);
> +		void (*setup_asic)(struct radeon_device *rdev);
> +		int (*enable)(struct radeon_device *rdev);
> +		void (*disable)(struct radeon_device *rdev);
> +		int (*set_power_state)(struct radeon_device *rdev);
> +		void (*display_configuration_changed)(struct radeon_device *rdev);
> +		void (*fini)(struct radeon_device *rdev);
> +		u32 (*get_sclk)(struct radeon_device *rdev, bool low);
> +		u32 (*get_mclk)(struct radeon_device *rdev, bool low);
> +		void (*print_power_state)(struct radeon_device *rdev, struct radeon_ps *ps);
> +	} dpm;
>  	/* pageflipping */
>  	struct {
>  		void (*pre_page_flip)(struct radeon_device *rdev, int crtc);
> @@ -2122,6 +2210,16 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v);
>  #define radeon_mc_wait_for_idle(rdev) (rdev)->asic->mc_wait_for_idle((rdev))
>  #define radeon_get_xclk(rdev) (rdev)->asic->get_xclk((rdev))
>  #define radeon_get_gpu_clock_counter(rdev) (rdev)->asic->get_gpu_clock_counter((rdev))
> +#define radeon_dpm_init(rdev) rdev->asic->dpm.init((rdev))
> +#define radeon_dpm_setup_asic(rdev) rdev->asic->dpm.setup_asic((rdev))
> +#define radeon_dpm_enable(rdev) rdev->asic->dpm.enable((rdev))
> +#define radeon_dpm_disable(rdev) rdev->asic->dpm.disable((rdev))
> +#define radeon_dpm_set_power_state(rdev) rdev->asic->dpm.set_power_state((rdev))
> +#define radeon_dpm_display_configuration_changed(rdev) rdev->asic->dpm.display_configuration_changed((rdev))
> +#define radeon_dpm_fini(rdev) rdev->asic->dpm.fini((rdev))
> +#define radeon_dpm_get_sclk(rdev, l) rdev->asic->dpm.get_sclk((rdev), (l))
> +#define radeon_dpm_get_mclk(rdev, l) rdev->asic->dpm.get_mclk((rdev), (l))
> +#define radeon_dpm_print_power_state(rdev, ps) rdev->asic->dpm.print_power_state((rdev), (ps))
>  
>  /* Common functions */
>  /* AGP */
> diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c
> index 02709e4..00cc52e 100644
> --- a/drivers/gpu/drm/radeon/radeon_drv.c
> +++ b/drivers/gpu/drm/radeon/radeon_drv.c
> @@ -165,6 +165,7 @@ int radeon_pcie_gen2 = -1;
>  int radeon_msi = -1;
>  int radeon_lockup_timeout = 10000;
>  int radeon_fastfb = 0;
> +int radeon_dpm = -1;
>  
>  MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers");
>  module_param_named(no_wb, radeon_no_wb, int, 0444);
> @@ -220,6 +221,9 @@ module_param_named(lockup_timeout, radeon_lockup_timeout, int, 0444);
>  MODULE_PARM_DESC(fastfb, "Direct FB access for IGP chips (0 = disable, 1 = enable)");
>  module_param_named(fastfb, radeon_fastfb, int, 0444);
>  
> +MODULE_PARM_DESC(dpm, "DPM support (1 = enable, 0 = disable, -1 = auto)");
> +module_param_named(dpm, radeon_dpm, int, 0444);
> +
>  static struct pci_device_id pciidlist[] = {
>  	radeon_PCI_IDS
>  };
> diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
> index e8c1bea..4f5422e 100644
> --- a/drivers/gpu/drm/radeon/radeon_pm.c
> +++ b/drivers/gpu/drm/radeon/radeon_pm.c
> @@ -388,7 +388,8 @@ static ssize_t radeon_get_pm_method(struct device *dev,
>  	int pm = rdev->pm.pm_method;
>  
>  	return snprintf(buf, PAGE_SIZE, "%s\n",
> -			(pm == PM_METHOD_DYNPM) ? "dynpm" : "profile");
> +			(pm == PM_METHOD_DYNPM) ? "dynpm" :
> +			(pm == PM_METHOD_PROFILE) ? "profile" : "dpm");
>  }
>  
>  static ssize_t radeon_set_pm_method(struct device *dev,
> @@ -399,6 +400,11 @@ static ssize_t radeon_set_pm_method(struct device *dev,
>  	struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
>  	struct radeon_device *rdev = ddev->dev_private;
>  
> +	/* we don't support the legacy modes with dpm */
> +	if (rdev->pm.pm_method == PM_METHOD_DPM) {
> +		count = -EINVAL;
> +		goto fail;
> +	}
>  
>  	if (strncmp("dynpm", buf, strlen("dynpm")) == 0) {
>  		mutex_lock(&rdev->pm.mutex);
> @@ -423,8 +429,48 @@ fail:
>  	return count;
>  }
>  
> +static ssize_t radeon_get_dpm_state(struct device *dev,
> +				    struct device_attribute *attr,
> +				    char *buf)
> +{
> +	struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
> +	struct radeon_device *rdev = ddev->dev_private;
> +	enum radeon_pm_state_type pm = rdev->pm.dpm.user_state;
> +
> +	return snprintf(buf, PAGE_SIZE, "%s\n",
> +			(pm == POWER_STATE_TYPE_BATTERY) ? "battery" :
> +			(pm == POWER_STATE_TYPE_BALANCED) ? "balanced" : "performance");
> +}
> +
> +static ssize_t radeon_set_dpm_state(struct device *dev,
> +				    struct device_attribute *attr,
> +				    const char *buf,
> +				    size_t count)
> +{
> +	struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
> +	struct radeon_device *rdev = ddev->dev_private;
> +
> +	mutex_lock(&rdev->pm.mutex);
> +	if (strncmp("battery", buf, strlen("battery")) == 0)
> +		rdev->pm.dpm.user_state = POWER_STATE_TYPE_BATTERY;
> +	else if (strncmp("balanced", buf, strlen("balanced")) == 0)
> +		rdev->pm.dpm.user_state = POWER_STATE_TYPE_BALANCED;
> +	else if (strncmp("performance", buf, strlen("performance")) == 0)
> +		rdev->pm.dpm.user_state = POWER_STATE_TYPE_PERFORMANCE;
> +	else {
> +		mutex_unlock(&rdev->pm.mutex);
> +		count = -EINVAL;
> +		goto fail;
> +	}
> +	mutex_unlock(&rdev->pm.mutex);
> +	radeon_pm_compute_clocks(rdev);
> +fail:
> +	return count;
> +}
> +
>  static DEVICE_ATTR(power_profile, S_IRUGO | S_IWUSR, radeon_get_pm_profile, radeon_set_pm_profile);
>  static DEVICE_ATTR(power_method, S_IRUGO | S_IWUSR, radeon_get_pm_method, radeon_set_pm_method);
> +static DEVICE_ATTR(power_dpm_state, S_IRUGO | S_IWUSR, radeon_get_dpm_state, radeon_set_dpm_state);
>  
>  static ssize_t radeon_hwmon_show_temp(struct device *dev,
>  				      struct device_attribute *attr,
> @@ -508,7 +554,228 @@ static void radeon_hwmon_fini(struct radeon_device *rdev)
>  	}
>  }
>  
> -void radeon_pm_suspend(struct radeon_device *rdev)
> +static void radeon_dpm_thermal_work_handler(struct work_struct *work)
> +{
> +	struct radeon_device *rdev =
> +		container_of(work, struct radeon_device,
> +			     pm.dpm.thermal.work);
> +	/* switch to the thermal state */
> +	enum radeon_pm_state_type dpm_state = POWER_STATE_TYPE_INTERNAL_THERMAL;
> +
> +	if (!rdev->pm.dpm_enabled)
> +		return;
> +
> +	if (rdev->asic->pm.get_temperature) {
> +		int temp = radeon_get_temperature(rdev);
> +
> +		if (temp < rdev->pm.dpm.thermal.min_temp)
> +			/* switch back the user state */
> +			dpm_state = rdev->pm.dpm.user_state;
> +	} else {
> +		if (rdev->pm.dpm.thermal.high_to_low)
> +			/* switch back the user state */
> +			dpm_state = rdev->pm.dpm.user_state;
> +	}
> +	radeon_dpm_enable_power_state(rdev, dpm_state);
> +}
> +
> +static struct radeon_ps *radeon_dpm_pick_power_state(struct radeon_device *rdev,
> +						     enum radeon_pm_state_type dpm_state)
> +{
> +	int i;
> +	struct radeon_ps *ps;
> +	u32 ui_class;
> +
> +restart_search:
> +	/* balanced states don't exist at the moment */
> +	if (dpm_state == POWER_STATE_TYPE_BALANCED)
> +		dpm_state = POWER_STATE_TYPE_PERFORMANCE;
> +
> +	/* Pick the best power state based on current conditions */
> +	for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
> +		ps = &rdev->pm.dpm.ps[i];
> +		ui_class = ps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK;
> +		switch (dpm_state) {
> +		/* user states */
> +		case POWER_STATE_TYPE_BATTERY:
> +			if (ui_class == ATOM_PPLIB_CLASSIFICATION_UI_BATTERY) {
> +				if (ps->caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) {
> +					if (rdev->pm.dpm.new_active_crtc_count < 2)
> +						return ps;
> +				} else
> +					return ps;
> +			}
> +			break;
> +		case POWER_STATE_TYPE_BALANCED:
> +			if (ui_class == ATOM_PPLIB_CLASSIFICATION_UI_BALANCED) {
> +				if (ps->caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) {
> +					if (rdev->pm.dpm.new_active_crtc_count < 2)
> +						return ps;
> +				} else
> +					return ps;
> +			}
> +			break;
> +		case POWER_STATE_TYPE_PERFORMANCE:
> +			if (ui_class == ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE) {
> +				if (ps->caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) {
> +					if (rdev->pm.dpm.new_active_crtc_count < 2)
> +						return ps;
> +				} else
> +					return ps;
> +			}
> +			break;
> +		/* internal states */
> +		case POWER_STATE_TYPE_INTERNAL_UVD:
> +			return rdev->pm.dpm.uvd_ps;
> +		case POWER_STATE_TYPE_INTERNAL_UVD_SD:
> +			if (ps->class & ATOM_PPLIB_CLASSIFICATION_SDSTATE)
> +				return ps;
> +			break;
> +		case POWER_STATE_TYPE_INTERNAL_UVD_HD:
> +			if (ps->class & ATOM_PPLIB_CLASSIFICATION_HDSTATE)
> +				return ps;
> +			break;
> +		case POWER_STATE_TYPE_INTERNAL_UVD_HD2:
> +			if (ps->class & ATOM_PPLIB_CLASSIFICATION_HD2STATE)
> +				return ps;
> +			break;
> +		case POWER_STATE_TYPE_INTERNAL_UVD_MVC:
> +			if (ps->class2 & ATOM_PPLIB_CLASSIFICATION2_MVC)
> +				return ps;
> +			break;
> +		case POWER_STATE_TYPE_INTERNAL_BOOT:
> +			return rdev->pm.dpm.boot_ps;
> +		case POWER_STATE_TYPE_INTERNAL_THERMAL:
> +			if (ps->class & ATOM_PPLIB_CLASSIFICATION_THERMAL)
> +				return ps;
> +			break;
> +		case POWER_STATE_TYPE_INTERNAL_ACPI:
> +			if (ps->class & ATOM_PPLIB_CLASSIFICATION_ACPI)
> +				return ps;
> +			break;
> +		case POWER_STATE_TYPE_INTERNAL_ULV:
> +			if (ps->class2 & ATOM_PPLIB_CLASSIFICATION2_ULV)
> +				return ps;
> +			break;
> +		default:
> +			break;
> +		}
> +	}
> +	/* use a fallback state if we didn't match */
> +	switch (dpm_state) {
> +	case POWER_STATE_TYPE_INTERNAL_UVD_SD:
> +	case POWER_STATE_TYPE_INTERNAL_UVD_HD:
> +	case POWER_STATE_TYPE_INTERNAL_UVD_HD2:
> +	case POWER_STATE_TYPE_INTERNAL_UVD_MVC:
> +		return rdev->pm.dpm.uvd_ps;
> +	case POWER_STATE_TYPE_INTERNAL_THERMAL:
> +		dpm_state = POWER_STATE_TYPE_INTERNAL_ACPI;
> +		goto restart_search;
> +	case POWER_STATE_TYPE_INTERNAL_ACPI:
> +		dpm_state = POWER_STATE_TYPE_BATTERY;
> +		goto restart_search;
> +	case POWER_STATE_TYPE_BATTERY:
> +		dpm_state = POWER_STATE_TYPE_PERFORMANCE;
> +		goto restart_search;
> +	default:
> +		break;
> +	}
> +
> +	return NULL;
> +}
> +
> +static void radeon_dpm_change_power_state_locked(struct radeon_device *rdev)
> +{
> +	int i;
> +	struct radeon_ps *ps;
> +	enum radeon_pm_state_type dpm_state;
> +
> +	/* if dpm init failed */
> +	if (!rdev->pm.dpm_enabled)
> +		return;
> +
> +	if (rdev->pm.dpm.user_state != rdev->pm.dpm.state) {
> +		/* add other state override checks here */
> +		if (!rdev->pm.dpm.thermal_active)
> +			rdev->pm.dpm.state = rdev->pm.dpm.user_state;
> +	}
> +	dpm_state = rdev->pm.dpm.state;
> +
> +	ps = radeon_dpm_pick_power_state(rdev, dpm_state);
> +	if (ps)
> +		rdev->pm.dpm.requested_ps = ps;
> +	else
> +		return;
> +
> +	/* no need to reprogram if nothing changed */
> +	if (rdev->pm.dpm.current_ps == rdev->pm.dpm.requested_ps) {
> +		/* update display watermarks based on new power state */
> +		if (rdev->pm.dpm.new_active_crtcs != rdev->pm.dpm.current_active_crtcs) {
> +			radeon_bandwidth_update(rdev);
> +			/* update displays */
> +			radeon_dpm_display_configuration_changed(rdev);
> +			rdev->pm.dpm.current_active_crtcs = rdev->pm.dpm.new_active_crtcs;
> +			rdev->pm.dpm.current_active_crtc_count = rdev->pm.dpm.new_active_crtc_count;
> +		}
> +		return;
> +	}
> +
> +	printk("switching from power state:\n");
> +	radeon_dpm_print_power_state(rdev, rdev->pm.dpm.current_ps);
> +	printk("switching to power state:\n");
> +	radeon_dpm_print_power_state(rdev, rdev->pm.dpm.requested_ps);
> +
> +	mutex_lock(&rdev->ddev->struct_mutex);
> +	down_write(&rdev->pm.mclk_lock);
> +	mutex_lock(&rdev->ring_lock);
> +
> +	/* update display watermarks based on new power state */
> +	radeon_bandwidth_update(rdev);
> +	/* update displays */
> +	radeon_dpm_display_configuration_changed(rdev);
> +
> +	rdev->pm.dpm.current_active_crtcs = rdev->pm.dpm.new_active_crtcs;
> +	rdev->pm.dpm.current_active_crtc_count = rdev->pm.dpm.new_active_crtc_count;
> +
> +	/* wait for the rings to drain */
> +	for (i = 0; i < RADEON_NUM_RINGS; i++) {
> +		struct radeon_ring *ring = &rdev->ring[i];
> +		if (ring->ready)
> +			radeon_fence_wait_empty_locked(rdev, i);
> +	}
> +
> +	/* program the new power state */
> +	radeon_dpm_set_power_state(rdev);
> +
> +	/* update current power state */
> +	rdev->pm.dpm.current_ps = rdev->pm.dpm.requested_ps;
> +
> +	mutex_unlock(&rdev->ring_lock);
> +	up_write(&rdev->pm.mclk_lock);
> +	mutex_unlock(&rdev->ddev->struct_mutex);
> +}
> +
> +void radeon_dpm_enable_power_state(struct radeon_device *rdev,
> +				   enum radeon_pm_state_type dpm_state)
> +{
> +	if (!rdev->pm.dpm_enabled)
> +		return;
> +
> +	mutex_lock(&rdev->pm.mutex);
> +	switch (dpm_state) {
> +	case POWER_STATE_TYPE_INTERNAL_THERMAL:
> +		rdev->pm.dpm.thermal_active = true;
> +		break;
> +	default:
> +		rdev->pm.dpm.thermal_active = false;
> +		break;
> +	}
> +	rdev->pm.dpm.state = dpm_state;
> +	mutex_unlock(&rdev->pm.mutex);
> +	radeon_pm_compute_clocks(rdev);
> +}
> +
> +static void radeon_pm_suspend_old(struct radeon_device *rdev)
>  {
>  	mutex_lock(&rdev->pm.mutex);
>  	if (rdev->pm.pm_method == PM_METHOD_DYNPM) {
> @@ -520,7 +787,26 @@ void radeon_pm_suspend(struct radeon_device *rdev)
>  	cancel_delayed_work_sync(&rdev->pm.dynpm_idle_work);
>  }
>  
> -void radeon_pm_resume(struct radeon_device *rdev)
> +static void radeon_pm_suspend_dpm(struct radeon_device *rdev)
> +{
> +	mutex_lock(&rdev->pm.mutex);
> +	/* disable dpm */
> +	radeon_dpm_disable(rdev);
> +	/* reset the power state */
> +	rdev->pm.dpm.current_ps = rdev->pm.dpm.requested_ps = rdev->pm.dpm.boot_ps;
> +	rdev->pm.dpm_enabled = false;
> +	mutex_unlock(&rdev->pm.mutex);
> +}
> +
> +void radeon_pm_suspend(struct radeon_device *rdev)
> +{
> +	if (rdev->pm.pm_method == PM_METHOD_DPM)
> +		radeon_pm_suspend_dpm(rdev);
> +	else
> +		radeon_pm_suspend_old(rdev);
> +}
> +
> +static void radeon_pm_resume_old(struct radeon_device *rdev)
>  {
>  	/* set up the default clocks if the MC ucode is loaded */
>  	if ((rdev->family >= CHIP_BARTS) &&
> @@ -555,12 +841,50 @@ void radeon_pm_resume(struct radeon_device *rdev)
>  	radeon_pm_compute_clocks(rdev);
>  }
>  
> -int radeon_pm_init(struct radeon_device *rdev)
> +static void radeon_pm_resume_dpm(struct radeon_device *rdev)
> +{
> +	int ret;
> +
> +	/* asic init will reset to the boot state */
> +	mutex_lock(&rdev->pm.mutex);
> +	rdev->pm.dpm.current_ps = rdev->pm.dpm.requested_ps = rdev->pm.dpm.boot_ps;
> +	radeon_dpm_setup_asic(rdev);
> +	ret = radeon_dpm_enable(rdev);
> +	mutex_unlock(&rdev->pm.mutex);
> +	if (ret) {
> +		DRM_ERROR("radeon: dpm resume failed\n");
> +		if ((rdev->family >= CHIP_BARTS) &&
> +		    (rdev->family <= CHIP_CAYMAN) &&
> +		    rdev->mc_fw) {
> +			if (rdev->pm.default_vddc)
> +				radeon_atom_set_voltage(rdev, rdev->pm.default_vddc,
> +							SET_VOLTAGE_TYPE_ASIC_VDDC);
> +			if (rdev->pm.default_vddci)
> +				radeon_atom_set_voltage(rdev, rdev->pm.default_vddci,
> +							SET_VOLTAGE_TYPE_ASIC_VDDCI);
> +			if (rdev->pm.default_sclk)
> +				radeon_set_engine_clock(rdev, rdev->pm.default_sclk);
> +			if (rdev->pm.default_mclk)
> +				radeon_set_memory_clock(rdev, rdev->pm.default_mclk);
> +		}
> +	} else {
> +		rdev->pm.dpm_enabled = true;
> +		radeon_pm_compute_clocks(rdev);
> +	}
> +}
> +
> +void radeon_pm_resume(struct radeon_device *rdev)
> +{
> +	if (rdev->pm.pm_method == PM_METHOD_DPM)
> +		radeon_pm_resume_dpm(rdev);
> +	else
> +		radeon_pm_resume_old(rdev);
> +}
> +
> +static int radeon_pm_init_old(struct radeon_device *rdev)
>  {
>  	int ret;
>  
> -	/* default to profile method */
> -	rdev->pm.pm_method = PM_METHOD_PROFILE;
>  	rdev->pm.profile = PM_PROFILE_DEFAULT;
>  	rdev->pm.dynpm_state = DYNPM_STATE_DISABLED;
>  	rdev->pm.dynpm_planned_action = DYNPM_ACTION_NONE;
> @@ -622,7 +946,103 @@ int radeon_pm_init(struct radeon_device *rdev)
>  	return 0;
>  }
>  
> -void radeon_pm_fini(struct radeon_device *rdev)
> +static void radeon_dpm_print_power_states(struct radeon_device *rdev)
> +{
> +	int i;
> +
> +	for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
> +		printk("== power state %d ==\n", i);
> +		radeon_dpm_print_power_state(rdev, &rdev->pm.dpm.ps[i]);
> +	}
> +}
> +
> +static int radeon_pm_init_dpm(struct radeon_device *rdev)
> +{
> +	int ret;
> +
> +	/* default to performance state */
> +	rdev->pm.dpm.state = POWER_STATE_TYPE_PERFORMANCE;
> +	rdev->pm.dpm.user_state = POWER_STATE_TYPE_PERFORMANCE;
> +	rdev->pm.default_sclk = rdev->clock.default_sclk;
> +	rdev->pm.default_mclk = rdev->clock.default_mclk;
> +	rdev->pm.current_sclk = rdev->clock.default_sclk;
> +	rdev->pm.current_mclk = rdev->clock.default_mclk;
> +	rdev->pm.int_thermal_type = THERMAL_TYPE_NONE;
> +
> +	if (rdev->bios && rdev->is_atom_bios)
> +		radeon_atombios_get_power_modes(rdev);
> +	else
> +		return -EINVAL;
> +
> +	/* set up the internal thermal sensor if applicable */
> +	ret = radeon_hwmon_init(rdev);
> +	if (ret)
> +		return ret;
> +
> +	INIT_WORK(&rdev->pm.dpm.thermal.work, radeon_dpm_thermal_work_handler);
> +	mutex_lock(&rdev->pm.mutex);
> +	radeon_dpm_init(rdev);
> +	rdev->pm.dpm.current_ps = rdev->pm.dpm.requested_ps = rdev->pm.dpm.boot_ps;
> +	radeon_dpm_print_power_states(rdev);
> +	radeon_dpm_setup_asic(rdev);
> +	ret = radeon_dpm_enable(rdev);
> +	mutex_unlock(&rdev->pm.mutex);
> +	if (ret) {
> +		rdev->pm.dpm_enabled = false;
> +		if ((rdev->family >= CHIP_BARTS) &&
> +		    (rdev->family <= CHIP_CAYMAN) &&
> +		    rdev->mc_fw) {
> +			if (rdev->pm.default_vddc)
> +				radeon_atom_set_voltage(rdev, rdev->pm.default_vddc,
> +							SET_VOLTAGE_TYPE_ASIC_VDDC);
> +			if (rdev->pm.default_vddci)
> +				radeon_atom_set_voltage(rdev, rdev->pm.default_vddci,
> +							SET_VOLTAGE_TYPE_ASIC_VDDCI);
> +			if (rdev->pm.default_sclk)
> +				radeon_set_engine_clock(rdev, rdev->pm.default_sclk);
> +			if (rdev->pm.default_mclk)
> +				radeon_set_memory_clock(rdev, rdev->pm.default_mclk);
> +		}
> +		DRM_ERROR("radeon: dpm initialization failed\n");
> +		return ret;
> +	}
> +	rdev->pm.dpm_enabled = true;
> +	radeon_pm_compute_clocks(rdev);
> +
> +	if (rdev->pm.num_power_states > 1) {
> +		ret = device_create_file(rdev->dev, &dev_attr_power_dpm_state);
> +		if (ret)
> +			DRM_ERROR("failed to create device file for dpm state\n");
> +		/* XXX: these are noops for dpm but are here for backwards compat */
> +		ret = device_create_file(rdev->dev, &dev_attr_power_profile);
> +		if (ret)
> +			DRM_ERROR("failed to create device file for power profile\n");
> +		ret = device_create_file(rdev->dev, &dev_attr_power_method);
> +		if (ret)
> +			DRM_ERROR("failed to create device file for power method\n");
> +		DRM_INFO("radeon: dpm initialized\n");
> +	}
> +
> +	return 0;
> +}
> +
> +int radeon_pm_init(struct radeon_device *rdev)
> +{
> +	/* enable dpm on rv6xx+ */
> +	switch (rdev->family) {
> +	default:
> +		/* default to profile method */
> +		rdev->pm.pm_method = PM_METHOD_PROFILE;
> +		break;
> +	}
> +
> +	if (rdev->pm.pm_method == PM_METHOD_DPM)
> +		return radeon_pm_init_dpm(rdev);
> +	else
> +		return radeon_pm_init_old(rdev);
> +}
> +
> +static void radeon_pm_fini_old(struct radeon_device *rdev)
>  {
>  	if (rdev->pm.num_power_states > 1) {
>  		mutex_lock(&rdev->pm.mutex);
> @@ -650,7 +1070,35 @@ void radeon_pm_fini(struct radeon_device *rdev)
>  	radeon_hwmon_fini(rdev);
>  }
>  
> -void radeon_pm_compute_clocks(struct radeon_device *rdev)
> +static void radeon_pm_fini_dpm(struct radeon_device *rdev)
> +{
> +	if (rdev->pm.num_power_states > 1) {
> +		mutex_lock(&rdev->pm.mutex);
> +		radeon_dpm_disable(rdev);
> +		mutex_unlock(&rdev->pm.mutex);
> +
> +		device_remove_file(rdev->dev, &dev_attr_power_dpm_state);
> +		/* XXX backwards compat */
> +		device_remove_file(rdev->dev, &dev_attr_power_profile);
> +		device_remove_file(rdev->dev, &dev_attr_power_method);
> +	}
> +	radeon_dpm_fini(rdev);
> +
> +	if (rdev->pm.power_state)
> +		kfree(rdev->pm.power_state);
> +
> +	radeon_hwmon_fini(rdev);
> +}
> +
> +void radeon_pm_fini(struct radeon_device *rdev)
> +{
> +	if (rdev->pm.pm_method == PM_METHOD_DPM)
> +		radeon_pm_fini_dpm(rdev);
> +	else
> +		radeon_pm_fini_old(rdev);
> +}
> +
> +static void radeon_pm_compute_clocks_old(struct radeon_device *rdev)
>  {
>  	struct drm_device *ddev = rdev->ddev;
>  	struct drm_crtc *crtc;
> @@ -721,6 +1169,38 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev)
>  	mutex_unlock(&rdev->pm.mutex);
>  }
>  
> +static void radeon_pm_compute_clocks_dpm(struct radeon_device *rdev)
> +{
> +	struct drm_device *ddev = rdev->ddev;
> +	struct drm_crtc *crtc;
> +	struct radeon_crtc *radeon_crtc;
> +
> +	mutex_lock(&rdev->pm.mutex);
> +
> +	rdev->pm.dpm.new_active_crtcs = 0;
> +	rdev->pm.dpm.new_active_crtc_count = 0;
> +	list_for_each_entry(crtc,
> +		&ddev->mode_config.crtc_list, head) {
> +		radeon_crtc = to_radeon_crtc(crtc);
> +		if (crtc->enabled) {
> +			rdev->pm.dpm.new_active_crtcs |= (1 << radeon_crtc->crtc_id);
> +			rdev->pm.dpm.new_active_crtc_count++;
> +		}
> +	}
> +
> +	radeon_dpm_change_power_state_locked(rdev);
> +
> +	mutex_unlock(&rdev->pm.mutex);
> +}
> +
> +void radeon_pm_compute_clocks(struct radeon_device *rdev)
> +{
> +	if (rdev->pm.pm_method == PM_METHOD_DPM)
> +		radeon_pm_compute_clocks_dpm(rdev);
> +	else
> +		radeon_pm_compute_clocks_old(rdev);
> +}
> +
>  static bool radeon_pm_in_vbl(struct radeon_device *rdev)
>  {
>  	int  crtc, vpos, hpos, vbl_status;
> -- 
> 1.7.7.5
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 075/165] drm/radeon/kms: add dpm support for rs780/rs880
  2013-06-26 13:22 ` [PATCH 075/165] drm/radeon/kms: add dpm support for rs780/rs880 alexdeucher
@ 2013-06-26 10:46   ` Jerome Glisse
  2013-06-26 18:19     ` Alex Deucher
  0 siblings, 1 reply; 142+ messages in thread
From: Jerome Glisse @ 2013-06-26 10:46 UTC (permalink / raw)
  To: alexdeucher; +Cc: Alex Deucher, dri-devel

On Wed, Jun 26, 2013 at 09:22:35AM -0400, alexdeucher@gmail.com wrote:
> From: Alex Deucher <alexander.deucher@amd.com>
> 
> This adds dpm support for rs780/rs880 asics.  This includes:
> - clockgating
> - dynamic engine clock scaling
> - dynamic voltage scaling
> 
> set radeon.dpm=1 to enable it.
> 
> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>

Depending on the answer to inline question :

Reviewed-by: Jerome Glisse <jglisse@redhat.com>

> ---
>  drivers/gpu/drm/radeon/Makefile      |    2 +-
>  drivers/gpu/drm/radeon/radeon_asic.c |   12 +
>  drivers/gpu/drm/radeon/radeon_asic.h |   12 +
>  drivers/gpu/drm/radeon/radeon_pm.c   |    7 +
>  drivers/gpu/drm/radeon/rs780_dpm.c   |  894 ++++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/radeon/rs780_dpm.h   |  109 ++++
>  drivers/gpu/drm/radeon/rs780d.h      |  168 +++++++
>  7 files changed, 1203 insertions(+), 1 deletions(-)
>  create mode 100644 drivers/gpu/drm/radeon/rs780_dpm.c
>  create mode 100644 drivers/gpu/drm/radeon/rs780_dpm.h
>  create mode 100644 drivers/gpu/drm/radeon/rs780d.h
> 
> diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile
> index a131a13..e44b046 100644
> --- a/drivers/gpu/drm/radeon/Makefile
> +++ b/drivers/gpu/drm/radeon/Makefile
> @@ -77,7 +77,7 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \
>  	evergreen_hdmi.o radeon_trace_points.o ni.o cayman_blit_shaders.o \
>  	atombios_encoders.o radeon_semaphore.o radeon_sa.o atombios_i2c.o si.o \
>  	si_blit_shaders.o radeon_prime.o radeon_uvd.o cik.o cik_blit_shaders.o \
> -	r600_dpm.o
> +	r600_dpm.o rs780_dpm.o
>  
>  radeon-$(CONFIG_COMPAT) += radeon_ioc32.o
>  radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o
> diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c
> index d9c8e9a..db3c930 100644
> --- a/drivers/gpu/drm/radeon/radeon_asic.c
> +++ b/drivers/gpu/drm/radeon/radeon_asic.c
> @@ -1194,6 +1194,18 @@ static struct radeon_asic rs780_asic = {
>  		.set_clock_gating = NULL,
>  		.get_temperature = &rv6xx_get_temp,
>  	},
> +	.dpm = {
> +		.init = &rs780_dpm_init,
> +		.setup_asic = &rs780_dpm_setup_asic,
> +		.enable = &rs780_dpm_enable,
> +		.disable = &rs780_dpm_disable,
> +		.set_power_state = &rs780_dpm_set_power_state,
> +		.display_configuration_changed = &rs780_dpm_display_configuration_changed,
> +		.fini = &rs780_dpm_fini,
> +		.get_sclk = &rs780_dpm_get_sclk,
> +		.get_mclk = &rs780_dpm_get_mclk,
> +		.print_power_state = &rs780_dpm_print_power_state,
> +	},
>  	.pflip = {
>  		.pre_page_flip = &rs600_pre_page_flip,
>  		.page_flip = &rs600_page_flip,
> diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
> index 8507cae..134bf57 100644
> --- a/drivers/gpu/drm/radeon/radeon_asic.h
> +++ b/drivers/gpu/drm/radeon/radeon_asic.h
> @@ -396,6 +396,18 @@ int r600_mc_wait_for_idle(struct radeon_device *rdev);
>  u32 r600_get_xclk(struct radeon_device *rdev);
>  uint64_t r600_get_gpu_clock_counter(struct radeon_device *rdev);
>  int rv6xx_get_temp(struct radeon_device *rdev);
> +/* rs780 dpm */
> +int rs780_dpm_init(struct radeon_device *rdev);
> +int rs780_dpm_enable(struct radeon_device *rdev);
> +void rs780_dpm_disable(struct radeon_device *rdev);
> +int rs780_dpm_set_power_state(struct radeon_device *rdev);
> +void rs780_dpm_setup_asic(struct radeon_device *rdev);
> +void rs780_dpm_display_configuration_changed(struct radeon_device *rdev);
> +void rs780_dpm_fini(struct radeon_device *rdev);
> +u32 rs780_dpm_get_sclk(struct radeon_device *rdev, bool low);
> +u32 rs780_dpm_get_mclk(struct radeon_device *rdev, bool low);
> +void rs780_dpm_print_power_state(struct radeon_device *rdev,
> +				 struct radeon_ps *ps);
>  
>  /* uvd */
>  int r600_uvd_init(struct radeon_device *rdev);
> diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
> index 4f5422e..853a8a2 100644
> --- a/drivers/gpu/drm/radeon/radeon_pm.c
> +++ b/drivers/gpu/drm/radeon/radeon_pm.c
> @@ -1030,6 +1030,13 @@ int radeon_pm_init(struct radeon_device *rdev)
>  {
>  	/* enable dpm on rv6xx+ */
>  	switch (rdev->family) {
> +	case CHIP_RS780:
> +	case CHIP_RS880:
> +		if (radeon_dpm == 1)
> +			rdev->pm.pm_method = PM_METHOD_DPM;
> +		else
> +			rdev->pm.pm_method = PM_METHOD_PROFILE;
> +		break;
>  	default:
>  		/* default to profile method */
>  		rdev->pm.pm_method = PM_METHOD_PROFILE;
> diff --git a/drivers/gpu/drm/radeon/rs780_dpm.c b/drivers/gpu/drm/radeon/rs780_dpm.c
> new file mode 100644
> index 0000000..f594900
> --- /dev/null
> +++ b/drivers/gpu/drm/radeon/rs780_dpm.c
> @@ -0,0 +1,894 @@
> +/*
> + * Copyright 2011 Advanced Micro Devices, Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + *
> + * Authors: Alex Deucher
> + */
> +
> +#include "drmP.h"
> +#include "radeon.h"
> +#include "rs780d.h"
> +#include "r600_dpm.h"
> +#include "rs780_dpm.h"
> +#include "atom.h"
> +
> +static struct igp_ps *rs780_get_ps(struct radeon_ps *rps)
> +{
> +	struct igp_ps *ps = rps->ps_priv;
> +
> +	return ps;
> +}
> +
> +static struct igp_power_info *rs780_get_pi(struct radeon_device *rdev)
> +{
> +	struct igp_power_info *pi = rdev->pm.dpm.priv;
> +
> +	return pi;
> +}
> +
> +static void rs780_get_pm_mode_parameters(struct radeon_device *rdev)
> +{
> +	struct igp_power_info *pi = rs780_get_pi(rdev);
> +	struct radeon_mode_info *minfo = &rdev->mode_info;
> +	struct drm_crtc *crtc;
> +	struct radeon_crtc *radeon_crtc;
> +	int i;
> +
> +	/* defaults */
> +	pi->crtc_id = 0;
> +	pi->refresh_rate = 60;
> +
> +	for (i = 0; i < rdev->num_crtc; i++) {
> +		crtc = (struct drm_crtc *)minfo->crtcs[i];
> +		if (crtc && crtc->enabled) {
> +			radeon_crtc = to_radeon_crtc(crtc);
> +			pi->crtc_id = radeon_crtc->crtc_id;
> +			if (crtc->mode.htotal && crtc->mode.vtotal)
> +				pi->refresh_rate =
> +					(crtc->mode.clock * 1000) /
> +					(crtc->mode.htotal * crtc->mode.vtotal);
> +			break;
> +		}
> +	}

Ok this looks wrong to me you look for the first enabled crtc but on those iirc
there could be 2 so first one might be a low refresh rate and second one an higher
one. Thus returning the first one might lead to PM decision that are wrong.

> +}
> +
> +static void rs780_voltage_scaling_enable(struct radeon_device *rdev, bool enable);
> +
> +static int rs780_initialize_dpm_power_state(struct radeon_device *rdev)
> +{
> +	struct atom_clock_dividers dividers;
> +	struct igp_ps *default_state = rs780_get_ps(rdev->pm.dpm.boot_ps);
> +	int i, ret;
> +
> +	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
> +					     default_state->sclk_low, false, &dividers);
> +	if (ret)
> +		return ret;
> +
> +	r600_engine_clock_entry_set_reference_divider(rdev, 0, dividers.ref_div);
> +	r600_engine_clock_entry_set_feedback_divider(rdev, 0, dividers.fb_div);
> +	r600_engine_clock_entry_set_post_divider(rdev, 0, dividers.post_div);
> +
> +	if (dividers.enable_post_div)
> +		r600_engine_clock_entry_enable_post_divider(rdev, 0, true);
> +	else
> +		r600_engine_clock_entry_enable_post_divider(rdev, 0, false);
> +
> +	r600_engine_clock_entry_set_step_time(rdev, 0, R600_SST_DFLT);
> +	r600_engine_clock_entry_enable_pulse_skipping(rdev, 0, false);
> +
> +	r600_engine_clock_entry_enable(rdev, 0, true);
> +	for (i = 1; i < R600_PM_NUMBER_OF_SCLKS; i++)
> +		r600_engine_clock_entry_enable(rdev, i, false);
> +
> +	r600_enable_mclk_control(rdev, false);
> +	r600_voltage_control_enable_pins(rdev, 0);
> +
> +	return 0;
> +}
> +
> +static int rs780_initialize_dpm_parameters(struct radeon_device *rdev)
> +{
> +	int ret = 0;
> +	int i;
> +
> +	r600_set_bsp(rdev, R600_BSU_DFLT, R600_BSP_DFLT);
> +
> +	r600_set_at(rdev, 0, 0, 0, 0);
> +
> +	r600_set_git(rdev, R600_GICST_DFLT);
> +
> +	for (i = 0; i < R600_PM_NUMBER_OF_TC; i++)
> +		r600_set_tc(rdev, i, 0, 0);
> +
> +	r600_select_td(rdev, R600_TD_DFLT);
> +	r600_set_vrc(rdev, 0);
> +
> +	r600_set_tpu(rdev, R600_TPU_DFLT);
> +	r600_set_tpc(rdev, R600_TPC_DFLT);
> +
> +	r600_set_sstu(rdev, R600_SSTU_DFLT);
> +	r600_set_sst(rdev, R600_SST_DFLT);
> +
> +	r600_set_fctu(rdev, R600_FCTU_DFLT);
> +	r600_set_fct(rdev, R600_FCT_DFLT);
> +
> +	r600_set_vddc3d_oorsu(rdev, R600_VDDC3DOORSU_DFLT);
> +	r600_set_vddc3d_oorphc(rdev, R600_VDDC3DOORPHC_DFLT);
> +	r600_set_vddc3d_oorsdc(rdev, R600_VDDC3DOORSDC_DFLT);
> +	r600_set_ctxcgtt3d_rphc(rdev, R600_CTXCGTT3DRPHC_DFLT);
> +	r600_set_ctxcgtt3d_rsdc(rdev, R600_CTXCGTT3DRSDC_DFLT);
> +
> +	r600_vid_rt_set_vru(rdev, R600_VRU_DFLT);
> +	r600_vid_rt_set_vrt(rdev, R600_VOLTAGERESPONSETIME_DFLT);
> +	r600_vid_rt_set_ssu(rdev, R600_SPLLSTEPUNIT_DFLT);
> +
> +	ret = rs780_initialize_dpm_power_state(rdev);
> +
> +	r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_LOW,     0);
> +	r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_MEDIUM,  0);
> +	r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_HIGH,    0);
> +
> +	r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_LOW,    0);
> +	r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_MEDIUM, 0);
> +	r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_HIGH,   0);
> +
> +	r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_LOW,    0);
> +	r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_MEDIUM, 0);
> +	r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_HIGH,   0);
> +
> +	r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_LOW,    R600_DISPLAY_WATERMARK_HIGH);
> +	r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_MEDIUM, R600_DISPLAY_WATERMARK_HIGH);
> +	r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_HIGH,   R600_DISPLAY_WATERMARK_HIGH);
> +
> +	r600_power_level_enable(rdev, R600_POWER_LEVEL_CTXSW, false);
> +	r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, false);
> +	r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, false);
> +	r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true);
> +
> +	r600_power_level_set_enter_index(rdev, R600_POWER_LEVEL_LOW);
> +
> +	r600_set_vrc(rdev, RS780_CGFTV_DFLT);
> +
> +	return ret;
> +}
> +
> +static void rs780_start_dpm(struct radeon_device *rdev)
> +{
> +	r600_enable_sclk_control(rdev, false);
> +	r600_enable_mclk_control(rdev, false);
> +
> +	r600_dynamicpm_enable(rdev, true);
> +
> +	radeon_wait_for_vblank(rdev, 0);
> +	radeon_wait_for_vblank(rdev, 1);
> +
> +	r600_enable_spll_bypass(rdev, true);
> +	r600_wait_for_spll_change(rdev);
> +	r600_enable_spll_bypass(rdev, false);
> +	r600_wait_for_spll_change(rdev);
> +
> +	r600_enable_spll_bypass(rdev, true);
> +	r600_wait_for_spll_change(rdev);
> +	r600_enable_spll_bypass(rdev, false);
> +	r600_wait_for_spll_change(rdev);
> +
> +	r600_enable_sclk_control(rdev, true);
> +}
> +
> +
> +static void rs780_preset_ranges_slow_clk_fbdiv_en(struct radeon_device *rdev)
> +{
> +	WREG32_P(FVTHROT_SLOW_CLK_FEEDBACK_DIV_REG1, RANGE_SLOW_CLK_FEEDBACK_DIV_EN,
> +		 ~RANGE_SLOW_CLK_FEEDBACK_DIV_EN);
> +
> +	WREG32_P(FVTHROT_SLOW_CLK_FEEDBACK_DIV_REG1,
> +		 RANGE0_SLOW_CLK_FEEDBACK_DIV(RS780_SLOWCLKFEEDBACKDIV_DFLT),
> +		 ~RANGE0_SLOW_CLK_FEEDBACK_DIV_MASK);
> +}
> +
> +static void rs780_preset_starting_fbdiv(struct radeon_device *rdev)
> +{
> +	u32 fbdiv = (RREG32(CG_SPLL_FUNC_CNTL) & SPLL_FB_DIV_MASK) >> SPLL_FB_DIV_SHIFT;
> +
> +	WREG32_P(FVTHROT_FBDIV_REG1, STARTING_FEEDBACK_DIV(fbdiv),
> +		 ~STARTING_FEEDBACK_DIV_MASK);
> +
> +	WREG32_P(FVTHROT_FBDIV_REG2, FORCED_FEEDBACK_DIV(fbdiv),
> +		 ~FORCED_FEEDBACK_DIV_MASK);
> +
> +	WREG32_P(FVTHROT_FBDIV_REG1, FORCE_FEEDBACK_DIV, ~FORCE_FEEDBACK_DIV);
> +}
> +
> +static void rs780_voltage_scaling_init(struct radeon_device *rdev)
> +{
> +	struct igp_power_info *pi = rs780_get_pi(rdev);
> +	struct drm_device *dev = rdev->ddev;
> +	u32 fv_throt_pwm_fb_div_range[3];
> +	u32 fv_throt_pwm_range[4];
> +
> +	if (dev->pdev->device == 0x9614) {
> +		fv_throt_pwm_fb_div_range[0] = RS780D_FVTHROTPWMFBDIVRANGEREG0_DFLT;
> +		fv_throt_pwm_fb_div_range[1] = RS780D_FVTHROTPWMFBDIVRANGEREG1_DFLT;
> +		fv_throt_pwm_fb_div_range[2] = RS780D_FVTHROTPWMFBDIVRANGEREG2_DFLT;
> +	} else if ((dev->pdev->device == 0x9714) ||
> +		   (dev->pdev->device == 0x9715)) {
> +		fv_throt_pwm_fb_div_range[0] = RS880D_FVTHROTPWMFBDIVRANGEREG0_DFLT;
> +		fv_throt_pwm_fb_div_range[1] = RS880D_FVTHROTPWMFBDIVRANGEREG1_DFLT;
> +		fv_throt_pwm_fb_div_range[2] = RS880D_FVTHROTPWMFBDIVRANGEREG2_DFLT;
> +	} else {
> +		fv_throt_pwm_fb_div_range[0] = RS780_FVTHROTPWMFBDIVRANGEREG0_DFLT;
> +		fv_throt_pwm_fb_div_range[1] = RS780_FVTHROTPWMFBDIVRANGEREG1_DFLT;
> +		fv_throt_pwm_fb_div_range[2] = RS780_FVTHROTPWMFBDIVRANGEREG2_DFLT;
> +	}
> +
> +	if (pi->pwm_voltage_control) {
> +		fv_throt_pwm_range[0] = pi->min_voltage;
> +		fv_throt_pwm_range[1] = pi->min_voltage;
> +		fv_throt_pwm_range[2] = pi->max_voltage;
> +		fv_throt_pwm_range[3] = pi->max_voltage;
> +	} else {
> +		fv_throt_pwm_range[0] = pi->invert_pwm_required ?
> +			RS780_FVTHROTPWMRANGE3_GPIO_DFLT : RS780_FVTHROTPWMRANGE0_GPIO_DFLT;
> +		fv_throt_pwm_range[1] = pi->invert_pwm_required ?
> +			RS780_FVTHROTPWMRANGE2_GPIO_DFLT : RS780_FVTHROTPWMRANGE1_GPIO_DFLT;
> +		fv_throt_pwm_range[2] = pi->invert_pwm_required ?
> +			RS780_FVTHROTPWMRANGE1_GPIO_DFLT : RS780_FVTHROTPWMRANGE2_GPIO_DFLT;
> +		fv_throt_pwm_range[3] = pi->invert_pwm_required ?
> +			RS780_FVTHROTPWMRANGE0_GPIO_DFLT : RS780_FVTHROTPWMRANGE3_GPIO_DFLT;
> +	}
> +
> +	WREG32_P(FVTHROT_PWM_CTRL_REG0,
> +		 STARTING_PWM_HIGHTIME(pi->max_voltage),
> +		 ~STARTING_PWM_HIGHTIME_MASK);
> +
> +	WREG32_P(FVTHROT_PWM_CTRL_REG0,
> +		 NUMBER_OF_CYCLES_IN_PERIOD(pi->num_of_cycles_in_period),
> +		 ~NUMBER_OF_CYCLES_IN_PERIOD_MASK);
> +
> +	WREG32_P(FVTHROT_PWM_CTRL_REG0, FORCE_STARTING_PWM_HIGHTIME,
> +		 ~FORCE_STARTING_PWM_HIGHTIME);
> +
> +	if (pi->invert_pwm_required)
> +		WREG32_P(FVTHROT_PWM_CTRL_REG0, INVERT_PWM_WAVEFORM, ~INVERT_PWM_WAVEFORM);
> +	else
> +		WREG32_P(FVTHROT_PWM_CTRL_REG0, 0, ~INVERT_PWM_WAVEFORM);
> +
> +	rs780_voltage_scaling_enable(rdev, true);
> +
> +	WREG32(FVTHROT_PWM_CTRL_REG1,
> +	       (MIN_PWM_HIGHTIME(pi->min_voltage) |
> +		MAX_PWM_HIGHTIME(pi->max_voltage)));
> +
> +	WREG32(FVTHROT_PWM_US_REG0, RS780_FVTHROTPWMUSREG0_DFLT);
> +	WREG32(FVTHROT_PWM_US_REG1, RS780_FVTHROTPWMUSREG1_DFLT);
> +	WREG32(FVTHROT_PWM_DS_REG0, RS780_FVTHROTPWMDSREG0_DFLT);
> +	WREG32(FVTHROT_PWM_DS_REG1, RS780_FVTHROTPWMDSREG1_DFLT);
> +
> +	WREG32_P(FVTHROT_PWM_FEEDBACK_DIV_REG1,
> +		 RANGE0_PWM_FEEDBACK_DIV(fv_throt_pwm_fb_div_range[0]),
> +		 ~RANGE0_PWM_FEEDBACK_DIV_MASK);
> +
> +	WREG32(FVTHROT_PWM_FEEDBACK_DIV_REG2,
> +	       (RANGE1_PWM_FEEDBACK_DIV(fv_throt_pwm_fb_div_range[1]) |
> +		RANGE2_PWM_FEEDBACK_DIV(fv_throt_pwm_fb_div_range[2])));
> +
> +	WREG32(FVTHROT_PWM_FEEDBACK_DIV_REG3,
> +	       (RANGE0_PWM(fv_throt_pwm_range[1]) |
> +		RANGE1_PWM(fv_throt_pwm_range[2])));
> +	WREG32(FVTHROT_PWM_FEEDBACK_DIV_REG4,
> +	       (RANGE2_PWM(fv_throt_pwm_range[1]) |
> +		RANGE3_PWM(fv_throt_pwm_range[2])));
> +}
> +
> +static void rs780_clk_scaling_enable(struct radeon_device *rdev, bool enable)
> +{
> +	if (enable)
> +		WREG32_P(FVTHROT_CNTRL_REG, ENABLE_FV_THROT | ENABLE_FV_UPDATE,
> +			 ~(ENABLE_FV_THROT | ENABLE_FV_UPDATE));
> +	else
> +		WREG32_P(FVTHROT_CNTRL_REG, 0,
> +			 ~(ENABLE_FV_THROT | ENABLE_FV_UPDATE));
> +}
> +
> +static void rs780_voltage_scaling_enable(struct radeon_device *rdev, bool enable)
> +{
> +	if (enable)
> +		WREG32_P(FVTHROT_CNTRL_REG, ENABLE_FV_THROT_IO, ~ENABLE_FV_THROT_IO);
> +	else
> +		WREG32_P(FVTHROT_CNTRL_REG, 0, ~ENABLE_FV_THROT_IO);
> +}
> +
> +static void rs780_set_engine_clock_wfc(struct radeon_device *rdev)
> +{
> +	WREG32(FVTHROT_UTC0, RS780_FVTHROTUTC0_DFLT);
> +	WREG32(FVTHROT_UTC1, RS780_FVTHROTUTC1_DFLT);
> +	WREG32(FVTHROT_UTC2, RS780_FVTHROTUTC2_DFLT);
> +	WREG32(FVTHROT_UTC3, RS780_FVTHROTUTC3_DFLT);
> +	WREG32(FVTHROT_UTC4, RS780_FVTHROTUTC4_DFLT);
> +
> +	WREG32(FVTHROT_DTC0, RS780_FVTHROTDTC0_DFLT);
> +	WREG32(FVTHROT_DTC1, RS780_FVTHROTDTC1_DFLT);
> +	WREG32(FVTHROT_DTC2, RS780_FVTHROTDTC2_DFLT);
> +	WREG32(FVTHROT_DTC3, RS780_FVTHROTDTC3_DFLT);
> +	WREG32(FVTHROT_DTC4, RS780_FVTHROTDTC4_DFLT);
> +}
> +
> +static void rs780_set_engine_clock_sc(struct radeon_device *rdev)
> +{
> +	WREG32_P(FVTHROT_FBDIV_REG2,
> +		 FB_DIV_TIMER_VAL(RS780_FBDIVTIMERVAL_DFLT),
> +		 ~FB_DIV_TIMER_VAL_MASK);
> +
> +	WREG32_P(FVTHROT_CNTRL_REG,
> +		 REFRESH_RATE_DIVISOR(0) | MINIMUM_CIP(0xf),
> +		 ~(REFRESH_RATE_DIVISOR_MASK | MINIMUM_CIP_MASK));
> +}
> +
> +static void rs780_set_engine_clock_tdc(struct radeon_device *rdev)
> +{
> +	WREG32_P(FVTHROT_CNTRL_REG, 0, ~(FORCE_TREND_SEL | TREND_SEL_MODE));
> +}
> +
> +static void rs780_set_engine_clock_ssc(struct radeon_device *rdev)
> +{
> +	WREG32(FVTHROT_FB_US_REG0, RS780_FVTHROTFBUSREG0_DFLT);
> +	WREG32(FVTHROT_FB_US_REG1, RS780_FVTHROTFBUSREG1_DFLT);
> +	WREG32(FVTHROT_FB_DS_REG0, RS780_FVTHROTFBDSREG0_DFLT);
> +	WREG32(FVTHROT_FB_DS_REG1, RS780_FVTHROTFBDSREG1_DFLT);
> +
> +	WREG32_P(FVTHROT_FBDIV_REG1, MAX_FEEDBACK_STEP(1), ~MAX_FEEDBACK_STEP_MASK);
> +}
> +
> +static void rs780_program_at(struct radeon_device *rdev)
> +{
> +	struct igp_power_info *pi = rs780_get_pi(rdev);
> +
> +	WREG32(FVTHROT_TARGET_REG, 30000000 / pi->refresh_rate);
> +	WREG32(FVTHROT_CB1, 1000000 * 5 / pi->refresh_rate);
> +	WREG32(FVTHROT_CB2, 1000000 * 10 / pi->refresh_rate);
> +	WREG32(FVTHROT_CB3, 1000000 * 30 / pi->refresh_rate);
> +	WREG32(FVTHROT_CB4, 1000000 * 50 / pi->refresh_rate);
> +}
> +
> +static void rs780_disable_vbios_powersaving(struct radeon_device *rdev)
> +{
> +	WREG32_P(CG_INTGFX_MISC, 0, ~0xFFF00000);
> +}
> +
> +static void rs780_force_voltage_to_high(struct radeon_device *rdev)
> +{
> +	struct igp_power_info *pi = rs780_get_pi(rdev);
> +	struct igp_ps *current_state = rs780_get_ps(rdev->pm.dpm.current_ps);
> +
> +	if ((current_state->max_voltage == RS780_VDDC_LEVEL_HIGH) &&
> +	    (current_state->min_voltage == RS780_VDDC_LEVEL_HIGH))
> +		return;
> +
> +	WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL);
> +
> +	udelay(1);
> +
> +	WREG32_P(FVTHROT_PWM_CTRL_REG0,
> +		 STARTING_PWM_HIGHTIME(pi->max_voltage),
> +		 ~STARTING_PWM_HIGHTIME_MASK);
> +
> +	WREG32_P(FVTHROT_PWM_CTRL_REG0,
> +		 FORCE_STARTING_PWM_HIGHTIME, ~FORCE_STARTING_PWM_HIGHTIME);
> +
> +	WREG32_P(FVTHROT_PWM_FEEDBACK_DIV_REG1, 0,
> +		~RANGE_PWM_FEEDBACK_DIV_EN);
> +
> +	udelay(1);
> +
> +	WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
> +}
> +
> +static int rs780_set_engine_clock_scaling(struct radeon_device *rdev)
> +{
> +	struct atom_clock_dividers min_dividers, max_dividers, current_max_dividers;
> +	struct igp_ps *new_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
> +	struct igp_ps *old_state = rs780_get_ps(rdev->pm.dpm.current_ps);
> +	int ret;
> +
> +	if ((new_state->sclk_high == old_state->sclk_high) &&
> +	    (new_state->sclk_low == old_state->sclk_low))
> +		return 0;
> +
> +	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
> +					     new_state->sclk_low, false, &min_dividers);
> +	if (ret)
> +		return ret;
> +
> +	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
> +					     new_state->sclk_high, false, &max_dividers);
> +	if (ret)
> +		return ret;
> +
> +	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
> +					     old_state->sclk_high, false, &current_max_dividers);
> +	if (ret)
> +		return ret;
> +
> +	WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL);
> +
> +	WREG32_P(FVTHROT_FBDIV_REG2, FORCED_FEEDBACK_DIV(max_dividers.fb_div),
> +		 ~FORCED_FEEDBACK_DIV_MASK);
> +	WREG32_P(FVTHROT_FBDIV_REG1, STARTING_FEEDBACK_DIV(max_dividers.fb_div),
> +		 ~STARTING_FEEDBACK_DIV_MASK);
> +	WREG32_P(FVTHROT_FBDIV_REG1, FORCE_FEEDBACK_DIV, ~FORCE_FEEDBACK_DIV);
> +
> +	udelay(100);
> +
> +	WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
> +
> +	if (max_dividers.fb_div > min_dividers.fb_div) {
> +		WREG32_P(FVTHROT_FBDIV_REG0,
> +			 MIN_FEEDBACK_DIV(min_dividers.fb_div) |
> +			 MAX_FEEDBACK_DIV(max_dividers.fb_div),
> +			 ~(MIN_FEEDBACK_DIV_MASK | MAX_FEEDBACK_DIV_MASK));
> +
> +		WREG32_P(FVTHROT_FBDIV_REG1, 0, ~FORCE_FEEDBACK_DIV);
> +	}
> +
> +	return 0;
> +}
> +
> +static void rs780_set_engine_clock_spc(struct radeon_device *rdev)
> +{
> +	struct igp_ps *new_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
> +	struct igp_ps *old_state = rs780_get_ps(rdev->pm.dpm.current_ps);
> +	struct igp_power_info *pi = rs780_get_pi(rdev);
> +
> +	if ((new_state->sclk_high == old_state->sclk_high) &&
> +	    (new_state->sclk_low == old_state->sclk_low))
> +		return;
> +
> +	if (pi->crtc_id == 0)
> +		WREG32_P(CG_INTGFX_MISC, 0, ~FVTHROT_VBLANK_SEL);
> +	else
> +		WREG32_P(CG_INTGFX_MISC, FVTHROT_VBLANK_SEL, ~FVTHROT_VBLANK_SEL);
> +
> +}
> +
> +static void rs780_activate_engine_clk_scaling(struct radeon_device *rdev)
> +{
> +	struct igp_ps *new_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
> +	struct igp_ps *old_state = rs780_get_ps(rdev->pm.dpm.current_ps);
> +
> +	if ((new_state->sclk_high == old_state->sclk_high) &&
> +	    (new_state->sclk_low == old_state->sclk_low))
> +		return;
> +
> +	rs780_clk_scaling_enable(rdev, true);
> +}
> +
> +static u32 rs780_get_voltage_for_vddc_level(struct radeon_device *rdev,
> +					    enum rs780_vddc_level vddc)
> +{
> +	struct igp_power_info *pi = rs780_get_pi(rdev);
> +
> +	if (vddc == RS780_VDDC_LEVEL_HIGH)
> +		return pi->max_voltage;
> +	else if (vddc == RS780_VDDC_LEVEL_LOW)
> +		return pi->min_voltage;
> +	else
> +		return pi->max_voltage;
> +}
> +
> +static void rs780_enable_voltage_scaling(struct radeon_device *rdev)
> +{
> +	struct igp_ps *new_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
> +	struct igp_power_info *pi = rs780_get_pi(rdev);
> +	enum rs780_vddc_level vddc_high, vddc_low;
> +
> +	udelay(100);
> +
> +	if ((new_state->max_voltage == RS780_VDDC_LEVEL_HIGH) &&
> +	    (new_state->min_voltage == RS780_VDDC_LEVEL_HIGH))
> +		return;
> +
> +	vddc_high = rs780_get_voltage_for_vddc_level(rdev,
> +						     new_state->max_voltage);
> +	vddc_low = rs780_get_voltage_for_vddc_level(rdev,
> +						    new_state->min_voltage);
> +
> +	WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL);
> +
> +	udelay(1);
> +	if (vddc_high > vddc_low) {
> +		WREG32_P(FVTHROT_PWM_FEEDBACK_DIV_REG1,
> +			 RANGE_PWM_FEEDBACK_DIV_EN, ~RANGE_PWM_FEEDBACK_DIV_EN);
> +
> +		WREG32_P(FVTHROT_PWM_CTRL_REG0, 0, ~FORCE_STARTING_PWM_HIGHTIME);
> +	} else if (vddc_high == vddc_low) {
> +		if (pi->max_voltage != vddc_high) {
> +			WREG32_P(FVTHROT_PWM_CTRL_REG0,
> +				 STARTING_PWM_HIGHTIME(vddc_high),
> +				 ~STARTING_PWM_HIGHTIME_MASK);
> +
> +			WREG32_P(FVTHROT_PWM_CTRL_REG0,
> +				 FORCE_STARTING_PWM_HIGHTIME,
> +				 ~FORCE_STARTING_PWM_HIGHTIME);
> +		}
> +	}
> +
> +	WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
> +}
> +
> +int rs780_dpm_enable(struct radeon_device *rdev)
> +{
> +	struct igp_power_info *pi = rs780_get_pi(rdev);
> +
> +	rs780_get_pm_mode_parameters(rdev);
> +	rs780_disable_vbios_powersaving(rdev);
> +
> +	if (r600_dynamicpm_enabled(rdev))
> +		return -EINVAL;
> +	if (rs780_initialize_dpm_parameters(rdev))
> +		return -EINVAL;
> +	rs780_start_dpm(rdev);
> +
> +	rs780_preset_ranges_slow_clk_fbdiv_en(rdev);
> +	rs780_preset_starting_fbdiv(rdev);
> +	if (pi->voltage_control)
> +		rs780_voltage_scaling_init(rdev);
> +	rs780_clk_scaling_enable(rdev, true);
> +	rs780_set_engine_clock_sc(rdev);
> +	rs780_set_engine_clock_wfc(rdev);
> +	rs780_program_at(rdev);
> +	rs780_set_engine_clock_tdc(rdev);
> +	rs780_set_engine_clock_ssc(rdev);
> +
> +	if (pi->gfx_clock_gating)
> +		r600_gfx_clockgating_enable(rdev, true);
> +
> +	return 0;
> +}
> +
> +void rs780_dpm_disable(struct radeon_device *rdev)
> +{
> +	struct igp_power_info *pi = rs780_get_pi(rdev);
> +
> +	r600_dynamicpm_enable(rdev, false);
> +
> +	rs780_clk_scaling_enable(rdev, false);
> +	rs780_voltage_scaling_enable(rdev, false);
> +
> +	if (pi->gfx_clock_gating)
> +		r600_gfx_clockgating_enable(rdev, false);
> +}
> +
> +int rs780_dpm_set_power_state(struct radeon_device *rdev)
> +{
> +	struct igp_power_info *pi = rs780_get_pi(rdev);
> +
> +	rs780_get_pm_mode_parameters(rdev);
> +
> +	if (pi->voltage_control) {
> +		rs780_force_voltage_to_high(rdev);
> +		mdelay(5);
> +	}
> +
> +	rs780_set_engine_clock_scaling(rdev);
> +	rs780_set_engine_clock_spc(rdev);
> +
> +	rs780_activate_engine_clk_scaling(rdev);
> +
> +	if (pi->voltage_control)
> +		rs780_enable_voltage_scaling(rdev);
> +
> +	return 0;
> +}
> +
> +void rs780_dpm_setup_asic(struct radeon_device *rdev)
> +{
> +
> +}
> +
> +void rs780_dpm_display_configuration_changed(struct radeon_device *rdev)
> +{
> +	rs780_get_pm_mode_parameters(rdev);
> +	rs780_program_at(rdev);
> +}
> +
> +union igp_info {
> +	struct _ATOM_INTEGRATED_SYSTEM_INFO info;
> +	struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2;
> +};
> +
> +union power_info {
> +	struct _ATOM_POWERPLAY_INFO info;
> +	struct _ATOM_POWERPLAY_INFO_V2 info_2;
> +	struct _ATOM_POWERPLAY_INFO_V3 info_3;
> +	struct _ATOM_PPLIB_POWERPLAYTABLE pplib;
> +	struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2;
> +	struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3;
> +};
> +
> +union pplib_clock_info {
> +	struct _ATOM_PPLIB_R600_CLOCK_INFO r600;
> +	struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780;
> +	struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen;
> +	struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo;
> +};
> +
> +union pplib_power_state {
> +	struct _ATOM_PPLIB_STATE v1;
> +	struct _ATOM_PPLIB_STATE_V2 v2;
> +};
> +
> +static void rs780_parse_pplib_non_clock_info(struct radeon_device *rdev,
> +					     struct radeon_ps *rps,
> +					     struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info,
> +					     u8 table_rev)
> +{
> +	rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings);
> +	rps->class = le16_to_cpu(non_clock_info->usClassification);
> +	rps->class2 = le16_to_cpu(non_clock_info->usClassification2);
> +
> +	if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) {
> +		rps->vclk = le32_to_cpu(non_clock_info->ulVCLK);
> +		rps->dclk = le32_to_cpu(non_clock_info->ulDCLK);
> +	} else if (r600_is_uvd_state(rps->class, rps->class2)) {
> +		rps->vclk = RS780_DEFAULT_VCLK_FREQ;
> +		rps->dclk = RS780_DEFAULT_DCLK_FREQ;
> +	} else {
> +		rps->vclk = 0;
> +		rps->dclk = 0;
> +	}
> +
> +	if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT)
> +		rdev->pm.dpm.boot_ps = rps;
> +	if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
> +		rdev->pm.dpm.uvd_ps = rps;
> +}
> +
> +static void rs780_parse_pplib_clock_info(struct radeon_device *rdev,
> +					 struct radeon_ps *rps,
> +					 union pplib_clock_info *clock_info)
> +{
> +	struct igp_ps *ps = rs780_get_ps(rps);
> +	u32 sclk;
> +
> +	sclk = le16_to_cpu(clock_info->rs780.usLowEngineClockLow);
> +	sclk |= clock_info->rs780.ucLowEngineClockHigh << 16;
> +	ps->sclk_low = sclk;
> +	sclk = le16_to_cpu(clock_info->rs780.usHighEngineClockLow);
> +	sclk |= clock_info->rs780.ucHighEngineClockHigh << 16;
> +	ps->sclk_high = sclk;
> +	switch (le16_to_cpu(clock_info->rs780.usVDDC)) {
> +	case ATOM_PPLIB_RS780_VOLTAGE_NONE:
> +	default:
> +		ps->min_voltage = RS780_VDDC_LEVEL_UNKNOWN;
> +		ps->max_voltage = RS780_VDDC_LEVEL_UNKNOWN;
> +		break;
> +	case ATOM_PPLIB_RS780_VOLTAGE_LOW:
> +		ps->min_voltage = RS780_VDDC_LEVEL_LOW;
> +		ps->max_voltage = RS780_VDDC_LEVEL_LOW;
> +		break;
> +	case ATOM_PPLIB_RS780_VOLTAGE_HIGH:
> +		ps->min_voltage = RS780_VDDC_LEVEL_HIGH;
> +		ps->max_voltage = RS780_VDDC_LEVEL_HIGH;
> +		break;
> +	case ATOM_PPLIB_RS780_VOLTAGE_VARIABLE:
> +		ps->min_voltage = RS780_VDDC_LEVEL_LOW;
> +		ps->max_voltage = RS780_VDDC_LEVEL_HIGH;
> +		break;
> +	}
> +	ps->flags = le32_to_cpu(clock_info->rs780.ulFlags);
> +
> +	if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) {
> +		ps->sclk_low = rdev->clock.default_sclk;
> +		ps->sclk_high = rdev->clock.default_sclk;
> +		ps->min_voltage = RS780_VDDC_LEVEL_HIGH;
> +		ps->max_voltage = RS780_VDDC_LEVEL_HIGH;
> +	}
> +}
> +
> +static int rs780_parse_power_table(struct radeon_device *rdev)
> +{
> +	struct radeon_mode_info *mode_info = &rdev->mode_info;
> +	struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
> +	union pplib_power_state *power_state;
> +	int i;
> +	union pplib_clock_info *clock_info;
> +	union power_info *power_info;
> +	int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
> +        u16 data_offset;
> +	u8 frev, crev;
> +	struct igp_ps *ps;
> +
> +	if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
> +				   &frev, &crev, &data_offset))
> +		return -EINVAL;
> +	power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
> +
> +	rdev->pm.dpm.ps = kzalloc(sizeof(struct radeon_ps) *
> +				  power_info->pplib.ucNumStates, GFP_KERNEL);
> +	if (!rdev->pm.dpm.ps)
> +		return -ENOMEM;
> +	rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps);
> +	rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime);
> +	rdev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime);
> +
> +	for (i = 0; i < power_info->pplib.ucNumStates; i++) {
> +		power_state = (union pplib_power_state *)
> +			(mode_info->atom_context->bios + data_offset +
> +			 le16_to_cpu(power_info->pplib.usStateArrayOffset) +
> +			 i * power_info->pplib.ucStateEntrySize);
> +		non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
> +			(mode_info->atom_context->bios + data_offset +
> +			 le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset) +
> +			 (power_state->v1.ucNonClockStateIndex *
> +			  power_info->pplib.ucNonClockSize));
> +		if (power_info->pplib.ucStateEntrySize - 1) {
> +			clock_info = (union pplib_clock_info *)
> +				(mode_info->atom_context->bios + data_offset +
> +				 le16_to_cpu(power_info->pplib.usClockInfoArrayOffset) +
> +				 (power_state->v1.ucClockStateIndices[0] *
> +				  power_info->pplib.ucClockInfoSize));
> +			ps = kzalloc(sizeof(struct igp_ps), GFP_KERNEL);
> +			if (ps == NULL) {
> +				kfree(rdev->pm.dpm.ps);
> +				return -ENOMEM;
> +			}
> +			rdev->pm.dpm.ps[i].ps_priv = ps;
> +			rs780_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i],
> +							 non_clock_info,
> +							 power_info->pplib.ucNonClockSize);
> +			rs780_parse_pplib_clock_info(rdev,
> +						     &rdev->pm.dpm.ps[i],
> +						     clock_info);
> +		}
> +	}
> +	rdev->pm.dpm.num_ps = power_info->pplib.ucNumStates;
> +	return 0;
> +}
> +
> +int rs780_dpm_init(struct radeon_device *rdev)
> +{
> +	struct igp_power_info *pi;
> +	int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);
> +	union igp_info *info;
> +	u16 data_offset;
> +	u8 frev, crev;
> +	int ret;
> +
> +	pi = kzalloc(sizeof(struct igp_power_info), GFP_KERNEL);
> +	if (pi == NULL)
> +		return -ENOMEM;
> +	rdev->pm.dpm.priv = pi;
> +
> +	ret = rs780_parse_power_table(rdev);
> +	if (ret)
> +		return ret;
> +
> +	pi->voltage_control = false;
> +	pi->gfx_clock_gating = true;
> +
> +	if (atom_parse_data_header(rdev->mode_info.atom_context, index, NULL,
> +				   &frev, &crev, &data_offset)) {
> +		info = (union igp_info *)(rdev->mode_info.atom_context->bios + data_offset);
> +
> +		/* Get various system informations from bios */
> +		switch (crev) {
> +		case 1:
> +			pi->num_of_cycles_in_period =
> +				info->info.ucNumberOfCyclesInPeriod;
> +			pi->num_of_cycles_in_period |=
> +				info->info.ucNumberOfCyclesInPeriodHi << 8;
> +			pi->invert_pwm_required =
> +				(pi->num_of_cycles_in_period & 0x8000) ? true : false;
> +			pi->boot_voltage = info->info.ucStartingPWM_HighTime;
> +			pi->max_voltage = info->info.ucMaxNBVoltage;
> +			pi->max_voltage |= info->info.ucMaxNBVoltageHigh << 8;
> +			pi->min_voltage = info->info.ucMinNBVoltage;
> +			pi->min_voltage |= info->info.ucMinNBVoltageHigh << 8;
> +			pi->inter_voltage_low =
> +				le16_to_cpu(info->info.usInterNBVoltageLow);
> +			pi->inter_voltage_high =
> +				le16_to_cpu(info->info.usInterNBVoltageHigh);
> +			pi->voltage_control = true;
> +			pi->bootup_uma_clk = info->info.usK8MemoryClock * 100;
> +			break;
> +		case 2:
> +			pi->num_of_cycles_in_period =
> +				le16_to_cpu(info->info_2.usNumberOfCyclesInPeriod);
> +			pi->invert_pwm_required =
> +				(pi->num_of_cycles_in_period & 0x8000) ? true : false;
> +			pi->boot_voltage =
> +				le16_to_cpu(info->info_2.usBootUpNBVoltage);
> +			pi->max_voltage =
> +				le16_to_cpu(info->info_2.usMaxNBVoltage);
> +			pi->min_voltage =
> +				le16_to_cpu(info->info_2.usMinNBVoltage);
> +			pi->system_config =
> +				le32_to_cpu(info->info_2.ulSystemConfig);
> +			pi->pwm_voltage_control =
> +				(pi->system_config & 0x4) ? true : false;
> +			pi->voltage_control = true;
> +			pi->bootup_uma_clk = le32_to_cpu(info->info_2.ulBootUpUMAClock);
> +			break;
> +		default:
> +			DRM_ERROR("No integrated system info for your GPU\n");
> +			return -EINVAL;
> +		}
> +		if (pi->min_voltage > pi->max_voltage)
> +			pi->voltage_control = false;
> +		if (pi->pwm_voltage_control) {
> +			if ((pi->num_of_cycles_in_period == 0) ||
> +			    (pi->max_voltage == 0) ||
> +			    (pi->min_voltage == 0))
> +				pi->voltage_control = false;
> +		} else {
> +			if ((pi->num_of_cycles_in_period == 0) ||
> +			    (pi->max_voltage == 0))
> +				pi->voltage_control = false;
> +		}
> +
> +		return 0;
> +	}
> +	radeon_dpm_fini(rdev);
> +	return -EINVAL;
> +}
> +
> +void rs780_dpm_print_power_state(struct radeon_device *rdev,
> +				 struct radeon_ps *rps)
> +{
> +	struct igp_ps *ps = rs780_get_ps(rps);
> +
> +	r600_dpm_print_class_info(rps->class, rps->class2);
> +	r600_dpm_print_cap_info(rps->caps);
> +	printk("\tuvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
> +	printk("\t\tpower level 0    sclk: %u vddc_index: %d\n",
> +	       ps->sclk_low, ps->min_voltage);
> +	printk("\t\tpower level 1    sclk: %u vddc_index: %d\n",
> +	       ps->sclk_high, ps->max_voltage);
> +	r600_dpm_print_ps_status(rdev, rps);
> +}
> +
> +void rs780_dpm_fini(struct radeon_device *rdev)
> +{
> +	int i;
> +
> +	for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
> +		kfree(rdev->pm.dpm.ps[i].ps_priv);
> +	}
> +	kfree(rdev->pm.dpm.ps);
> +	kfree(rdev->pm.dpm.priv);
> +}
> +
> +u32 rs780_dpm_get_sclk(struct radeon_device *rdev, bool low)
> +{
> +	struct igp_ps *requested_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
> +
> +	if (low)
> +		return requested_state->sclk_low;
> +	else
> +		return requested_state->sclk_high;
> +}
> +
> +u32 rs780_dpm_get_mclk(struct radeon_device *rdev, bool low)
> +{
> +	struct igp_power_info *pi = rs780_get_pi(rdev);
> +
> +	return pi->bootup_uma_clk;
> +}
> diff --git a/drivers/gpu/drm/radeon/rs780_dpm.h b/drivers/gpu/drm/radeon/rs780_dpm.h
> new file mode 100644
> index 0000000..47a40b1
> --- /dev/null
> +++ b/drivers/gpu/drm/radeon/rs780_dpm.h
> @@ -0,0 +1,109 @@
> +/*
> + * Copyright 2011 Advanced Micro Devices, Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + *
> + */
> +#ifndef __RS780_DPM_H__
> +#define __RS780_DPM_H__
> +
> +enum rs780_vddc_level {
> +	RS780_VDDC_LEVEL_UNKNOWN = 0,
> +	RS780_VDDC_LEVEL_LOW = 1,
> +	RS780_VDDC_LEVEL_HIGH = 2,
> +};
> +
> +struct igp_power_info {
> +	/* flags */
> +	bool invert_pwm_required;
> +	bool pwm_voltage_control;
> +	bool voltage_control;
> +	bool gfx_clock_gating;
> +	/* stored values */
> +	u32 system_config;
> +	u32 bootup_uma_clk;
> +	u16 max_voltage;
> +	u16 min_voltage;
> +	u16 boot_voltage;
> +	u16 inter_voltage_low;
> +	u16 inter_voltage_high;
> +	u16 num_of_cycles_in_period;
> +	/* variable */
> +	int crtc_id;
> +	int refresh_rate;
> +};
> +
> +struct igp_ps {
> +	enum rs780_vddc_level min_voltage;
> +	enum rs780_vddc_level max_voltage;
> +	u32 sclk_low;
> +	u32 sclk_high;
> +	u32 flags;
> +};
> +
> +#define RS780_CGFTV_DFLT                 0x0303000f
> +#define RS780_FBDIVTIMERVAL_DFLT         0x2710
> +
> +#define RS780_FVTHROTUTC0_DFLT   0x04010040
> +#define RS780_FVTHROTUTC1_DFLT   0x04010040
> +#define RS780_FVTHROTUTC2_DFLT   0x04010040
> +#define RS780_FVTHROTUTC3_DFLT   0x04010040
> +#define RS780_FVTHROTUTC4_DFLT   0x04010040
> +
> +#define RS780_FVTHROTDTC0_DFLT 0x04010040
> +#define RS780_FVTHROTDTC1_DFLT 0x04010040
> +#define RS780_FVTHROTDTC2_DFLT 0x04010040
> +#define RS780_FVTHROTDTC3_DFLT 0x04010040
> +#define RS780_FVTHROTDTC4_DFLT 0x04010040
> +
> +#define RS780_FVTHROTFBUSREG0_DFLT       0x00001001
> +#define RS780_FVTHROTFBUSREG1_DFLT       0x00002002
> +#define RS780_FVTHROTFBDSREG0_DFLT       0x00004001
> +#define RS780_FVTHROTFBDSREG1_DFLT       0x00020010
> +
> +#define RS780_FVTHROTPWMUSREG0_DFLT      0x00002001
> +#define RS780_FVTHROTPWMUSREG1_DFLT      0x00004003
> +#define RS780_FVTHROTPWMDSREG0_DFLT      0x00002001
> +#define RS780_FVTHROTPWMDSREG1_DFLT      0x00004003
> +
> +#define RS780_FVTHROTPWMFBDIVRANGEREG0_DFLT  0x37
> +#define RS780_FVTHROTPWMFBDIVRANGEREG1_DFLT  0x4b
> +#define RS780_FVTHROTPWMFBDIVRANGEREG2_DFLT  0x8b
> +
> +#define RS780D_FVTHROTPWMFBDIVRANGEREG0_DFLT  0x8b
> +#define RS780D_FVTHROTPWMFBDIVRANGEREG1_DFLT  0x8c
> +#define RS780D_FVTHROTPWMFBDIVRANGEREG2_DFLT  0xb5
> +
> +#define RS880D_FVTHROTPWMFBDIVRANGEREG0_DFLT  0x8d
> +#define RS880D_FVTHROTPWMFBDIVRANGEREG1_DFLT  0x8e
> +#define RS880D_FVTHROTPWMFBDIVRANGEREG2_DFLT  0xBa
> +
> +#define RS780_FVTHROTPWMRANGE0_GPIO_DFLT  0x1a
> +#define RS780_FVTHROTPWMRANGE1_GPIO_DFLT  0x1a
> +#define RS780_FVTHROTPWMRANGE2_GPIO_DFLT  0x0
> +#define RS780_FVTHROTPWMRANGE3_GPIO_DFLT  0x0
> +
> +#define RS780_SLOWCLKFEEDBACKDIV_DFLT 110
> +
> +#define RS780_CGCLKGATING_DFLT           0x0000E204
> +
> +#define RS780_DEFAULT_VCLK_FREQ  53300 /* 10 khz */
> +#define RS780_DEFAULT_DCLK_FREQ  40000 /* 10 khz */
> +
> +#endif
> diff --git a/drivers/gpu/drm/radeon/rs780d.h b/drivers/gpu/drm/radeon/rs780d.h
> new file mode 100644
> index 0000000..b1142ed
> --- /dev/null
> +++ b/drivers/gpu/drm/radeon/rs780d.h
> @@ -0,0 +1,168 @@
> +/*
> + * Copyright 2011 Advanced Micro Devices, Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + *
> + */
> +#ifndef __RS780D_H__
> +#define __RS780D_H__
> +
> +#define CG_SPLL_FUNC_CNTL                                 0x600
> +#       define SPLL_RESET                                (1 << 0)
> +#       define SPLL_SLEEP                                (1 << 1)
> +#       define SPLL_REF_DIV(x)                           ((x) << 2)
> +#       define SPLL_REF_DIV_MASK                         (7 << 2)
> +#       define SPLL_FB_DIV(x)                            ((x) << 5)
> +#       define SPLL_FB_DIV_MASK                          (0xff << 2)
> +#       define SPLL_FB_DIV_SHIFT                         2
> +#       define SPLL_PULSEEN                              (1 << 13)
> +#       define SPLL_PULSENUM(x)                          ((x) << 14)
> +#       define SPLL_PULSENUM_MASK                        (3 << 14)
> +#       define SPLL_SW_HILEN(x)                          ((x) << 16)
> +#       define SPLL_SW_HILEN_MASK                        (0xf << 16)
> +#       define SPLL_SW_LOLEN(x)                          ((x) << 20)
> +#       define SPLL_SW_LOLEN_MASK                        (0xf << 20)
> +#       define SPLL_DIVEN                                (1 << 24)
> +#       define SPLL_BYPASS_EN                            (1 << 25)
> +#       define SPLL_CHG_STATUS                           (1 << 29)
> +#       define SPLL_CTLREQ                               (1 << 30)
> +#       define SPLL_CTLACK                               (1 << 31)
> +
> +/* RS780/RS880 PM */
> +#define	FVTHROT_CNTRL_REG				0x3000
> +#define		DONT_WAIT_FOR_FBDIV_WRAP		(1 << 0)
> +#define		MINIMUM_CIP(x)				((x) << 1)
> +#define		MINIMUM_CIP_SHIFT			1
> +#define		MINIMUM_CIP_MASK			0x1fffffe
> +#define		REFRESH_RATE_DIVISOR(x)			((x) << 25)
> +#define		REFRESH_RATE_DIVISOR_SHIFT		25
> +#define		REFRESH_RATE_DIVISOR_MASK		(0x3 << 25)
> +#define		ENABLE_FV_THROT				(1 << 27)
> +#define		ENABLE_FV_UPDATE			(1 << 28)
> +#define		TREND_SEL_MODE				(1 << 29)
> +#define		FORCE_TREND_SEL				(1 << 30)
> +#define		ENABLE_FV_THROT_IO			(1 << 31)
> +#define	FVTHROT_TARGET_REG				0x3004
> +#define		TARGET_IDLE_COUNT(x)			((x) << 0)
> +#define		TARGET_IDLE_COUNT_MASK			0xffffff
> +#define		TARGET_IDLE_COUNT_SHIFT			0
> +#define	FVTHROT_CB1					0x3008
> +#define	FVTHROT_CB2					0x300c
> +#define	FVTHROT_CB3					0x3010
> +#define	FVTHROT_CB4					0x3014
> +#define	FVTHROT_UTC0					0x3018
> +#define	FVTHROT_UTC1					0x301c
> +#define	FVTHROT_UTC2					0x3020
> +#define	FVTHROT_UTC3					0x3024
> +#define	FVTHROT_UTC4					0x3028
> +#define	FVTHROT_DTC0					0x302c
> +#define	FVTHROT_DTC1					0x3030
> +#define	FVTHROT_DTC2					0x3034
> +#define	FVTHROT_DTC3					0x3038
> +#define	FVTHROT_DTC4					0x303c
> +#define	FVTHROT_FBDIV_REG0				0x3040
> +#define		MIN_FEEDBACK_DIV(x)			((x) << 0)
> +#define		MIN_FEEDBACK_DIV_MASK			0xfff
> +#define		MIN_FEEDBACK_DIV_SHIFT			0
> +#define		MAX_FEEDBACK_DIV(x)			((x) << 12)
> +#define		MAX_FEEDBACK_DIV_MASK			(0xfff << 12)
> +#define		MAX_FEEDBACK_DIV_SHIFT			12
> +#define	FVTHROT_FBDIV_REG1				0x3044
> +#define		MAX_FEEDBACK_STEP(x)			((x) << 0)
> +#define		MAX_FEEDBACK_STEP_MASK			0xfff
> +#define		MAX_FEEDBACK_STEP_SHIFT			0
> +#define		STARTING_FEEDBACK_DIV(x)		((x) << 12)
> +#define		STARTING_FEEDBACK_DIV_MASK		(0xfff << 12)
> +#define		STARTING_FEEDBACK_DIV_SHIFT		12
> +#define		FORCE_FEEDBACK_DIV			(1 << 24)
> +#define	FVTHROT_FBDIV_REG2				0x3048
> +#define		FORCED_FEEDBACK_DIV(x)			((x) << 0)
> +#define		FORCED_FEEDBACK_DIV_MASK		0xfff
> +#define		FORCED_FEEDBACK_DIV_SHIFT		0
> +#define		FB_DIV_TIMER_VAL(x)			((x) << 12)
> +#define		FB_DIV_TIMER_VAL_MASK			(0xffff << 12)
> +#define		FB_DIV_TIMER_VAL_SHIFT			12
> +#define	FVTHROT_FB_US_REG0				0x304c
> +#define	FVTHROT_FB_US_REG1				0x3050
> +#define	FVTHROT_FB_DS_REG0				0x3054
> +#define	FVTHROT_FB_DS_REG1				0x3058
> +#define	FVTHROT_PWM_CTRL_REG0				0x305c
> +#define		STARTING_PWM_HIGHTIME(x)		((x) << 0)
> +#define		STARTING_PWM_HIGHTIME_MASK		0xfff
> +#define		STARTING_PWM_HIGHTIME_SHIFT		0
> +#define		NUMBER_OF_CYCLES_IN_PERIOD(x)		((x) << 12)
> +#define		NUMBER_OF_CYCLES_IN_PERIOD_MASK		(0xfff << 12)
> +#define		NUMBER_OF_CYCLES_IN_PERIOD_SHIFT	12
> +#define		FORCE_STARTING_PWM_HIGHTIME		(1 << 24)
> +#define		INVERT_PWM_WAVEFORM			(1 << 25)
> +#define	FVTHROT_PWM_CTRL_REG1				0x3060
> +#define		MIN_PWM_HIGHTIME(x)			((x) << 0)
> +#define		MIN_PWM_HIGHTIME_MASK			0xfff
> +#define		MIN_PWM_HIGHTIME_SHIFT			0
> +#define		MAX_PWM_HIGHTIME(x)			((x) << 12)
> +#define		MAX_PWM_HIGHTIME_MASK			(0xfff << 12)
> +#define		MAX_PWM_HIGHTIME_SHIFT			12
> +#define	FVTHROT_PWM_US_REG0				0x3064
> +#define	FVTHROT_PWM_US_REG1				0x3068
> +#define	FVTHROT_PWM_DS_REG0				0x306c
> +#define	FVTHROT_PWM_DS_REG1				0x3070
> +#define	FVTHROT_STATUS_REG0				0x3074
> +#define		CURRENT_FEEDBACK_DIV_MASK		0xfff
> +#define		CURRENT_FEEDBACK_DIV_SHIFT		0
> +#define	FVTHROT_STATUS_REG1				0x3078
> +#define	FVTHROT_STATUS_REG2				0x307c
> +#define	CG_INTGFX_MISC					0x3080
> +#define		FVTHROT_VBLANK_SEL			(1 << 9)
> +#define	FVTHROT_PWM_FEEDBACK_DIV_REG1			0x308c
> +#define		RANGE0_PWM_FEEDBACK_DIV(x)		((x) << 0)
> +#define		RANGE0_PWM_FEEDBACK_DIV_MASK		0xfff
> +#define		RANGE0_PWM_FEEDBACK_DIV_SHIFT		0
> +#define		RANGE_PWM_FEEDBACK_DIV_EN		(1 << 12)
> +#define	FVTHROT_PWM_FEEDBACK_DIV_REG2			0x3090
> +#define		RANGE1_PWM_FEEDBACK_DIV(x)		((x) << 0)
> +#define		RANGE1_PWM_FEEDBACK_DIV_MASK		0xfff
> +#define		RANGE1_PWM_FEEDBACK_DIV_SHIFT		0
> +#define		RANGE2_PWM_FEEDBACK_DIV(x)		((x) << 12)
> +#define		RANGE2_PWM_FEEDBACK_DIV_MASK		(0xfff << 12)
> +#define		RANGE2_PWM_FEEDBACK_DIV_SHIFT		12
> +#define	FVTHROT_PWM_FEEDBACK_DIV_REG3			0x3094
> +#define		RANGE0_PWM(x)				((x) << 0)
> +#define		RANGE0_PWM_MASK				0xfff
> +#define		RANGE0_PWM_SHIFT			0
> +#define		RANGE1_PWM(x)				((x) << 12)
> +#define		RANGE1_PWM_MASK				(0xfff << 12)
> +#define		RANGE1_PWM_SHIFT			12
> +#define	FVTHROT_PWM_FEEDBACK_DIV_REG4			0x3098
> +#define		RANGE2_PWM(x)				((x) << 0)
> +#define		RANGE2_PWM_MASK				0xfff
> +#define		RANGE2_PWM_SHIFT			0
> +#define		RANGE3_PWM(x)				((x) << 12)
> +#define		RANGE3_PWM_MASK				(0xfff << 12)
> +#define		RANGE3_PWM_SHIFT			12
> +#define	FVTHROT_SLOW_CLK_FEEDBACK_DIV_REG1		0x30ac
> +#define		RANGE0_SLOW_CLK_FEEDBACK_DIV(x)		((x) << 0)
> +#define		RANGE0_SLOW_CLK_FEEDBACK_DIV_MASK	0xfff
> +#define		RANGE0_SLOW_CLK_FEEDBACK_DIV_SHIFT	0
> +#define		RANGE_SLOW_CLK_FEEDBACK_DIV_EN		(1 << 12)
> +
> +#define	GFX_MACRO_BYPASS_CNTL				0x30c0
> +#define		SPLL_BYPASS_CNTL			(1 << 0)
> +#define		UPLL_BYPASS_CNTL			(1 << 1)
> +
> +#endif
> -- 
> 1.7.7.5
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 080/165] drm/radeon/kms: add dpm support for sumo asics
  2013-06-26 13:22 ` [PATCH 080/165] drm/radeon/kms: add dpm support for sumo asics alexdeucher
@ 2013-06-26 11:19   ` Jerome Glisse
  0 siblings, 0 replies; 142+ messages in thread
From: Jerome Glisse @ 2013-06-26 11:19 UTC (permalink / raw)
  To: alexdeucher; +Cc: Alex Deucher, dri-devel

On Wed, Jun 26, 2013 at 09:22:40AM -0400, alexdeucher@gmail.com wrote:
> From: Alex Deucher <alexander.deucher@amd.com>
> 
> This adds dpm support for sumo asics.  This includes:
> - clockgating
> - powergating
> - dynamic engine clock scaling
> - dynamic voltage scaling
> 
> set radeon.dpm=1 to enable it.
> 
> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>

Reviewed-by: Jerome Glisse <jglisse@redhat.com>

> ---
>  drivers/gpu/drm/radeon/Makefile      |    2 +-
>  drivers/gpu/drm/radeon/radeon_asic.c |   12 +
>  drivers/gpu/drm/radeon/radeon_asic.h |   11 +
>  drivers/gpu/drm/radeon/radeon_pm.c   |    3 +
>  drivers/gpu/drm/radeon/sumo_dpm.c    | 1677 ++++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/radeon/sumo_dpm.h    |  199 ++++
>  drivers/gpu/drm/radeon/sumo_smc.c    |  224 +++++
>  drivers/gpu/drm/radeon/sumod.h       |  362 ++++++++
>  8 files changed, 2489 insertions(+), 1 deletions(-)
>  create mode 100644 drivers/gpu/drm/radeon/sumo_dpm.c
>  create mode 100644 drivers/gpu/drm/radeon/sumo_dpm.h
>  create mode 100644 drivers/gpu/drm/radeon/sumo_smc.c
>  create mode 100644 drivers/gpu/drm/radeon/sumod.h
> 
> diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile
> index af3dd8f..7c77e1d 100644
> --- a/drivers/gpu/drm/radeon/Makefile
> +++ b/drivers/gpu/drm/radeon/Makefile
> @@ -78,7 +78,7 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \
>  	atombios_encoders.o radeon_semaphore.o radeon_sa.o atombios_i2c.o si.o \
>  	si_blit_shaders.o radeon_prime.o radeon_uvd.o cik.o cik_blit_shaders.o \
>  	r600_dpm.o rs780_dpm.o rv6xx_dpm.o rv770_dpm.o rv730_dpm.o rv740_dpm.o \
> -	rv770_smc.o cypress_dpm.o btc_dpm.o
> +	rv770_smc.o cypress_dpm.o btc_dpm.o sumo_dpm.o sumo_smc.o
>  
>  radeon-$(CONFIG_COMPAT) += radeon_ioc32.o
>  radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o
> diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c
> index 20f65ad..8b541b4 100644
> --- a/drivers/gpu/drm/radeon/radeon_asic.c
> +++ b/drivers/gpu/drm/radeon/radeon_asic.c
> @@ -1539,6 +1539,18 @@ static struct radeon_asic sumo_asic = {
>  		.set_uvd_clocks = &sumo_set_uvd_clocks,
>  		.get_temperature = &sumo_get_temp,
>  	},
> +	.dpm = {
> +		.init = &sumo_dpm_init,
> +		.setup_asic = &sumo_dpm_setup_asic,
> +		.enable = &sumo_dpm_enable,
> +		.disable = &sumo_dpm_disable,
> +		.set_power_state = &sumo_dpm_set_power_state,
> +		.display_configuration_changed = &sumo_dpm_display_configuration_changed,
> +		.fini = &sumo_dpm_fini,
> +		.get_sclk = &sumo_dpm_get_sclk,
> +		.get_mclk = &sumo_dpm_get_mclk,
> +		.print_power_state = &sumo_dpm_print_power_state,
> +	},
>  	.pflip = {
>  		.pre_page_flip = &evergreen_pre_page_flip,
>  		.page_flip = &evergreen_page_flip,
> diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
> index 214429b..f6c0984 100644
> --- a/drivers/gpu/drm/radeon/radeon_asic.h
> +++ b/drivers/gpu/drm/radeon/radeon_asic.h
> @@ -536,6 +536,17 @@ int btc_dpm_enable(struct radeon_device *rdev);
>  void btc_dpm_disable(struct radeon_device *rdev);
>  int btc_dpm_set_power_state(struct radeon_device *rdev);
>  void btc_dpm_fini(struct radeon_device *rdev);
> +int sumo_dpm_init(struct radeon_device *rdev);
> +int sumo_dpm_enable(struct radeon_device *rdev);
> +void sumo_dpm_disable(struct radeon_device *rdev);
> +int sumo_dpm_set_power_state(struct radeon_device *rdev);
> +void sumo_dpm_setup_asic(struct radeon_device *rdev);
> +void sumo_dpm_display_configuration_changed(struct radeon_device *rdev);
> +void sumo_dpm_fini(struct radeon_device *rdev);
> +u32 sumo_dpm_get_sclk(struct radeon_device *rdev, bool low);
> +u32 sumo_dpm_get_mclk(struct radeon_device *rdev, bool low);
> +void sumo_dpm_print_power_state(struct radeon_device *rdev,
> +				struct radeon_ps *ps);
>  
>  /*
>   * cayman
> diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
> index 0a770b5..b924bcc1 100644
> --- a/drivers/gpu/drm/radeon/radeon_pm.c
> +++ b/drivers/gpu/drm/radeon/radeon_pm.c
> @@ -1049,6 +1049,9 @@ int radeon_pm_init(struct radeon_device *rdev)
>  	case CHIP_JUNIPER:
>  	case CHIP_CYPRESS:
>  	case CHIP_HEMLOCK:
> +	case CHIP_PALM:
> +	case CHIP_SUMO:
> +	case CHIP_SUMO2:
>  	case CHIP_BARTS:
>  	case CHIP_TURKS:
>  	case CHIP_CAICOS:
> diff --git a/drivers/gpu/drm/radeon/sumo_dpm.c b/drivers/gpu/drm/radeon/sumo_dpm.c
> new file mode 100644
> index 0000000..4f49450
> --- /dev/null
> +++ b/drivers/gpu/drm/radeon/sumo_dpm.c
> @@ -0,0 +1,1677 @@
> +/*
> + * Copyright 2012 Advanced Micro Devices, Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + *
> + */
> +
> +#include "drmP.h"
> +#include "radeon.h"
> +#include "sumod.h"
> +#include "r600_dpm.h"
> +#include "cypress_dpm.h"
> +#include "sumo_dpm.h"
> +#include "atom.h"
> +
> +#define SUMO_MAX_DEEPSLEEP_DIVIDER_ID 5
> +#define SUMO_MINIMUM_ENGINE_CLOCK 800
> +#define BOOST_DPM_LEVEL 7
> +
> +static const u32 sumo_utc[SUMO_PM_NUMBER_OF_TC] =
> +{
> +	SUMO_UTC_DFLT_00,
> +	SUMO_UTC_DFLT_01,
> +	SUMO_UTC_DFLT_02,
> +	SUMO_UTC_DFLT_03,
> +	SUMO_UTC_DFLT_04,
> +	SUMO_UTC_DFLT_05,
> +	SUMO_UTC_DFLT_06,
> +	SUMO_UTC_DFLT_07,
> +	SUMO_UTC_DFLT_08,
> +	SUMO_UTC_DFLT_09,
> +	SUMO_UTC_DFLT_10,
> +	SUMO_UTC_DFLT_11,
> +	SUMO_UTC_DFLT_12,
> +	SUMO_UTC_DFLT_13,
> +	SUMO_UTC_DFLT_14,
> +};
> +
> +static const u32 sumo_dtc[SUMO_PM_NUMBER_OF_TC] =
> +{
> +	SUMO_DTC_DFLT_00,
> +	SUMO_DTC_DFLT_01,
> +	SUMO_DTC_DFLT_02,
> +	SUMO_DTC_DFLT_03,
> +	SUMO_DTC_DFLT_04,
> +	SUMO_DTC_DFLT_05,
> +	SUMO_DTC_DFLT_06,
> +	SUMO_DTC_DFLT_07,
> +	SUMO_DTC_DFLT_08,
> +	SUMO_DTC_DFLT_09,
> +	SUMO_DTC_DFLT_10,
> +	SUMO_DTC_DFLT_11,
> +	SUMO_DTC_DFLT_12,
> +	SUMO_DTC_DFLT_13,
> +	SUMO_DTC_DFLT_14,
> +};
> +
> +struct sumo_ps *sumo_get_ps(struct radeon_ps *rps)
> +{
> +	struct sumo_ps *ps = rps->ps_priv;
> +
> +	return ps;
> +}
> +
> +struct sumo_power_info *sumo_get_pi(struct radeon_device *rdev)
> +{
> +	struct sumo_power_info *pi = rdev->pm.dpm.priv;
> +
> +	return pi;
> +}
> +
> +u32 sumo_get_xclk(struct radeon_device *rdev)
> +{
> +	return rdev->clock.spll.reference_freq;
> +}
> +
> +static void sumo_gfx_clockgating_enable(struct radeon_device *rdev, bool enable)
> +{
> +	if (enable)
> +		WREG32_P(SCLK_PWRMGT_CNTL, DYN_GFX_CLK_OFF_EN, ~DYN_GFX_CLK_OFF_EN);
> +	else {
> +		WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_GFX_CLK_OFF_EN);
> +		WREG32_P(SCLK_PWRMGT_CNTL, GFX_CLK_FORCE_ON, ~GFX_CLK_FORCE_ON);
> +		WREG32_P(SCLK_PWRMGT_CNTL, 0, ~GFX_CLK_FORCE_ON);
> +		RREG32(GB_ADDR_CONFIG);
> +	}
> +}
> +
> +#define CGCG_CGTT_LOCAL0_MASK 0xE5BFFFFF
> +#define CGCG_CGTT_LOCAL1_MASK 0xEFFF07FF
> +
> +static void sumo_mg_clockgating_enable(struct radeon_device *rdev, bool enable)
> +{
> +	u32 local0;
> +	u32 local1;
> +
> +	local0 = RREG32(CG_CGTT_LOCAL_0);
> +	local1 = RREG32(CG_CGTT_LOCAL_1);
> +
> +	if (enable) {
> +		WREG32(CG_CGTT_LOCAL_0, (0 & CGCG_CGTT_LOCAL0_MASK) | (local0 & ~CGCG_CGTT_LOCAL0_MASK) );
> +		WREG32(CG_CGTT_LOCAL_1, (0 & CGCG_CGTT_LOCAL1_MASK) | (local1 & ~CGCG_CGTT_LOCAL1_MASK) );
> +	} else {
> +		WREG32(CG_CGTT_LOCAL_0, (0xFFFFFFFF & CGCG_CGTT_LOCAL0_MASK) | (local0 & ~CGCG_CGTT_LOCAL0_MASK) );
> +		WREG32(CG_CGTT_LOCAL_1, (0xFFFFCFFF & CGCG_CGTT_LOCAL1_MASK) | (local1 & ~CGCG_CGTT_LOCAL1_MASK) );
> +	}
> +}
> +
> +static void sumo_program_git(struct radeon_device *rdev)
> +{
> +	u32 p, u;
> +	u32 xclk = sumo_get_xclk(rdev);
> +
> +	r600_calculate_u_and_p(SUMO_GICST_DFLT,
> +			       xclk, 16, &p, &u);
> +
> +	WREG32_P(CG_GIT, CG_GICST(p), ~CG_GICST_MASK);
> +}
> +
> +static void sumo_program_grsd(struct radeon_device *rdev)
> +{
> +	u32 p, u;
> +	u32 xclk = sumo_get_xclk(rdev);
> +	u32 grs = 256 * 25 / 100;
> +
> +	r600_calculate_u_and_p(1, xclk, 14, &p, &u);
> +
> +	WREG32(CG_GCOOR, PHC(grs) | SDC(p) | SU(u));
> +}
> +
> +static void sumo_gfx_clockgating_initialize(struct radeon_device *rdev)
> +{
> +	sumo_program_git(rdev);
> +	sumo_program_grsd(rdev);
> +}
> +
> +static void sumo_gfx_powergating_initialize(struct radeon_device *rdev)
> +{
> +	u32 rcu_pwr_gating_cntl;
> +	u32 p, u;
> +	u32 p_c, p_p, d_p;
> +	u32 r_t, i_t;
> +	u32 xclk = sumo_get_xclk(rdev);
> +
> +	if (rdev->family == CHIP_PALM) {
> +		p_c = 4;
> +		d_p = 10;
> +		r_t = 10;
> +		i_t = 4;
> +		p_p = 50 + 1000/200 + 6 * 32;
> +	} else {
> +		p_c = 16;
> +		d_p = 50;
> +		r_t = 50;
> +		i_t  = 50;
> +		p_p = 113;
> +	}
> +
> +	WREG32(CG_SCRATCH2, 0x01B60A17);
> +
> +	r600_calculate_u_and_p(SUMO_GFXPOWERGATINGT_DFLT,
> +			       xclk, 16, &p, &u);
> +
> +	WREG32_P(CG_PWR_GATING_CNTL, PGP(p) | PGU(u),
> +		 ~(PGP_MASK | PGU_MASK));
> +
> +	r600_calculate_u_and_p(SUMO_VOLTAGEDROPT_DFLT,
> +			       xclk, 16, &p, &u);
> +
> +	WREG32_P(CG_CG_VOLTAGE_CNTL, PGP(p) | PGU(u),
> +		 ~(PGP_MASK | PGU_MASK));
> +
> +	if (rdev->family == CHIP_PALM) {
> +		WREG32_RCU(RCU_PWR_GATING_SEQ0, 0x10103210);
> +		WREG32_RCU(RCU_PWR_GATING_SEQ1, 0x10101010);
> +	} else {
> +		WREG32_RCU(RCU_PWR_GATING_SEQ0, 0x76543210);
> +		WREG32_RCU(RCU_PWR_GATING_SEQ1, 0xFEDCBA98);
> +	}
> +
> +	rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL);
> +	rcu_pwr_gating_cntl &=
> +		~(RSVD_MASK | PCV_MASK | PGS_MASK);
> +	rcu_pwr_gating_cntl |= PCV(p_c) | PGS(1) | PWR_GATING_EN;
> +	if (rdev->family == CHIP_PALM) {
> +		rcu_pwr_gating_cntl &= ~PCP_MASK;
> +		rcu_pwr_gating_cntl |= PCP(0x77);
> +	}
> +	WREG32_RCU(RCU_PWR_GATING_CNTL, rcu_pwr_gating_cntl);
> +
> +	rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL_2);
> +	rcu_pwr_gating_cntl &= ~(MPPU_MASK | MPPD_MASK);
> +	rcu_pwr_gating_cntl |= MPPU(p_p) | MPPD(50);
> +	WREG32_RCU(RCU_PWR_GATING_CNTL_2, rcu_pwr_gating_cntl);
> +
> +	rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL_3);
> +	rcu_pwr_gating_cntl &= ~(DPPU_MASK | DPPD_MASK);
> +	rcu_pwr_gating_cntl |= DPPU(d_p) | DPPD(50);
> +	WREG32_RCU(RCU_PWR_GATING_CNTL_3, rcu_pwr_gating_cntl);
> +
> +	rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL_4);
> +	rcu_pwr_gating_cntl &= ~(RT_MASK | IT_MASK);
> +	rcu_pwr_gating_cntl |= RT(r_t) | IT(i_t);
> +	WREG32_RCU(RCU_PWR_GATING_CNTL_4, rcu_pwr_gating_cntl);
> +
> +	if (rdev->family == CHIP_PALM)
> +		WREG32_RCU(RCU_PWR_GATING_CNTL_5, 0xA02);
> +
> +	sumo_smu_pg_init(rdev);
> +
> +	rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL);
> +	rcu_pwr_gating_cntl &=
> +		~(RSVD_MASK | PCV_MASK | PGS_MASK);
> +	rcu_pwr_gating_cntl |= PCV(p_c) | PGS(4) | PWR_GATING_EN;
> +	if (rdev->family == CHIP_PALM) {
> +		rcu_pwr_gating_cntl &= ~PCP_MASK;
> +		rcu_pwr_gating_cntl |= PCP(0x77);
> +	}
> +	WREG32_RCU(RCU_PWR_GATING_CNTL, rcu_pwr_gating_cntl);
> +
> +	if (rdev->family == CHIP_PALM) {
> +		rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL_2);
> +		rcu_pwr_gating_cntl &= ~(MPPU_MASK | MPPD_MASK);
> +		rcu_pwr_gating_cntl |= MPPU(113) | MPPD(50);
> +		WREG32_RCU(RCU_PWR_GATING_CNTL_2, rcu_pwr_gating_cntl);
> +
> +		rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL_3);
> +		rcu_pwr_gating_cntl &= ~(DPPU_MASK | DPPD_MASK);
> +		rcu_pwr_gating_cntl |= DPPU(16) | DPPD(50);
> +		WREG32_RCU(RCU_PWR_GATING_CNTL_3, rcu_pwr_gating_cntl);
> +	}
> +
> +	sumo_smu_pg_init(rdev);
> +
> +	rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL);
> +	rcu_pwr_gating_cntl &=
> +		~(RSVD_MASK | PCV_MASK | PGS_MASK);
> +	rcu_pwr_gating_cntl |= PGS(5) | PWR_GATING_EN;
> +
> +	if (rdev->family == CHIP_PALM) {
> +		rcu_pwr_gating_cntl |= PCV(4);
> +		rcu_pwr_gating_cntl &= ~PCP_MASK;
> +		rcu_pwr_gating_cntl |= PCP(0x77);
> +	} else
> +		rcu_pwr_gating_cntl |= PCV(11);
> +	WREG32_RCU(RCU_PWR_GATING_CNTL, rcu_pwr_gating_cntl);
> +
> +	if (rdev->family == CHIP_PALM) {
> +		rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL_2);
> +		rcu_pwr_gating_cntl &= ~(MPPU_MASK | MPPD_MASK);
> +		rcu_pwr_gating_cntl |= MPPU(113) | MPPD(50);
> +		WREG32_RCU(RCU_PWR_GATING_CNTL_2, rcu_pwr_gating_cntl);
> +
> +		rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL_3);
> +		rcu_pwr_gating_cntl &= ~(DPPU_MASK | DPPD_MASK);
> +		rcu_pwr_gating_cntl |= DPPU(22) | DPPD(50);
> +		WREG32_RCU(RCU_PWR_GATING_CNTL_3, rcu_pwr_gating_cntl);
> +	}
> +
> +	sumo_smu_pg_init(rdev);
> +}
> +
> +static void sumo_gfx_powergating_enable(struct radeon_device *rdev, bool enable)
> +{
> +	if (enable)
> +		WREG32_P(CG_PWR_GATING_CNTL, DYN_PWR_DOWN_EN, ~DYN_PWR_DOWN_EN);
> +	else {
> +		WREG32_P(CG_PWR_GATING_CNTL, 0, ~DYN_PWR_DOWN_EN);
> +		RREG32(GB_ADDR_CONFIG);
> +	}
> +}
> +
> +static int sumo_enable_clock_power_gating(struct radeon_device *rdev)
> +{
> +	struct sumo_power_info *pi = sumo_get_pi(rdev);
> +
> +	if (pi->enable_gfx_clock_gating)
> +		sumo_gfx_clockgating_initialize(rdev);
> +	if (pi->enable_gfx_power_gating)
> +		sumo_gfx_powergating_initialize(rdev);
> +	if (pi->enable_mg_clock_gating)
> +		sumo_mg_clockgating_enable(rdev, true);
> +	if (pi->enable_gfx_clock_gating)
> +		sumo_gfx_clockgating_enable(rdev, true);
> +	if (pi->enable_gfx_power_gating)
> +		sumo_gfx_powergating_enable(rdev, true);
> +
> +	return 0;
> +}
> +
> +static void sumo_disable_clock_power_gating(struct radeon_device *rdev)
> +{
> +	struct sumo_power_info *pi = sumo_get_pi(rdev);
> +
> +	if (pi->enable_gfx_clock_gating)
> +		sumo_gfx_clockgating_enable(rdev, false);
> +	if (pi->enable_gfx_power_gating)
> +		sumo_gfx_powergating_enable(rdev, false);
> +	if (pi->enable_mg_clock_gating)
> +		sumo_mg_clockgating_enable(rdev, false);
> +}
> +
> +static void sumo_calculate_bsp(struct radeon_device *rdev,
> +			       u32 high_clk)
> +{
> +	struct sumo_power_info *pi = sumo_get_pi(rdev);
> +	u32 xclk = sumo_get_xclk(rdev);
> +
> +	pi->pasi = 65535 * 100 / high_clk;
> +	pi->asi = 65535 * 100 / high_clk;
> +
> +	r600_calculate_u_and_p(pi->asi,
> +			       xclk, 16, &pi->bsp, &pi->bsu);
> +
> +	r600_calculate_u_and_p(pi->pasi,
> +			       xclk, 16, &pi->pbsp, &pi->pbsu);
> +
> +	pi->dsp = BSP(pi->bsp) | BSU(pi->bsu);
> +	pi->psp = BSP(pi->pbsp) | BSU(pi->pbsu);
> +}
> +
> +static void sumo_init_bsp(struct radeon_device *rdev)
> +{
> +	struct sumo_power_info *pi = sumo_get_pi(rdev);
> +
> +	WREG32(CG_BSP_0, pi->psp);
> +}
> +
> +
> +static void sumo_program_bsp(struct radeon_device *rdev)
> +{
> +	struct sumo_power_info *pi = sumo_get_pi(rdev);
> +	struct sumo_ps *ps = sumo_get_ps(rdev->pm.dpm.requested_ps);
> +	u32 i;
> +	u32 highest_engine_clock = ps->levels[ps->num_levels - 1].sclk;
> +
> +	if (ps->flags & SUMO_POWERSTATE_FLAGS_BOOST_STATE)
> +		highest_engine_clock = pi->boost_pl.sclk;
> +
> +	sumo_calculate_bsp(rdev, highest_engine_clock);
> +
> +	for (i = 0; i < ps->num_levels - 1; i++)
> +		WREG32(CG_BSP_0 + (i * 4), pi->dsp);
> +
> +	WREG32(CG_BSP_0 + (i * 4), pi->psp);
> +
> +	if (ps->flags & SUMO_POWERSTATE_FLAGS_BOOST_STATE)
> +		WREG32(CG_BSP_0 + (BOOST_DPM_LEVEL * 4), pi->psp);
> +}
> +
> +static void sumo_write_at(struct radeon_device *rdev,
> +			  u32 index, u32 value)
> +{
> +	if (index == 0)
> +		WREG32(CG_AT_0, value);
> +	else if (index == 1)
> +		WREG32(CG_AT_1, value);
> +	else if (index == 2)
> +		WREG32(CG_AT_2, value);
> +	else if (index == 3)
> +		WREG32(CG_AT_3, value);
> +	else if (index == 4)
> +		WREG32(CG_AT_4, value);
> +	else if (index == 5)
> +		WREG32(CG_AT_5, value);
> +	else if (index == 6)
> +		WREG32(CG_AT_6, value);
> +	else if (index == 7)
> +		WREG32(CG_AT_7, value);
> +}
> +
> +static void sumo_program_at(struct radeon_device *rdev)
> +{
> +	struct sumo_power_info *pi = sumo_get_pi(rdev);
> +	struct sumo_ps *ps = sumo_get_ps(rdev->pm.dpm.requested_ps);
> +	u32 asi;
> +	u32 i;
> +	u32 m_a;
> +	u32 a_t;
> +	u32 r[SUMO_MAX_HARDWARE_POWERLEVELS];
> +	u32 l[SUMO_MAX_HARDWARE_POWERLEVELS];
> +
> +	r[0] = SUMO_R_DFLT0;
> +	r[1] = SUMO_R_DFLT1;
> +	r[2] = SUMO_R_DFLT2;
> +	r[3] = SUMO_R_DFLT3;
> +	r[4] = SUMO_R_DFLT4;
> +
> +	l[0] = SUMO_L_DFLT0;
> +	l[1] = SUMO_L_DFLT1;
> +	l[2] = SUMO_L_DFLT2;
> +	l[3] = SUMO_L_DFLT3;
> +	l[4] = SUMO_L_DFLT4;
> +
> +	for (i = 0; i < ps->num_levels; i++) {
> +		asi = (i == ps->num_levels - 1) ? pi->pasi : pi->asi;
> +
> +		m_a = asi * ps->levels[i].sclk / 100;
> +
> +		a_t = CG_R(m_a * r[i] / 100) | CG_L(m_a * l[i] / 100);
> +
> +		sumo_write_at(rdev, i, a_t);
> +	}
> +
> +	if (ps->flags & SUMO_POWERSTATE_FLAGS_BOOST_STATE) {
> +		asi = pi->pasi;
> +
> +		m_a = asi * pi->boost_pl.sclk / 100;
> +
> +		a_t = CG_R(m_a * r[ps->num_levels - 1] / 100) |
> +			CG_L(m_a * l[ps->num_levels - 1] / 100);
> +
> +		sumo_write_at(rdev, BOOST_DPM_LEVEL, a_t);
> +	}
> +}
> +
> +static void sumo_program_tp(struct radeon_device *rdev)
> +{
> +	int i;
> +	enum r600_td td = R600_TD_DFLT;
> +
> +	for (i = 0; i < SUMO_PM_NUMBER_OF_TC; i++) {
> +		WREG32_P(CG_FFCT_0 + (i * 4), UTC_0(sumo_utc[i]), ~UTC_0_MASK);
> +		WREG32_P(CG_FFCT_0 + (i * 4), DTC_0(sumo_dtc[i]), ~DTC_0_MASK);
> +	}
> +
> +	if (td == R600_TD_AUTO)
> +		WREG32_P(SCLK_PWRMGT_CNTL, 0, ~FIR_FORCE_TREND_SEL);
> +	else
> +		WREG32_P(SCLK_PWRMGT_CNTL, FIR_FORCE_TREND_SEL, ~FIR_FORCE_TREND_SEL);
> +
> +	if (td == R600_TD_UP)
> +		WREG32_P(SCLK_PWRMGT_CNTL, 0, ~FIR_TREND_MODE);
> +
> +	if (td == R600_TD_DOWN)
> +		WREG32_P(SCLK_PWRMGT_CNTL, FIR_TREND_MODE, ~FIR_TREND_MODE);
> +}
> +
> +static void sumo_program_vc(struct radeon_device *rdev)
> +{
> +	WREG32(CG_FTV, SUMO_VRC_DFLT);
> +}
> +
> +static void sumo_clear_vc(struct radeon_device *rdev)
> +{
> +	WREG32(CG_FTV, 0);
> +}
> +
> +static void sumo_program_sstp(struct radeon_device *rdev)
> +{
> +	u32 p, u;
> +	u32 xclk = sumo_get_xclk(rdev);
> +
> +	r600_calculate_u_and_p(SUMO_SST_DFLT,
> +			       xclk, 16, &p, &u);
> +
> +	WREG32(CG_SSP, SSTU(u) | SST(p));
> +}
> +
> +static void sumo_set_divider_value(struct radeon_device *rdev,
> +				   u32 index, u32 divider)
> +{
> +	u32 reg_index = index / 4;
> +	u32 field_index = index % 4;
> +
> +	if (field_index == 0)
> +		WREG32_P(CG_SCLK_DPM_CTRL + (reg_index * 4),
> +			 SCLK_FSTATE_0_DIV(divider), ~SCLK_FSTATE_0_DIV_MASK);
> +	else if (field_index == 1)
> +		WREG32_P(CG_SCLK_DPM_CTRL + (reg_index * 4),
> +			 SCLK_FSTATE_1_DIV(divider), ~SCLK_FSTATE_1_DIV_MASK);
> +	else if (field_index == 2)
> +		WREG32_P(CG_SCLK_DPM_CTRL + (reg_index * 4),
> +			 SCLK_FSTATE_2_DIV(divider), ~SCLK_FSTATE_2_DIV_MASK);
> +	else if (field_index == 3)
> +		WREG32_P(CG_SCLK_DPM_CTRL + (reg_index * 4),
> +			 SCLK_FSTATE_3_DIV(divider), ~SCLK_FSTATE_3_DIV_MASK);
> +}
> +
> +static void sumo_set_ds_dividers(struct radeon_device *rdev,
> +				 u32 index, u32 divider)
> +{
> +	struct sumo_power_info *pi = sumo_get_pi(rdev);
> +
> +	if (pi->enable_sclk_ds) {
> +		u32 dpm_ctrl = RREG32(CG_SCLK_DPM_CTRL_6);
> +
> +		dpm_ctrl &= ~(0x7 << (index * 3));
> +		dpm_ctrl |= (divider << (index * 3));
> +		WREG32(CG_SCLK_DPM_CTRL_6, dpm_ctrl);
> +	}
> +}
> +
> +static void sumo_set_ss_dividers(struct radeon_device *rdev,
> +				 u32 index, u32 divider)
> +{
> +	struct sumo_power_info *pi = sumo_get_pi(rdev);
> +
> +	if (pi->enable_sclk_ds) {
> +		u32 dpm_ctrl = RREG32(CG_SCLK_DPM_CTRL_11);
> +
> +		dpm_ctrl &= ~(0x7 << (index * 3));
> +		dpm_ctrl |= (divider << (index * 3));
> +		WREG32(CG_SCLK_DPM_CTRL_11, dpm_ctrl);
> +	}
> +}
> +
> +static void sumo_set_vid(struct radeon_device *rdev, u32 index, u32 vid)
> +{
> +	u32 voltage_cntl = RREG32(CG_DPM_VOLTAGE_CNTL);
> +
> +	voltage_cntl &= ~(DPM_STATE0_LEVEL_MASK << (index * 2));
> +	voltage_cntl |= (vid << (DPM_STATE0_LEVEL_SHIFT + index * 2));
> +	WREG32(CG_DPM_VOLTAGE_CNTL, voltage_cntl);
> +}
> +
> +static void sumo_set_allos_gnb_slow(struct radeon_device *rdev, u32 index, u32 gnb_slow)
> +{
> +	struct sumo_power_info *pi = sumo_get_pi(rdev);
> +	u32 temp = gnb_slow;
> +	u32 cg_sclk_dpm_ctrl_3;
> +
> +	if (pi->driver_nbps_policy_disable)
> +		temp = 1;
> +
> +	cg_sclk_dpm_ctrl_3 = RREG32(CG_SCLK_DPM_CTRL_3);
> +	cg_sclk_dpm_ctrl_3 &= ~(GNB_SLOW_FSTATE_0_MASK << index);
> +	cg_sclk_dpm_ctrl_3 |= (temp << (GNB_SLOW_FSTATE_0_SHIFT + index));
> +
> +	WREG32(CG_SCLK_DPM_CTRL_3, cg_sclk_dpm_ctrl_3);
> +}
> +
> +static void sumo_program_power_level(struct radeon_device *rdev,
> +				     struct sumo_pl *pl, u32 index)
> +{
> +	struct sumo_power_info *pi = sumo_get_pi(rdev);
> +	int ret;
> +	struct atom_clock_dividers dividers;
> +	u32 ds_en = RREG32(DEEP_SLEEP_CNTL) & ENABLE_DS;
> +
> +        ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
> +                                             pl->sclk, false, &dividers);

Indentation issue (space instead of tab).

> +	if (ret)
> +		return;
> +
> +	sumo_set_divider_value(rdev, index, dividers.post_div);
> +
> +	sumo_set_vid(rdev, index, pl->vddc_index);
> +
> +	if (pl->ss_divider_index == 0 || pl->ds_divider_index == 0) {
> +		if (ds_en)
> +			WREG32_P(DEEP_SLEEP_CNTL, 0, ~ENABLE_DS);
> +	} else {
> +		sumo_set_ss_dividers(rdev, index, pl->ss_divider_index);
> +		sumo_set_ds_dividers(rdev, index, pl->ds_divider_index);
> +
> +		if (!ds_en)
> +			WREG32_P(DEEP_SLEEP_CNTL, ENABLE_DS, ~ENABLE_DS);
> +	}
> +
> +	sumo_set_allos_gnb_slow(rdev, index, pl->allow_gnb_slow);
> +
> +	if (pi->enable_boost)
> +		sumo_set_tdp_limit(rdev, index, pl->sclk_dpm_tdp_limit);
> +}
> +
> +static void sumo_power_level_enable(struct radeon_device *rdev, u32 index, bool enable)
> +{
> +	u32 reg_index = index / 4;
> +	u32 field_index = index % 4;
> +
> +	if (field_index == 0)
> +		WREG32_P(CG_SCLK_DPM_CTRL + (reg_index * 4),
> +			 enable ? SCLK_FSTATE_0_VLD : 0, ~SCLK_FSTATE_0_VLD);
> +	else if (field_index == 1)
> +		WREG32_P(CG_SCLK_DPM_CTRL + (reg_index * 4),
> +			 enable ? SCLK_FSTATE_1_VLD : 0, ~SCLK_FSTATE_1_VLD);
> +	else if (field_index == 2)
> +		WREG32_P(CG_SCLK_DPM_CTRL + (reg_index * 4),
> +			 enable ? SCLK_FSTATE_2_VLD : 0, ~SCLK_FSTATE_2_VLD);
> +	else if (field_index == 3)
> +		WREG32_P(CG_SCLK_DPM_CTRL + (reg_index * 4),
> +			 enable ? SCLK_FSTATE_3_VLD : 0, ~SCLK_FSTATE_3_VLD);
> +}
> +
> +static bool sumo_dpm_enabled(struct radeon_device *rdev)
> +{
> +	if (RREG32(CG_SCLK_DPM_CTRL_3) & DPM_SCLK_ENABLE)
> +		return true;
> +	else
> +		return false;
> +}
> +
> +static void sumo_start_dpm(struct radeon_device *rdev)
> +{
> +	WREG32_P(CG_SCLK_DPM_CTRL_3, DPM_SCLK_ENABLE, ~DPM_SCLK_ENABLE);
> +}
> +
> +static void sumo_stop_dpm(struct radeon_device *rdev)
> +{
> +	WREG32_P(CG_SCLK_DPM_CTRL_3, 0, ~DPM_SCLK_ENABLE);
> +}
> +
> +static void sumo_set_forced_mode(struct radeon_device *rdev, bool enable)
> +{
> +	if (enable)
> +		WREG32_P(CG_SCLK_DPM_CTRL_3, FORCE_SCLK_STATE_EN, ~FORCE_SCLK_STATE_EN);
> +	else
> +		WREG32_P(CG_SCLK_DPM_CTRL_3, 0, ~FORCE_SCLK_STATE_EN);
> +}
> +
> +static void sumo_set_forced_mode_enabled(struct radeon_device *rdev)
> +{
> +	int i;
> +
> +	sumo_set_forced_mode(rdev, true);
> +	for (i = 0; i < rdev->usec_timeout; i++) {
> +		if (RREG32(CG_SCLK_STATUS) & SCLK_OVERCLK_DETECT)
> +			break;
> +		udelay(1);
> +	}
> +}
> +
> +static void sumo_wait_for_level_0(struct radeon_device *rdev)
> +{
> +	int i;
> +
> +	for (i = 0; i < rdev->usec_timeout; i++) {
> +		if ((RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURR_SCLK_INDEX_MASK) == 0)
> +			break;
> +		udelay(1);
> +	}
> +	for (i = 0; i < rdev->usec_timeout; i++) {
> +		if ((RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURR_INDEX_MASK) == 0)
> +			break;
> +		udelay(1);
> +	}
> +}
> +
> +static void sumo_set_forced_mode_disabled(struct radeon_device *rdev)
> +{
> +	sumo_set_forced_mode(rdev, false);
> +}
> +
> +static void sumo_enable_power_level_0(struct radeon_device *rdev)
> +{
> +	sumo_power_level_enable(rdev, 0, true);
> +}
> +
> +static void sumo_patch_boost_state(struct radeon_device *rdev)
> +{
> +	struct sumo_power_info *pi = sumo_get_pi(rdev);
> +	struct sumo_ps *new_ps = sumo_get_ps(rdev->pm.dpm.requested_ps);
> +
> +	if (new_ps->flags & SUMO_POWERSTATE_FLAGS_BOOST_STATE) {
> +		pi->boost_pl = new_ps->levels[new_ps->num_levels - 1];
> +		pi->boost_pl.sclk = pi->sys_info.boost_sclk;
> +		pi->boost_pl.vddc_index = pi->sys_info.boost_vid_2bit;
> +		pi->boost_pl.sclk_dpm_tdp_limit = pi->sys_info.sclk_dpm_tdp_limit_boost;
> +	}
> +}
> +
> +static void sumo_pre_notify_alt_vddnb_change(struct radeon_device *rdev)
> +{
> +	struct sumo_ps *new_ps = sumo_get_ps(rdev->pm.dpm.requested_ps);
> +	struct sumo_ps *old_ps = sumo_get_ps(rdev->pm.dpm.current_ps);
> +	u32 nbps1_old = 0;
> +	u32 nbps1_new = 0;
> +
> +	if (old_ps != NULL)
> +		nbps1_old = (old_ps->flags & SUMO_POWERSTATE_FLAGS_FORCE_NBPS1_STATE) ? 1 : 0;
> +
> +	nbps1_new = (new_ps->flags & SUMO_POWERSTATE_FLAGS_FORCE_NBPS1_STATE) ? 1 : 0;
> +
> +	if (nbps1_old == 1 && nbps1_new == 0)
> +		sumo_smu_notify_alt_vddnb_change(rdev, 0, 0);
> +}
> +
> +static void sumo_post_notify_alt_vddnb_change(struct radeon_device *rdev)
> +{
> +	struct sumo_ps *new_ps = sumo_get_ps(rdev->pm.dpm.requested_ps);
> +	struct sumo_ps *old_ps = sumo_get_ps(rdev->pm.dpm.current_ps);
> +	u32 nbps1_old = 0;
> +	u32 nbps1_new = 0;
> +
> +	if (old_ps != NULL)
> +		nbps1_old = (old_ps->flags & SUMO_POWERSTATE_FLAGS_FORCE_NBPS1_STATE)? 1 : 0;
> +
> +	nbps1_new = (new_ps->flags & SUMO_POWERSTATE_FLAGS_FORCE_NBPS1_STATE)? 1 : 0;
> +
> +	if (nbps1_old == 0 && nbps1_new == 1)
> +		sumo_smu_notify_alt_vddnb_change(rdev, 1, 1);
> +}
> +
> +static void sumo_enable_boost(struct radeon_device *rdev, bool enable)
> +{
> +	struct sumo_ps *new_ps = sumo_get_ps(rdev->pm.dpm.requested_ps);
> +
> +	if (enable) {
> +		if (new_ps->flags & SUMO_POWERSTATE_FLAGS_BOOST_STATE)
> +			sumo_boost_state_enable(rdev, true);
> +	} else
> +		sumo_boost_state_enable(rdev, false);
> +}
> +
> +static void sumo_update_current_power_levels(struct radeon_device *rdev)
> +{
> +	struct sumo_ps *new_ps = sumo_get_ps(rdev->pm.dpm.requested_ps);
> +	struct sumo_power_info *pi = sumo_get_pi(rdev);
> +
> +	pi->current_ps = *new_ps;
> +}
> +
> +static void sumo_set_forced_level(struct radeon_device *rdev, u32 index)
> +{
> +	WREG32_P(CG_SCLK_DPM_CTRL_3, FORCE_SCLK_STATE(index), ~FORCE_SCLK_STATE_MASK);
> +}
> +
> +static void sumo_set_forced_level_0(struct radeon_device *rdev)
> +{
> +	sumo_set_forced_level(rdev, 0);
> +}
> +
> +static void sumo_program_wl(struct radeon_device *rdev)
> +{
> +	struct sumo_ps *new_ps = sumo_get_ps(rdev->pm.dpm.requested_ps);
> +	u32 dpm_ctrl4 = RREG32(CG_SCLK_DPM_CTRL_4);
> +
> +	dpm_ctrl4 &= 0xFFFFFF00;
> +	dpm_ctrl4 |= (1 << (new_ps->num_levels - 1));
> +
> +	if (new_ps->flags & SUMO_POWERSTATE_FLAGS_BOOST_STATE)
> +		dpm_ctrl4 |= (1 << BOOST_DPM_LEVEL);
> +
> +	WREG32(CG_SCLK_DPM_CTRL_4, dpm_ctrl4);
> +}
> +
> +static void sumo_program_power_levels_0_to_n(struct radeon_device *rdev)
> +{
> +	struct sumo_power_info *pi = sumo_get_pi(rdev);
> +	struct sumo_ps *new_ps = sumo_get_ps(rdev->pm.dpm.requested_ps);
> +	struct sumo_ps *old_ps = sumo_get_ps(rdev->pm.dpm.current_ps);
> +	u32 i;
> +	u32 n_current_state_levels = (old_ps == NULL) ? 1 : old_ps->num_levels;
> +
> +	for (i = 0; i < new_ps->num_levels; i++) {
> +		sumo_program_power_level(rdev, &new_ps->levels[i], i);
> +		sumo_power_level_enable(rdev, i, true);
> +	}
> +
> +	for (i = new_ps->num_levels; i < n_current_state_levels; i++)
> +		sumo_power_level_enable(rdev, i, false);
> +
> +	if (new_ps->flags & SUMO_POWERSTATE_FLAGS_BOOST_STATE)
> +		sumo_program_power_level(rdev, &pi->boost_pl, BOOST_DPM_LEVEL);
> +}
> +
> +static void sumo_enable_acpi_pm(struct radeon_device *rdev)
> +{
> +	WREG32_P(GENERAL_PWRMGT, STATIC_PM_EN, ~STATIC_PM_EN);
> +}
> +
> +static void sumo_program_power_level_enter_state(struct radeon_device *rdev)
> +{
> +	WREG32_P(CG_SCLK_DPM_CTRL_5, SCLK_FSTATE_BOOTUP(0), ~SCLK_FSTATE_BOOTUP_MASK);
> +}
> +
> +static void sumo_program_acpi_power_level(struct radeon_device *rdev)
> +{
> +	struct sumo_power_info *pi = sumo_get_pi(rdev);
> +	struct atom_clock_dividers dividers;
> +	int ret;
> +
> +        ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
> +                                             pi->acpi_pl.sclk,
> +					     false, &dividers);
> +	if (ret)
> +		return;
> +
> +	WREG32_P(CG_ACPI_CNTL, SCLK_ACPI_DIV(dividers.post_div), ~SCLK_ACPI_DIV_MASK);
> +	WREG32_P(CG_ACPI_VOLTAGE_CNTL, 0, ~ACPI_VOLTAGE_EN);
> +}
> +
> +static void sumo_program_bootup_state(struct radeon_device *rdev)
> +{
> +	struct sumo_power_info *pi = sumo_get_pi(rdev);
> +	u32 dpm_ctrl4 = RREG32(CG_SCLK_DPM_CTRL_4);
> +	u32 i;
> +
> +	sumo_program_power_level(rdev, &pi->boot_pl, 0);
> +
> +	dpm_ctrl4 &= 0xFFFFFF00;
> +	WREG32(CG_SCLK_DPM_CTRL_4, dpm_ctrl4);
> +
> +	for (i = 1; i < 8; i++)
> +		sumo_power_level_enable(rdev, i, false);
> +}
> +
> +static void sumo_take_smu_control(struct radeon_device *rdev, bool enable)
> +{
> +	u32 v = RREG32(DOUT_SCRATCH3);
> +
> +	if (enable)
> +		v |= 0x4;
> +	else
> +		v &= 0xFFFFFFFB;
> +
> +	WREG32(DOUT_SCRATCH3, v);
> +}
> +
> +static void sumo_enable_sclk_ds(struct radeon_device *rdev, bool enable)
> +{
> +	if (enable) {
> +		u32 deep_sleep_cntl = RREG32(DEEP_SLEEP_CNTL);
> +		u32 deep_sleep_cntl2 = RREG32(DEEP_SLEEP_CNTL2);
> +		u32 t = 1;
> +
> +		deep_sleep_cntl &= ~R_DIS;
> +		deep_sleep_cntl &= ~HS_MASK;
> +		deep_sleep_cntl |= HS(t > 4095 ? 4095 : t);
> +
> +		deep_sleep_cntl2 |= LB_UFP_EN;
> +		deep_sleep_cntl2 &= INOUT_C_MASK;
> +		deep_sleep_cntl2 |= INOUT_C(0xf);
> +
> +		WREG32(DEEP_SLEEP_CNTL2, deep_sleep_cntl2);
> +		WREG32(DEEP_SLEEP_CNTL, deep_sleep_cntl);
> +	} else
> +		WREG32_P(DEEP_SLEEP_CNTL, 0, ~ENABLE_DS);
> +}
> +
> +static void sumo_program_bootup_at(struct radeon_device *rdev)
> +{
> +	WREG32_P(CG_AT_0, CG_R(0xffff), ~CG_R_MASK);
> +	WREG32_P(CG_AT_0, CG_L(0), ~CG_L_MASK);
> +}
> +
> +static void sumo_reset_am(struct radeon_device *rdev)
> +{
> +	WREG32_P(SCLK_PWRMGT_CNTL, FIR_RESET, ~FIR_RESET);
> +}
> +
> +static void sumo_start_am(struct radeon_device *rdev)
> +{
> +	WREG32_P(SCLK_PWRMGT_CNTL, 0, ~FIR_RESET);
> +}
> +
> +static void sumo_program_ttp(struct radeon_device *rdev)
> +{
> +	u32 xclk = sumo_get_xclk(rdev);
> +	u32 p, u;
> +	u32 cg_sclk_dpm_ctrl_5 = RREG32(CG_SCLK_DPM_CTRL_5);
> +
> +	r600_calculate_u_and_p(1000,
> +			       xclk, 16, &p, &u);
> +
> +	cg_sclk_dpm_ctrl_5 &= ~(TT_TP_MASK | TT_TU_MASK);
> +	cg_sclk_dpm_ctrl_5 |= TT_TP(p) | TT_TU(u);
> +
> +	WREG32(CG_SCLK_DPM_CTRL_5, cg_sclk_dpm_ctrl_5);
> +}
> +
> +static void sumo_program_ttt(struct radeon_device *rdev)
> +{
> +	u32 cg_sclk_dpm_ctrl_3 = RREG32(CG_SCLK_DPM_CTRL_3);
> +	struct sumo_power_info *pi = sumo_get_pi(rdev);
> +
> +	cg_sclk_dpm_ctrl_3 &= ~(GNB_TT_MASK | GNB_THERMTHRO_MASK);
> +	cg_sclk_dpm_ctrl_3 |= GNB_TT(pi->thermal_auto_throttling + 49);
> +
> +	WREG32(CG_SCLK_DPM_CTRL_3, cg_sclk_dpm_ctrl_3);
> +}
> +
> +
> +static void sumo_enable_voltage_scaling(struct radeon_device *rdev, bool enable)
> +{
> +	if (enable) {
> +		WREG32_P(CG_DPM_VOLTAGE_CNTL, DPM_VOLTAGE_EN, ~DPM_VOLTAGE_EN);
> +		WREG32_P(CG_CG_VOLTAGE_CNTL, 0, ~CG_VOLTAGE_EN);
> +	} else {
> +		WREG32_P(CG_CG_VOLTAGE_CNTL, CG_VOLTAGE_EN, ~CG_VOLTAGE_EN);
> +		WREG32_P(CG_DPM_VOLTAGE_CNTL, 0, ~DPM_VOLTAGE_EN);
> +	}
> +}
> +
> +static void sumo_override_cnb_thermal_events(struct radeon_device *rdev)
> +{
> +	WREG32_P(CG_SCLK_DPM_CTRL_3, CNB_THERMTHRO_MASK_SCLK,
> +		 ~CNB_THERMTHRO_MASK_SCLK);
> +}
> +
> +static void sumo_program_dc_hto(struct radeon_device *rdev)
> +{
> +	u32 cg_sclk_dpm_ctrl_4 = RREG32(CG_SCLK_DPM_CTRL_4);
> +	u32 p, u;
> +	u32 xclk = sumo_get_xclk(rdev);
> +
> +	r600_calculate_u_and_p(100000,
> +			       xclk, 14, &p, &u);
> +
> +	cg_sclk_dpm_ctrl_4 &= ~(DC_HDC_MASK | DC_HU_MASK);
> +	cg_sclk_dpm_ctrl_4 |= DC_HDC(p) | DC_HU(u);
> +
> +	WREG32(CG_SCLK_DPM_CTRL_4, cg_sclk_dpm_ctrl_4);
> +}
> +
> +static void sumo_force_nbp_state(struct radeon_device *rdev)
> +{
> +	struct sumo_power_info *pi = sumo_get_pi(rdev);
> +	struct sumo_ps *new_ps = sumo_get_ps(rdev->pm.dpm.requested_ps);
> +
> +	if (!pi->driver_nbps_policy_disable) {
> +		if (new_ps->flags & SUMO_POWERSTATE_FLAGS_FORCE_NBPS1_STATE)
> +			WREG32_P(CG_SCLK_DPM_CTRL_3, FORCE_NB_PSTATE_1, ~FORCE_NB_PSTATE_1);
> +		else
> +			WREG32_P(CG_SCLK_DPM_CTRL_3, 0, ~FORCE_NB_PSTATE_1);
> +	}
> +}
> +
> +static u32 sumo_get_sleep_divider_from_id(u32 id)
> +{
> +	return 1 << id;
> +}
> +
> +static u32 sumo_get_sleep_divider_id_from_clock(struct radeon_device *rdev,
> +						u32 sclk,
> +						u32 min_sclk_in_sr)
> +{
> +	struct sumo_power_info *pi = sumo_get_pi(rdev);
> +	u32 i;
> +	u32 temp;
> +	u32 min = (min_sclk_in_sr > SUMO_MINIMUM_ENGINE_CLOCK) ?
> +		min_sclk_in_sr : SUMO_MINIMUM_ENGINE_CLOCK;
> +
> +	if (sclk < min)
> +		return 0;
> +
> +	if (!pi->enable_sclk_ds)
> +		return 0;
> +
> +	for (i = SUMO_MAX_DEEPSLEEP_DIVIDER_ID;  ; i--) {
> +		temp = sclk / sumo_get_sleep_divider_from_id(i);
> +
> +		if (temp >= min || i == 0)
> +			break;
> +	}
> +	return i;
> +}
> +
> +static u32 sumo_get_valid_engine_clock(struct radeon_device *rdev,
> +				       u32 lower_limit)
> +{
> +	struct sumo_power_info *pi = sumo_get_pi(rdev);
> +	u32 i;
> +
> +	for (i = 0; i < pi->sys_info.sclk_voltage_mapping_table.num_max_dpm_entries; i++) {
> +		if (pi->sys_info.sclk_voltage_mapping_table.entries[i].sclk_frequency >= lower_limit)
> +			return pi->sys_info.sclk_voltage_mapping_table.entries[i].sclk_frequency;
> +	}
> +
> +	return pi->sys_info.sclk_voltage_mapping_table.entries[pi->sys_info.sclk_voltage_mapping_table.num_max_dpm_entries - 1].sclk_frequency;
> +}
> +
> +static void sumo_patch_thermal_state(struct radeon_device *rdev,
> +				     struct sumo_ps *ps,
> +				     struct sumo_ps *current_ps)
> +{
> +	struct sumo_power_info *pi = sumo_get_pi(rdev);
> +	u32 sclk_in_sr = pi->sys_info.min_sclk; /* ??? */
> +	u32 current_vddc;
> +	u32 current_sclk;
> +	u32 current_index = 0;
> +
> +	if (current_ps) {
> +		current_vddc = current_ps->levels[current_index].vddc_index;
> +		current_sclk = current_ps->levels[current_index].sclk;
> +	} else {
> +		current_vddc = pi->boot_pl.vddc_index;
> +		current_sclk = pi->boot_pl.sclk;
> +	}
> +
> +	ps->levels[0].vddc_index = current_vddc;
> +
> +	if (ps->levels[0].sclk > current_sclk)
> +		ps->levels[0].sclk = current_sclk;
> +
> +	ps->levels[0].ss_divider_index =
> +		sumo_get_sleep_divider_id_from_clock(rdev, ps->levels[0].sclk, sclk_in_sr);
> +
> +	ps->levels[0].ds_divider_index =
> +		sumo_get_sleep_divider_id_from_clock(rdev, ps->levels[0].sclk, SUMO_MINIMUM_ENGINE_CLOCK);
> +
> +	if (ps->levels[0].ds_divider_index > ps->levels[0].ss_divider_index + 1)
> +		ps->levels[0].ds_divider_index = ps->levels[0].ss_divider_index + 1;
> +
> +	if (ps->levels[0].ss_divider_index == ps->levels[0].ds_divider_index) {
> +		if (ps->levels[0].ss_divider_index > 1)
> +			ps->levels[0].ss_divider_index = ps->levels[0].ss_divider_index - 1;
> +	}
> +
> +	if (ps->levels[0].ss_divider_index == 0)
> +		ps->levels[0].ds_divider_index = 0;
> +
> +	if (ps->levels[0].ds_divider_index == 0)
> +		ps->levels[0].ss_divider_index = 0;
> +}
> +
> +static void sumo_apply_state_adjust_rules(struct radeon_device *rdev)
> +{
> +	struct radeon_ps *rps = rdev->pm.dpm.requested_ps;
> +	struct sumo_ps *ps = sumo_get_ps(rps);
> +	struct sumo_ps *current_ps = sumo_get_ps(rdev->pm.dpm.current_ps);
> +	struct sumo_power_info *pi = sumo_get_pi(rdev);
> +	u32 min_voltage = 0; /* ??? */
> +	u32 min_sclk = pi->sys_info.min_sclk; /* XXX check against disp reqs */
> +	u32 sclk_in_sr = pi->sys_info.min_sclk; /* ??? */
> +	u32 i;
> +
> +	if (rps->class & ATOM_PPLIB_CLASSIFICATION_THERMAL)
> +		return sumo_patch_thermal_state(rdev, ps, current_ps);
> +
> +	if (pi->enable_boost) {
> +		if (rps->class & ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE)
> +			ps->flags |= SUMO_POWERSTATE_FLAGS_BOOST_STATE;
> +	}
> +
> +	if ((rps->class & ATOM_PPLIB_CLASSIFICATION_UI_BATTERY) ||
> +	    (rps->class & ATOM_PPLIB_CLASSIFICATION_SDSTATE) ||
> +	    (rps->class & ATOM_PPLIB_CLASSIFICATION_HDSTATE))
> +		ps->flags |= SUMO_POWERSTATE_FLAGS_FORCE_NBPS1_STATE;
> +
> +	for (i = 0; i < ps->num_levels; i++) {
> +		if (ps->levels[i].vddc_index < min_voltage)
> +			ps->levels[i].vddc_index = min_voltage;
> +
> +		if (ps->levels[i].sclk < min_sclk)
> +			ps->levels[i].sclk =
> +				sumo_get_valid_engine_clock(rdev, min_sclk);
> +
> +		ps->levels[i].ss_divider_index =
> +			sumo_get_sleep_divider_id_from_clock(rdev, ps->levels[i].sclk, sclk_in_sr);
> +
> +		ps->levels[i].ds_divider_index =
> +			sumo_get_sleep_divider_id_from_clock(rdev, ps->levels[i].sclk, SUMO_MINIMUM_ENGINE_CLOCK);
> +
> +		if (ps->levels[i].ds_divider_index > ps->levels[i].ss_divider_index + 1)
> +			ps->levels[i].ds_divider_index = ps->levels[i].ss_divider_index + 1;
> +
> +		if (ps->levels[i].ss_divider_index == ps->levels[i].ds_divider_index) {
> +			if (ps->levels[i].ss_divider_index > 1)
> +				ps->levels[i].ss_divider_index = ps->levels[i].ss_divider_index - 1;
> +		}
> +
> +		if (ps->levels[i].ss_divider_index == 0)
> +			ps->levels[i].ds_divider_index = 0;
> +
> +		if (ps->levels[i].ds_divider_index == 0)
> +			ps->levels[i].ss_divider_index = 0;
> +
> +		if (ps->flags & SUMO_POWERSTATE_FLAGS_FORCE_NBPS1_STATE)
> +			ps->levels[i].allow_gnb_slow = 1;
> +		else if ((rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE) ||
> +			 (rps->class2 & ATOM_PPLIB_CLASSIFICATION2_MVC))
> +			ps->levels[i].allow_gnb_slow = 0;
> +		else if (i == ps->num_levels - 1)
> +			ps->levels[i].allow_gnb_slow = 0;
> +		else
> +			ps->levels[i].allow_gnb_slow = 1;
> +	}
> +}
> +
> +static void sumo_cleanup_asic(struct radeon_device *rdev)
> +{
> +	sumo_take_smu_control(rdev, false);
> +}
> +
> +static int sumo_set_thermal_temperature_range(struct radeon_device *rdev,
> +					      int min_temp, int max_temp)
> +{
> +	int low_temp = 0 * 1000;
> +	int high_temp = 255 * 1000;
> +
> +	if (low_temp < min_temp)
> +		low_temp = min_temp;
> +	if (high_temp > max_temp)
> +		high_temp = max_temp;
> +	if (high_temp < low_temp) {
> +		DRM_ERROR("invalid thermal range: %d - %d\n", low_temp, high_temp);
> +		return -EINVAL;
> +	}
> +
> +	WREG32_P(CG_THERMAL_INT, DIG_THERM_INTH(49 + (high_temp / 1000)), ~DIG_THERM_INTH_MASK);
> +	WREG32_P(CG_THERMAL_INT, DIG_THERM_INTL(49 + (low_temp / 1000)), ~DIG_THERM_INTL_MASK);
> +
> +	rdev->pm.dpm.thermal.min_temp = low_temp;
> +	rdev->pm.dpm.thermal.max_temp = high_temp;
> +
> +	return 0;
> +}
> +
> +int sumo_dpm_enable(struct radeon_device *rdev)
> +{
> +	struct sumo_power_info *pi = sumo_get_pi(rdev);
> +
> +	if (sumo_dpm_enabled(rdev))
> +		return -EINVAL;
> +
> +	sumo_enable_clock_power_gating(rdev);
> +	sumo_program_bootup_state(rdev);
> +	sumo_init_bsp(rdev);
> +	sumo_reset_am(rdev);
> +	sumo_program_tp(rdev);
> +	sumo_program_bootup_at(rdev);
> +	sumo_start_am(rdev);
> +	if (pi->enable_auto_thermal_throttling) {
> +		sumo_program_ttp(rdev);
> +		sumo_program_ttt(rdev);
> +	}
> +	sumo_program_dc_hto(rdev);
> +	sumo_program_power_level_enter_state(rdev);
> +	sumo_enable_voltage_scaling(rdev, true);
> +	sumo_program_sstp(rdev);
> +	sumo_program_vc(rdev);
> +	sumo_override_cnb_thermal_events(rdev);
> +	sumo_start_dpm(rdev);
> +	sumo_wait_for_level_0(rdev);
> +	if (pi->enable_sclk_ds)
> +		sumo_enable_sclk_ds(rdev, true);
> +	if (pi->enable_boost)
> +		sumo_enable_boost_timer(rdev);
> +
> +	if (rdev->irq.installed &&
> +	    r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
> +		sumo_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
> +		rdev->irq.dpm_thermal = true;
> +		radeon_irq_set(rdev);
> +	}
> +
> +	return 0;
> +}
> +
> +void sumo_dpm_disable(struct radeon_device *rdev)
> +{
> +	struct sumo_power_info *pi = sumo_get_pi(rdev);
> +
> +	if (!sumo_dpm_enabled(rdev))
> +		return;
> +	sumo_disable_clock_power_gating(rdev);
> +	if (pi->enable_sclk_ds)
> +		sumo_enable_sclk_ds(rdev, false);
> +	sumo_clear_vc(rdev);
> +	sumo_wait_for_level_0(rdev);
> +	sumo_stop_dpm(rdev);
> +	sumo_enable_voltage_scaling(rdev, false);
> +
> +	if (rdev->irq.installed &&
> +	    r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
> +		rdev->irq.dpm_thermal = false;
> +		radeon_irq_set(rdev);
> +	}
> +}
> +
> +int sumo_dpm_set_power_state(struct radeon_device *rdev)
> +{
> +	struct sumo_power_info *pi = sumo_get_pi(rdev);
> +
> +	if (pi->enable_dynamic_patch_ps)
> +		sumo_apply_state_adjust_rules(rdev);
> +	sumo_update_current_power_levels(rdev);
> +	if (pi->enable_boost) {
> +		sumo_enable_boost(rdev, false);
> +		sumo_patch_boost_state(rdev);
> +	}
> +	if (pi->enable_dpm) {
> +		sumo_pre_notify_alt_vddnb_change(rdev);
> +		sumo_enable_power_level_0(rdev);
> +		sumo_set_forced_level_0(rdev);
> +		sumo_set_forced_mode_enabled(rdev);
> +		sumo_wait_for_level_0(rdev);
> +		sumo_program_power_levels_0_to_n(rdev);
> +		sumo_program_wl(rdev);
> +		sumo_program_bsp(rdev);
> +		sumo_program_at(rdev);
> +		sumo_force_nbp_state(rdev);
> +		sumo_set_forced_mode_disabled(rdev);
> +		sumo_set_forced_mode_enabled(rdev);
> +		sumo_set_forced_mode_disabled(rdev);
> +		sumo_post_notify_alt_vddnb_change(rdev);
> +	}
> +	if (pi->enable_boost)
> +		sumo_enable_boost(rdev, true);
> +
> +	return 0;
> +}
> +
> +void sumo_dpm_reset_asic(struct radeon_device *rdev)
> +{
> +	sumo_program_bootup_state(rdev);
> +	sumo_enable_power_level_0(rdev);
> +	sumo_set_forced_level_0(rdev);
> +	sumo_set_forced_mode_enabled(rdev);
> +	sumo_wait_for_level_0(rdev);
> +	sumo_set_forced_mode_disabled(rdev);
> +	sumo_set_forced_mode_enabled(rdev);
> +	sumo_set_forced_mode_disabled(rdev);
> +}
> +
> +void sumo_dpm_setup_asic(struct radeon_device *rdev)
> +{
> +	struct sumo_power_info *pi = sumo_get_pi(rdev);
> +
> +	sumo_initialize_m3_arb(rdev);
> +	pi->fw_version = sumo_get_running_fw_version(rdev);
> +	DRM_INFO("Found smc ucode version: 0x%08x\n", pi->fw_version);
> +	sumo_program_acpi_power_level(rdev);
> +	sumo_enable_acpi_pm(rdev);
> +	sumo_take_smu_control(rdev, true);
> +}
> +
> +void sumo_dpm_display_configuration_changed(struct radeon_device *rdev)
> +{
> +
> +}
> +
> +union power_info {
> +	struct _ATOM_POWERPLAY_INFO info;
> +	struct _ATOM_POWERPLAY_INFO_V2 info_2;
> +	struct _ATOM_POWERPLAY_INFO_V3 info_3;
> +	struct _ATOM_PPLIB_POWERPLAYTABLE pplib;
> +	struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2;
> +	struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3;
> +};
> +
> +union pplib_clock_info {
> +	struct _ATOM_PPLIB_R600_CLOCK_INFO r600;
> +	struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780;
> +	struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen;
> +	struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo;
> +};
> +
> +union pplib_power_state {
> +	struct _ATOM_PPLIB_STATE v1;
> +	struct _ATOM_PPLIB_STATE_V2 v2;
> +};
> +
> +static void sumo_patch_boot_state(struct radeon_device *rdev,
> +				  struct sumo_ps *ps)
> +{
> +	struct sumo_power_info *pi = sumo_get_pi(rdev);
> +
> +	ps->num_levels = 1;
> +	ps->flags = 0;
> +	ps->levels[0] = pi->boot_pl;
> +}
> +
> +static void sumo_parse_pplib_non_clock_info(struct radeon_device *rdev,
> +					    struct radeon_ps *rps,
> +					    struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info,
> +					    u8 table_rev)
> +{
> +	struct sumo_ps *ps = sumo_get_ps(rps);
> +
> +	rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings);
> +	rps->class = le16_to_cpu(non_clock_info->usClassification);
> +	rps->class2 = le16_to_cpu(non_clock_info->usClassification2);
> +
> +	if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) {
> +		rps->vclk = le32_to_cpu(non_clock_info->ulVCLK);
> +		rps->dclk = le32_to_cpu(non_clock_info->ulDCLK);
> +	} else {
> +		rps->vclk = 0;
> +		rps->dclk = 0;
> +	}
> +
> +	if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) {
> +		rdev->pm.dpm.boot_ps = rps;
> +		sumo_patch_boot_state(rdev, ps);
> +	}
> +	if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
> +		rdev->pm.dpm.uvd_ps = rps;
> +}
> +
> +static void sumo_parse_pplib_clock_info(struct radeon_device *rdev,
> +					struct radeon_ps *rps, int index,
> +					union pplib_clock_info *clock_info)
> +{
> +	struct sumo_power_info *pi = sumo_get_pi(rdev);
> +	struct sumo_ps *ps = sumo_get_ps(rps);
> +	struct sumo_pl *pl = &ps->levels[index];
> +	u32 sclk;
> +
> +	sclk = le16_to_cpu(clock_info->sumo.usEngineClockLow);
> +	sclk |= clock_info->sumo.ucEngineClockHigh << 16;
> +	pl->sclk = sclk;
> +	pl->vddc_index = clock_info->sumo.vddcIndex;
> +	pl->sclk_dpm_tdp_limit = clock_info->sumo.tdpLimit;
> +
> +	ps->num_levels = index + 1;
> +
> +	if (pi->enable_sclk_ds) {
> +		pl->ds_divider_index = 5;
> +		pl->ss_divider_index = 4;
> +	}
> +}
> +
> +static int sumo_parse_power_table(struct radeon_device *rdev)
> +{
> +	struct radeon_mode_info *mode_info = &rdev->mode_info;
> +	struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
> +	union pplib_power_state *power_state;
> +	int i, j, k, non_clock_array_index, clock_array_index;
> +	union pplib_clock_info *clock_info;
> +	struct _StateArray *state_array;
> +	struct _ClockInfoArray *clock_info_array;
> +	struct _NonClockInfoArray *non_clock_info_array;
> +	union power_info *power_info;
> +	int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
> +        u16 data_offset;
> +	u8 frev, crev;
> +	u8 *power_state_offset;
> +	struct sumo_ps *ps;
> +
> +	if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
> +				   &frev, &crev, &data_offset))
> +		return -EINVAL;
> +	power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
> +
> +	state_array = (struct _StateArray *)
> +		(mode_info->atom_context->bios + data_offset +
> +		 le16_to_cpu(power_info->pplib.usStateArrayOffset));
> +	clock_info_array = (struct _ClockInfoArray *)
> +		(mode_info->atom_context->bios + data_offset +
> +		 le16_to_cpu(power_info->pplib.usClockInfoArrayOffset));
> +	non_clock_info_array = (struct _NonClockInfoArray *)
> +		(mode_info->atom_context->bios + data_offset +
> +		 le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset));
> +
> +	rdev->pm.dpm.ps = kzalloc(sizeof(struct radeon_ps) *
> +				  state_array->ucNumEntries, GFP_KERNEL);
> +	if (!rdev->pm.dpm.ps)
> +		return -ENOMEM;
> +	power_state_offset = (u8 *)state_array->states;
> +	rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps);
> +	rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime);
> +	rdev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime);
> +	for (i = 0; i < state_array->ucNumEntries; i++) {
> +		power_state = (union pplib_power_state *)power_state_offset;
> +		non_clock_array_index = power_state->v2.nonClockInfoIndex;
> +		non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
> +			&non_clock_info_array->nonClockInfo[non_clock_array_index];
> +		if (!rdev->pm.power_state[i].clock_info)
> +			return -EINVAL;
> +		ps = kzalloc(sizeof(struct sumo_ps), GFP_KERNEL);
> +		if (ps == NULL) {
> +			kfree(rdev->pm.dpm.ps);
> +			return -ENOMEM;
> +		}
> +		rdev->pm.dpm.ps[i].ps_priv = ps;
> +		k = 0;
> +		for (j = 0; j < power_state->v2.ucNumDPMLevels; j++) {
> +			clock_array_index = power_state->v2.clockInfoIndex[j];
> +			if (k >= SUMO_MAX_HARDWARE_POWERLEVELS)
> +				break;
> +			clock_info = (union pplib_clock_info *)
> +				&clock_info_array->clockInfo[clock_array_index * clock_info_array->ucEntrySize];
> +			sumo_parse_pplib_clock_info(rdev,
> +						    &rdev->pm.dpm.ps[i], k,
> +						    clock_info);
> +			k++;
> +		}
> +		sumo_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i],
> +						non_clock_info,
> +						non_clock_info_array->ucEntrySize);
> +		power_state_offset += 2 + power_state->v2.ucNumDPMLevels;
> +	}
> +	rdev->pm.dpm.num_ps = state_array->ucNumEntries;
> +	return 0;
> +}
> +
> +static u32 sumo_convert_vid2_to_vid7(struct radeon_device *rdev, u32 vid_2bit)
> +{
> +	struct sumo_power_info *pi = sumo_get_pi(rdev);
> +	u32 i;
> +
> +	for (i = 0; i < pi->sys_info.vid_mapping_table.num_entries; i++) {
> +		if (pi->sys_info.vid_mapping_table.entries[i].vid_2bit == vid_2bit)
> +			return pi->sys_info.vid_mapping_table.entries[i].vid_7bit;
> +	}
> +
> +	return pi->sys_info.vid_mapping_table.entries[pi->sys_info.vid_mapping_table.num_entries - 1].vid_7bit;
> +}
> +
> +static u16 sumo_convert_voltage_index_to_value(struct radeon_device *rdev,
> +					       u32 vid_2bit)
> +{
> +	u32 vid_7bit = sumo_convert_vid2_to_vid7(rdev, vid_2bit);
> +
> +	if (vid_7bit > 0x7C)
> +		return 0;
> +
> +	return (15500 - vid_7bit * 125 + 5) / 10;
> +}
> +
> +static void sumo_construct_display_voltage_mapping_table(struct radeon_device *rdev,
> +							 ATOM_CLK_VOLT_CAPABILITY *table)
> +{
> +	struct sumo_power_info *pi = sumo_get_pi(rdev);
> +	u32 i;
> +
> +	for (i = 0; i < SUMO_MAX_NUMBER_VOLTAGES; i++) {
> +		if (table[i].ulMaximumSupportedCLK == 0)
> +			break;
> +
> +		pi->sys_info.disp_clk_voltage_mapping_table.display_clock_frequency[i] =
> +			table[i].ulMaximumSupportedCLK;
> +	}
> +
> +	pi->sys_info.disp_clk_voltage_mapping_table.num_max_voltage_levels = i;
> +
> +	if (pi->sys_info.disp_clk_voltage_mapping_table.num_max_voltage_levels == 0) {
> +		pi->sys_info.disp_clk_voltage_mapping_table.display_clock_frequency[0] = 80000;
> +		pi->sys_info.disp_clk_voltage_mapping_table.num_max_voltage_levels = 1;
> +	}
> +}
> +
> +static void sumo_construct_sclk_voltage_mapping_table(struct radeon_device *rdev,
> +						      ATOM_AVAILABLE_SCLK_LIST *table)
> +{
> +	struct sumo_power_info *pi = sumo_get_pi(rdev);
> +	u32 i;
> +	u32 n = 0;
> +	u32 prev_sclk = 0;
> +
> +	for (i = 0; i < SUMO_MAX_HARDWARE_POWERLEVELS; i++) {
> +		if (table[i].ulSupportedSCLK > prev_sclk) {
> +			pi->sys_info.sclk_voltage_mapping_table.entries[n].sclk_frequency =
> +				table[i].ulSupportedSCLK;
> +			pi->sys_info.sclk_voltage_mapping_table.entries[n].vid_2bit =
> +				table[i].usVoltageIndex;
> +			prev_sclk = table[i].ulSupportedSCLK;
> +			n++;
> +		}
> +	}
> +
> +	pi->sys_info.sclk_voltage_mapping_table.num_max_dpm_entries = n;
> +}
> +
> +static void sumo_construct_vid_mapping_table(struct radeon_device *rdev,
> +					     ATOM_AVAILABLE_SCLK_LIST *table)
> +{
> +	struct sumo_power_info *pi = sumo_get_pi(rdev);
> +	u32 i, j;
> +
> +	for (i = 0; i < SUMO_MAX_HARDWARE_POWERLEVELS; i++) {
> +		if (table[i].ulSupportedSCLK != 0) {
> +			pi->sys_info.vid_mapping_table.entries[table[i].usVoltageIndex].vid_7bit =
> +				table[i].usVoltageID;
> +			pi->sys_info.vid_mapping_table.entries[table[i].usVoltageIndex].vid_2bit =
> +				table[i].usVoltageIndex;
> +		}
> +	}
> +
> +	for (i = 0; i < SUMO_MAX_NUMBER_VOLTAGES; i++) {
> +		if (pi->sys_info.vid_mapping_table.entries[i].vid_7bit == 0) {
> +			for (j = i + 1; j < SUMO_MAX_NUMBER_VOLTAGES; j++) {
> +				if (pi->sys_info.vid_mapping_table.entries[j].vid_7bit != 0) {
> +					pi->sys_info.vid_mapping_table.entries[i] =
> +						pi->sys_info.vid_mapping_table.entries[j];
> +					pi->sys_info.vid_mapping_table.entries[j].vid_7bit = 0;
> +					break;
> +				}
> +			}
> +
> +			if (j == SUMO_MAX_NUMBER_VOLTAGES)
> +				break;
> +		}
> +	}
> +
> +	pi->sys_info.vid_mapping_table.num_entries = i;
> +}
> +
> +union igp_info {
> +	struct _ATOM_INTEGRATED_SYSTEM_INFO info;
> +	struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2;
> +	struct _ATOM_INTEGRATED_SYSTEM_INFO_V5 info_5;
> +	struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 info_6;
> +};
> +
> +static int sumo_parse_sys_info_table(struct radeon_device *rdev)
> +{
> +	struct sumo_power_info *pi = sumo_get_pi(rdev);
> +	struct radeon_mode_info *mode_info = &rdev->mode_info;
> +	int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);
> +	union igp_info *igp_info;
> +	u8 frev, crev;
> +	u16 data_offset;
> +	int i;
> +
> +	if (atom_parse_data_header(mode_info->atom_context, index, NULL,
> +				   &frev, &crev, &data_offset)) {
> +		igp_info = (union igp_info *)(mode_info->atom_context->bios +
> +					      data_offset);
> +
> +		if (crev != 6) {
> +			DRM_ERROR("Unsupported IGP table: %d %d\n", frev, crev);
> +			return -EINVAL;
> +		}
> +		pi->sys_info.bootup_sclk = le32_to_cpu(igp_info->info_6.ulBootUpEngineClock);
> +		pi->sys_info.min_sclk = le32_to_cpu(igp_info->info_6.ulMinEngineClock);
> +		pi->sys_info.bootup_uma_clk = le32_to_cpu(igp_info->info_6.ulBootUpUMAClock);
> +		pi->sys_info.bootup_nb_voltage_index =
> +			le16_to_cpu(igp_info->info_6.usBootUpNBVoltage);
> +		if (igp_info->info_6.ucHtcTmpLmt == 0)
> +			pi->sys_info.htc_tmp_lmt = 203;
> +		else
> +			pi->sys_info.htc_tmp_lmt = igp_info->info_6.ucHtcTmpLmt;
> +		if (igp_info->info_6.ucHtcHystLmt == 0)
> +			pi->sys_info.htc_hyst_lmt = 5;
> +		else
> +			pi->sys_info.htc_hyst_lmt = igp_info->info_6.ucHtcHystLmt;
> +		if (pi->sys_info.htc_tmp_lmt <= pi->sys_info.htc_hyst_lmt) {
> +			DRM_ERROR("The htcTmpLmt should be larger than htcHystLmt.\n");
> +		}
> +		for (i = 0; i < NUMBER_OF_M3ARB_PARAM_SETS; i++) {
> +			pi->sys_info.csr_m3_arb_cntl_default[i] =
> +				le32_to_cpu(igp_info->info_6.ulCSR_M3_ARB_CNTL_DEFAULT[i]);
> +			pi->sys_info.csr_m3_arb_cntl_uvd[i] =
> +				le32_to_cpu(igp_info->info_6.ulCSR_M3_ARB_CNTL_UVD[i]);
> +			pi->sys_info.csr_m3_arb_cntl_fs3d[i] =
> +				le32_to_cpu(igp_info->info_6.ulCSR_M3_ARB_CNTL_FS3D[i]);
> +		}
> +		pi->sys_info.sclk_dpm_boost_margin =
> +			le32_to_cpu(igp_info->info_6.SclkDpmBoostMargin);
> +		pi->sys_info.sclk_dpm_throttle_margin =
> +			le32_to_cpu(igp_info->info_6.SclkDpmThrottleMargin);
> +		pi->sys_info.sclk_dpm_tdp_limit_pg =
> +			le16_to_cpu(igp_info->info_6.SclkDpmTdpLimitPG);
> +		pi->sys_info.gnb_tdp_limit = le16_to_cpu(igp_info->info_6.GnbTdpLimit);
> +		pi->sys_info.sclk_dpm_tdp_limit_boost =
> +			le16_to_cpu(igp_info->info_6.SclkDpmTdpLimitBoost);
> +		pi->sys_info.boost_sclk = le32_to_cpu(igp_info->info_6.ulBoostEngineCLock);
> +		pi->sys_info.boost_vid_2bit = igp_info->info_6.ulBoostVid_2bit;
> +		if (igp_info->info_6.EnableBoost)
> +			pi->sys_info.enable_boost = true;
> +		else
> +			pi->sys_info.enable_boost = false;
> +		sumo_construct_display_voltage_mapping_table(rdev,
> +							     igp_info->info_6.sDISPCLK_Voltage);
> +		sumo_construct_sclk_voltage_mapping_table(rdev,
> +							  igp_info->info_6.sAvail_SCLK);
> +		sumo_construct_vid_mapping_table(rdev, igp_info->info_6.sAvail_SCLK);
> +
> +	}
> +	return 0;
> +}
> +
> +static void sumo_construct_boot_and_acpi_state(struct radeon_device *rdev)
> +{
> +	struct sumo_power_info *pi = sumo_get_pi(rdev);
> +
> +	pi->boot_pl.sclk = pi->sys_info.bootup_sclk;
> +	pi->boot_pl.vddc_index = pi->sys_info.bootup_nb_voltage_index;
> +	pi->boot_pl.ds_divider_index = 0;
> +	pi->boot_pl.ss_divider_index = 0;
> +	pi->boot_pl.allow_gnb_slow = 1;
> +	pi->acpi_pl = pi->boot_pl;
> +	pi->current_ps.num_levels = 1;
> +	pi->current_ps.levels[0] = pi->boot_pl;
> +}
> +
> +int sumo_dpm_init(struct radeon_device *rdev)
> +{
> +	struct sumo_power_info *pi;
> +	u32 hw_rev = (RREG32(HW_REV) & ATI_REV_ID_MASK) >> ATI_REV_ID_SHIFT;
> +	int ret;
> +
> +	pi = kzalloc(sizeof(struct sumo_power_info), GFP_KERNEL);
> +	if (pi == NULL)
> +		return -ENOMEM;
> +	rdev->pm.dpm.priv = pi;
> +
> +	pi->driver_nbps_policy_disable = false;
> +	if ((rdev->family == CHIP_PALM) && (hw_rev < 3))
> +		pi->disable_gfx_power_gating_in_uvd = true;
> +	else
> +		pi->disable_gfx_power_gating_in_uvd = false;
> +	pi->enable_alt_vddnb = true;
> +	pi->enable_sclk_ds = true;
> +	pi->enable_dynamic_m3_arbiter = false;
> +	pi->enable_dynamic_patch_ps = true;
> +	pi->enable_gfx_power_gating = true;
> +	pi->enable_gfx_clock_gating = true;
> +	pi->enable_mg_clock_gating = true;
> +	pi->enable_auto_thermal_throttling = true;
> +
> +	ret = sumo_parse_sys_info_table(rdev);
> +	if (ret)
> +		return ret;
> +
> +	sumo_construct_boot_and_acpi_state(rdev);
> +
> +	ret = sumo_parse_power_table(rdev);
> +	if (ret)
> +		return ret;
> +
> +	pi->pasi = CYPRESS_HASI_DFLT;
> +	pi->asi = RV770_ASI_DFLT;
> +	pi->thermal_auto_throttling = pi->sys_info.htc_tmp_lmt;
> +	pi->enable_boost = pi->sys_info.enable_boost;
> +	pi->enable_dpm = true;
> +
> +	return 0;
> +}
> +
> +void sumo_dpm_print_power_state(struct radeon_device *rdev,
> +				struct radeon_ps *rps)
> +{
> +	int i;
> +	struct sumo_ps *ps = sumo_get_ps(rps);
> +
> +	r600_dpm_print_class_info(rps->class, rps->class2);
> +	r600_dpm_print_cap_info(rps->caps);
> +	printk("\tuvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
> +	for (i = 0; i < ps->num_levels; i++) {
> +		struct sumo_pl *pl = &ps->levels[i];
> +		printk("\t\tpower level %d    sclk: %u vddc: %u\n",
> +		       i, pl->sclk,
> +		       sumo_convert_voltage_index_to_value(rdev, pl->vddc_index));
> +	}
> +	r600_dpm_print_ps_status(rdev, rps);
> +}
> +
> +void sumo_dpm_fini(struct radeon_device *rdev)
> +{
> +	int i;
> +
> +	sumo_cleanup_asic(rdev); /* ??? */
> +
> +	for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
> +		kfree(rdev->pm.dpm.ps[i].ps_priv);
> +	}
> +	kfree(rdev->pm.dpm.ps);
> +	kfree(rdev->pm.dpm.priv);
> +}
> +
> +u32 sumo_dpm_get_sclk(struct radeon_device *rdev, bool low)
> +{
> +	struct sumo_ps *requested_state = sumo_get_ps(rdev->pm.dpm.requested_ps);
> +
> +	if (low)
> +		return requested_state->levels[0].sclk;
> +	else
> +		return requested_state->levels[requested_state->num_levels - 1].sclk;
> +}
> +
> +u32 sumo_dpm_get_mclk(struct radeon_device *rdev, bool low)
> +{
> +	struct sumo_power_info *pi = sumo_get_pi(rdev);
> +
> +	return pi->sys_info.bootup_uma_clk;
> +}
> diff --git a/drivers/gpu/drm/radeon/sumo_dpm.h b/drivers/gpu/drm/radeon/sumo_dpm.h
> new file mode 100644
> index 0000000..561bee1
> --- /dev/null
> +++ b/drivers/gpu/drm/radeon/sumo_dpm.h
> @@ -0,0 +1,199 @@
> +/*
> + * Copyright 2012 Advanced Micro Devices, Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + *
> + */
> +#ifndef __SUMO_DPM_H__
> +#define __SUMO_DPM_H__
> +
> +#define SUMO_MAX_HARDWARE_POWERLEVELS 5
> +#define SUMO_PM_NUMBER_OF_TC 15
> +
> +struct sumo_pl {
> +	u32 sclk;
> +	u32 vddc_index;
> +	u32 ds_divider_index;
> +	u32 ss_divider_index;
> +	u32 allow_gnb_slow;
> +	u32 sclk_dpm_tdp_limit;
> +};
> +
> +/* used for the flags field */
> +#define SUMO_POWERSTATE_FLAGS_FORCE_NBPS1_STATE (1 << 0)
> +#define SUMO_POWERSTATE_FLAGS_BOOST_STATE       (1 << 1)
> +
> +struct sumo_ps {
> +	struct sumo_pl levels[SUMO_MAX_HARDWARE_POWERLEVELS];
> +	u32 num_levels;
> +	/* flags */
> +	u32 flags;
> +};
> +
> +#define NUMBER_OF_M3ARB_PARAM_SETS 10
> +#define SUMO_MAX_NUMBER_VOLTAGES    4
> +
> +struct sumo_disp_clock_voltage_mapping_table {
> +	u32 num_max_voltage_levels;
> +	u32 display_clock_frequency[SUMO_MAX_NUMBER_VOLTAGES];
> +};
> +
> +struct sumo_vid_mapping_entry {
> +	u16 vid_2bit;
> +	u16 vid_7bit;
> +};
> +
> +struct sumo_vid_mapping_table {
> +	u32 num_entries;
> +	struct sumo_vid_mapping_entry entries[SUMO_MAX_NUMBER_VOLTAGES];
> +};
> +
> +struct sumo_sclk_voltage_mapping_entry {
> +	u32 sclk_frequency;
> +	u16 vid_2bit;
> +	u16 rsv;
> +};
> +
> +struct sumo_sclk_voltage_mapping_table {
> +	u32 num_max_dpm_entries;
> +	struct sumo_sclk_voltage_mapping_entry entries[SUMO_MAX_HARDWARE_POWERLEVELS];
> +};
> +
> +struct sumo_sys_info {
> +	u32 bootup_sclk;
> +	u32 min_sclk;
> +	u32 bootup_uma_clk;
> +	u16 bootup_nb_voltage_index;
> +	u8 htc_tmp_lmt;
> +	u8 htc_hyst_lmt;
> +	struct sumo_sclk_voltage_mapping_table sclk_voltage_mapping_table;
> +	struct sumo_disp_clock_voltage_mapping_table disp_clk_voltage_mapping_table;
> +	struct sumo_vid_mapping_table vid_mapping_table;
> +	u32 csr_m3_arb_cntl_default[NUMBER_OF_M3ARB_PARAM_SETS];
> +	u32 csr_m3_arb_cntl_uvd[NUMBER_OF_M3ARB_PARAM_SETS];
> +	u32 csr_m3_arb_cntl_fs3d[NUMBER_OF_M3ARB_PARAM_SETS];
> +	u32 sclk_dpm_boost_margin;
> +	u32 sclk_dpm_throttle_margin;
> +	u32 sclk_dpm_tdp_limit_pg;
> +	u32 gnb_tdp_limit;
> +	u32 sclk_dpm_tdp_limit_boost;
> +	u32 boost_sclk;
> +	u32 boost_vid_2bit;
> +	bool enable_boost;
> +};
> +
> +struct sumo_power_info {
> +	u32 asi;
> +	u32 pasi;
> +	u32 bsp;
> +	u32 bsu;
> +	u32 pbsp;
> +	u32 pbsu;
> +	u32 dsp;
> +	u32 psp;
> +	u32 thermal_auto_throttling;
> +	u32 uvd_m3_arbiter;
> +	u32 fw_version;
> +	struct sumo_sys_info sys_info;
> +	struct sumo_pl acpi_pl;
> +	struct sumo_pl boot_pl;
> +	struct sumo_pl boost_pl;
> +	struct sumo_ps current_ps;
> +	bool disable_gfx_power_gating_in_uvd;
> +	bool driver_nbps_policy_disable;
> +	bool enable_alt_vddnb;
> +	bool enable_dynamic_m3_arbiter;
> +	bool enable_gfx_clock_gating;
> +	bool enable_gfx_power_gating;
> +	bool enable_mg_clock_gating;
> +	bool enable_sclk_ds;
> +	bool enable_auto_thermal_throttling;
> +	bool enable_dynamic_patch_ps;
> +	bool enable_dpm;
> +	bool enable_boost;
> +};
> +
> +#define SUMO_UTC_DFLT_00                     0x48
> +#define SUMO_UTC_DFLT_01                     0x44
> +#define SUMO_UTC_DFLT_02                     0x44
> +#define SUMO_UTC_DFLT_03                     0x44
> +#define SUMO_UTC_DFLT_04                     0x44
> +#define SUMO_UTC_DFLT_05                     0x44
> +#define SUMO_UTC_DFLT_06                     0x44
> +#define SUMO_UTC_DFLT_07                     0x44
> +#define SUMO_UTC_DFLT_08                     0x44
> +#define SUMO_UTC_DFLT_09                     0x44
> +#define SUMO_UTC_DFLT_10                     0x44
> +#define SUMO_UTC_DFLT_11                     0x44
> +#define SUMO_UTC_DFLT_12                     0x44
> +#define SUMO_UTC_DFLT_13                     0x44
> +#define SUMO_UTC_DFLT_14                     0x44
> +
> +#define SUMO_DTC_DFLT_00                     0x48
> +#define SUMO_DTC_DFLT_01                     0x44
> +#define SUMO_DTC_DFLT_02                     0x44
> +#define SUMO_DTC_DFLT_03                     0x44
> +#define SUMO_DTC_DFLT_04                     0x44
> +#define SUMO_DTC_DFLT_05                     0x44
> +#define SUMO_DTC_DFLT_06                     0x44
> +#define SUMO_DTC_DFLT_07                     0x44
> +#define SUMO_DTC_DFLT_08                     0x44
> +#define SUMO_DTC_DFLT_09                     0x44
> +#define SUMO_DTC_DFLT_10                     0x44
> +#define SUMO_DTC_DFLT_11                     0x44
> +#define SUMO_DTC_DFLT_12                     0x44
> +#define SUMO_DTC_DFLT_13                     0x44
> +#define SUMO_DTC_DFLT_14                     0x44
> +
> +#define SUMO_AH_DFLT               5
> +
> +#define SUMO_R_DFLT0               70
> +#define SUMO_R_DFLT1               70
> +#define SUMO_R_DFLT2               70
> +#define SUMO_R_DFLT3               70
> +#define SUMO_R_DFLT4               100
> +
> +#define SUMO_L_DFLT0               0
> +#define SUMO_L_DFLT1               20
> +#define SUMO_L_DFLT2               20
> +#define SUMO_L_DFLT3               20
> +#define SUMO_L_DFLT4               20
> +#define SUMO_VRC_DFLT              0x30033
> +#define SUMO_MGCGTTLOCAL0_DFLT     0
> +#define SUMO_MGCGTTLOCAL1_DFLT     0
> +#define SUMO_GICST_DFLT            19
> +#define SUMO_SST_DFLT              8
> +#define SUMO_VOLTAGEDROPT_DFLT     1
> +#define SUMO_GFXPOWERGATINGT_DFLT  100
> +
> +/* sumo_dpm.c */
> +u32 sumo_get_xclk(struct radeon_device *rdev);
> +
> +
> +/* sumo_smc.c */
> +void sumo_initialize_m3_arb(struct radeon_device *rdev);
> +void sumo_smu_pg_init(struct radeon_device *rdev);
> +void sumo_set_tdp_limit(struct radeon_device *rdev, u32 index, u32 tdp_limit);
> +void sumo_smu_notify_alt_vddnb_change(struct radeon_device *rdev,
> +				      bool powersaving, bool force_nbps1);
> +void sumo_boost_state_enable(struct radeon_device *rdev, bool enable);
> +void sumo_enable_boost_timer(struct radeon_device *rdev);
> +u32 sumo_get_running_fw_version(struct radeon_device *rdev);
> +
> +#endif
> diff --git a/drivers/gpu/drm/radeon/sumo_smc.c b/drivers/gpu/drm/radeon/sumo_smc.c
> new file mode 100644
> index 0000000..9d0ae9b
> --- /dev/null
> +++ b/drivers/gpu/drm/radeon/sumo_smc.c
> @@ -0,0 +1,224 @@
> +/*
> + * Copyright 2012 Advanced Micro Devices, Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + *
> + */
> +
> +#include <linux/firmware.h>
> +#include "drmP.h"
> +#include "radeon.h"
> +#include "sumod.h"
> +#include "sumo_dpm.h"
> +#include "ppsmc.h"
> +#include "radeon_ucode.h"
> +
> +#define SUMO_SMU_SERVICE_ROUTINE_PG_INIT        1
> +#define SUMO_SMU_SERVICE_ROUTINE_ALTVDDNB_NOTIFY  27
> +#define SUMO_SMU_SERVICE_ROUTINE_GFX_SRV_ID_20  20
> +
> +struct sumo_ps *sumo_get_ps(struct radeon_ps *rps);
> +struct sumo_power_info *sumo_get_pi(struct radeon_device *rdev);
> +
> +static void sumo_send_msg_to_smu(struct radeon_device *rdev, u32 id)
> +{
> +	u32 gfx_int_req;
> +	int i;
> +
> +	for (i = 0; i < rdev->usec_timeout; i++) {
> +		if (RREG32(GFX_INT_STATUS) & INT_DONE)
> +			break;
> +		udelay(1);
> +	}
> +
> +	gfx_int_req = SERV_INDEX(id) | INT_REQ;
> +	WREG32(GFX_INT_REQ, gfx_int_req);
> +
> +	for (i = 0; i < rdev->usec_timeout; i++) {
> +		if (RREG32(GFX_INT_REQ) & INT_REQ)
> +			break;
> +		udelay(1);
> +	}
> +
> +	for (i = 0; i < rdev->usec_timeout; i++) {
> +		if (RREG32(GFX_INT_STATUS) & INT_ACK)
> +			break;
> +		udelay(1);
> +	}
> +
> +	for (i = 0; i < rdev->usec_timeout; i++) {
> +		if (RREG32(GFX_INT_STATUS) & INT_DONE)
> +			break;
> +		udelay(1);
> +	}
> +
> +	gfx_int_req &= ~INT_REQ;
> +	WREG32(GFX_INT_REQ, gfx_int_req);
> +}
> +
> +void sumo_initialize_m3_arb(struct radeon_device *rdev)
> +{
> +	struct sumo_power_info *pi = sumo_get_pi(rdev);
> +	u32 i;
> +
> +	if (!pi->enable_dynamic_m3_arbiter)
> +		return;
> +
> +	for (i = 0; i < NUMBER_OF_M3ARB_PARAM_SETS; i++)
> +		WREG32_RCU(MCU_M3ARB_PARAMS + (i * 4),
> +			   pi->sys_info.csr_m3_arb_cntl_default[i]);
> +
> +	for (; i < NUMBER_OF_M3ARB_PARAM_SETS * 2; i++)
> +		WREG32_RCU(MCU_M3ARB_PARAMS + (i * 4),
> +			   pi->sys_info.csr_m3_arb_cntl_uvd[i % NUMBER_OF_M3ARB_PARAM_SETS]);
> +
> +	for (; i < NUMBER_OF_M3ARB_PARAM_SETS * 3; i++)
> +		WREG32_RCU(MCU_M3ARB_PARAMS + (i * 4),
> +			   pi->sys_info.csr_m3_arb_cntl_fs3d[i % NUMBER_OF_M3ARB_PARAM_SETS]);
> +}
> +
> +static bool sumo_is_alt_vddnb_supported(struct radeon_device *rdev)
> +{
> +	struct sumo_power_info *pi = sumo_get_pi(rdev);
> +	bool return_code = false;
> +
> +	if (!pi->enable_alt_vddnb)
> +		return return_code;
> +
> +	if ((rdev->family == CHIP_SUMO) || (rdev->family == CHIP_SUMO2)) {
> +		if (pi->fw_version >= 0x00010C00)
> +			return_code = true;
> +	}
> +
> +	return return_code;
> +}
> +
> +void sumo_smu_notify_alt_vddnb_change(struct radeon_device *rdev,
> +				      bool powersaving, bool force_nbps1)
> +{
> +	u32 param = 0;
> +
> +	if (!sumo_is_alt_vddnb_supported(rdev))
> +		return;
> +
> +	if (powersaving)
> +		param |= 1;
> +
> +	if (force_nbps1)
> +		param |= 2;
> +
> +	WREG32_RCU(RCU_ALTVDDNB_NOTIFY, param);
> +
> +	sumo_send_msg_to_smu(rdev, SUMO_SMU_SERVICE_ROUTINE_ALTVDDNB_NOTIFY);
> +}
> +
> +void sumo_smu_pg_init(struct radeon_device *rdev)
> +{
> +	sumo_send_msg_to_smu(rdev, SUMO_SMU_SERVICE_ROUTINE_PG_INIT);
> +}
> +
> +static u32 sumo_power_of_4(u32 unit)
> +{
> +	u32 ret = 1;
> +	u32 i;
> +
> +	for (i = 0; i < unit; i++)
> +		ret *= 4;
> +
> +	return ret;
> +}
> +
> +void sumo_enable_boost_timer(struct radeon_device *rdev)
> +{
> +	struct sumo_power_info *pi = sumo_get_pi(rdev);
> +	u32 period, unit, timer_value;
> +	u32 xclk = sumo_get_xclk(rdev);
> +
> +	unit = (RREG32_RCU(RCU_LCLK_SCALING_CNTL) & LCLK_SCALING_TIMER_PRESCALER_MASK)
> +		>> LCLK_SCALING_TIMER_PRESCALER_SHIFT;
> +
> +	period = 100 * (xclk / 100 / sumo_power_of_4(unit));
> +
> +	timer_value = (period << 16) | (unit << 4);
> +
> +	WREG32_RCU(RCU_GNB_PWR_REP_TIMER_CNTL, timer_value);
> +	WREG32_RCU(RCU_BOOST_MARGIN, pi->sys_info.sclk_dpm_boost_margin);
> +	WREG32_RCU(RCU_THROTTLE_MARGIN, pi->sys_info.sclk_dpm_throttle_margin);
> +	WREG32_RCU(GNB_TDP_LIMIT, pi->sys_info.gnb_tdp_limit);
> +	WREG32_RCU(RCU_SclkDpmTdpLimitPG, pi->sys_info.sclk_dpm_tdp_limit_pg);
> +
> +	sumo_send_msg_to_smu(rdev, SUMO_SMU_SERVICE_ROUTINE_GFX_SRV_ID_20);
> +}
> +
> +void sumo_set_tdp_limit(struct radeon_device *rdev, u32 index, u32 tdp_limit)
> +{
> +	u32 regoffset = 0;
> +	u32 shift = 0;
> +	u32 mask = 0xFFF;
> +	u32 sclk_dpm_tdp_limit;
> +
> +	switch (index) {
> +        case 0:

Indentation issue (space instead of tab) same issue for all case below.

> +		regoffset = RCU_SclkDpmTdpLimit01;
> +		shift = 16;
> +		break;
> +        case 1:
> +		regoffset = RCU_SclkDpmTdpLimit01;
> +		shift = 0;
> +		break;
> +        case 2:
> +		regoffset = RCU_SclkDpmTdpLimit23;
> +		shift = 16;
> +		break;
> +        case 3:
> +		regoffset = RCU_SclkDpmTdpLimit23;
> +		shift = 0;
> +		break;
> +        case 4:
> +		regoffset = RCU_SclkDpmTdpLimit47;
> +		shift = 16;
> +		break;
> +        case 7:
> +		regoffset = RCU_SclkDpmTdpLimit47;
> +		shift = 0;
> +		break;
> +        default:
> +		break;
> +	}
> +
> +	sclk_dpm_tdp_limit = RREG32_RCU(regoffset);
> +	sclk_dpm_tdp_limit &= ~(mask << shift);
> +	sclk_dpm_tdp_limit |= (tdp_limit << shift);
> +	WREG32_RCU(regoffset, sclk_dpm_tdp_limit);
> +}
> +
> +void sumo_boost_state_enable(struct radeon_device *rdev, bool enable)
> +{
> +	u32 boost_disable = RREG32_RCU(RCU_GPU_BOOST_DISABLE);
> +
> +	boost_disable &= 0xFFFFFFFE;
> +	boost_disable |= (enable ? 0 : 1);
> +	WREG32_RCU(RCU_GPU_BOOST_DISABLE, boost_disable);
> +}
> +
> +u32 sumo_get_running_fw_version(struct radeon_device *rdev)
> +{
> +	return RREG32_RCU(RCU_FW_VERSION);
> +}
> +
> diff --git a/drivers/gpu/drm/radeon/sumod.h b/drivers/gpu/drm/radeon/sumod.h
> new file mode 100644
> index 0000000..a5deba6
> --- /dev/null
> +++ b/drivers/gpu/drm/radeon/sumod.h
> @@ -0,0 +1,362 @@
> +/*
> + * Copyright 2012 Advanced Micro Devices, Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + *
> + * Authors: Alex Deucher
> + */
> +#ifndef _SUMOD_H_
> +#define _SUMOD_H_
> +
> +/* pm registers */
> +
> +/* rcu */
> +#define RCU_FW_VERSION                                  0x30c
> +
> +#define RCU_PWR_GATING_SEQ0                             0x408
> +#define RCU_PWR_GATING_SEQ1                             0x40c
> +#define RCU_PWR_GATING_CNTL                             0x410
> +#       define PWR_GATING_EN                            (1 << 0)
> +#       define RSVD_MASK                                (0x3 << 1)
> +#       define PCV(x)                                   ((x) << 3)
> +#       define PCV_MASK                                 (0x1f << 3)
> +#       define PCV_SHIFT                                3
> +#       define PCP(x)                                   ((x) << 8)
> +#       define PCP_MASK                                 (0xf << 8)
> +#       define PCP_SHIFT                                8
> +#       define RPW(x)                                   ((x) << 16)
> +#       define RPW_MASK                                 (0xf << 16)
> +#       define RPW_SHIFT                                16
> +#       define ID(x)                                    ((x) << 24)
> +#       define ID_MASK                                  (0xf << 24)
> +#       define ID_SHIFT                                 24
> +#       define PGS(x)                                   ((x) << 28)
> +#       define PGS_MASK                                 (0xf << 28)
> +#       define PGS_SHIFT                                28
> +
> +#define RCU_ALTVDDNB_NOTIFY                             0x430
> +#define RCU_LCLK_SCALING_CNTL                           0x434
> +#       define LCLK_SCALING_EN                          (1 << 0)
> +#       define LCLK_SCALING_TYPE                        (1 << 1)
> +#       define LCLK_SCALING_TIMER_PRESCALER(x)          ((x) << 4)
> +#       define LCLK_SCALING_TIMER_PRESCALER_MASK        (0xf << 4)
> +#       define LCLK_SCALING_TIMER_PRESCALER_SHIFT       4
> +#       define LCLK_SCALING_TIMER_PERIOD(x)             ((x) << 16)
> +#       define LCLK_SCALING_TIMER_PERIOD_MASK           (0xf << 16)
> +#       define LCLK_SCALING_TIMER_PERIOD_SHIFT          16
> +
> +#define RCU_PWR_GATING_CNTL_2                           0x4a0
> +#       define MPPU(x)                                  ((x) << 0)
> +#       define MPPU_MASK                                (0xffff << 0)
> +#       define MPPU_SHIFT                               0
> +#       define MPPD(x)                                  ((x) << 16)
> +#       define MPPD_MASK                                (0xffff << 16)
> +#       define MPPD_SHIFT                               16
> +#define RCU_PWR_GATING_CNTL_3                           0x4a4
> +#       define DPPU(x)                                  ((x) << 0)
> +#       define DPPU_MASK                                (0xffff << 0)
> +#       define DPPU_SHIFT                               0
> +#       define DPPD(x)                                  ((x) << 16)
> +#       define DPPD_MASK                                (0xffff << 16)
> +#       define DPPD_SHIFT                               16
> +#define RCU_PWR_GATING_CNTL_4                           0x4a8
> +#       define RT(x)                                    ((x) << 0)
> +#       define RT_MASK                                  (0xffff << 0)
> +#       define RT_SHIFT                                 0
> +#       define IT(x)                                    ((x) << 16)
> +#       define IT_MASK                                  (0xffff << 16)
> +#       define IT_SHIFT                                 16
> +
> +/* yes these two have the same address */
> +#define RCU_PWR_GATING_CNTL_5                           0x504
> +#define RCU_GPU_BOOST_DISABLE                           0x508
> +
> +#define MCU_M3ARB_INDEX                                 0x504
> +#define MCU_M3ARB_PARAMS                                0x508
> +
> +#define RCU_GNB_PWR_REP_TIMER_CNTL                      0x50C
> +
> +#define RCU_SclkDpmTdpLimit01                           0x514
> +#define RCU_SclkDpmTdpLimit23                           0x518
> +#define RCU_SclkDpmTdpLimit47                           0x51C
> +#define RCU_SclkDpmTdpLimitPG                           0x520
> +
> +#define GNB_TDP_LIMIT                                   0x540
> +#define RCU_BOOST_MARGIN                                0x544
> +#define RCU_THROTTLE_MARGIN                             0x548
> +
> +#define SMU_PCIE_PG_ARGS                                0x58C
> +#define SMU_PCIE_PG_ARGS_2                              0x598
> +#define SMU_PCIE_PG_ARGS_3                              0x59C
> +
> +/* mmio */
> +#define RCU_STATUS                                      0x11c
> +#       define GMC_PWR_GATER_BUSY                       (1 << 8)
> +#       define GFX_PWR_GATER_BUSY                       (1 << 9)
> +#       define UVD_PWR_GATER_BUSY                       (1 << 10)
> +#       define PCIE_PWR_GATER_BUSY                      (1 << 11)
> +#       define GMC_PWR_GATER_STATE                      (1 << 12)
> +#       define GFX_PWR_GATER_STATE                      (1 << 13)
> +#       define UVD_PWR_GATER_STATE                      (1 << 14)
> +#       define PCIE_PWR_GATER_STATE                     (1 << 15)
> +#       define GFX1_PWR_GATER_BUSY                      (1 << 16)
> +#       define GFX2_PWR_GATER_BUSY                      (1 << 17)
> +#       define GFX1_PWR_GATER_STATE                     (1 << 18)
> +#       define GFX2_PWR_GATER_STATE                     (1 << 19)
> +
> +#define GFX_INT_REQ                                     0x120
> +#       define INT_REQ                                  (1 << 0)
> +#       define SERV_INDEX(x)                            ((x) << 1)
> +#       define SERV_INDEX_MASK                          (0xff << 1)
> +#       define SERV_INDEX_SHIFT                         1
> +#define GFX_INT_STATUS                                  0x124
> +#       define INT_ACK                                  (1 << 0)
> +#       define INT_DONE                                 (1 << 1)
> +
> +#define CG_SCLK_CNTL                                    0x600
> +#       define SCLK_DIVIDER(x)                          ((x) << 0)
> +#       define SCLK_DIVIDER_MASK                        (0x7f << 0)
> +#       define SCLK_DIVIDER_SHIFT                       0
> +#define CG_SCLK_STATUS                                  0x604
> +#       define SCLK_OVERCLK_DETECT                      (1 << 2)
> +
> +#define GENERAL_PWRMGT                                  0x63c
> +#       define STATIC_PM_EN                             (1 << 1)
> +
> +#define SCLK_PWRMGT_CNTL                                0x644
> +#       define SCLK_PWRMGT_OFF                          (1 << 0)
> +#       define SCLK_LOW_D1                              (1 << 1)
> +#       define FIR_RESET                                (1 << 4)
> +#       define FIR_FORCE_TREND_SEL                      (1 << 5)
> +#       define FIR_TREND_MODE                           (1 << 6)
> +#       define DYN_GFX_CLK_OFF_EN                       (1 << 7)
> +#       define GFX_CLK_FORCE_ON                         (1 << 8)
> +#       define GFX_CLK_REQUEST_OFF                      (1 << 9)
> +#       define GFX_CLK_FORCE_OFF                        (1 << 10)
> +#       define GFX_CLK_OFF_ACPI_D1                      (1 << 11)
> +#       define GFX_CLK_OFF_ACPI_D2                      (1 << 12)
> +#       define GFX_CLK_OFF_ACPI_D3                      (1 << 13)
> +#       define GFX_VOLTAGE_CHANGE_EN                    (1 << 16)
> +#       define GFX_VOLTAGE_CHANGE_MODE                  (1 << 17)
> +
> +#define TARGET_AND_CURRENT_PROFILE_INDEX                0x66c
> +#       define TARG_SCLK_INDEX(x)                       ((x) << 6)
> +#       define TARG_SCLK_INDEX_MASK                     (0x7 << 6)
> +#       define TARG_SCLK_INDEX_SHIFT                    6
> +#       define CURR_SCLK_INDEX(x)                       ((x) << 9)
> +#       define CURR_SCLK_INDEX_MASK                     (0x7 << 9)
> +#       define CURR_SCLK_INDEX_SHIFT                    9
> +#       define TARG_INDEX(x)                            ((x) << 12)
> +#       define TARG_INDEX_MASK                          (0x7 << 12)
> +#       define TARG_INDEX_SHIFT                         12
> +#       define CURR_INDEX(x)                            ((x) << 15)
> +#       define CURR_INDEX_MASK                          (0x7 << 15)
> +#       define CURR_INDEX_SHIFT                         15
> +
> +#define CG_SCLK_DPM_CTRL                                0x684
> +#       define SCLK_FSTATE_0_DIV(x)                     ((x) << 0)
> +#       define SCLK_FSTATE_0_DIV_MASK                   (0x7f << 0)
> +#       define SCLK_FSTATE_0_DIV_SHIFT                  0
> +#       define SCLK_FSTATE_0_VLD                        (1 << 7)
> +#       define SCLK_FSTATE_1_DIV(x)                     ((x) << 8)
> +#       define SCLK_FSTATE_1_DIV_MASK                   (0x7f << 8)
> +#       define SCLK_FSTATE_1_DIV_SHIFT                  8
> +#       define SCLK_FSTATE_1_VLD                        (1 << 15)
> +#       define SCLK_FSTATE_2_DIV(x)                     ((x) << 16)
> +#       define SCLK_FSTATE_2_DIV_MASK                   (0x7f << 16)
> +#       define SCLK_FSTATE_2_DIV_SHIFT                  16
> +#       define SCLK_FSTATE_2_VLD                        (1 << 23)
> +#       define SCLK_FSTATE_3_DIV(x)                     ((x) << 24)
> +#       define SCLK_FSTATE_3_DIV_MASK                   (0x7f << 24)
> +#       define SCLK_FSTATE_3_DIV_SHIFT                  24
> +#       define SCLK_FSTATE_3_VLD                        (1 << 31)
> +#define CG_SCLK_DPM_CTRL_2                              0x688
> +#define CG_GCOOR                                        0x68c
> +#       define PHC(x)                                   ((x) << 0)
> +#       define PHC_MASK                                 (0x1f << 0)
> +#       define PHC_SHIFT                                0
> +#       define SDC(x)                                   ((x) << 9)
> +#       define SDC_MASK                                 (0x3ff << 9)
> +#       define SDC_SHIFT                                9
> +#       define SU(x)                                    ((x) << 23)
> +#       define SU_MASK                                  (0xf << 23)
> +#       define SU_SHIFT                                 23
> +#       define DIV_ID(x)                                ((x) << 28)
> +#       define DIV_ID_MASK                              (0x7 << 28)
> +#       define DIV_ID_SHIFT                             28
> +
> +#define CG_FTV                                          0x690
> +#define CG_FFCT_0                                       0x694
> +#       define UTC_0(x)                                 ((x) << 0)
> +#       define UTC_0_MASK                               (0x3ff << 0)
> +#       define UTC_0_SHIFT                              0
> +#       define DTC_0(x)                                 ((x) << 10)
> +#       define DTC_0_MASK                               (0x3ff << 10)
> +#       define DTC_0_SHIFT                              10
> +
> +#define CG_GIT                                          0x6d8
> +#       define CG_GICST(x)                              ((x) << 0)
> +#       define CG_GICST_MASK                            (0xffff << 0)
> +#       define CG_GICST_SHIFT                           0
> +#       define CG_GIPOT(x)                              ((x) << 16)
> +#       define CG_GIPOT_MASK                            (0xffff << 16)
> +#       define CG_GIPOT_SHIFT                           16
> +
> +#define CG_SCLK_DPM_CTRL_3                              0x6e0
> +#       define FORCE_SCLK_STATE(x)                      ((x) << 0)
> +#       define FORCE_SCLK_STATE_MASK                    (0x7 << 0)
> +#       define FORCE_SCLK_STATE_SHIFT                   0
> +#       define FORCE_SCLK_STATE_EN                      (1 << 3)
> +#       define GNB_TT(x)                                ((x) << 8)
> +#       define GNB_TT_MASK                              (0xff << 8)
> +#       define GNB_TT_SHIFT                             8
> +#       define GNB_THERMTHRO_MASK                       (1 << 16)
> +#       define CNB_THERMTHRO_MASK_SCLK                  (1 << 17)
> +#       define DPM_SCLK_ENABLE                          (1 << 18)
> +#       define GNB_SLOW_FSTATE_0_MASK                   (1 << 23)
> +#       define GNB_SLOW_FSTATE_0_SHIFT                  23
> +#       define FORCE_NB_PSTATE_1                        (1 << 31)
> +
> +#define CG_SSP                                          0x6e8
> +#       define SST(x)                                   ((x) << 0)
> +#       define SST_MASK                                 (0xffff << 0)
> +#       define SST_SHIFT                                0
> +#       define SSTU(x)                                  ((x) << 16)
> +#       define SSTU_MASK                                (0xffff << 16)
> +#       define SSTU_SHIFT                               16
> +
> +#define CG_ACPI_CNTL                                    0x70c
> +#       define SCLK_ACPI_DIV(x)                         ((x) << 0)
> +#       define SCLK_ACPI_DIV_MASK                       (0x7f << 0)
> +#       define SCLK_ACPI_DIV_SHIFT                      0
> +
> +#define CG_SCLK_DPM_CTRL_4                              0x71c
> +#       define DC_HDC(x)                                ((x) << 14)
> +#       define DC_HDC_MASK                              (0x3fff << 14)
> +#       define DC_HDC_SHIFT                             14
> +#       define DC_HU(x)                                 ((x) << 28)
> +#       define DC_HU_MASK                               (0xf << 28)
> +#       define DC_HU_SHIFT                              28
> +#define CG_SCLK_DPM_CTRL_5                              0x720
> +#       define SCLK_FSTATE_BOOTUP(x)                    ((x) << 0)
> +#       define SCLK_FSTATE_BOOTUP_MASK                  (0x7 << 0)
> +#       define SCLK_FSTATE_BOOTUP_SHIFT                 0
> +#       define TT_TP(x)                                 ((x) << 3)
> +#       define TT_TP_MASK                               (0xffff << 3)
> +#       define TT_TP_SHIFT                              3
> +#       define TT_TU(x)                                 ((x) << 19)
> +#       define TT_TU_MASK                               (0xff << 19)
> +#       define TT_TU_SHIFT                              19
> +#define CG_SCLK_DPM_CTRL_6                              0x724
> +#define CG_AT_0                                         0x728
> +#       define CG_R(x)                                  ((x) << 0)
> +#       define CG_R_MASK                                (0xffff << 0)
> +#       define CG_R_SHIFT                               0
> +#       define CG_L(x)                                  ((x) << 16)
> +#       define CG_L_MASK                                (0xffff << 16)
> +#       define CG_L_SHIFT                               16
> +#define CG_AT_1                                         0x72c
> +#define CG_AT_2                                         0x730
> +#define	CG_THERMAL_INT					0x734
> +#define		DIG_THERM_INTH(x)			((x) << 8)
> +#define		DIG_THERM_INTH_MASK			0x0000FF00
> +#define		DIG_THERM_INTH_SHIFT			8
> +#define		DIG_THERM_INTL(x)			((x) << 16)
> +#define		DIG_THERM_INTL_MASK			0x00FF0000
> +#define		DIG_THERM_INTL_SHIFT			16
> +#define 	THERM_INT_MASK_HIGH			(1 << 24)
> +#define 	THERM_INT_MASK_LOW			(1 << 25)
> +#define CG_AT_3                                         0x738
> +#define CG_AT_4                                         0x73c
> +#define CG_AT_5                                         0x740
> +#define CG_AT_6                                         0x744
> +#define CG_AT_7                                         0x748
> +
> +#define CG_BSP_0                                        0x750
> +#       define BSP(x)                                   ((x) << 0)
> +#       define BSP_MASK                                 (0xffff << 0)
> +#       define BSP_SHIFT                                0
> +#       define BSU(x)                                   ((x) << 16)
> +#       define BSU_MASK                                 (0xf << 16)
> +#       define BSU_SHIFT                                16
> +
> +#define CG_CG_VOLTAGE_CNTL                              0x770
> +#       define REQ                                      (1 << 0)
> +#       define LEVEL(x)                                 ((x) << 1)
> +#       define LEVEL_MASK                               (0x3 << 1)
> +#       define LEVEL_SHIFT                              1
> +#       define CG_VOLTAGE_EN                            (1 << 3)
> +#       define FORCE                                    (1 << 4)
> +#       define PERIOD(x)                                ((x) << 8)
> +#       define PERIOD_MASK                              (0xffff << 8)
> +#       define PERIOD_SHIFT                             8
> +#       define UNIT(x)                                  ((x) << 24)
> +#       define UNIT_MASK                                (0xf << 24)
> +#       define UNIT_SHIFT                               24
> +
> +#define CG_ACPI_VOLTAGE_CNTL                            0x780
> +#       define ACPI_VOLTAGE_EN                          (1 << 8)
> +
> +#define CG_DPM_VOLTAGE_CNTL                             0x788
> +#       define DPM_STATE0_LEVEL_MASK                    (0x3 << 0)
> +#       define DPM_STATE0_LEVEL_SHIFT                   0
> +#       define DPM_VOLTAGE_EN                           (1 << 16)
> +
> +#define CG_PWR_GATING_CNTL                              0x7ac
> +#       define DYN_PWR_DOWN_EN                          (1 << 0)
> +#       define ACPI_PWR_DOWN_EN                         (1 << 1)
> +#       define GFX_CLK_OFF_PWR_DOWN_EN                  (1 << 2)
> +#       define IOC_DISGPU_PWR_DOWN_EN                   (1 << 3)
> +#       define FORCE_POWR_ON                            (1 << 4)
> +#       define PGP(x)                                   ((x) << 8)
> +#       define PGP_MASK                                 (0xffff << 8)
> +#       define PGP_SHIFT                                8
> +#       define PGU(x)                                   ((x) << 24)
> +#       define PGU_MASK                                 (0xf << 24)
> +#       define PGU_SHIFT                                24
> +
> +#define CG_CGTT_LOCAL_0                                 0x7d0
> +#define CG_CGTT_LOCAL_1                                 0x7d4
> +
> +#define DEEP_SLEEP_CNTL                                 0x818
> +#       define R_DIS                                    (1 << 3)
> +#       define HS(x)                                    ((x) << 4)
> +#       define HS_MASK                                  (0xfff << 4)
> +#       define HS_SHIFT                                 4
> +#       define ENABLE_DS                                (1 << 31)
> +#define DEEP_SLEEP_CNTL2                                0x81c
> +#       define LB_UFP_EN                                (1 << 0)
> +#       define INOUT_C(x)                               ((x) << 4)
> +#       define INOUT_C_MASK                             (0xff << 4)
> +#       define INOUT_C_SHIFT                            4
> +
> +#define CG_SCRATCH2                                     0x824
> +
> +#define CG_SCLK_DPM_CTRL_11                             0x830
> +
> +#define HW_REV   					0x5564
> +#       define ATI_REV_ID_MASK                          (0xf << 28)
> +#       define ATI_REV_ID_SHIFT                         28
> +/* 0 = A0, 1 = A1, 2 = B0, 3 = C0, etc. */
> +
> +#define DOUT_SCRATCH3   				0x611c
> +
> +#define GB_ADDR_CONFIG  				0x98f8
> +
> +#endif
> -- 
> 1.7.7.5
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 093/165] drm/radeon/kms: add dpm support for cayman
  2013-06-26 13:22 ` [PATCH 093/165] drm/radeon/kms: add dpm support for cayman alexdeucher
@ 2013-06-26 11:29   ` Jerome Glisse
  0 siblings, 0 replies; 142+ messages in thread
From: Jerome Glisse @ 2013-06-26 11:29 UTC (permalink / raw)
  To: alexdeucher; +Cc: Alex Deucher, dri-devel

On Wed, Jun 26, 2013 at 09:22:53AM -0400, alexdeucher@gmail.com wrote:
> From: Alex Deucher <alexander.deucher@amd.com>
> 
> This adds dpm support for cayman asics.  This includes:
> - clockgating
> - dynamic engine clock scaling
> - dynamic memory clock scaling
> - dynamic voltage scaling
> - dynamic pcie gen1/gen2 switching (requires additional acpi support)
> - power containment
> - shader power scaling
> 
> Set radeon.dpm=1 to enable.
> 
> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>

Reviewed-by: Jerome Glisse <jglisse@redhat.com>

> ---
>  drivers/gpu/drm/radeon/Makefile       |    2 +-
>  drivers/gpu/drm/radeon/btc_dpm.c      |   36 +-
>  drivers/gpu/drm/radeon/btc_dpm.h      |   20 +-
>  drivers/gpu/drm/radeon/cypress_dpm.c  |   11 +-
>  drivers/gpu/drm/radeon/cypress_dpm.h  |    4 +
>  drivers/gpu/drm/radeon/ni.c           |    4 +-
>  drivers/gpu/drm/radeon/ni_dpm.c       | 4093 +++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/radeon/ni_dpm.h       |  233 ++
>  drivers/gpu/drm/radeon/nid.h          |  552 +++++
>  drivers/gpu/drm/radeon/nislands_smc.h |  329 +++
>  drivers/gpu/drm/radeon/ppsmc.h        |   12 +
>  drivers/gpu/drm/radeon/radeon_asic.c  |   12 +
>  drivers/gpu/drm/radeon/radeon_asic.h  |   10 +
>  drivers/gpu/drm/radeon/radeon_pm.c    |    1 +
>  drivers/gpu/drm/radeon/radeon_ucode.h |    5 +
>  drivers/gpu/drm/radeon/rv770_smc.c    |   27 +
>  16 files changed, 5323 insertions(+), 28 deletions(-)
>  create mode 100644 drivers/gpu/drm/radeon/ni_dpm.c
>  create mode 100644 drivers/gpu/drm/radeon/ni_dpm.h
>  create mode 100644 drivers/gpu/drm/radeon/nislands_smc.h
> 
> diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile
> index 2239ec2..32d1c7f 100644
> --- a/drivers/gpu/drm/radeon/Makefile
> +++ b/drivers/gpu/drm/radeon/Makefile
> @@ -79,7 +79,7 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \
>  	si_blit_shaders.o radeon_prime.o radeon_uvd.o cik.o cik_blit_shaders.o \
>  	r600_dpm.o rs780_dpm.o rv6xx_dpm.o rv770_dpm.o rv730_dpm.o rv740_dpm.o \
>  	rv770_smc.o cypress_dpm.o btc_dpm.o sumo_dpm.o sumo_smc.o trinity_dpm.o \
> -	trinity_smc.o
> +	trinity_smc.o ni_dpm.o
>  
>  radeon-$(CONFIG_COMPAT) += radeon_ioc32.o
>  radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o
> diff --git a/drivers/gpu/drm/radeon/btc_dpm.c b/drivers/gpu/drm/radeon/btc_dpm.c
> index 989592e..79f5ed4 100644
> --- a/drivers/gpu/drm/radeon/btc_dpm.c
> +++ b/drivers/gpu/drm/radeon/btc_dpm.c
> @@ -1152,7 +1152,7 @@ static const u32 turks_sysls_enable[] =
>  
>  #endif
>  
> -u32 btc_valid_sclk[] =
> +u32 btc_valid_sclk[40] =
>  {
>  	5000,   10000,  15000,  20000,  25000,  30000,  35000,  40000,  45000,  50000,
>  	55000,  60000,  65000,  70000,  75000,  80000,  85000,  90000,  95000,  100000,
> @@ -1168,8 +1168,8 @@ static const struct radeon_blacklist_clocks btc_blacklist_clocks[] =
>          { 25000, 30000, RADEON_SCLK_UP }
>  };
>  
> -static void btc_apply_voltage_dependency_rules(struct radeon_clock_voltage_dependency_table *table,
> -					       u32 clock, u16 max_voltage, u16 *voltage)
> +void btc_apply_voltage_dependency_rules(struct radeon_clock_voltage_dependency_table *table,
> +					u32 clock, u16 max_voltage, u16 *voltage)
>  {
>  	u32 i;
>  
> @@ -1219,9 +1219,9 @@ static u32 btc_get_valid_sclk(struct radeon_device *rdev,
>  				    max_sclk, requested_sclk);
>  }
>  
> -static void btc_skip_blacklist_clocks(struct radeon_device *rdev,
> -				      const u32 max_sclk, const u32 max_mclk,
> -				      u32 *sclk, u32 *mclk)
> +void btc_skip_blacklist_clocks(struct radeon_device *rdev,
> +			       const u32 max_sclk, const u32 max_mclk,
> +			       u32 *sclk, u32 *mclk)
>  {
>  	int i, num_blacklist_clocks;
>  
> @@ -1246,9 +1246,9 @@ static void btc_skip_blacklist_clocks(struct radeon_device *rdev,
>  	}
>  }
>  
> -static void btc_adjust_clock_combinations(struct radeon_device *rdev,
> -					  const struct radeon_clock_and_voltage_limits *max_limits,
> -					  struct rv7xx_pl *pl)
> +void btc_adjust_clock_combinations(struct radeon_device *rdev,
> +				   const struct radeon_clock_and_voltage_limits *max_limits,
> +				   struct rv7xx_pl *pl)
>  {
>  
>  	if ((pl->mclk == 0) || (pl->sclk == 0))
> @@ -1285,9 +1285,9 @@ static u16 btc_find_voltage(struct atom_voltage_table *table, u16 voltage)
>  	return table->entries[table->count - 1].value;
>  }
>  
> -static void btc_apply_voltage_delta_rules(struct radeon_device *rdev,
> -					  u16 max_vddc, u16 max_vddci,
> -					  u16 *vddc, u16 *vddci)
> +void btc_apply_voltage_delta_rules(struct radeon_device *rdev,
> +				   u16 max_vddc, u16 max_vddci,
> +				   u16 *vddc, u16 *vddci)
>  {
>  	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
>  	u16 new_voltage;
> @@ -1417,8 +1417,8 @@ static int btc_populate_smc_acpi_state(struct radeon_device *rdev,
>  	return ret;
>  }
>  
> -static void btc_program_mgcg_hw_sequence(struct radeon_device *rdev,
> -					 const u32 *sequence, u32 count)
> +void btc_program_mgcg_hw_sequence(struct radeon_device *rdev,
> +				  const u32 *sequence, u32 count)
>  {
>  	u32 i, length = count * 3;
>  	u32 tmp;
> @@ -1596,7 +1596,7 @@ static void btc_ls_clock_gating_enable(struct radeon_device *rdev,
>  	btc_program_mgcg_hw_sequence(rdev, p, count);
>  }
>  
> -static bool btc_dpm_enabled(struct radeon_device *rdev)
> +bool btc_dpm_enabled(struct radeon_device *rdev)
>  {
>  	if (rv770_is_smc_running(rdev))
>  		return true;
> @@ -1692,7 +1692,7 @@ static void btc_set_at_for_uvd(struct radeon_device *rdev)
>  
>  }
>  
> -static void btc_notify_uvd_to_smc(struct radeon_device *rdev)
> +void btc_notify_uvd_to_smc(struct radeon_device *rdev)
>  {
>  	struct radeon_ps *radeon_new_state = rdev->pm.dpm.requested_ps;
>  	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
> @@ -1708,7 +1708,7 @@ static void btc_notify_uvd_to_smc(struct radeon_device *rdev)
>  	}
>  }
>  
> -static int btc_reset_to_default(struct radeon_device *rdev)
> +int btc_reset_to_default(struct radeon_device *rdev)
>  {
>  	if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_ResetToDefaults) != PPSMC_Result_OK)
>  		return -EINVAL;
> @@ -1730,7 +1730,7 @@ static void btc_stop_smc(struct radeon_device *rdev)
>  	r7xx_stop_smc(rdev);
>  }
>  
> -static void btc_read_arb_registers(struct radeon_device *rdev)
> +void btc_read_arb_registers(struct radeon_device *rdev)
>  {
>  	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
>  	struct evergreen_arb_registers *arb_registers =
> diff --git a/drivers/gpu/drm/radeon/btc_dpm.h b/drivers/gpu/drm/radeon/btc_dpm.h
> index 807024d..c22d39f 100644
> --- a/drivers/gpu/drm/radeon/btc_dpm.h
> +++ b/drivers/gpu/drm/radeon/btc_dpm.h
> @@ -33,6 +33,24 @@
>  #define BTC_CGULVPARAMETER_DFLT                       0x00040035
>  #define BTC_CGULVCONTROL_DFLT                         0x00001450
>  
> -extern u32 btc_valid_sclk[];
> +extern u32 btc_valid_sclk[40];
> +
> +void btc_read_arb_registers(struct radeon_device *rdev);
> +void btc_program_mgcg_hw_sequence(struct radeon_device *rdev,
> +				  const u32 *sequence, u32 count);
> +void btc_skip_blacklist_clocks(struct radeon_device *rdev,
> +			       const u32 max_sclk, const u32 max_mclk,
> +			       u32 *sclk, u32 *mclk);
> +void btc_adjust_clock_combinations(struct radeon_device *rdev,
> +				   const struct radeon_clock_and_voltage_limits *max_limits,
> +				   struct rv7xx_pl *pl);
> +void btc_apply_voltage_dependency_rules(struct radeon_clock_voltage_dependency_table *table,
> +					u32 clock, u16 max_voltage, u16 *voltage);
> +void btc_apply_voltage_delta_rules(struct radeon_device *rdev,
> +				   u16 max_vddc, u16 max_vddci,
> +				   u16 *vddc, u16 *vddci);
> +bool btc_dpm_enabled(struct radeon_device *rdev);
> +int btc_reset_to_default(struct radeon_device *rdev);
> +void btc_notify_uvd_to_smc(struct radeon_device *rdev);
>  
>  #endif
> diff --git a/drivers/gpu/drm/radeon/cypress_dpm.c b/drivers/gpu/drm/radeon/cypress_dpm.c
> index 403ee15..22297b1 100644
> --- a/drivers/gpu/drm/radeon/cypress_dpm.c
> +++ b/drivers/gpu/drm/radeon/cypress_dpm.c
> @@ -45,9 +45,6 @@ struct rv7xx_ps *rv770_get_ps(struct radeon_ps *rps);
>  struct rv7xx_power_info *rv770_get_pi(struct radeon_device *rdev);
>  struct evergreen_power_info *evergreen_get_pi(struct radeon_device *rdev);
>  
> -static u8 cypress_get_mclk_frequency_ratio(struct radeon_device *rdev,
> -					   u32 memory_clock, bool strobe_mode);
> -
>  static void cypress_enable_bif_dynamic_pcie_gen2(struct radeon_device *rdev,
>  						 bool enable)
>  {
> @@ -416,7 +413,7 @@ static int cypress_populate_voltage_value(struct radeon_device *rdev,
>  	return 0;
>  }
>  
> -static u8 cypress_get_strobe_mode_settings(struct radeon_device *rdev, u32 mclk)
> +u8 cypress_get_strobe_mode_settings(struct radeon_device *rdev, u32 mclk)
>  {
>  	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
>  	u8 result = 0;
> @@ -434,7 +431,7 @@ static u8 cypress_get_strobe_mode_settings(struct radeon_device *rdev, u32 mclk)
>  	return result;
>  }
>  
> -static u32 cypress_map_clkf_to_ibias(struct radeon_device *rdev, u32 clkf)
> +u32 cypress_map_clkf_to_ibias(struct radeon_device *rdev, u32 clkf)
>  {
>  	u32 ref_clk = rdev->clock.mpll.reference_freq;
>  	u32 vco = clkf * ref_clk;
> @@ -603,8 +600,8 @@ static int cypress_populate_mclk_value(struct radeon_device *rdev,
>  	return 0;
>  }
>  
> -static u8 cypress_get_mclk_frequency_ratio(struct radeon_device *rdev,
> -					   u32 memory_clock, bool strobe_mode)
> +u8 cypress_get_mclk_frequency_ratio(struct radeon_device *rdev,
> +				    u32 memory_clock, bool strobe_mode)
>  {
>  	u8 mc_para_index;
>  
> diff --git a/drivers/gpu/drm/radeon/cypress_dpm.h b/drivers/gpu/drm/radeon/cypress_dpm.h
> index 9e24d7a..9b6198e 100644
> --- a/drivers/gpu/drm/radeon/cypress_dpm.h
> +++ b/drivers/gpu/drm/radeon/cypress_dpm.h
> @@ -141,5 +141,9 @@ void cypress_enable_mclk_control(struct radeon_device *rdev,
>  				 bool enable);
>  void cypress_start_dpm(struct radeon_device *rdev);
>  void cypress_advertise_gen2_capability(struct radeon_device *rdev);
> +u32 cypress_map_clkf_to_ibias(struct radeon_device *rdev, u32 clkf);
> +u8 cypress_get_mclk_frequency_ratio(struct radeon_device *rdev,
> +				    u32 memory_clock, bool strobe_mode);
> +u8 cypress_get_strobe_mode_settings(struct radeon_device *rdev, u32 mclk);
>  
>  #endif
> diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c
> index 7407762..ad65143 100644
> --- a/drivers/gpu/drm/radeon/ni.c
> +++ b/drivers/gpu/drm/radeon/ni.c
> @@ -194,6 +194,7 @@ MODULE_FIRMWARE("radeon/CAYMAN_pfp.bin");
>  MODULE_FIRMWARE("radeon/CAYMAN_me.bin");
>  MODULE_FIRMWARE("radeon/CAYMAN_mc.bin");
>  MODULE_FIRMWARE("radeon/CAYMAN_rlc.bin");
> +MODULE_FIRMWARE("radeon/CAYMAN_smc.bin");
>  MODULE_FIRMWARE("radeon/ARUBA_pfp.bin");
>  MODULE_FIRMWARE("radeon/ARUBA_me.bin");
>  MODULE_FIRMWARE("radeon/ARUBA_rlc.bin");
> @@ -734,6 +735,7 @@ int ni_init_microcode(struct radeon_device *rdev)
>  		me_req_size = CAYMAN_PM4_UCODE_SIZE * 4;
>  		rlc_req_size = CAYMAN_RLC_UCODE_SIZE * 4;
>  		mc_req_size = CAYMAN_MC_UCODE_SIZE * 4;
> +		smc_req_size = ALIGN(CAYMAN_SMC_UCODE_SIZE, 4);
>  		break;
>  	case CHIP_ARUBA:
>  		chip_name = "ARUBA";
> @@ -797,7 +799,7 @@ int ni_init_microcode(struct radeon_device *rdev)
>  		}
>  	}
>  
> -	if ((rdev->family >= CHIP_BARTS) && (rdev->family <= CHIP_CAICOS)) {
> +	if ((rdev->family >= CHIP_BARTS) && (rdev->family <= CHIP_CAYMAN)) {
>  		snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", chip_name);
>  		err = request_firmware(&rdev->smc_fw, fw_name, &pdev->dev);
>  		if (err)
> diff --git a/drivers/gpu/drm/radeon/ni_dpm.c b/drivers/gpu/drm/radeon/ni_dpm.c
> new file mode 100644
> index 0000000..635bf04
> --- /dev/null
> +++ b/drivers/gpu/drm/radeon/ni_dpm.c
> @@ -0,0 +1,4093 @@
> +/*
> + * Copyright 2012 Advanced Micro Devices, Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + *
> + */
> +
> +#include "drmP.h"
> +#include "radeon.h"
> +#include "nid.h"
> +#include "r600_dpm.h"
> +#include "ni_dpm.h"
> +#include "atom.h"
> +
> +#define MC_CG_ARB_FREQ_F0           0x0a
> +#define MC_CG_ARB_FREQ_F1           0x0b
> +#define MC_CG_ARB_FREQ_F2           0x0c
> +#define MC_CG_ARB_FREQ_F3           0x0d
> +
> +#define SMC_RAM_END 0xC000
> +
> +static const struct ni_cac_weights cac_weights_cayman_xt =
> +{
> +	0x15,
> +	0x2,
> +	0x19,
> +	0x2,
> +	0x8,
> +	0x14,
> +	0x2,
> +	0x16,
> +	0xE,
> +	0x17,
> +	0x13,
> +	0x2B,
> +	0x10,
> +	0x7,
> +	0x5,
> +	0x5,
> +	0x5,
> +	0x2,
> +	0x3,
> +	0x9,
> +	0x10,
> +	0x10,
> +	0x2B,
> +	0xA,
> +	0x9,
> +	0x4,
> +	0xD,
> +	0xD,
> +	0x3E,
> +	0x18,
> +	0x14,
> +	0,
> +	0x3,
> +	0x3,
> +	0x5,
> +	0,
> +	0x2,
> +	0,
> +	0,
> +	0,
> +	0,
> +	0,
> +	0,
> +	0,
> +	0,
> +	0,
> +	0x1CC,
> +	0,
> +	0x164,
> +	1,
> +	1,
> +	1,
> +	1,
> +	12,
> +	12,
> +	12,
> +	0x12,
> +	0x1F,
> +	132,
> +	5,
> +	7,
> +	0,
> +	{ 0, 0, 0, 0, 0, 0, 0, 0 },
> +	{ 0, 0, 0, 0 },
> +	true
> +};
> +
> +static const struct ni_cac_weights cac_weights_cayman_pro =
> +{
> +	0x16,
> +	0x4,
> +	0x10,
> +	0x2,
> +	0xA,
> +	0x16,
> +	0x2,
> +	0x18,
> +	0x10,
> +	0x1A,
> +	0x16,
> +	0x2D,
> +	0x12,
> +	0xA,
> +	0x6,
> +	0x6,
> +	0x6,
> +	0x2,
> +	0x4,
> +	0xB,
> +	0x11,
> +	0x11,
> +	0x2D,
> +	0xC,
> +	0xC,
> +	0x7,
> +	0x10,
> +	0x10,
> +	0x3F,
> +	0x1A,
> +	0x16,
> +	0,
> +	0x7,
> +	0x4,
> +	0x6,
> +	1,
> +	0x2,
> +	0x1,
> +	0,
> +	0,
> +	0,
> +	0,
> +	0,
> +	0,
> +	0x30,
> +	0,
> +	0x1CF,
> +	0,
> +	0x166,
> +	1,
> +	1,
> +	1,
> +	1,
> +	12,
> +	12,
> +	12,
> +	0x15,
> +	0x1F,
> +	132,
> +	6,
> +	6,
> +	0,
> +	{ 0, 0, 0, 0, 0, 0, 0, 0 },
> +	{ 0, 0, 0, 0 },
> +	true
> +};
> +
> +static const struct ni_cac_weights cac_weights_cayman_le =
> +{
> +	0x7,
> +	0xE,
> +	0x1,
> +	0xA,
> +	0x1,
> +	0x3F,
> +	0x2,
> +	0x18,
> +	0x10,
> +	0x1A,
> +	0x1,
> +	0x3F,
> +	0x1,
> +	0xE,
> +	0x6,
> +	0x6,
> +	0x6,
> +	0x2,
> +	0x4,
> +	0x9,
> +	0x1A,
> +	0x1A,
> +	0x2C,
> +	0xA,
> +	0x11,
> +	0x8,
> +	0x19,
> +	0x19,
> +	0x1,
> +	0x1,
> +	0x1A,
> +	0,
> +	0x8,
> +	0x5,
> +	0x8,
> +	0x1,
> +	0x3,
> +	0x1,
> +	0,
> +	0,
> +	0,
> +	0,
> +	0,
> +	0,
> +	0x38,
> +	0x38,
> +	0x239,
> +	0x3,
> +	0x18A,
> +	1,
> +	1,
> +	1,
> +	1,
> +	12,
> +	12,
> +	12,
> +	0x15,
> +	0x22,
> +	132,
> +	6,
> +	6,
> +	0,
> +	{ 0, 0, 0, 0, 0, 0, 0, 0 },
> +	{ 0, 0, 0, 0 },
> +	true
> +};
> +
> +#define NISLANDS_MGCG_SEQUENCE  300
> +
> +static const u32 cayman_cgcg_cgls_default[] =
> +{
> +	0x000008f8, 0x00000010, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x00000011, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x00000012, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x00000013, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x00000014, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x00000015, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x00000016, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x00000017, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x00000018, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x00000019, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x0000001a, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x0000001b, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x00000020, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x00000021, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x00000022, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x00000023, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x00000024, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x00000025, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x00000026, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x00000027, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x00000028, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x00000029, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x0000002a, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x0000002b, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff
> +};
> +#define CAYMAN_CGCG_CGLS_DEFAULT_LENGTH sizeof(cayman_cgcg_cgls_default) / (3 * sizeof(u32))
> +
> +static const u32 cayman_cgcg_cgls_disable[] =
> +{
> +	0x000008f8, 0x00000010, 0xffffffff,
> +	0x000008fc, 0xffffffff, 0xffffffff,
> +	0x000008f8, 0x00000011, 0xffffffff,
> +	0x000008fc, 0xffffffff, 0xffffffff,
> +	0x000008f8, 0x00000012, 0xffffffff,
> +	0x000008fc, 0xffffffff, 0xffffffff,
> +	0x000008f8, 0x00000013, 0xffffffff,
> +	0x000008fc, 0xffffffff, 0xffffffff,
> +	0x000008f8, 0x00000014, 0xffffffff,
> +	0x000008fc, 0xffffffff, 0xffffffff,
> +	0x000008f8, 0x00000015, 0xffffffff,
> +	0x000008fc, 0xffffffff, 0xffffffff,
> +	0x000008f8, 0x00000016, 0xffffffff,
> +	0x000008fc, 0xffffffff, 0xffffffff,
> +	0x000008f8, 0x00000017, 0xffffffff,
> +	0x000008fc, 0xffffffff, 0xffffffff,
> +	0x000008f8, 0x00000018, 0xffffffff,
> +	0x000008fc, 0xffffffff, 0xffffffff,
> +	0x000008f8, 0x00000019, 0xffffffff,
> +	0x000008fc, 0xffffffff, 0xffffffff,
> +	0x000008f8, 0x0000001a, 0xffffffff,
> +	0x000008fc, 0xffffffff, 0xffffffff,
> +	0x000008f8, 0x0000001b, 0xffffffff,
> +	0x000008fc, 0xffffffff, 0xffffffff,
> +	0x000008f8, 0x00000020, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x00000021, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x00000022, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x00000023, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x00000024, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x00000025, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x00000026, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x00000027, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x00000028, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x00000029, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x0000002a, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x0000002b, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x00000644, 0x000f7902, 0x001f4180,
> +	0x00000644, 0x000f3802, 0x001f4180
> +};
> +#define CAYMAN_CGCG_CGLS_DISABLE_LENGTH sizeof(cayman_cgcg_cgls_disable) / (3 * sizeof(u32))
> +
> +static const u32 cayman_cgcg_cgls_enable[] =
> +{
> +	0x00000644, 0x000f7882, 0x001f4080,
> +	0x000008f8, 0x00000010, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x00000011, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x00000012, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x00000013, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x00000014, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x00000015, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x00000016, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x00000017, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x00000018, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x00000019, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x0000001a, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x0000001b, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x00000020, 0xffffffff,
> +	0x000008fc, 0xffffffff, 0xffffffff,
> +	0x000008f8, 0x00000021, 0xffffffff,
> +	0x000008fc, 0xffffffff, 0xffffffff,
> +	0x000008f8, 0x00000022, 0xffffffff,
> +	0x000008fc, 0xffffffff, 0xffffffff,
> +	0x000008f8, 0x00000023, 0xffffffff,
> +	0x000008fc, 0xffffffff, 0xffffffff,
> +	0x000008f8, 0x00000024, 0xffffffff,
> +	0x000008fc, 0xffffffff, 0xffffffff,
> +	0x000008f8, 0x00000025, 0xffffffff,
> +	0x000008fc, 0xffffffff, 0xffffffff,
> +	0x000008f8, 0x00000026, 0xffffffff,
> +	0x000008fc, 0xffffffff, 0xffffffff,
> +	0x000008f8, 0x00000027, 0xffffffff,
> +	0x000008fc, 0xffffffff, 0xffffffff,
> +	0x000008f8, 0x00000028, 0xffffffff,
> +	0x000008fc, 0xffffffff, 0xffffffff,
> +	0x000008f8, 0x00000029, 0xffffffff,
> +	0x000008fc, 0xffffffff, 0xffffffff,
> +	0x000008f8, 0x0000002a, 0xffffffff,
> +	0x000008fc, 0xffffffff, 0xffffffff,
> +	0x000008f8, 0x0000002b, 0xffffffff,
> +	0x000008fc, 0xffffffff, 0xffffffff
> +};
> +#define CAYMAN_CGCG_CGLS_ENABLE_LENGTH  sizeof(cayman_cgcg_cgls_enable) / (3 * sizeof(u32))
> +
> +static const u32 cayman_mgcg_default[] =
> +{
> +	0x0000802c, 0xc0000000, 0xffffffff,
> +	0x00003fc4, 0xc0000000, 0xffffffff,
> +	0x00005448, 0x00000100, 0xffffffff,
> +	0x000055e4, 0x00000100, 0xffffffff,
> +	0x0000160c, 0x00000100, 0xffffffff,
> +	0x00008984, 0x06000100, 0xffffffff,
> +	0x0000c164, 0x00000100, 0xffffffff,
> +	0x00008a18, 0x00000100, 0xffffffff,
> +	0x0000897c, 0x06000100, 0xffffffff,
> +	0x00008b28, 0x00000100, 0xffffffff,
> +	0x00009144, 0x00800200, 0xffffffff,
> +	0x00009a60, 0x00000100, 0xffffffff,
> +	0x00009868, 0x00000100, 0xffffffff,
> +	0x00008d58, 0x00000100, 0xffffffff,
> +	0x00009510, 0x00000100, 0xffffffff,
> +	0x0000949c, 0x00000100, 0xffffffff,
> +	0x00009654, 0x00000100, 0xffffffff,
> +	0x00009030, 0x00000100, 0xffffffff,
> +	0x00009034, 0x00000100, 0xffffffff,
> +	0x00009038, 0x00000100, 0xffffffff,
> +	0x0000903c, 0x00000100, 0xffffffff,
> +	0x00009040, 0x00000100, 0xffffffff,
> +	0x0000a200, 0x00000100, 0xffffffff,
> +	0x0000a204, 0x00000100, 0xffffffff,
> +	0x0000a208, 0x00000100, 0xffffffff,
> +	0x0000a20c, 0x00000100, 0xffffffff,
> +	0x00009744, 0x00000100, 0xffffffff,
> +	0x00003f80, 0x00000100, 0xffffffff,
> +	0x0000a210, 0x00000100, 0xffffffff,
> +	0x0000a214, 0x00000100, 0xffffffff,
> +	0x000004d8, 0x00000100, 0xffffffff,
> +	0x00009664, 0x00000100, 0xffffffff,
> +	0x00009698, 0x00000100, 0xffffffff,
> +	0x000004d4, 0x00000200, 0xffffffff,
> +	0x000004d0, 0x00000000, 0xffffffff,
> +	0x000030cc, 0x00000104, 0xffffffff,
> +	0x0000d0c0, 0x00000100, 0xffffffff,
> +	0x0000d8c0, 0x00000100, 0xffffffff,
> +	0x0000802c, 0x40000000, 0xffffffff,
> +	0x00003fc4, 0x40000000, 0xffffffff,
> +	0x0000915c, 0x00010000, 0xffffffff,
> +	0x00009160, 0x00030002, 0xffffffff,
> +	0x00009164, 0x00050004, 0xffffffff,
> +	0x00009168, 0x00070006, 0xffffffff,
> +	0x00009178, 0x00070000, 0xffffffff,
> +	0x0000917c, 0x00030002, 0xffffffff,
> +	0x00009180, 0x00050004, 0xffffffff,
> +	0x0000918c, 0x00010006, 0xffffffff,
> +	0x00009190, 0x00090008, 0xffffffff,
> +	0x00009194, 0x00070000, 0xffffffff,
> +	0x00009198, 0x00030002, 0xffffffff,
> +	0x0000919c, 0x00050004, 0xffffffff,
> +	0x000091a8, 0x00010006, 0xffffffff,
> +	0x000091ac, 0x00090008, 0xffffffff,
> +	0x000091b0, 0x00070000, 0xffffffff,
> +	0x000091b4, 0x00030002, 0xffffffff,
> +	0x000091b8, 0x00050004, 0xffffffff,
> +	0x000091c4, 0x00010006, 0xffffffff,
> +	0x000091c8, 0x00090008, 0xffffffff,
> +	0x000091cc, 0x00070000, 0xffffffff,
> +	0x000091d0, 0x00030002, 0xffffffff,
> +	0x000091d4, 0x00050004, 0xffffffff,
> +	0x000091e0, 0x00010006, 0xffffffff,
> +	0x000091e4, 0x00090008, 0xffffffff,
> +	0x000091e8, 0x00000000, 0xffffffff,
> +	0x000091ec, 0x00070000, 0xffffffff,
> +	0x000091f0, 0x00030002, 0xffffffff,
> +	0x000091f4, 0x00050004, 0xffffffff,
> +	0x00009200, 0x00010006, 0xffffffff,
> +	0x00009204, 0x00090008, 0xffffffff,
> +	0x00009208, 0x00070000, 0xffffffff,
> +	0x0000920c, 0x00030002, 0xffffffff,
> +	0x00009210, 0x00050004, 0xffffffff,
> +	0x0000921c, 0x00010006, 0xffffffff,
> +	0x00009220, 0x00090008, 0xffffffff,
> +	0x00009224, 0x00070000, 0xffffffff,
> +	0x00009228, 0x00030002, 0xffffffff,
> +	0x0000922c, 0x00050004, 0xffffffff,
> +	0x00009238, 0x00010006, 0xffffffff,
> +	0x0000923c, 0x00090008, 0xffffffff,
> +	0x00009240, 0x00070000, 0xffffffff,
> +	0x00009244, 0x00030002, 0xffffffff,
> +	0x00009248, 0x00050004, 0xffffffff,
> +	0x00009254, 0x00010006, 0xffffffff,
> +	0x00009258, 0x00090008, 0xffffffff,
> +	0x0000925c, 0x00070000, 0xffffffff,
> +	0x00009260, 0x00030002, 0xffffffff,
> +	0x00009264, 0x00050004, 0xffffffff,
> +	0x00009270, 0x00010006, 0xffffffff,
> +	0x00009274, 0x00090008, 0xffffffff,
> +	0x00009278, 0x00070000, 0xffffffff,
> +	0x0000927c, 0x00030002, 0xffffffff,
> +	0x00009280, 0x00050004, 0xffffffff,
> +	0x0000928c, 0x00010006, 0xffffffff,
> +	0x00009290, 0x00090008, 0xffffffff,
> +	0x000092a8, 0x00070000, 0xffffffff,
> +	0x000092ac, 0x00030002, 0xffffffff,
> +	0x000092b0, 0x00050004, 0xffffffff,
> +	0x000092bc, 0x00010006, 0xffffffff,
> +	0x000092c0, 0x00090008, 0xffffffff,
> +	0x000092c4, 0x00070000, 0xffffffff,
> +	0x000092c8, 0x00030002, 0xffffffff,
> +	0x000092cc, 0x00050004, 0xffffffff,
> +	0x000092d8, 0x00010006, 0xffffffff,
> +	0x000092dc, 0x00090008, 0xffffffff,
> +	0x00009294, 0x00000000, 0xffffffff,
> +	0x0000802c, 0x40010000, 0xffffffff,
> +	0x00003fc4, 0x40010000, 0xffffffff,
> +	0x0000915c, 0x00010000, 0xffffffff,
> +	0x00009160, 0x00030002, 0xffffffff,
> +	0x00009164, 0x00050004, 0xffffffff,
> +	0x00009168, 0x00070006, 0xffffffff,
> +	0x00009178, 0x00070000, 0xffffffff,
> +	0x0000917c, 0x00030002, 0xffffffff,
> +	0x00009180, 0x00050004, 0xffffffff,
> +	0x0000918c, 0x00010006, 0xffffffff,
> +	0x00009190, 0x00090008, 0xffffffff,
> +	0x00009194, 0x00070000, 0xffffffff,
> +	0x00009198, 0x00030002, 0xffffffff,
> +	0x0000919c, 0x00050004, 0xffffffff,
> +	0x000091a8, 0x00010006, 0xffffffff,
> +	0x000091ac, 0x00090008, 0xffffffff,
> +	0x000091b0, 0x00070000, 0xffffffff,
> +	0x000091b4, 0x00030002, 0xffffffff,
> +	0x000091b8, 0x00050004, 0xffffffff,
> +	0x000091c4, 0x00010006, 0xffffffff,
> +	0x000091c8, 0x00090008, 0xffffffff,
> +	0x000091cc, 0x00070000, 0xffffffff,
> +	0x000091d0, 0x00030002, 0xffffffff,
> +	0x000091d4, 0x00050004, 0xffffffff,
> +	0x000091e0, 0x00010006, 0xffffffff,
> +	0x000091e4, 0x00090008, 0xffffffff,
> +	0x000091e8, 0x00000000, 0xffffffff,
> +	0x000091ec, 0x00070000, 0xffffffff,
> +	0x000091f0, 0x00030002, 0xffffffff,
> +	0x000091f4, 0x00050004, 0xffffffff,
> +	0x00009200, 0x00010006, 0xffffffff,
> +	0x00009204, 0x00090008, 0xffffffff,
> +	0x00009208, 0x00070000, 0xffffffff,
> +	0x0000920c, 0x00030002, 0xffffffff,
> +	0x00009210, 0x00050004, 0xffffffff,
> +	0x0000921c, 0x00010006, 0xffffffff,
> +	0x00009220, 0x00090008, 0xffffffff,
> +	0x00009224, 0x00070000, 0xffffffff,
> +	0x00009228, 0x00030002, 0xffffffff,
> +	0x0000922c, 0x00050004, 0xffffffff,
> +	0x00009238, 0x00010006, 0xffffffff,
> +	0x0000923c, 0x00090008, 0xffffffff,
> +	0x00009240, 0x00070000, 0xffffffff,
> +	0x00009244, 0x00030002, 0xffffffff,
> +	0x00009248, 0x00050004, 0xffffffff,
> +	0x00009254, 0x00010006, 0xffffffff,
> +	0x00009258, 0x00090008, 0xffffffff,
> +	0x0000925c, 0x00070000, 0xffffffff,
> +	0x00009260, 0x00030002, 0xffffffff,
> +	0x00009264, 0x00050004, 0xffffffff,
> +	0x00009270, 0x00010006, 0xffffffff,
> +	0x00009274, 0x00090008, 0xffffffff,
> +	0x00009278, 0x00070000, 0xffffffff,
> +	0x0000927c, 0x00030002, 0xffffffff,
> +	0x00009280, 0x00050004, 0xffffffff,
> +	0x0000928c, 0x00010006, 0xffffffff,
> +	0x00009290, 0x00090008, 0xffffffff,
> +	0x000092a8, 0x00070000, 0xffffffff,
> +	0x000092ac, 0x00030002, 0xffffffff,
> +	0x000092b0, 0x00050004, 0xffffffff,
> +	0x000092bc, 0x00010006, 0xffffffff,
> +	0x000092c0, 0x00090008, 0xffffffff,
> +	0x000092c4, 0x00070000, 0xffffffff,
> +	0x000092c8, 0x00030002, 0xffffffff,
> +	0x000092cc, 0x00050004, 0xffffffff,
> +	0x000092d8, 0x00010006, 0xffffffff,
> +	0x000092dc, 0x00090008, 0xffffffff,
> +	0x00009294, 0x00000000, 0xffffffff,
> +	0x0000802c, 0xc0000000, 0xffffffff,
> +	0x00003fc4, 0xc0000000, 0xffffffff,
> +	0x000008f8, 0x00000010, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x00000011, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x00000012, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x00000013, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x00000014, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x00000015, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x00000016, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x00000017, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x00000018, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x00000019, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x0000001a, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x0000001b, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff
> +};
> +#define CAYMAN_MGCG_DEFAULT_LENGTH sizeof(cayman_mgcg_default) / (3 * sizeof(u32))
> +
> +static const u32 cayman_mgcg_disable[] =
> +{
> +	0x0000802c, 0xc0000000, 0xffffffff,
> +	0x000008f8, 0x00000000, 0xffffffff,
> +	0x000008fc, 0xffffffff, 0xffffffff,
> +	0x000008f8, 0x00000001, 0xffffffff,
> +	0x000008fc, 0xffffffff, 0xffffffff,
> +	0x000008f8, 0x00000002, 0xffffffff,
> +	0x000008fc, 0xffffffff, 0xffffffff,
> +	0x000008f8, 0x00000003, 0xffffffff,
> +	0x000008fc, 0xffffffff, 0xffffffff,
> +	0x00009150, 0x00600000, 0xffffffff
> +};
> +#define CAYMAN_MGCG_DISABLE_LENGTH   sizeof(cayman_mgcg_disable) / (3 * sizeof(u32))
> +
> +static const u32 cayman_mgcg_enable[] =
> +{
> +	0x0000802c, 0xc0000000, 0xffffffff,
> +	0x000008f8, 0x00000000, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x00000001, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x000008f8, 0x00000002, 0xffffffff,
> +	0x000008fc, 0x00600000, 0xffffffff,
> +	0x000008f8, 0x00000003, 0xffffffff,
> +	0x000008fc, 0x00000000, 0xffffffff,
> +	0x00009150, 0x96944200, 0xffffffff
> +};
> +
> +#define CAYMAN_MGCG_ENABLE_LENGTH   sizeof(cayman_mgcg_enable) / (3 * sizeof(u32))
> +
> +#define NISLANDS_SYSLS_SEQUENCE  100
> +
> +static const u32 cayman_sysls_default[] =
> +{
> +	/* Register,   Value,     Mask bits */
> +	0x000055e8, 0x00000000, 0xffffffff,
> +	0x0000d0bc, 0x00000000, 0xffffffff,
> +	0x0000d8bc, 0x00000000, 0xffffffff,
> +	0x000015c0, 0x000c1401, 0xffffffff,
> +	0x0000264c, 0x000c0400, 0xffffffff,
> +	0x00002648, 0x000c0400, 0xffffffff,
> +	0x00002650, 0x000c0400, 0xffffffff,
> +	0x000020b8, 0x000c0400, 0xffffffff,
> +	0x000020bc, 0x000c0400, 0xffffffff,
> +	0x000020c0, 0x000c0c80, 0xffffffff,
> +	0x0000f4a0, 0x000000c0, 0xffffffff,
> +	0x0000f4a4, 0x00680fff, 0xffffffff,
> +	0x00002f50, 0x00000404, 0xffffffff,
> +	0x000004c8, 0x00000001, 0xffffffff,
> +	0x000064ec, 0x00000000, 0xffffffff,
> +	0x00000c7c, 0x00000000, 0xffffffff,
> +	0x00008dfc, 0x00000000, 0xffffffff
> +};
> +#define CAYMAN_SYSLS_DEFAULT_LENGTH sizeof(cayman_sysls_default) / (3 * sizeof(u32))
> +
> +static const u32 cayman_sysls_disable[] =
> +{
> +	/* Register,   Value,     Mask bits */
> +	0x0000d0c0, 0x00000000, 0xffffffff,
> +	0x0000d8c0, 0x00000000, 0xffffffff,
> +	0x000055e8, 0x00000000, 0xffffffff,
> +	0x0000d0bc, 0x00000000, 0xffffffff,
> +	0x0000d8bc, 0x00000000, 0xffffffff,
> +	0x000015c0, 0x00041401, 0xffffffff,
> +	0x0000264c, 0x00040400, 0xffffffff,
> +	0x00002648, 0x00040400, 0xffffffff,
> +	0x00002650, 0x00040400, 0xffffffff,
> +	0x000020b8, 0x00040400, 0xffffffff,
> +	0x000020bc, 0x00040400, 0xffffffff,
> +	0x000020c0, 0x00040c80, 0xffffffff,
> +	0x0000f4a0, 0x000000c0, 0xffffffff,
> +	0x0000f4a4, 0x00680000, 0xffffffff,
> +	0x00002f50, 0x00000404, 0xffffffff,
> +	0x000004c8, 0x00000001, 0xffffffff,
> +	0x000064ec, 0x00007ffd, 0xffffffff,
> +	0x00000c7c, 0x0000ff00, 0xffffffff,
> +	0x00008dfc, 0x0000007f, 0xffffffff
> +};
> +#define CAYMAN_SYSLS_DISABLE_LENGTH sizeof(cayman_sysls_disable) / (3 * sizeof(u32))
> +
> +static const u32 cayman_sysls_enable[] =
> +{
> +	/* Register,   Value,     Mask bits */
> +	0x000055e8, 0x00000001, 0xffffffff,
> +	0x0000d0bc, 0x00000100, 0xffffffff,
> +	0x0000d8bc, 0x00000100, 0xffffffff,
> +	0x000015c0, 0x000c1401, 0xffffffff,
> +	0x0000264c, 0x000c0400, 0xffffffff,
> +	0x00002648, 0x000c0400, 0xffffffff,
> +	0x00002650, 0x000c0400, 0xffffffff,
> +	0x000020b8, 0x000c0400, 0xffffffff,
> +	0x000020bc, 0x000c0400, 0xffffffff,
> +	0x000020c0, 0x000c0c80, 0xffffffff,
> +	0x0000f4a0, 0x000000c0, 0xffffffff,
> +	0x0000f4a4, 0x00680fff, 0xffffffff,
> +	0x00002f50, 0x00000903, 0xffffffff,
> +	0x000004c8, 0x00000000, 0xffffffff,
> +	0x000064ec, 0x00000000, 0xffffffff,
> +	0x00000c7c, 0x00000000, 0xffffffff,
> +	0x00008dfc, 0x00000000, 0xffffffff
> +};
> +#define CAYMAN_SYSLS_ENABLE_LENGTH sizeof(cayman_sysls_enable) / (3 * sizeof(u32))
> +
> +struct rv7xx_power_info *rv770_get_pi(struct radeon_device *rdev);
> +struct evergreen_power_info *evergreen_get_pi(struct radeon_device *rdev);
> +
> +static struct ni_power_info *ni_get_pi(struct radeon_device *rdev)
> +{
> +        struct ni_power_info *pi = rdev->pm.dpm.priv;
> +
> +        return pi;
> +}
> +
> +struct ni_ps *ni_get_ps(struct radeon_ps *rps)
> +{
> +	struct ni_ps *ps = rps->ps_priv;
> +
> +	return ps;
> +}
> +
> +/* XXX: fix for kernel use  */
> +#if 0
> +static double ni_exp(double x)
> +{
> +	int count = 1;
> +	double sum = 1.0, term, tolerance = 0.000000001, y = x;
> +
> +	if (x < 0)
> +		y = -1 * x;
> +	term  = y;
> +
> +	while (term >= tolerance) {
> +		sum = sum + term;
> +		count = count + 1;
> +		term  = term * (y / count);
> +	}
> +
> +	if (x < 0)
> +		sum = 1.0 / sum;
> +
> +	return sum;
> +}
> +#endif
> +
> +static void ni_calculate_leakage_for_v_and_t_formula(const struct ni_leakage_coeffients *coeff,
> +						     u16 v, s32 t,
> +						     u32 ileakage,
> +						     u32 *leakage)
> +{
> +/* XXX: fix for kernel use  */
> +#if 0
> +	double kt, kv, leakage_w, i_leakage, vddc, temperature;
> +
> +	i_leakage   = ((double)ileakage) / 1000;
> +	vddc        = ((double)v) / 1000;
> +	temperature = ((double)t) / 1000;
> +
> +	kt = (((double)(coeff->at)) / 1000) * ni_exp((((double)(coeff->bt)) / 1000) * temperature);
> +	kv = (((double)(coeff->av)) / 1000) * ni_exp((((double)(coeff->bv)) / 1000) * vddc);
> +
> +	leakage_w = i_leakage * kt * kv * vddc;
> +
> +	*leakage = (u32)(leakage_w * 1000);
> +#endif
> +}
> +
> +static void ni_calculate_leakage_for_v_and_t(struct radeon_device *rdev,
> +					     const struct ni_leakage_coeffients *coeff,
> +					     u16 v,
> +					     s32 t,
> +					     u32 i_leakage,
> +					     u32 *leakage)
> +{
> +	ni_calculate_leakage_for_v_and_t_formula(coeff, v, t, i_leakage, leakage);
> +}
> +
> +static void ni_apply_state_adjust_rules(struct radeon_device *rdev)
> +{
> +	struct ni_power_info *ni_pi = ni_get_pi(rdev);
> +	struct radeon_ps *rps = rdev->pm.dpm.requested_ps;
> +	struct ni_ps *ps = ni_get_ps(rps);
> +	struct radeon_clock_and_voltage_limits *max_limits;
> +	bool disable_mclk_switching;
> +	u32 mclk, sclk;
> +	u16 vddc, vddci;
> +	int i;
> +
> +	/* point to the hw copy since this function will modify the ps */
> +	ni_pi->hw_ps = *ps;
> +	rdev->pm.dpm.hw_ps.ps_priv = &ni_pi->hw_ps;
> +	ps = &ni_pi->hw_ps;
> +
> +	if (rdev->pm.dpm.new_active_crtc_count > 1)
> +		disable_mclk_switching = true;
> +	else
> +		disable_mclk_switching = false;
> +
> +	if (rdev->pm.dpm.ac_power)
> +		max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
> +	else
> +		max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc;
> +
> +	if (rdev->pm.dpm.ac_power == false) {
> +		for (i = 0; i < ps->performance_level_count; i++) {
> +			if (ps->performance_levels[i].mclk > max_limits->mclk)
> +				ps->performance_levels[i].mclk = max_limits->mclk;
> +			if (ps->performance_levels[i].sclk > max_limits->sclk)
> +				ps->performance_levels[i].sclk = max_limits->sclk;
> +			if (ps->performance_levels[i].vddc > max_limits->vddc)
> +				ps->performance_levels[i].vddc = max_limits->vddc;
> +			if (ps->performance_levels[i].vddci > max_limits->vddci)
> +				ps->performance_levels[i].vddci = max_limits->vddci;
> +		}
> +	}
> +
> +	/* XXX validate the min clocks required for display */
> +
> +	if (disable_mclk_switching) {
> +		mclk  = ps->performance_levels[ps->performance_level_count - 1].mclk;
> +		sclk = ps->performance_levels[0].sclk;
> +		vddc = ps->performance_levels[0].vddc;
> +		vddci = ps->performance_levels[ps->performance_level_count - 1].vddci;
> +	} else {
> +		sclk = ps->performance_levels[0].sclk;
> +		mclk = ps->performance_levels[0].mclk;
> +		vddc = ps->performance_levels[0].vddc;
> +		vddci = ps->performance_levels[0].vddci;
> +	}
> +
> +	/* adjusted low state */
> +	ps->performance_levels[0].sclk = sclk;
> +	ps->performance_levels[0].mclk = mclk;
> +	ps->performance_levels[0].vddc = vddc;
> +	ps->performance_levels[0].vddci = vddci;
> +
> +	btc_skip_blacklist_clocks(rdev, max_limits->sclk, max_limits->mclk,
> +				  &ps->performance_levels[0].sclk,
> +				  &ps->performance_levels[0].mclk);
> +
> +	for (i = 1; i < ps->performance_level_count; i++) {
> +		if (ps->performance_levels[i].sclk < ps->performance_levels[i - 1].sclk)
> +			ps->performance_levels[i].sclk = ps->performance_levels[i - 1].sclk;
> +		if (ps->performance_levels[i].vddc < ps->performance_levels[i - 1].vddc)
> +			ps->performance_levels[i].vddc = ps->performance_levels[i - 1].vddc;
> +	}
> +
> +	if (disable_mclk_switching) {
> +		mclk = ps->performance_levels[0].mclk;
> +		for (i = 1; i < ps->performance_level_count; i++) {
> +			if (mclk < ps->performance_levels[i].mclk)
> +				mclk = ps->performance_levels[i].mclk;
> +		}
> +		for (i = 0; i < ps->performance_level_count; i++) {
> +			ps->performance_levels[i].mclk = mclk;
> +			ps->performance_levels[i].vddci = vddci;
> +		}
> +	} else {
> +		for (i = 1; i < ps->performance_level_count; i++) {
> +			if (ps->performance_levels[i].mclk < ps->performance_levels[i - 1].mclk)
> +				ps->performance_levels[i].mclk = ps->performance_levels[i - 1].mclk;
> +			if (ps->performance_levels[i].vddci < ps->performance_levels[i - 1].vddci)
> +				ps->performance_levels[i].vddci = ps->performance_levels[i - 1].vddci;
> +		}
> +	}
> +
> +	for (i = 1; i < ps->performance_level_count; i++)
> +		btc_skip_blacklist_clocks(rdev, max_limits->sclk, max_limits->mclk,
> +					  &ps->performance_levels[i].sclk,
> +					  &ps->performance_levels[i].mclk);
> +
> +	for (i = 0; i < ps->performance_level_count; i++)
> +		btc_adjust_clock_combinations(rdev, max_limits,
> +					      &ps->performance_levels[i]);
> +
> +	for (i = 0; i < ps->performance_level_count; i++) {
> +		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);
> +		btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk,
> +						   ps->performance_levels[i].mclk,
> +						   max_limits->vddci, &ps->performance_levels[i].vddci);
> +		btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk,
> +						   ps->performance_levels[i].mclk,
> +						   max_limits->vddc,  &ps->performance_levels[i].vddc);
> +		/* XXX validate the voltage required for display */
> +	}
> +
> +	for (i = 0; i < ps->performance_level_count; i++) {
> +		btc_apply_voltage_delta_rules(rdev,
> +					      max_limits->vddc, max_limits->vddci,
> +					      &ps->performance_levels[i].vddc,
> +					      &ps->performance_levels[i].vddci);
> +	}
> +
> +	ps->dc_compatible = true;
> +	for (i = 0; i < ps->performance_level_count; i++) {
> +		if (ps->performance_levels[i].vddc > rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc.vddc)
> +			ps->dc_compatible = false;
> +
> +		if (ps->performance_levels[i].vddc < rdev->pm.dpm.dyn_state.min_vddc_for_pcie_gen2)
> +			ps->performance_levels[i].flags &= ~ATOM_PPLIB_R600_FLAGS_PCIEGEN2;
> +	}
> +}
> +
> +static void ni_cg_clockgating_default(struct radeon_device *rdev)
> +{
> +	u32 count;
> +	const u32 *ps = NULL;
> +
> +	ps = (const u32 *)&cayman_cgcg_cgls_default;
> +	count = CAYMAN_CGCG_CGLS_DEFAULT_LENGTH;
> +
> +	btc_program_mgcg_hw_sequence(rdev, ps, count);
> +}
> +
> +static void ni_gfx_clockgating_enable(struct radeon_device *rdev,
> +				      bool enable)
> +{
> +	u32 count;
> +	const u32 *ps = NULL;
> +
> +	if (enable) {
> +		ps = (const u32 *)&cayman_cgcg_cgls_enable;
> +		count = CAYMAN_CGCG_CGLS_ENABLE_LENGTH;
> +	} else {
> +		ps = (const u32 *)&cayman_cgcg_cgls_disable;
> +		count = CAYMAN_CGCG_CGLS_DISABLE_LENGTH;
> +	}
> +
> +	btc_program_mgcg_hw_sequence(rdev, ps, count);
> +}
> +
> +static void ni_mg_clockgating_default(struct radeon_device *rdev)
> +{
> +	u32 count;
> +	const u32 *ps = NULL;
> +
> +	ps = (const u32 *)&cayman_mgcg_default;
> +	count = CAYMAN_MGCG_DEFAULT_LENGTH;
> +
> +	btc_program_mgcg_hw_sequence(rdev, ps, count);
> +}
> +
> +static void ni_mg_clockgating_enable(struct radeon_device *rdev,
> +				     bool enable)
> +{
> +	u32 count;
> +	const u32 *ps = NULL;
> +
> +	if (enable) {
> +		ps = (const u32 *)&cayman_mgcg_enable;
> +		count = CAYMAN_MGCG_ENABLE_LENGTH;
> +	} else {
> +		ps = (const u32 *)&cayman_mgcg_disable;
> +		count = CAYMAN_MGCG_DISABLE_LENGTH;
> +	}
> +
> +	btc_program_mgcg_hw_sequence(rdev, ps, count);
> +}
> +
> +static void ni_ls_clockgating_default(struct radeon_device *rdev)
> +{
> +	u32 count;
> +	const u32 *ps = NULL;
> +
> +	ps = (const u32 *)&cayman_sysls_default;
> +	count = CAYMAN_SYSLS_DEFAULT_LENGTH;
> +
> +	btc_program_mgcg_hw_sequence(rdev, ps, count);
> +}
> +
> +static void ni_ls_clockgating_enable(struct radeon_device *rdev,
> +				     bool enable)
> +{
> +	u32 count;
> +	const u32 *ps = NULL;
> +
> +	if (enable) {
> +		ps = (const u32 *)&cayman_sysls_enable;
> +		count = CAYMAN_SYSLS_ENABLE_LENGTH;
> +	} else {
> +		ps = (const u32 *)&cayman_sysls_disable;
> +		count = CAYMAN_SYSLS_DISABLE_LENGTH;
> +	}
> +
> +	btc_program_mgcg_hw_sequence(rdev, ps, count);
> +
> +}
> +
> +static int ni_patch_single_dependency_table_based_on_leakage(struct radeon_device *rdev,
> +							     struct radeon_clock_voltage_dependency_table *table)
> +{
> +	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
> +	u32 i;
> +
> +	if (table) {
> +		for (i = 0; i < table->count; i++) {
> +			if (0xff01 == table->entries[i].v) {
> +				if (pi->max_vddc == 0)
> +					return -EINVAL;
> +				table->entries[i].v = pi->max_vddc;
> +			}
> +		}
> +	}
> +	return 0;
> +}
> +
> +static int ni_patch_dependency_tables_based_on_leakage(struct radeon_device *rdev)
> +{
> +	int ret = 0;
> +
> +	ret = ni_patch_single_dependency_table_based_on_leakage(rdev,
> +								&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk);
> +
> +	ret = ni_patch_single_dependency_table_based_on_leakage(rdev,
> +								&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk);
> +	return ret;
> +}
> +
> +static void ni_stop_dpm(struct radeon_device *rdev)
> +{
> +	WREG32_P(GENERAL_PWRMGT, 0, ~GLOBAL_PWRMGT_EN);
> +}
> +
> +#if 0
> +static int ni_notify_hw_of_power_source(struct radeon_device *rdev,
> +					bool ac_power)
> +{
> +	if (ac_power)
> +		return (rv770_send_msg_to_smc(rdev, PPSMC_MSG_RunningOnAC) == PPSMC_Result_OK) ?
> +			0 : -EINVAL;
> +
> +	return 0;
> +}
> +#endif
> +
> +static PPSMC_Result ni_send_msg_to_smc_with_parameter(struct radeon_device *rdev,
> +						      PPSMC_Msg msg, u32 parameter)
> +{
> +	WREG32(SMC_SCRATCH0, parameter);
> +	return rv770_send_msg_to_smc(rdev, msg);
> +}
> +
> +static int ni_restrict_performance_levels_before_switch(struct radeon_device *rdev)
> +{
> +	if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_NoForcedLevel) != PPSMC_Result_OK)
> +		return -EINVAL;
> +
> +	return (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 1) == PPSMC_Result_OK) ?
> +		0 : -EINVAL;
> +}
> +
> +static void ni_stop_smc(struct radeon_device *rdev)
> +{
> +	u32 tmp;
> +	int i;
> +
> +	for (i = 0; i < rdev->usec_timeout; i++) {
> +		tmp = RREG32(LB_SYNC_RESET_SEL) & LB_SYNC_RESET_SEL_MASK;
> +		if (tmp != 1)
> +			break;
> +		udelay(1);
> +	}
> +
> +	udelay(100);
> +
> +	r7xx_stop_smc(rdev);
> +}
> +
> +static int ni_process_firmware_header(struct radeon_device *rdev)
> +{
> +        struct rv7xx_power_info *pi = rv770_get_pi(rdev);
> +        struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
> +        struct ni_power_info *ni_pi = ni_get_pi(rdev);
> +	u32 tmp;
> +	int ret;
> +
> +	ret = rv770_read_smc_sram_dword(rdev,
> +					NISLANDS_SMC_FIRMWARE_HEADER_LOCATION +
> +					NISLANDS_SMC_FIRMWARE_HEADER_stateTable,
> +					&tmp, pi->sram_end);
> +
> +	if (ret)
> +		return ret;
> +
> +	pi->state_table_start = (u16)tmp;
> +
> +	ret = rv770_read_smc_sram_dword(rdev,
> +					NISLANDS_SMC_FIRMWARE_HEADER_LOCATION +
> +					NISLANDS_SMC_FIRMWARE_HEADER_softRegisters,
> +					&tmp, pi->sram_end);
> +
> +	if (ret)
> +		return ret;
> +
> +	pi->soft_regs_start = (u16)tmp;
> +
> +	ret = rv770_read_smc_sram_dword(rdev,
> +					NISLANDS_SMC_FIRMWARE_HEADER_LOCATION +
> +					NISLANDS_SMC_FIRMWARE_HEADER_mcRegisterTable,
> +					&tmp, pi->sram_end);
> +
> +	if (ret)
> +		return ret;
> +
> +	eg_pi->mc_reg_table_start = (u16)tmp;
> +
> +	ret = rv770_read_smc_sram_dword(rdev,
> +					NISLANDS_SMC_FIRMWARE_HEADER_LOCATION +
> +					NISLANDS_SMC_FIRMWARE_HEADER_fanTable,
> +					&tmp, pi->sram_end);
> +
> +	if (ret)
> +		return ret;
> +
> +	ni_pi->fan_table_start = (u16)tmp;
> +
> +	ret = rv770_read_smc_sram_dword(rdev,
> +					NISLANDS_SMC_FIRMWARE_HEADER_LOCATION +
> +					NISLANDS_SMC_FIRMWARE_HEADER_mcArbDramAutoRefreshTable,
> +					&tmp, pi->sram_end);
> +
> +	if (ret)
> +		return ret;
> +
> +	ni_pi->arb_table_start = (u16)tmp;
> +
> +	ret = rv770_read_smc_sram_dword(rdev,
> +					NISLANDS_SMC_FIRMWARE_HEADER_LOCATION +
> +					NISLANDS_SMC_FIRMWARE_HEADER_cacTable,
> +					&tmp, pi->sram_end);
> +
> +	if (ret)
> +		return ret;
> +
> +	ni_pi->cac_table_start = (u16)tmp;
> +
> +	ret = rv770_read_smc_sram_dword(rdev,
> +					NISLANDS_SMC_FIRMWARE_HEADER_LOCATION +
> +					NISLANDS_SMC_FIRMWARE_HEADER_spllTable,
> +					&tmp, pi->sram_end);
> +
> +	if (ret)
> +		return ret;
> +
> +	ni_pi->spll_table_start = (u16)tmp;
> +
> +
> +	return ret;
> +}
> +
> +static void ni_read_clock_registers(struct radeon_device *rdev)
> +{
> +	struct ni_power_info *ni_pi = ni_get_pi(rdev);
> +
> +	ni_pi->clock_registers.cg_spll_func_cntl = RREG32(CG_SPLL_FUNC_CNTL);
> +	ni_pi->clock_registers.cg_spll_func_cntl_2 = RREG32(CG_SPLL_FUNC_CNTL_2);
> +	ni_pi->clock_registers.cg_spll_func_cntl_3 = RREG32(CG_SPLL_FUNC_CNTL_3);
> +	ni_pi->clock_registers.cg_spll_func_cntl_4 = RREG32(CG_SPLL_FUNC_CNTL_4);
> +	ni_pi->clock_registers.cg_spll_spread_spectrum = RREG32(CG_SPLL_SPREAD_SPECTRUM);
> +	ni_pi->clock_registers.cg_spll_spread_spectrum_2 = RREG32(CG_SPLL_SPREAD_SPECTRUM_2);
> +	ni_pi->clock_registers.mpll_ad_func_cntl = RREG32(MPLL_AD_FUNC_CNTL);
> +	ni_pi->clock_registers.mpll_ad_func_cntl_2 = RREG32(MPLL_AD_FUNC_CNTL_2);
> +	ni_pi->clock_registers.mpll_dq_func_cntl = RREG32(MPLL_DQ_FUNC_CNTL);
> +	ni_pi->clock_registers.mpll_dq_func_cntl_2 = RREG32(MPLL_DQ_FUNC_CNTL_2);
> +	ni_pi->clock_registers.mclk_pwrmgt_cntl = RREG32(MCLK_PWRMGT_CNTL);
> +	ni_pi->clock_registers.dll_cntl = RREG32(DLL_CNTL);
> +	ni_pi->clock_registers.mpll_ss1 = RREG32(MPLL_SS1);
> +	ni_pi->clock_registers.mpll_ss2 = RREG32(MPLL_SS2);
> +}
> +
> +#if 0
> +static int ni_enter_ulp_state(struct radeon_device *rdev)
> +{
> +	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
> +
> +	if (pi->gfx_clock_gating) {
> +                WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_GFX_CLK_OFF_EN);
> +		WREG32_P(SCLK_PWRMGT_CNTL, GFX_CLK_FORCE_ON, ~GFX_CLK_FORCE_ON);
> +                WREG32_P(SCLK_PWRMGT_CNTL, 0, ~GFX_CLK_FORCE_ON);
> +		RREG32(GB_ADDR_CONFIG);
> +        }
> +
> +	WREG32_P(SMC_MSG, HOST_SMC_MSG(PPSMC_MSG_SwitchToMinimumPower),
> +                 ~HOST_SMC_MSG_MASK);
> +
> +	udelay(25000);
> +
> +	return 0;
> +}
> +#endif
> +
> +static void ni_program_response_times(struct radeon_device *rdev)
> +{
> +	u32 voltage_response_time, backbias_response_time, acpi_delay_time, vbi_time_out;
> +	u32 vddc_dly, bb_dly, acpi_dly, vbi_dly, mclk_switch_limit;
> +	u32 reference_clock;
> +
> +	rv770_write_smc_soft_register(rdev, NI_SMC_SOFT_REGISTER_mvdd_chg_time, 1);
> +
> +        voltage_response_time = (u32)rdev->pm.dpm.voltage_response_time;
> +        backbias_response_time = (u32)rdev->pm.dpm.backbias_response_time;
> +
> +        if (voltage_response_time == 0)
> +                voltage_response_time = 1000;
> +
> +        if (backbias_response_time == 0)
> +                backbias_response_time = 1000;
> +

^
Broken indentation.

> +	acpi_delay_time = 15000;
> +	vbi_time_out = 100000;
> +
> +	reference_clock = radeon_get_xclk(rdev);
> +
> +	vddc_dly = (voltage_response_time  * reference_clock) / 1600;
> +	bb_dly   = (backbias_response_time * reference_clock) / 1600;
> +	acpi_dly = (acpi_delay_time * reference_clock) / 1600;
> +	vbi_dly  = (vbi_time_out * reference_clock) / 1600;
> +
> +	mclk_switch_limit = (460 * reference_clock) / 100;
> +
> +	rv770_write_smc_soft_register(rdev, NI_SMC_SOFT_REGISTER_delay_vreg,  vddc_dly);
> +	rv770_write_smc_soft_register(rdev, NI_SMC_SOFT_REGISTER_delay_bbias, bb_dly);
> +	rv770_write_smc_soft_register(rdev, NI_SMC_SOFT_REGISTER_delay_acpi,  acpi_dly);
> +	rv770_write_smc_soft_register(rdev, NI_SMC_SOFT_REGISTER_mclk_chg_timeout, vbi_dly);
> +	rv770_write_smc_soft_register(rdev, NI_SMC_SOFT_REGISTER_mc_block_delay, 0xAA);
> +	rv770_write_smc_soft_register(rdev, NI_SMC_SOFT_REGISTER_mclk_switch_lim, mclk_switch_limit);
> +}
> +
> +static void ni_populate_smc_voltage_table(struct radeon_device *rdev,
> +					  struct atom_voltage_table *voltage_table,
> +					  NISLANDS_SMC_STATETABLE *table)
> +{
> +	unsigned int i;
> +
> +	for (i = 0; i < voltage_table->count; i++) {
> +		table->highSMIO[i] = 0;
> +		table->lowSMIO[i] |= cpu_to_be32(voltage_table->entries[i].smio_low);
> +	}
> +}
> +
> +static void ni_populate_smc_voltage_tables(struct radeon_device *rdev,
> +					   NISLANDS_SMC_STATETABLE *table)
> +{
> +	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
> +        struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
^
Broken indentation.

> +	unsigned char i;
> +
> +	if (eg_pi->vddc_voltage_table.count) {
> +		ni_populate_smc_voltage_table(rdev, &eg_pi->vddc_voltage_table, table);
> +		table->voltageMaskTable.highMask[NISLANDS_SMC_VOLTAGEMASK_VDDC] = 0;
> +		table->voltageMaskTable.lowMask[NISLANDS_SMC_VOLTAGEMASK_VDDC] =
> +			cpu_to_be32(eg_pi->vddc_voltage_table.mask_low);
> +
> +		for (i = 0; i < eg_pi->vddc_voltage_table.count; i++) {
> +			if (pi->max_vddc_in_table <= eg_pi->vddc_voltage_table.entries[i].value) {
> +				table->maxVDDCIndexInPPTable = i;
> +				break;
> +			}
> +		}
> +	}
> +
> +	if (eg_pi->vddci_voltage_table.count) {
> +		ni_populate_smc_voltage_table(rdev, &eg_pi->vddci_voltage_table, table);
> +
> +		table->voltageMaskTable.highMask[NISLANDS_SMC_VOLTAGEMASK_VDDCI] = 0;
> +		table->voltageMaskTable.lowMask[NISLANDS_SMC_VOLTAGEMASK_VDDCI] =
> +			cpu_to_be32(eg_pi->vddc_voltage_table.mask_low);
> +	}
> +}
> +
> +static int ni_populate_voltage_value(struct radeon_device *rdev,
> +				     struct atom_voltage_table *table,
> +				     u16 value,
> +				     NISLANDS_SMC_VOLTAGE_VALUE *voltage)
> +{
> +	unsigned int i;
> +
> +	for (i = 0; i < table->count; i++) {
> +		if (value <= table->entries[i].value) {
> +			voltage->index = (u8)i;
> +			voltage->value = cpu_to_be16(table->entries[i].value);
> +			break;
> +		}
> +	}
> +
> +	if (i >= table->count)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +static void ni_populate_mvdd_value(struct radeon_device *rdev,
> +				   u32 mclk,
> +				   NISLANDS_SMC_VOLTAGE_VALUE *voltage)
> +{
> +        struct rv7xx_power_info *pi = rv770_get_pi(rdev);
> +        struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
^
Broken indentation.
> +
> +	if (!pi->mvdd_control) {
> +		voltage->index = eg_pi->mvdd_high_index;
> +                voltage->value = cpu_to_be16(MVDD_HIGH_VALUE);
> +		return;
> +        }
> +
> +        if (mclk <= pi->mvdd_split_frequency) {
> +                voltage->index = eg_pi->mvdd_low_index;
> +                voltage->value = cpu_to_be16(MVDD_LOW_VALUE);
^
Broken indentation.
> +	} else {
> +		voltage->index = eg_pi->mvdd_high_index;
> +		voltage->value = cpu_to_be16(MVDD_HIGH_VALUE);
> +        }
^
Broken indentation.
> +}
> +
> +static int ni_get_std_voltage_value(struct radeon_device *rdev,
> +				    NISLANDS_SMC_VOLTAGE_VALUE *voltage,
> +				    u16 *std_voltage)
> +{
> +	if (rdev->pm.dpm.dyn_state.cac_leakage_table.entries &&
> +	    ((u32)voltage->index < rdev->pm.dpm.dyn_state.cac_leakage_table.count))
> +		*std_voltage = rdev->pm.dpm.dyn_state.cac_leakage_table.entries[voltage->index].vddc;
> +	else
> +		*std_voltage = be16_to_cpu(voltage->value);
> +
> +	return 0;
> +}
> +
> +static void ni_populate_std_voltage_value(struct radeon_device *rdev,
> +					  u16 value, u8 index,
> +					  NISLANDS_SMC_VOLTAGE_VALUE *voltage)
> +{
> +	voltage->index = index;
> +	voltage->value = cpu_to_be16(value);
> +}
> +
> +static u32 ni_get_smc_power_scaling_factor(struct radeon_device *rdev)
> +{
> +	u32 xclk_period;
> +	u32 xclk = radeon_get_xclk(rdev);
> +	u32 tmp = RREG32(CG_CAC_CTRL) & TID_CNT_MASK;
> +
> +	xclk_period = (1000000000UL / xclk);
> +	xclk_period /= 10000UL;
> +
> +	return tmp * xclk_period;
> +}
> +
> +static u32 ni_scale_power_for_smc(u32 power_in_watts, u32 scaling_factor)
> +{
> +	return (power_in_watts * scaling_factor) << 2;
> +}
> +
> +static u32 ni_calculate_power_boost_limit(struct radeon_device *rdev,
> +					  struct radeon_ps *radeon_state,
> +					  u32 near_tdp_limit)
> +{
> +	struct ni_ps *state = ni_get_ps(radeon_state);
> +	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
> +	struct ni_power_info *ni_pi = ni_get_pi(rdev);
> +	u32 power_boost_limit = 0;
> +	int ret;
> +
> +	if (ni_pi->enable_power_containment &&
> +	    ni_pi->use_power_boost_limit) {
> +		NISLANDS_SMC_VOLTAGE_VALUE vddc;
> +		u16 std_vddc_med;
> +		u16 std_vddc_high;
> +		u64 tmp;
> +
> +		if (state->performance_level_count < 3)
> +			return 0;
> +
> +		ret = ni_populate_voltage_value(rdev, &eg_pi->vddc_voltage_table,
> +						state->performance_levels[state->performance_level_count - 2].vddc,
> +						&vddc);
> +		if (ret)
> +			return 0;
> +
> +		ret = ni_get_std_voltage_value(rdev, &vddc, &std_vddc_med);
> +		if (ret)
> +			return 0;
> +
> +		ret = ni_populate_voltage_value(rdev, &eg_pi->vddc_voltage_table,
> +						state->performance_levels[state->performance_level_count - 1].vddc,
> +						&vddc);
> +		if (ret)
> +			return 0;
> +
> +		ret = ni_get_std_voltage_value(rdev, &vddc, &std_vddc_high);
> +		if (ret)
> +			return 0;
> +
> +		tmp = ((u64)near_tdp_limit * ((u64)std_vddc_med * (u64)std_vddc_med) * 90) /
> +			((u64)std_vddc_high * (u64)std_vddc_high * 100);
> +		if (tmp >> 32)
> +			return 0;
> +		power_boost_limit = (u32)tmp;
> +	}
> +
> +	return power_boost_limit;
> +}
> +
> +static int ni_calculate_adjusted_tdp_limits(struct radeon_device *rdev,
> +					    bool adjust_polarity,
> +					    u32 tdp_adjustment,
> +					    u32 *tdp_limit,
> +					    u32 *near_tdp_limit)
> +{
> +	if (tdp_adjustment > (u32)rdev->pm.dpm.tdp_od_limit)
> +		return -EINVAL;
> +
> +	if (adjust_polarity) {
> +		*tdp_limit = ((100 + tdp_adjustment) * rdev->pm.dpm.tdp_limit) / 100;
> +		*near_tdp_limit = rdev->pm.dpm.near_tdp_limit + (*tdp_limit - rdev->pm.dpm.tdp_limit);
> +	} else {
> +		*tdp_limit = ((100 - tdp_adjustment) * rdev->pm.dpm.tdp_limit) / 100;
> +		*near_tdp_limit = rdev->pm.dpm.near_tdp_limit - (rdev->pm.dpm.tdp_limit - *tdp_limit);
> +	}
> +
> +	return 0;
> +}
> +
> +static int ni_populate_smc_tdp_limits(struct radeon_device *rdev)
> +{
> +	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
> +	struct ni_power_info *ni_pi = ni_get_pi(rdev);
> +
> +	if (ni_pi->enable_power_containment) {
> +		struct radeon_ps *radeon_state = rdev->pm.dpm.requested_ps;
> +		NISLANDS_SMC_STATETABLE *smc_table = &ni_pi->smc_statetable;
> +		u32 scaling_factor = ni_get_smc_power_scaling_factor(rdev);
> +		u32 tdp_limit;
> +		u32 near_tdp_limit;
> +		u32 power_boost_limit;
> +		int ret;
> +
> +		if (scaling_factor == 0)
> +			return -EINVAL;
> +
> +		memset(smc_table, 0, sizeof(NISLANDS_SMC_STATETABLE));
> +
> +		ret = ni_calculate_adjusted_tdp_limits(rdev,
> +						       false, /* ??? */
> +						       rdev->pm.dpm.tdp_adjustment,
> +						       &tdp_limit,
> +						       &near_tdp_limit);
> +		if (ret)
> +			return ret;
> +
> +		power_boost_limit = ni_calculate_power_boost_limit(rdev, radeon_state,
> +								   near_tdp_limit);
> +
> +		smc_table->dpm2Params.TDPLimit =
> +			cpu_to_be32(ni_scale_power_for_smc(tdp_limit, scaling_factor));
> +		smc_table->dpm2Params.NearTDPLimit =
> +			cpu_to_be32(ni_scale_power_for_smc(near_tdp_limit, scaling_factor));
> +		smc_table->dpm2Params.SafePowerLimit =
> +			cpu_to_be32(ni_scale_power_for_smc((near_tdp_limit * NISLANDS_DPM2_TDP_SAFE_LIMIT_PERCENT) / 100,
> +							   scaling_factor));
> +		smc_table->dpm2Params.PowerBoostLimit =
> +			cpu_to_be32(ni_scale_power_for_smc(power_boost_limit, scaling_factor));
> +
> +		ret = rv770_copy_bytes_to_smc(rdev,
> +					      (u16)(pi->state_table_start + offsetof(NISLANDS_SMC_STATETABLE, dpm2Params) +
> +						    offsetof(PP_NIslands_DPM2Parameters, TDPLimit)),
> +					      (u8 *)(&smc_table->dpm2Params.TDPLimit),
> +					      sizeof(u32) * 4, pi->sram_end);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int ni_copy_and_switch_arb_sets(struct radeon_device *rdev,
> +				       u32 arb_freq_src, u32 arb_freq_dest)
> +{
> +	u32 mc_arb_dram_timing;
> +	u32 mc_arb_dram_timing2;
> +	u32 burst_time;
> +	u32 mc_cg_config;
> +
> +	switch (arb_freq_src) {
> +        case MC_CG_ARB_FREQ_F0:
> +		mc_arb_dram_timing  = RREG32(MC_ARB_DRAM_TIMING);
> +		mc_arb_dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2);
> +		burst_time = (RREG32(MC_ARB_BURST_TIME) & STATE0_MASK) >> STATE0_SHIFT;
> +		break;
> +        case MC_CG_ARB_FREQ_F1:
> +		mc_arb_dram_timing  = RREG32(MC_ARB_DRAM_TIMING_1);
> +		mc_arb_dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2_1);
> +		burst_time = (RREG32(MC_ARB_BURST_TIME) & STATE1_MASK) >> STATE1_SHIFT;
> +		break;
> +        case MC_CG_ARB_FREQ_F2:
> +		mc_arb_dram_timing  = RREG32(MC_ARB_DRAM_TIMING_2);
> +		mc_arb_dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2_2);
> +		burst_time = (RREG32(MC_ARB_BURST_TIME) & STATE2_MASK) >> STATE2_SHIFT;
> +		break;
> +        case MC_CG_ARB_FREQ_F3:
> +		mc_arb_dram_timing  = RREG32(MC_ARB_DRAM_TIMING_3);
> +		mc_arb_dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2_3);
> +		burst_time = (RREG32(MC_ARB_BURST_TIME) & STATE3_MASK) >> STATE3_SHIFT;
> +		break;
> +        default:
> +		return -EINVAL;
> +	}
> +
> +	switch (arb_freq_dest) {
> +        case MC_CG_ARB_FREQ_F0:
> +		WREG32(MC_ARB_DRAM_TIMING, mc_arb_dram_timing);
> +		WREG32(MC_ARB_DRAM_TIMING2, mc_arb_dram_timing2);
> +		WREG32_P(MC_ARB_BURST_TIME, STATE0(burst_time), ~STATE0_MASK);
> +		break;
> +        case MC_CG_ARB_FREQ_F1:
> +		WREG32(MC_ARB_DRAM_TIMING_1, mc_arb_dram_timing);
> +		WREG32(MC_ARB_DRAM_TIMING2_1, mc_arb_dram_timing2);
> +		WREG32_P(MC_ARB_BURST_TIME, STATE1(burst_time), ~STATE1_MASK);
> +		break;
> +        case MC_CG_ARB_FREQ_F2:
> +		WREG32(MC_ARB_DRAM_TIMING_2, mc_arb_dram_timing);
> +		WREG32(MC_ARB_DRAM_TIMING2_2, mc_arb_dram_timing2);
> +		WREG32_P(MC_ARB_BURST_TIME, STATE2(burst_time), ~STATE2_MASK);
> +		break;
> +        case MC_CG_ARB_FREQ_F3:
^
Broken indentation.
> +		WREG32(MC_ARB_DRAM_TIMING_3, mc_arb_dram_timing);
> +		WREG32(MC_ARB_DRAM_TIMING2_3, mc_arb_dram_timing2);
> +		WREG32_P(MC_ARB_BURST_TIME, STATE3(burst_time), ~STATE3_MASK);
> +		break;
> +        default:
^
Broken indentation.
> +		return -EINVAL;
> +	}
> +
> +	mc_cg_config = RREG32(MC_CG_CONFIG) | 0x0000000F;
> +	WREG32(MC_CG_CONFIG, mc_cg_config);
> +	WREG32_P(MC_ARB_CG, CG_ARB_REQ(arb_freq_dest), ~CG_ARB_REQ_MASK);
> +
> +	return 0;
> +}
> +
> +static int ni_init_arb_table_index(struct radeon_device *rdev)
> +{
> +	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
> +	struct ni_power_info *ni_pi = ni_get_pi(rdev);
> +	u32 tmp;
> +	int ret;
> +
> +	ret = rv770_read_smc_sram_dword(rdev, ni_pi->arb_table_start,
> +					&tmp, pi->sram_end);
> +	if (ret)
> +		return ret;
> +
> +	tmp &= 0x00FFFFFF;
> +	tmp |= ((u32)MC_CG_ARB_FREQ_F1) << 24;
> +
> +	return rv770_write_smc_sram_dword(rdev, ni_pi->arb_table_start,
> +					  tmp, pi->sram_end);
> +}
> +
> +static int ni_initial_switch_from_arb_f0_to_f1(struct radeon_device *rdev)
> +{
> +	return ni_copy_and_switch_arb_sets(rdev, MC_CG_ARB_FREQ_F0, MC_CG_ARB_FREQ_F1);
> +}
> +
> +static int ni_force_switch_to_arb_f0(struct radeon_device *rdev)
> +{
> +	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
> +	struct ni_power_info *ni_pi = ni_get_pi(rdev);
> +	u32 tmp;
> +	int ret;
> +
> +	ret = rv770_read_smc_sram_dword(rdev, ni_pi->arb_table_start,
> +					&tmp, pi->sram_end);
> +	if (ret)
> +		return ret;
> +
> +	tmp = (tmp >> 24) & 0xff;
> +
> +	if (tmp == MC_CG_ARB_FREQ_F0)
> +		return 0;
> +
> +	return ni_copy_and_switch_arb_sets(rdev, tmp, MC_CG_ARB_FREQ_F0);
> +}
> +
> +static int ni_populate_memory_timing_parameters(struct radeon_device *rdev,
> +						struct rv7xx_pl *pl,
> +						SMC_NIslands_MCArbDramTimingRegisterSet *arb_regs)
> +{
> +	u32 dram_timing;
> +	u32 dram_timing2;
> +
> +	arb_regs->mc_arb_rfsh_rate =
> +		(u8)rv770_calculate_memory_refresh_rate(rdev, pl->sclk);
> +
> +
> +	radeon_atom_set_engine_dram_timings(rdev,
> +                                            pl->sclk,
> +                                            pl->mclk);
> +
> +	dram_timing = RREG32(MC_ARB_DRAM_TIMING);
> +	dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2);
> +
> +	arb_regs->mc_arb_dram_timing  = cpu_to_be32(dram_timing);
> +	arb_regs->mc_arb_dram_timing2 = cpu_to_be32(dram_timing2);
> +
> +	return 0;
> +}
> +
> +static int ni_do_program_memory_timing_parameters(struct radeon_device *rdev,
> +						  struct radeon_ps *radeon_state,
> +						  unsigned int first_arb_set)
> +{
> +	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
> +	struct ni_power_info *ni_pi = ni_get_pi(rdev);
> +	struct ni_ps *state = ni_get_ps(radeon_state);
> +	SMC_NIslands_MCArbDramTimingRegisterSet arb_regs = { 0 };
> +	int i, ret = 0;
> +
> +	for (i = 0; i < state->performance_level_count; i++) {
> +		ret = ni_populate_memory_timing_parameters(rdev, &state->performance_levels[i], &arb_regs);
> +		if (ret)
> +			break;
> +
> +		ret = rv770_copy_bytes_to_smc(rdev,
> +					      (u16)(ni_pi->arb_table_start +
> +						    offsetof(SMC_NIslands_MCArbDramTimingRegisters, data) +
> +						    sizeof(SMC_NIslands_MCArbDramTimingRegisterSet) * (first_arb_set + i)),
> +					      (u8 *)&arb_regs,
> +					      (u16)sizeof(SMC_NIslands_MCArbDramTimingRegisterSet),
> +					      pi->sram_end);
> +		if (ret)
> +			break;
> +	}
> +	return ret;
> +}
> +
> +static int ni_program_memory_timing_parameters(struct radeon_device *rdev)
> +{
> +	struct radeon_ps *radeon_new_state = rdev->pm.dpm.requested_ps;
> +
> +	return ni_do_program_memory_timing_parameters(rdev, radeon_new_state,
> +						      NISLANDS_DRIVER_STATE_ARB_INDEX);
> +}
> +
> +static void ni_populate_initial_mvdd_value(struct radeon_device *rdev,
> +					   struct NISLANDS_SMC_VOLTAGE_VALUE *voltage)
> +{
> +	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
> +
> +	voltage->index = eg_pi->mvdd_high_index;
> +	voltage->value = cpu_to_be16(MVDD_HIGH_VALUE);
> +}
> +
> +static int ni_populate_smc_initial_state(struct radeon_device *rdev,
> +					 struct radeon_ps *radeon_initial_state,
> +					 NISLANDS_SMC_STATETABLE *table)
> +{
> +	struct ni_ps *initial_state = ni_get_ps(radeon_initial_state);
> +	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
> +	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
> +	struct ni_power_info *ni_pi = ni_get_pi(rdev);
> +	u32 reg;
> +	int ret;
> +
> +	table->initialState.levels[0].mclk.vMPLL_AD_FUNC_CNTL =
> +		cpu_to_be32(ni_pi->clock_registers.mpll_ad_func_cntl);
> +	table->initialState.levels[0].mclk.vMPLL_AD_FUNC_CNTL_2 =
> +		cpu_to_be32(ni_pi->clock_registers.mpll_ad_func_cntl_2);
> +	table->initialState.levels[0].mclk.vMPLL_DQ_FUNC_CNTL =
> +		cpu_to_be32(ni_pi->clock_registers.mpll_dq_func_cntl);
> +	table->initialState.levels[0].mclk.vMPLL_DQ_FUNC_CNTL_2 =
> +		cpu_to_be32(ni_pi->clock_registers.mpll_dq_func_cntl_2);
> +	table->initialState.levels[0].mclk.vMCLK_PWRMGT_CNTL =
> +		cpu_to_be32(ni_pi->clock_registers.mclk_pwrmgt_cntl);
> +	table->initialState.levels[0].mclk.vDLL_CNTL =
> +		cpu_to_be32(ni_pi->clock_registers.dll_cntl);
> +	table->initialState.levels[0].mclk.vMPLL_SS =
> +		cpu_to_be32(ni_pi->clock_registers.mpll_ss1);
> +	table->initialState.levels[0].mclk.vMPLL_SS2 =
> +		cpu_to_be32(ni_pi->clock_registers.mpll_ss2);
> +	table->initialState.levels[0].mclk.mclk_value =
> +		cpu_to_be32(initial_state->performance_levels[0].mclk);
> +
> +	table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL =
> +		cpu_to_be32(ni_pi->clock_registers.cg_spll_func_cntl);
> +	table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_2 =
> +		cpu_to_be32(ni_pi->clock_registers.cg_spll_func_cntl_2);
> +	table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_3 =
> +		cpu_to_be32(ni_pi->clock_registers.cg_spll_func_cntl_3);
> +	table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_4 =
> +		cpu_to_be32(ni_pi->clock_registers.cg_spll_func_cntl_4);
> +	table->initialState.levels[0].sclk.vCG_SPLL_SPREAD_SPECTRUM =
> +		cpu_to_be32(ni_pi->clock_registers.cg_spll_spread_spectrum);
> +	table->initialState.levels[0].sclk.vCG_SPLL_SPREAD_SPECTRUM_2 =
> +		cpu_to_be32(ni_pi->clock_registers.cg_spll_spread_spectrum_2);
> +	table->initialState.levels[0].sclk.sclk_value =
> +		cpu_to_be32(initial_state->performance_levels[0].sclk);
> +	table->initialState.levels[0].arbRefreshState =
> +		NISLANDS_INITIAL_STATE_ARB_INDEX;
> +
> +	table->initialState.levels[0].ACIndex = 0;
> +
> +	ret = ni_populate_voltage_value(rdev, &eg_pi->vddc_voltage_table,
> +					initial_state->performance_levels[0].vddc,
> +					&table->initialState.levels[0].vddc);
> +	if (!ret) {
> +		u16 std_vddc;
> +
> +		ret = ni_get_std_voltage_value(rdev,
> +					       &table->initialState.levels[0].vddc,
> +					       &std_vddc);
> +		if (!ret)
> +			ni_populate_std_voltage_value(rdev, std_vddc,
> +						      table->initialState.levels[0].vddc.index,
> +						      &table->initialState.levels[0].std_vddc);
> +	}
> +
> +	if (eg_pi->vddci_control)
> +		ni_populate_voltage_value(rdev,
> +					  &eg_pi->vddci_voltage_table,
> +					  initial_state->performance_levels[0].vddci,
> +					  &table->initialState.levels[0].vddci);
> +
> +	ni_populate_initial_mvdd_value(rdev, &table->initialState.levels[0].mvdd);
> +
> +	reg = CG_R(0xffff) | CG_L(0);
> +	table->initialState.levels[0].aT = cpu_to_be32(reg);
> +
> +	table->initialState.levels[0].bSP = cpu_to_be32(pi->dsp);
> +
> +	if (pi->boot_in_gen2)
> +		table->initialState.levels[0].gen2PCIE = 1;
> +	else
> +		table->initialState.levels[0].gen2PCIE = 0;
> +
> +	if (pi->mem_gddr5) {
> +		table->initialState.levels[0].strobeMode =
> +			cypress_get_strobe_mode_settings(rdev,
> +							 initial_state->performance_levels[0].mclk);
> +
> +		if (initial_state->performance_levels[0].mclk > pi->mclk_edc_enable_threshold)
> +			table->initialState.levels[0].mcFlags = NISLANDS_SMC_MC_EDC_RD_FLAG | NISLANDS_SMC_MC_EDC_WR_FLAG;
> +		else
> +			table->initialState.levels[0].mcFlags =  0;
> +	}
> +
> +	table->initialState.levelCount = 1;
> +
> +	table->initialState.flags |= PPSMC_SWSTATE_FLAG_DC;
> +
> +	table->initialState.levels[0].dpm2.MaxPS = 0;
> +	table->initialState.levels[0].dpm2.NearTDPDec = 0;
> +	table->initialState.levels[0].dpm2.AboveSafeInc = 0;
> +	table->initialState.levels[0].dpm2.BelowSafeInc = 0;
> +
> +	reg = MIN_POWER_MASK | MAX_POWER_MASK;
> +	table->initialState.levels[0].SQPowerThrottle = cpu_to_be32(reg);
> +
> +	reg = MAX_POWER_DELTA_MASK | STI_SIZE_MASK | LTI_RATIO_MASK;
> +	table->initialState.levels[0].SQPowerThrottle_2 = cpu_to_be32(reg);
> +
> +	return 0;
> +}
> +
> +static int ni_populate_smc_acpi_state(struct radeon_device *rdev,
> +				      NISLANDS_SMC_STATETABLE *table)
> +{
> +	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
> +	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
> +	struct ni_power_info *ni_pi = ni_get_pi(rdev);
> +	u32 mpll_ad_func_cntl   = ni_pi->clock_registers.mpll_ad_func_cntl;
> +	u32 mpll_ad_func_cntl_2 = ni_pi->clock_registers.mpll_ad_func_cntl_2;
> +	u32 mpll_dq_func_cntl   = ni_pi->clock_registers.mpll_dq_func_cntl;
> +	u32 mpll_dq_func_cntl_2 = ni_pi->clock_registers.mpll_dq_func_cntl_2;
> +	u32 spll_func_cntl      = ni_pi->clock_registers.cg_spll_func_cntl;
> +	u32 spll_func_cntl_2    = ni_pi->clock_registers.cg_spll_func_cntl_2;
> +	u32 spll_func_cntl_3    = ni_pi->clock_registers.cg_spll_func_cntl_3;
> +	u32 spll_func_cntl_4    = ni_pi->clock_registers.cg_spll_func_cntl_4;
> +	u32 mclk_pwrmgt_cntl    = ni_pi->clock_registers.mclk_pwrmgt_cntl;
> +	u32 dll_cntl            = ni_pi->clock_registers.dll_cntl;
> +	u32 reg;
> +	int ret;
> +
> +	table->ACPIState = table->initialState;
> +
> +	table->ACPIState.flags &= ~PPSMC_SWSTATE_FLAG_DC;
> +
> +	if (pi->acpi_vddc) {
> +		ret = ni_populate_voltage_value(rdev,
> +						&eg_pi->vddc_voltage_table,
> +						pi->acpi_vddc, &table->ACPIState.levels[0].vddc);
> +		if (!ret) {
> +			u16 std_vddc;
> +
> +			ret = ni_get_std_voltage_value(rdev,
> +						       &table->ACPIState.levels[0].vddc, &std_vddc);
> +			if (!ret)
> +				ni_populate_std_voltage_value(rdev, std_vddc,
> +							      table->ACPIState.levels[0].vddc.index,
> +							      &table->ACPIState.levels[0].std_vddc);
> +		}
> +
> +		if (pi->pcie_gen2) {
> +			if (pi->acpi_pcie_gen2)
> +				table->ACPIState.levels[0].gen2PCIE = 1;
> +			else
> +				table->ACPIState.levels[0].gen2PCIE = 0;
> +		} else {
> +			table->ACPIState.levels[0].gen2PCIE = 0;
> +		}
> +	} else {
> +		ret = ni_populate_voltage_value(rdev,
> +						&eg_pi->vddc_voltage_table,
> +						pi->min_vddc_in_table,
> +						&table->ACPIState.levels[0].vddc);
> +		if (!ret) {
> +			u16 std_vddc;
> +
> +			ret = ni_get_std_voltage_value(rdev,
> +						       &table->ACPIState.levels[0].vddc,
> +						       &std_vddc);
> +			if (!ret)
> +				ni_populate_std_voltage_value(rdev, std_vddc,
> +							      table->ACPIState.levels[0].vddc.index,
> +							      &table->ACPIState.levels[0].std_vddc);
> +		}
> +		table->ACPIState.levels[0].gen2PCIE = 0;
> +	}
> +
> +	if (eg_pi->acpi_vddci) {
> +		if (eg_pi->vddci_control)
> +			ni_populate_voltage_value(rdev,
> +						  &eg_pi->vddci_voltage_table,
> +						  eg_pi->acpi_vddci,
> +						  &table->ACPIState.levels[0].vddci);
> +	}
> +
> +
> +	mpll_ad_func_cntl &= ~PDNB;
> +
> +	mpll_ad_func_cntl_2 |= BIAS_GEN_PDNB | RESET_EN;
> +
> +        if (pi->mem_gddr5)
> +                mpll_dq_func_cntl &= ~PDNB;
> +        mpll_dq_func_cntl_2 |= BIAS_GEN_PDNB | RESET_EN | BYPASS;
> +
> +
> +        mclk_pwrmgt_cntl |= (MRDCKA0_RESET |
> +                             MRDCKA1_RESET |
> +                             MRDCKB0_RESET |
> +                             MRDCKB1_RESET |
> +                             MRDCKC0_RESET |
> +                             MRDCKC1_RESET |
> +                             MRDCKD0_RESET |
> +                             MRDCKD1_RESET);
^
Broken indentation.
> +
> +        mclk_pwrmgt_cntl &= ~(MRDCKA0_PDNB |
> +                              MRDCKA1_PDNB |
> +			      MRDCKB0_PDNB |
> +                              MRDCKB1_PDNB |
> +			      MRDCKC0_PDNB |
> +                              MRDCKC1_PDNB |
> +                              MRDCKD0_PDNB |
> +                              MRDCKD1_PDNB);
> +
> +	dll_cntl |= (MRDCKA0_BYPASS |
> +                     MRDCKA1_BYPASS |
> +                     MRDCKB0_BYPASS |
> +                     MRDCKB1_BYPASS |
> +                     MRDCKC0_BYPASS |
> +                     MRDCKC1_BYPASS |
> +                     MRDCKD0_BYPASS |
> +                     MRDCKD1_BYPASS);
^
Broken indentation.
> +
> +        spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK;
> +	spll_func_cntl_2 |= SCLK_MUX_SEL(4);
> +
> +	table->ACPIState.levels[0].mclk.vMPLL_AD_FUNC_CNTL = cpu_to_be32(mpll_ad_func_cntl);
> +	table->ACPIState.levels[0].mclk.vMPLL_AD_FUNC_CNTL_2 = cpu_to_be32(mpll_ad_func_cntl_2);
> +	table->ACPIState.levels[0].mclk.vMPLL_DQ_FUNC_CNTL = cpu_to_be32(mpll_dq_func_cntl);
> +	table->ACPIState.levels[0].mclk.vMPLL_DQ_FUNC_CNTL_2 = cpu_to_be32(mpll_dq_func_cntl_2);
> +	table->ACPIState.levels[0].mclk.vMCLK_PWRMGT_CNTL = cpu_to_be32(mclk_pwrmgt_cntl);
> +	table->ACPIState.levels[0].mclk.vDLL_CNTL = cpu_to_be32(dll_cntl);
> +
> +	table->ACPIState.levels[0].mclk.mclk_value = 0;
> +
> +	table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL = cpu_to_be32(spll_func_cntl);
> +	table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_2 = cpu_to_be32(spll_func_cntl_2);
> +	table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_3 = cpu_to_be32(spll_func_cntl_3);
> +	table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_4 = cpu_to_be32(spll_func_cntl_4);
> +
> +	table->ACPIState.levels[0].sclk.sclk_value = 0;
> +
> +	ni_populate_mvdd_value(rdev, 0, &table->ACPIState.levels[0].mvdd);
> +
> +	if (eg_pi->dynamic_ac_timing)
> +		table->ACPIState.levels[0].ACIndex = 1;
> +
> +	table->ACPIState.levels[0].dpm2.MaxPS = 0;
> +	table->ACPIState.levels[0].dpm2.NearTDPDec = 0;
> +	table->ACPIState.levels[0].dpm2.AboveSafeInc = 0;
> +	table->ACPIState.levels[0].dpm2.BelowSafeInc = 0;
> +
> +	reg = MIN_POWER_MASK | MAX_POWER_MASK;
> +	table->ACPIState.levels[0].SQPowerThrottle = cpu_to_be32(reg);
> +
> +	reg = MAX_POWER_DELTA_MASK | STI_SIZE_MASK | LTI_RATIO_MASK;
> +	table->ACPIState.levels[0].SQPowerThrottle_2 = cpu_to_be32(reg);
> +
> +	return 0;
> +}
> +
> +static int ni_init_smc_table(struct radeon_device *rdev)
> +{
> +	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
> +	struct ni_power_info *ni_pi = ni_get_pi(rdev);
> +	int ret;
> +	struct radeon_ps *radeon_boot_state = rdev->pm.dpm.boot_ps;
> +	NISLANDS_SMC_STATETABLE *table = &ni_pi->smc_statetable;
> +
> +	memset(table, 0, sizeof(NISLANDS_SMC_STATETABLE));
> +
> +	ni_populate_smc_voltage_tables(rdev, table);
> +
> +        switch (rdev->pm.int_thermal_type) {
> +        case THERMAL_TYPE_NI:
> +        case THERMAL_TYPE_EMC2103_WITH_INTERNAL:
> +                table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_INTERNAL;
> +                break;
> +        case THERMAL_TYPE_NONE:
> +                table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_NONE;
^
Broken indentation.
> +		break;
> +        default:
> +                table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_EXTERNAL;
> +                break;
> +        }
> +
> +	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_HARDWAREDC)
> +		table->systemFlags |= PPSMC_SYSTEMFLAG_GPIO_DC;
> +
> +	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_REGULATOR_HOT)
> +		table->systemFlags |= PPSMC_SYSTEMFLAG_REGULATOR_HOT;
> +
> +	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC)
> +		table->systemFlags |= PPSMC_SYSTEMFLAG_STEPVDDC;
> +
> +	if (pi->mem_gddr5)
> +		table->systemFlags |= PPSMC_SYSTEMFLAG_GDDR5;
> +
> +	ret = ni_populate_smc_initial_state(rdev, radeon_boot_state, table);
> +	if (ret)
> +		return ret;
> +
> +	ret = ni_populate_smc_acpi_state(rdev, table);
> +	if (ret)
> +		return ret;
> +
> +	table->driverState = table->initialState;
> +
> +	table->ULVState = table->initialState;
> +
> +	ret = ni_do_program_memory_timing_parameters(rdev, radeon_boot_state,
> +						     NISLANDS_INITIAL_STATE_ARB_INDEX);
> +	if (ret)
> +		return ret;
> +
> +	return rv770_copy_bytes_to_smc(rdev, pi->state_table_start, (u8 *)table,
> +				       sizeof(NISLANDS_SMC_STATETABLE), pi->sram_end);
> +}
> +
> +static int ni_calculate_sclk_params(struct radeon_device *rdev,
> +				    u32 engine_clock,
> +				    NISLANDS_SMC_SCLK_VALUE *sclk)
> +{
> +        struct rv7xx_power_info *pi = rv770_get_pi(rdev);
^
Broken indentation.
> +	struct ni_power_info *ni_pi = ni_get_pi(rdev);
> +	struct atom_clock_dividers dividers;
> +	u32 spll_func_cntl = ni_pi->clock_registers.cg_spll_func_cntl;
> +	u32 spll_func_cntl_2 = ni_pi->clock_registers.cg_spll_func_cntl_2;
> +	u32 spll_func_cntl_3 = ni_pi->clock_registers.cg_spll_func_cntl_3;
> +	u32 spll_func_cntl_4 = ni_pi->clock_registers.cg_spll_func_cntl_4;
> +	u32 cg_spll_spread_spectrum = ni_pi->clock_registers.cg_spll_spread_spectrum;
> +	u32 cg_spll_spread_spectrum_2 = ni_pi->clock_registers.cg_spll_spread_spectrum_2;
> +	u64 tmp;
> +	u32 reference_clock = rdev->clock.spll.reference_freq;
> +	u32 reference_divider;
> +	u32 fbdiv;
> +	int ret;
> +
> +        ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
> +                                             engine_clock, false, &dividers);
> +	if (ret)
> +		return ret;
> +
> +	reference_divider = 1 + dividers.ref_div;
> +
> +	tmp = (u64) engine_clock * reference_divider * dividers.post_div;
> +
> +	fbdiv = (u32) ((16384 * tmp) / reference_clock);
> +
> +        spll_func_cntl &= ~(SPLL_PDIV_A_MASK | SPLL_REF_DIV_MASK);
> +        spll_func_cntl |= SPLL_REF_DIV(dividers.ref_div);
> +        spll_func_cntl |= SPLL_PDIV_A(dividers.post_div);
> +
> +        spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK;
> +        spll_func_cntl_2 |= SCLK_MUX_SEL(2);
^
Broken indentation.
> +
> +	spll_func_cntl_3 &= ~SPLL_FB_DIV_MASK;
> +        spll_func_cntl_3 |= SPLL_FB_DIV(fbdiv);
> +        spll_func_cntl_3 |= SPLL_DITHEN;
> +
> +	if (pi->sclk_ss) {
> +                struct radeon_atom_ss ss;
> +                u32 vco_freq = engine_clock * dividers.post_div;
> +
> +                if (radeon_atombios_get_asic_ss_info(rdev, &ss,
> +                                                     ASIC_INTERNAL_ENGINE_SS, vco_freq)) {
> +                        u32 clk_s = reference_clock * 5 / (reference_divider * ss.rate);
> +                        u32 clk_v = 4 * ss.percentage * fbdiv / (clk_s * 10000);
> +
> +                        cg_spll_spread_spectrum &= ~CLK_S_MASK;
> +			cg_spll_spread_spectrum |= CLK_S(clk_s);
> +                        cg_spll_spread_spectrum |= SSEN;
> +
> +                        cg_spll_spread_spectrum_2 &= ~CLK_V_MASK;
> +                        cg_spll_spread_spectrum_2 |= CLK_V(clk_v);
^
Broken indentation.
> +		}
> +	}
> +
> +	sclk->sclk_value = engine_clock;
> +	sclk->vCG_SPLL_FUNC_CNTL = spll_func_cntl;
> +	sclk->vCG_SPLL_FUNC_CNTL_2 = spll_func_cntl_2;
> +	sclk->vCG_SPLL_FUNC_CNTL_3 = spll_func_cntl_3;
> +	sclk->vCG_SPLL_FUNC_CNTL_4 = spll_func_cntl_4;
> +	sclk->vCG_SPLL_SPREAD_SPECTRUM = cg_spll_spread_spectrum;
> +	sclk->vCG_SPLL_SPREAD_SPECTRUM_2 = cg_spll_spread_spectrum_2;
> +
> +	return 0;
> +}
> +
> +static int ni_populate_sclk_value(struct radeon_device *rdev,
> +				  u32 engine_clock,
> +				  NISLANDS_SMC_SCLK_VALUE *sclk)
> +{
> +	NISLANDS_SMC_SCLK_VALUE sclk_tmp;
> +	int ret;
> +
> +	ret = ni_calculate_sclk_params(rdev, engine_clock, &sclk_tmp);
> +	if (!ret) {
> +		sclk->sclk_value = cpu_to_be32(sclk_tmp.sclk_value);
> +		sclk->vCG_SPLL_FUNC_CNTL = cpu_to_be32(sclk_tmp.vCG_SPLL_FUNC_CNTL);
> +		sclk->vCG_SPLL_FUNC_CNTL_2 = cpu_to_be32(sclk_tmp.vCG_SPLL_FUNC_CNTL_2);
> +		sclk->vCG_SPLL_FUNC_CNTL_3 = cpu_to_be32(sclk_tmp.vCG_SPLL_FUNC_CNTL_3);
> +		sclk->vCG_SPLL_FUNC_CNTL_4 = cpu_to_be32(sclk_tmp.vCG_SPLL_FUNC_CNTL_4);
> +		sclk->vCG_SPLL_SPREAD_SPECTRUM = cpu_to_be32(sclk_tmp.vCG_SPLL_SPREAD_SPECTRUM);
> +		sclk->vCG_SPLL_SPREAD_SPECTRUM_2 = cpu_to_be32(sclk_tmp.vCG_SPLL_SPREAD_SPECTRUM_2);
> +	}
> +
> +	return ret;
> +}
> +
> +static int ni_init_smc_spll_table(struct radeon_device *rdev)
> +{
> +        struct rv7xx_power_info *pi = rv770_get_pi(rdev);
> +	struct ni_power_info *ni_pi = ni_get_pi(rdev);
> +	SMC_NISLANDS_SPLL_DIV_TABLE *spll_table;
> +	NISLANDS_SMC_SCLK_VALUE sclk_params;
> +	u32 fb_div;
> +	u32 p_div;
> +	u32 clk_s;
> +	u32 clk_v;
> +	u32 sclk = 0;
> +	int i, ret;
> +	u32 tmp;
> +
> +	if (ni_pi->spll_table_start == 0)
> +		return -EINVAL;
> +
> +	spll_table = kzalloc(sizeof(SMC_NISLANDS_SPLL_DIV_TABLE), GFP_KERNEL);
> +	if (spll_table == NULL)
> +		return -ENOMEM;
> +
> +	for (i = 0; i < 256; i++) {
> +		ret = ni_calculate_sclk_params(rdev, sclk, &sclk_params);
> +		if (ret)
> +			break;
> +
> +		p_div = (sclk_params.vCG_SPLL_FUNC_CNTL & SPLL_PDIV_A_MASK) >> SPLL_PDIV_A_SHIFT;
> +		fb_div = (sclk_params.vCG_SPLL_FUNC_CNTL_3 & SPLL_FB_DIV_MASK) >> SPLL_FB_DIV_SHIFT;
> +		clk_s = (sclk_params.vCG_SPLL_SPREAD_SPECTRUM & CLK_S_MASK) >> CLK_S_SHIFT;
> +		clk_v = (sclk_params.vCG_SPLL_SPREAD_SPECTRUM_2 & CLK_V_MASK) >> CLK_V_SHIFT;
> +
> +		fb_div &= ~0x00001FFF;
> +		fb_div >>= 1;
> +		clk_v >>= 6;
> +
> +		if (p_div & ~(SMC_NISLANDS_SPLL_DIV_TABLE_PDIV_MASK >> SMC_NISLANDS_SPLL_DIV_TABLE_PDIV_SHIFT))
> +			ret = -EINVAL;
> +
> +		if (clk_s & ~(SMC_NISLANDS_SPLL_DIV_TABLE_CLKS_MASK >> SMC_NISLANDS_SPLL_DIV_TABLE_CLKS_SHIFT))
> +			ret = -EINVAL;
> +
> +		if (clk_s & ~(SMC_NISLANDS_SPLL_DIV_TABLE_CLKS_MASK >> SMC_NISLANDS_SPLL_DIV_TABLE_CLKS_SHIFT))
> +			ret = -EINVAL;
> +
> +		if (clk_v & ~(SMC_NISLANDS_SPLL_DIV_TABLE_CLKV_MASK >> SMC_NISLANDS_SPLL_DIV_TABLE_CLKV_SHIFT))
> +			ret = -EINVAL;
> +
> +		if (ret)
> +			break;
> +
> +		tmp = ((fb_div << SMC_NISLANDS_SPLL_DIV_TABLE_FBDIV_SHIFT) & SMC_NISLANDS_SPLL_DIV_TABLE_FBDIV_MASK) |
> +			((p_div << SMC_NISLANDS_SPLL_DIV_TABLE_PDIV_SHIFT) & SMC_NISLANDS_SPLL_DIV_TABLE_PDIV_MASK);
> +		spll_table->freq[i] = cpu_to_be32(tmp);
> +
> +		tmp = ((clk_v << SMC_NISLANDS_SPLL_DIV_TABLE_CLKV_SHIFT) & SMC_NISLANDS_SPLL_DIV_TABLE_CLKV_MASK) |
> +			((clk_s << SMC_NISLANDS_SPLL_DIV_TABLE_CLKS_SHIFT) & SMC_NISLANDS_SPLL_DIV_TABLE_CLKS_MASK);
> +		spll_table->ss[i] = cpu_to_be32(tmp);
> +
> +		sclk += 512;
> +	}
> +
> +	if (!ret)
> +		ret = rv770_copy_bytes_to_smc(rdev, ni_pi->spll_table_start, (u8 *)spll_table,
> +					      sizeof(SMC_NISLANDS_SPLL_DIV_TABLE), pi->sram_end);
> +
> +	kfree(spll_table);
> +
> +	return ret;
> +}
> +
> +static int ni_populate_mclk_value(struct radeon_device *rdev,
> +				  u32 engine_clock,
> +				  u32 memory_clock,
> +				  NISLANDS_SMC_MCLK_VALUE *mclk,
> +				  bool strobe_mode,
> +				  bool dll_state_on)
> +{
> +	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
> +	struct ni_power_info *ni_pi = ni_get_pi(rdev);
> +	u32 mpll_ad_func_cntl = ni_pi->clock_registers.mpll_ad_func_cntl;
> +	u32 mpll_ad_func_cntl_2 = ni_pi->clock_registers.mpll_ad_func_cntl_2;
> +	u32 mpll_dq_func_cntl = ni_pi->clock_registers.mpll_dq_func_cntl;
> +	u32 mpll_dq_func_cntl_2 = ni_pi->clock_registers.mpll_dq_func_cntl_2;
> +	u32 mclk_pwrmgt_cntl = ni_pi->clock_registers.mclk_pwrmgt_cntl;
> +	u32 dll_cntl = ni_pi->clock_registers.dll_cntl;
> +	u32 mpll_ss1 = ni_pi->clock_registers.mpll_ss1;
> +	u32 mpll_ss2 = ni_pi->clock_registers.mpll_ss2;
> +	struct atom_clock_dividers dividers;
> +	u32 ibias;
> +	u32 dll_speed;
> +	int ret;
> +	u32 mc_seq_misc7;
> +
> +        ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_MEMORY_PLL_PARAM,
> +                                             memory_clock, strobe_mode, &dividers);
^
Broken indentation.
> +	if (ret)
> +		return ret;
> +
> +	if (!strobe_mode) {
> +		mc_seq_misc7 = RREG32(MC_SEQ_MISC7);
> +
> +		if (mc_seq_misc7 & 0x8000000)
> +			dividers.post_div = 1;
> +	}
> +
> +	ibias = cypress_map_clkf_to_ibias(rdev, dividers.whole_fb_div);
> +
> +        mpll_ad_func_cntl &= ~(CLKR_MASK |
> +                               YCLK_POST_DIV_MASK |
> +                               CLKF_MASK |
> +                               CLKFRAC_MASK |
> +                               IBIAS_MASK);
> +        mpll_ad_func_cntl |= CLKR(dividers.ref_div);
> +        mpll_ad_func_cntl |= YCLK_POST_DIV(dividers.post_div);
> +        mpll_ad_func_cntl |= CLKF(dividers.whole_fb_div);
> +        mpll_ad_func_cntl |= CLKFRAC(dividers.frac_fb_div);
^
Broken indentation.
> +	mpll_ad_func_cntl |= IBIAS(ibias);
> +
> +        if (dividers.vco_mode)
^
Broken indentation.
> +		mpll_ad_func_cntl_2 |= VCO_MODE;
> +	else
> +		mpll_ad_func_cntl_2 &= ~VCO_MODE;
> +
> +	if (pi->mem_gddr5) {
> +                mpll_dq_func_cntl &= ~(CLKR_MASK |
> +                                       YCLK_POST_DIV_MASK |
> +                                       CLKF_MASK |
> +                                       CLKFRAC_MASK |
> +                                       IBIAS_MASK);
> +                mpll_dq_func_cntl |= CLKR(dividers.ref_div);
> +                mpll_dq_func_cntl |= YCLK_POST_DIV(dividers.post_div);
> +                mpll_dq_func_cntl |= CLKF(dividers.whole_fb_div);
> +                mpll_dq_func_cntl |= CLKFRAC(dividers.frac_fb_div);
> +                mpll_dq_func_cntl |= IBIAS(ibias);
> +
> +		if (strobe_mode)
> +			mpll_dq_func_cntl &= ~PDNB;
> +                else
> +			mpll_dq_func_cntl |= PDNB;
> +
> +		if (dividers.vco_mode)
> +			mpll_dq_func_cntl_2 |= VCO_MODE;
> +		else
> +                        mpll_dq_func_cntl_2 &= ~VCO_MODE;
> +	}
> +
> +	if (pi->mclk_ss) {
> +                struct radeon_atom_ss ss;
> +                u32 vco_freq = memory_clock * dividers.post_div;
> +
> +                if (radeon_atombios_get_asic_ss_info(rdev, &ss,
> +						     ASIC_INTERNAL_MEMORY_SS, vco_freq)) {
> +			u32 reference_clock = rdev->clock.mpll.reference_freq;
> +                        u32 decoded_ref = rv740_get_decoded_reference_divider(dividers.ref_div);
> +			u32 clk_s = reference_clock * 5 / (decoded_ref * ss.rate);
> +                        u32 clk_v = ss.percentage *
> +                                (0x4000 * dividers.whole_fb_div + 0x800 * dividers.frac_fb_div) / (clk_s * 625);
> +
> +                        mpll_ss1 &= ~CLKV_MASK;
> +                        mpll_ss1 |= CLKV(clk_v);
> +
> +                        mpll_ss2 &= ~CLKS_MASK;
> +                        mpll_ss2 |= CLKS(clk_s);
> +		}
> +	}
> +
> +        dll_speed = rv740_get_dll_speed(pi->mem_gddr5,
> +                                        memory_clock);
> +
> +        mclk_pwrmgt_cntl &= ~DLL_SPEED_MASK;
> +        mclk_pwrmgt_cntl |= DLL_SPEED(dll_speed);
> +        if (dll_state_on)
> +                mclk_pwrmgt_cntl |= (MRDCKA0_PDNB |
> +                                     MRDCKA1_PDNB |
> +                                     MRDCKB0_PDNB |
> +                                     MRDCKB1_PDNB |
> +                                     MRDCKC0_PDNB |
> +                                     MRDCKC1_PDNB |
> +                                     MRDCKD0_PDNB |
> +                                     MRDCKD1_PDNB);
> +        else
> +                mclk_pwrmgt_cntl &= ~(MRDCKA0_PDNB |
> +                                      MRDCKA1_PDNB |
> +                                      MRDCKB0_PDNB |
> +                                      MRDCKB1_PDNB |
> +                                      MRDCKC0_PDNB |
> +                                      MRDCKC1_PDNB |
> +                                      MRDCKD0_PDNB |
> +                                      MRDCKD1_PDNB);
> +
> +
> +	mclk->mclk_value = cpu_to_be32(memory_clock);
> +	mclk->vMPLL_AD_FUNC_CNTL = cpu_to_be32(mpll_ad_func_cntl);
> +	mclk->vMPLL_AD_FUNC_CNTL_2 = cpu_to_be32(mpll_ad_func_cntl_2);
> +	mclk->vMPLL_DQ_FUNC_CNTL = cpu_to_be32(mpll_dq_func_cntl);
> +	mclk->vMPLL_DQ_FUNC_CNTL_2 = cpu_to_be32(mpll_dq_func_cntl_2);
> +	mclk->vMCLK_PWRMGT_CNTL = cpu_to_be32(mclk_pwrmgt_cntl);
> +	mclk->vDLL_CNTL = cpu_to_be32(dll_cntl);
> +	mclk->vMPLL_SS = cpu_to_be32(mpll_ss1);
> +	mclk->vMPLL_SS2 = cpu_to_be32(mpll_ss2);
> +
> +	return 0;
> +}
> +
> +static void ni_populate_smc_sp(struct radeon_device *rdev,
> +			       struct radeon_ps *radeon_state,
> +			       NISLANDS_SMC_SWSTATE *smc_state)
> +{
> +	struct ni_ps *ps = ni_get_ps(radeon_state);
> +	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
> +	int i;
> +
> +	for (i = 0; i < ps->performance_level_count - 1; i++)
> +		smc_state->levels[i].bSP = cpu_to_be32(pi->dsp);
> +
> +	smc_state->levels[ps->performance_level_count - 1].bSP =
> +		cpu_to_be32(pi->psp);
> +}
> +
> +static int ni_convert_power_level_to_smc(struct radeon_device *rdev,
> +					 struct rv7xx_pl *pl,
> +					 NISLANDS_SMC_HW_PERFORMANCE_LEVEL *level)
> +{
> +	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
> +        struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
> +        struct ni_power_info *ni_pi = ni_get_pi(rdev);
> +	int ret;
> +	bool dll_state_on;
> +	u16 std_vddc;
> +	u32 tmp = RREG32(DC_STUTTER_CNTL);
> +
> +	level->gen2PCIE = pi->pcie_gen2 ?
> +		((pl->flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) ? 1 : 0) : 0;
> +
> +	ret = ni_populate_sclk_value(rdev, pl->sclk, &level->sclk);
> +	if (ret)
> +		return ret;
> +
> +	level->mcFlags =  0;
> +	if (pi->mclk_stutter_mode_threshold &&
> +	    (pl->mclk <= pi->mclk_stutter_mode_threshold) &&
> +	    !eg_pi->uvd_enabled &&
> +	    (tmp & DC_STUTTER_ENABLE_A) &&
> +	    (tmp & DC_STUTTER_ENABLE_B))
> +		level->mcFlags |= NISLANDS_SMC_MC_STUTTER_EN;
> +
> +	if (pi->mem_gddr5) {
> +		if (pl->mclk > pi->mclk_edc_enable_threshold)
> +			level->mcFlags |= NISLANDS_SMC_MC_EDC_RD_FLAG;
> +		if (pl->mclk > eg_pi->mclk_edc_wr_enable_threshold)
> +			level->mcFlags |= NISLANDS_SMC_MC_EDC_WR_FLAG;
> +
> +		level->strobeMode = cypress_get_strobe_mode_settings(rdev, pl->mclk);
> +
> +		if (level->strobeMode & NISLANDS_SMC_STROBE_ENABLE) {
> +			if (cypress_get_mclk_frequency_ratio(rdev, pl->mclk, true) >=
> +			    ((RREG32(MC_SEQ_MISC7) >> 16) & 0xf))
> +				dll_state_on = ((RREG32(MC_SEQ_MISC5) >> 1) & 0x1) ? true : false;
> +			else
> +				dll_state_on = ((RREG32(MC_SEQ_MISC6) >> 1) & 0x1) ? true : false;
> +		} else {
> +			dll_state_on = false;
> +			if (pl->mclk > ni_pi->mclk_rtt_mode_threshold)
> +				level->mcFlags |= NISLANDS_SMC_MC_RTT_ENABLE;
> +		}
> +
> +		ret = ni_populate_mclk_value(rdev, pl->sclk, pl->mclk,
> +					     &level->mclk,
> +					     (level->strobeMode & NISLANDS_SMC_STROBE_ENABLE) != 0,
> +					     dll_state_on);
> +	} else
> +		ret = ni_populate_mclk_value(rdev, pl->sclk, pl->mclk, &level->mclk, 1, 1);
> +
> +	if (ret)
> +		return ret;
> +
> +	ret = ni_populate_voltage_value(rdev, &eg_pi->vddc_voltage_table,
> +					pl->vddc, &level->vddc);
> +	if (ret)
> +		return ret;
> +
> +	ret = ni_get_std_voltage_value(rdev, &level->vddc, &std_vddc);
> +	if (ret)
> +		return ret;
> +
> +	ni_populate_std_voltage_value(rdev, std_vddc,
> +				      level->vddc.index, &level->std_vddc);
> +
> +	if (eg_pi->vddci_control) {
> +		ret = ni_populate_voltage_value(rdev, &eg_pi->vddci_voltage_table,
> +						pl->vddci, &level->vddci);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ni_populate_mvdd_value(rdev, pl->mclk, &level->mvdd);
> +
> +	return ret;
> +}
> +
> +static int ni_populate_smc_t(struct radeon_device *rdev,
> +			     struct radeon_ps *radeon_state,
> +			     NISLANDS_SMC_SWSTATE *smc_state)
> +{
> +        struct rv7xx_power_info *pi = rv770_get_pi(rdev);
> +        struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
> +	struct ni_ps *state = ni_get_ps(radeon_state);
> +	u32 a_t;
> +	u32 t_l, t_h;
> +	u32 high_bsp;
> +	int i, ret;
> +
> +	if (state->performance_level_count >= 9)
> +		return -EINVAL;
> +
> +	if (state->performance_level_count < 2) {
> +		a_t = CG_R(0xffff) | CG_L(0);
> +		smc_state->levels[0].aT = cpu_to_be32(a_t);
> +		return 0;
> +	}
> +
> +	smc_state->levels[0].aT = cpu_to_be32(0);
> +
> +	for (i = 0; i <= state->performance_level_count - 2; i++) {
> +		if (eg_pi->uvd_enabled)
> +			ret = r600_calculate_at(
> +				1000 * (i * (eg_pi->smu_uvd_hs ? 2 : 8) + 2),
> +				100 * R600_AH_DFLT,
> +				state->performance_levels[i + 1].sclk,
> +				state->performance_levels[i].sclk,
> +				&t_l,
> +				&t_h);
> +		else
> +			ret = r600_calculate_at(
> +				1000 * (i + 1),
> +				100 * R600_AH_DFLT,
> +				state->performance_levels[i + 1].sclk,
> +				state->performance_levels[i].sclk,
> +				&t_l,
> +				&t_h);
> +
> +		if (ret) {
> +			t_h = (i + 1) * 1000 - 50 * R600_AH_DFLT;
> +			t_l = (i + 1) * 1000 + 50 * R600_AH_DFLT;
> +		}
> +
> +		a_t = be32_to_cpu(smc_state->levels[i].aT) & ~CG_R_MASK;
> +		a_t |= CG_R(t_l * pi->bsp / 20000);
> +		smc_state->levels[i].aT = cpu_to_be32(a_t);
> +
> +		high_bsp = (i == state->performance_level_count - 2) ?
> +			pi->pbsp : pi->bsp;
> +
> +		a_t = CG_R(0xffff) | CG_L(t_h * high_bsp / 20000);
> +		smc_state->levels[i + 1].aT = cpu_to_be32(a_t);
> +	}
> +
> +	return 0;
> +}
> +
> +static int ni_populate_power_containment_values(struct radeon_device *rdev,
> +						struct radeon_ps *radeon_state,
> +						NISLANDS_SMC_SWSTATE *smc_state)
> +{
> +        struct rv7xx_power_info *pi = rv770_get_pi(rdev);
> +        struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
> +	struct ni_power_info *ni_pi = ni_get_pi(rdev);
> +	struct ni_ps *state = ni_get_ps(radeon_state);
> +	u32 prev_sclk;
> +	u32 max_sclk;
> +	u32 min_sclk;
> +	int i, ret;
> +	u32 tdp_limit;
> +	u32 near_tdp_limit;
> +	u32 power_boost_limit;
> +	u8 max_ps_percent;
> +
> +	if (ni_pi->enable_power_containment == false)
> +		return 0;
> +
> +	if (state->performance_level_count == 0)
> +		return -EINVAL;
> +
> +	if (smc_state->levelCount != state->performance_level_count)
> +		return -EINVAL;
> +
> +	ret = ni_calculate_adjusted_tdp_limits(rdev,
> +					       false, /* ??? */
> +					       rdev->pm.dpm.tdp_adjustment,
> +					       &tdp_limit,
> +					       &near_tdp_limit);
> +	if (ret)
> +		return ret;
> +
> +	power_boost_limit = ni_calculate_power_boost_limit(rdev, radeon_state, near_tdp_limit);
> +
> +	ret = rv770_write_smc_sram_dword(rdev,
> +					 pi->state_table_start +
> +					 offsetof(NISLANDS_SMC_STATETABLE, dpm2Params) +
> +					 offsetof(PP_NIslands_DPM2Parameters, PowerBoostLimit),
> +					 ni_scale_power_for_smc(power_boost_limit, ni_get_smc_power_scaling_factor(rdev)),
> +					 pi->sram_end);
> +	if (ret)
> +		power_boost_limit = 0;
> +
> +	smc_state->levels[0].dpm2.MaxPS = 0;
> +	smc_state->levels[0].dpm2.NearTDPDec = 0;
> +	smc_state->levels[0].dpm2.AboveSafeInc = 0;
> +	smc_state->levels[0].dpm2.BelowSafeInc = 0;
> +	smc_state->levels[0].stateFlags |= power_boost_limit ? PPSMC_STATEFLAG_POWERBOOST : 0;
> +
> +	for (i = 1; i < state->performance_level_count; i++) {
> +		prev_sclk = state->performance_levels[i-1].sclk;
> +		max_sclk  = state->performance_levels[i].sclk;
> +		max_ps_percent = (i != (state->performance_level_count - 1)) ?
> +			NISLANDS_DPM2_MAXPS_PERCENT_M : NISLANDS_DPM2_MAXPS_PERCENT_H;
> +
> +		if (max_sclk < prev_sclk)
> +			return -EINVAL;
> +
> +		if ((max_ps_percent == 0) || (prev_sclk == max_sclk) || eg_pi->uvd_enabled)
> +			min_sclk = max_sclk;
> +		else if (1 == i)
> +			min_sclk = prev_sclk;
> +		else
> +			min_sclk = (prev_sclk * (u32)max_ps_percent) / 100;
> +
> +		if (min_sclk < state->performance_levels[0].sclk)
> +			min_sclk = state->performance_levels[0].sclk;
> +
> +		if (min_sclk == 0)
> +			return -EINVAL;
> +
> +		smc_state->levels[i].dpm2.MaxPS =
> +			(u8)((NISLANDS_DPM2_MAX_PULSE_SKIP * (max_sclk - min_sclk)) / max_sclk);
> +		smc_state->levels[i].dpm2.NearTDPDec = NISLANDS_DPM2_NEAR_TDP_DEC;
> +		smc_state->levels[i].dpm2.AboveSafeInc = NISLANDS_DPM2_ABOVE_SAFE_INC;
> +		smc_state->levels[i].dpm2.BelowSafeInc = NISLANDS_DPM2_BELOW_SAFE_INC;
> +		smc_state->levels[i].stateFlags |=
> +			((i != (state->performance_level_count - 1)) && power_boost_limit) ?
> +			PPSMC_STATEFLAG_POWERBOOST : 0;
> +	}
> +
> +	return 0;
> +}
> +
> +static int ni_populate_sq_ramping_values(struct radeon_device *rdev,
> +					 struct radeon_ps *radeon_state,
> +					 NISLANDS_SMC_SWSTATE *smc_state)
> +{
> +	struct ni_power_info *ni_pi = ni_get_pi(rdev);
> +	struct ni_ps *state = ni_get_ps(radeon_state);
> +	u32 sq_power_throttle;
> +	u32 sq_power_throttle2;
> +	bool enable_sq_ramping = ni_pi->enable_sq_ramping;
> +	int i;
> +
> +	if (state->performance_level_count == 0)
> +		return -EINVAL;
> +
> +	if (smc_state->levelCount != state->performance_level_count)
> +		return -EINVAL;
> +
> +	if (rdev->pm.dpm.sq_ramping_threshold == 0)
> +		return -EINVAL;
> +
> +	if (NISLANDS_DPM2_SQ_RAMP_MAX_POWER > (MAX_POWER_MASK >> MAX_POWER_SHIFT))
> +		enable_sq_ramping = false;
> +
> +	if (NISLANDS_DPM2_SQ_RAMP_MIN_POWER > (MIN_POWER_MASK >> MIN_POWER_SHIFT))
> +		enable_sq_ramping = false;
> +
> +	if (NISLANDS_DPM2_SQ_RAMP_MAX_POWER_DELTA > (MAX_POWER_DELTA_MASK >> MAX_POWER_DELTA_SHIFT))
> +		enable_sq_ramping = false;
> +
> +	if (NISLANDS_DPM2_SQ_RAMP_STI_SIZE > (STI_SIZE_MASK >> STI_SIZE_SHIFT))
> +		enable_sq_ramping = false;
> +
> +	if (NISLANDS_DPM2_SQ_RAMP_LTI_RATIO <= (LTI_RATIO_MASK >> LTI_RATIO_SHIFT))
> +		enable_sq_ramping = false;
> +
> +	for (i = 0; i < state->performance_level_count; i++) {
> +		sq_power_throttle  = 0;
> +		sq_power_throttle2 = 0;
> +
> +		if ((state->performance_levels[i].sclk >= rdev->pm.dpm.sq_ramping_threshold) &&
> +		    enable_sq_ramping) {
> +			sq_power_throttle |= MAX_POWER(NISLANDS_DPM2_SQ_RAMP_MAX_POWER);
> +			sq_power_throttle |= MIN_POWER(NISLANDS_DPM2_SQ_RAMP_MIN_POWER);
> +			sq_power_throttle2 |= MAX_POWER_DELTA(NISLANDS_DPM2_SQ_RAMP_MAX_POWER_DELTA);
> +			sq_power_throttle2 |= STI_SIZE(NISLANDS_DPM2_SQ_RAMP_STI_SIZE);
> +			sq_power_throttle2 |= LTI_RATIO(NISLANDS_DPM2_SQ_RAMP_LTI_RATIO);
> +		} else {
> +			sq_power_throttle |= MAX_POWER_MASK | MIN_POWER_MASK;
> +			sq_power_throttle2 |= MAX_POWER_DELTA_MASK | STI_SIZE_MASK | LTI_RATIO_MASK;
> +		}
> +
> +		smc_state->levels[i].SQPowerThrottle   = cpu_to_be32(sq_power_throttle);
> +		smc_state->levels[i].SQPowerThrottle_2 = cpu_to_be32(sq_power_throttle2);
> +	}
> +
> +	return 0;
> +}
> +
> +static int ni_enable_power_containment(struct radeon_device *rdev, bool enable)
> +{
> +        struct ni_power_info *ni_pi = ni_get_pi(rdev);
> +	PPSMC_Result smc_result;
> +	int ret = 0;
> +
> +	if (ni_pi->enable_power_containment) {
> +		if (enable) {
> +			struct radeon_ps *radeon_new_state = rdev->pm.dpm.requested_ps;
> +
> +			if (!r600_is_uvd_state(radeon_new_state->class, radeon_new_state->class2)) {
> +				smc_result = rv770_send_msg_to_smc(rdev, PPSMC_TDPClampingActive);
> +				if (smc_result != PPSMC_Result_OK) {
> +					ret = -EINVAL;
> +					ni_pi->pc_enabled = false;
> +				} else {
> +					ni_pi->pc_enabled = true;
> +				}
> +			}
> +		} else {
> +			smc_result = rv770_send_msg_to_smc(rdev, PPSMC_TDPClampingInactive);
> +			if (smc_result != PPSMC_Result_OK)
> +				ret = -EINVAL;
> +			ni_pi->pc_enabled = false;
> +		}
> +	}
> +
> +	return ret;
> +}
> +
> +static int ni_convert_power_state_to_smc(struct radeon_device *rdev,
> +					 struct radeon_ps *radeon_state,
> +					 NISLANDS_SMC_SWSTATE *smc_state)
> +{
> +        struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
> +	struct ni_power_info *ni_pi = ni_get_pi(rdev);
> +	struct ni_ps *state = ni_get_ps(radeon_state);
> +	int i, ret;
> +	u32 threshold = state->performance_levels[state->performance_level_count - 1].sclk * 100 / 100;
> +
> +	if (!(radeon_state->caps & ATOM_PPLIB_DISALLOW_ON_DC))
> +		smc_state->flags |= PPSMC_SWSTATE_FLAG_DC;
> +
> +	smc_state->levelCount = 0;
> +
> +	if (state->performance_level_count > NISLANDS_MAX_SMC_PERFORMANCE_LEVELS_PER_SWSTATE)
> +		return -EINVAL;
> +
> +	for (i = 0; i < state->performance_level_count; i++) {
> +		ret = ni_convert_power_level_to_smc(rdev, &state->performance_levels[i],
> +						    &smc_state->levels[i]);
> +		smc_state->levels[i].arbRefreshState =
> +			(u8)(NISLANDS_DRIVER_STATE_ARB_INDEX + i);
> +
> +		if (ret)
> +			return ret;
> +
> +		if (ni_pi->enable_power_containment)
> +			smc_state->levels[i].displayWatermark =
> +				(state->performance_levels[i].sclk < threshold) ?
> +				PPSMC_DISPLAY_WATERMARK_LOW : PPSMC_DISPLAY_WATERMARK_HIGH;
> +		else
> +			smc_state->levels[i].displayWatermark = (i < 2) ?
> +				PPSMC_DISPLAY_WATERMARK_LOW : PPSMC_DISPLAY_WATERMARK_HIGH;
> +
> +		if (eg_pi->dynamic_ac_timing)
> +			smc_state->levels[i].ACIndex = NISLANDS_MCREGISTERTABLE_FIRST_DRIVERSTATE_SLOT + i;
> +		else
> +			smc_state->levels[i].ACIndex = 0;
> +
> +		smc_state->levelCount++;
> +	}
> +
> +	rv770_write_smc_soft_register(rdev, NI_SMC_SOFT_REGISTER_watermark_threshold,
> +				      cpu_to_be32(threshold / 512));
> +
> +	ni_populate_smc_sp(rdev, radeon_state, smc_state);
> +
> +	ret = ni_populate_power_containment_values(rdev, radeon_state, smc_state);
> +	if (ret)
> +		ni_pi->enable_power_containment = false;
> +
> +	ret = ni_populate_sq_ramping_values(rdev, radeon_state, smc_state);
> +	if (ret)
> +		ni_pi->enable_sq_ramping = false;
> +
> +	return ni_populate_smc_t(rdev, radeon_state, smc_state);
> +}
> +
> +static int ni_upload_sw_state(struct radeon_device *rdev)
> +{
> +	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
> +	struct radeon_ps *radeon_new_state = rdev->pm.dpm.requested_ps;
> +	u16 address = pi->state_table_start +
> +		offsetof(NISLANDS_SMC_STATETABLE, driverState);
> +	u16 state_size = sizeof(NISLANDS_SMC_SWSTATE) +
> +		((NISLANDS_MAX_SMC_PERFORMANCE_LEVELS_PER_SWSTATE - 1) * sizeof(NISLANDS_SMC_HW_PERFORMANCE_LEVEL));
> +	int ret;
> +	NISLANDS_SMC_SWSTATE *smc_state = kzalloc(state_size, GFP_KERNEL);
> +
> +	if (smc_state == NULL)
> +		return -ENOMEM;
> +
> +	ret = ni_convert_power_state_to_smc(rdev, radeon_new_state, smc_state);
> +	if (ret)
> +		goto done;
> +
> +	ret = rv770_copy_bytes_to_smc(rdev, address, (u8 *)smc_state, state_size, pi->sram_end);
> +
> +done:
> +	kfree(smc_state);
> +
> +	return ret;
> +}
> +
> +static int ni_set_mc_special_registers(struct radeon_device *rdev,
> +				       struct ni_mc_reg_table *table)
> +{
> +	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
> +	u8 i, j, k;
> +	u32 temp_reg;
> +
> +	for (i = 0, j = table->last; i < table->last; i++) {
> +		switch (table->mc_reg_address[i].s1) {
> +		case MC_SEQ_MISC1 >> 2:
> +			if (j >= SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE)
> +				return -EINVAL;
> +			temp_reg = RREG32(MC_PMG_CMD_EMRS);
> +			table->mc_reg_address[j].s1 = MC_PMG_CMD_EMRS >> 2;
> +			table->mc_reg_address[j].s0 = MC_SEQ_PMG_CMD_EMRS_LP >> 2;
> +			for (k = 0; k < table->num_entries; k++)
> +				table->mc_reg_table_entry[k].mc_data[j] =
> +					((temp_reg & 0xffff0000)) |
> +					((table->mc_reg_table_entry[k].mc_data[i] & 0xffff0000) >> 16);
> +			j++;
> +			if (j >= SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE)
> +				return -EINVAL;
> +
> +			temp_reg = RREG32(MC_PMG_CMD_MRS);
> +			table->mc_reg_address[j].s1 = MC_PMG_CMD_MRS >> 2;
> +			table->mc_reg_address[j].s0 = MC_SEQ_PMG_CMD_MRS_LP >> 2;
> +			for(k = 0; k < table->num_entries; k++) {
> +				table->mc_reg_table_entry[k].mc_data[j] =
> +					(temp_reg & 0xffff0000) |
> +					(table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff);
> +				if (!pi->mem_gddr5)
> +					table->mc_reg_table_entry[k].mc_data[j] |= 0x100;
> +			}
> +			j++;
> +			if (j > SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE)
> +				return -EINVAL;
> +			break;
> +		case MC_SEQ_RESERVE_M >> 2:
> +			temp_reg = RREG32(MC_PMG_CMD_MRS1);
> +			table->mc_reg_address[j].s1 = MC_PMG_CMD_MRS1 >> 2;
> +			table->mc_reg_address[j].s0 = MC_SEQ_PMG_CMD_MRS1_LP >> 2;
> +			for (k = 0; k < table->num_entries; k++)
> +				table->mc_reg_table_entry[k].mc_data[j] =
> +					(temp_reg & 0xffff0000) |
> +					(table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff);
> +			j++;
> +			if (j > SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE)
> +				return -EINVAL;
> +			break;
> +		default:
> +			break;
> +		}
> +	}
> +
> +	table->last = j;
> +
> +	return 0;
> +}
> +
> +static bool ni_check_s0_mc_reg_index(u16 in_reg, u16 *out_reg)
> +{
> +	bool result = true;
> +
> +	switch (in_reg) {
> +        case  MC_SEQ_RAS_TIMING >> 2:
> +		*out_reg = MC_SEQ_RAS_TIMING_LP >> 2;
> +		break;
> +        case MC_SEQ_CAS_TIMING >> 2:
> +		*out_reg = MC_SEQ_CAS_TIMING_LP >> 2;
> +		break;
> +        case MC_SEQ_MISC_TIMING >> 2:
> +		*out_reg = MC_SEQ_MISC_TIMING_LP >> 2;
> +		break;
> +        case MC_SEQ_MISC_TIMING2 >> 2:
> +		*out_reg = MC_SEQ_MISC_TIMING2_LP >> 2;
> +		break;
> +        case MC_SEQ_RD_CTL_D0 >> 2:
> +		*out_reg = MC_SEQ_RD_CTL_D0_LP >> 2;
> +		break;
> +        case MC_SEQ_RD_CTL_D1 >> 2:
> +		*out_reg = MC_SEQ_RD_CTL_D1_LP >> 2;
> +		break;
> +        case MC_SEQ_WR_CTL_D0 >> 2:
> +		*out_reg = MC_SEQ_WR_CTL_D0_LP >> 2;
> +		break;
> +        case MC_SEQ_WR_CTL_D1 >> 2:
> +		*out_reg = MC_SEQ_WR_CTL_D1_LP >> 2;
> +		break;
> +        case MC_PMG_CMD_EMRS >> 2:
> +		*out_reg = MC_SEQ_PMG_CMD_EMRS_LP >> 2;
> +		break;
> +        case MC_PMG_CMD_MRS >> 2:
> +		*out_reg = MC_SEQ_PMG_CMD_MRS_LP >> 2;
> +		break;
> +        case MC_PMG_CMD_MRS1 >> 2:
> +		*out_reg = MC_SEQ_PMG_CMD_MRS1_LP >> 2;
> +		break;
> +        case MC_SEQ_PMG_TIMING >> 2:
> +		*out_reg = MC_SEQ_PMG_TIMING_LP >> 2;
> +		break;
> +        case MC_PMG_CMD_MRS2 >> 2:
> +		*out_reg = MC_SEQ_PMG_CMD_MRS2_LP >> 2;
> +		break;
> +        default:
> +		result = false;
> +		break;
> +	}
> +
> +	return result;
> +}
> +
> +static void ni_set_valid_flag(struct ni_mc_reg_table *table)
> +{
> +	u8 i, j;
> +
> +	for (i = 0; i < table->last; i++) {
> +		for (j = 1; j < table->num_entries; j++) {
> +			if (table->mc_reg_table_entry[j-1].mc_data[i] != table->mc_reg_table_entry[j].mc_data[i]) {
> +				table->valid_flag |= 1 << i;
> +				break;
> +			}
> +		}
> +	}
> +}
> +
> +static void ni_set_s0_mc_reg_index(struct ni_mc_reg_table *table)
> +{
> +	u32 i;
> +	u16 address;
> +
> +	for (i = 0; i < table->last; i++)
> +		table->mc_reg_address[i].s0 =
> +			ni_check_s0_mc_reg_index(table->mc_reg_address[i].s1, &address) ?
> +			address : table->mc_reg_address[i].s1;
> +}
> +
> +static int ni_copy_vbios_mc_reg_table(struct atom_mc_reg_table *table,
> +				      struct ni_mc_reg_table *ni_table)
> +{
> +	u8 i, j;
> +
> +	if (table->last > SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE)
> +		return -EINVAL;
> +	if (table->num_entries > MAX_AC_TIMING_ENTRIES)
> +		return -EINVAL;
> +
> +	for (i = 0; i < table->last; i++)
> +		ni_table->mc_reg_address[i].s1 = table->mc_reg_address[i].s1;
> +	ni_table->last = table->last;
> +
> +	for (i = 0; i < table->num_entries; i++) {
> +		ni_table->mc_reg_table_entry[i].mclk_max =
> +			table->mc_reg_table_entry[i].mclk_max;
> +		for (j = 0; j < table->last; j++)
> +			ni_table->mc_reg_table_entry[i].mc_data[j] =
> +				table->mc_reg_table_entry[i].mc_data[j];
> +	}
> +	ni_table->num_entries = table->num_entries;
> +
> +	return 0;
> +}
> +
> +static int ni_initialize_mc_reg_table(struct radeon_device *rdev)
> +{
> +	struct ni_power_info *ni_pi = ni_get_pi(rdev);
> +	int ret;
> +	struct atom_mc_reg_table *table;
> +	struct ni_mc_reg_table *ni_table = &ni_pi->mc_reg_table;
> +	u8 module_index = rv770_get_memory_module_index(rdev);
> +
> +        table = kzalloc(sizeof(struct atom_mc_reg_table), GFP_KERNEL);
> +        if (!table)
> +                return -ENOMEM;
> +
> +	WREG32(MC_SEQ_RAS_TIMING_LP, RREG32(MC_SEQ_RAS_TIMING));
> +	WREG32(MC_SEQ_CAS_TIMING_LP, RREG32(MC_SEQ_CAS_TIMING));
> +	WREG32(MC_SEQ_MISC_TIMING_LP, RREG32(MC_SEQ_MISC_TIMING));
> +	WREG32(MC_SEQ_MISC_TIMING2_LP, RREG32(MC_SEQ_MISC_TIMING2));
> +	WREG32(MC_SEQ_PMG_CMD_EMRS_LP, RREG32(MC_PMG_CMD_EMRS));
> +	WREG32(MC_SEQ_PMG_CMD_MRS_LP, RREG32(MC_PMG_CMD_MRS));
> +	WREG32(MC_SEQ_PMG_CMD_MRS1_LP, RREG32(MC_PMG_CMD_MRS1));
> +	WREG32(MC_SEQ_WR_CTL_D0_LP, RREG32(MC_SEQ_WR_CTL_D0));
> +	WREG32(MC_SEQ_WR_CTL_D1_LP, RREG32(MC_SEQ_WR_CTL_D1));
> +	WREG32(MC_SEQ_RD_CTL_D0_LP, RREG32(MC_SEQ_RD_CTL_D0));
> +	WREG32(MC_SEQ_RD_CTL_D1_LP, RREG32(MC_SEQ_RD_CTL_D1));
> +	WREG32(MC_SEQ_PMG_TIMING_LP, RREG32(MC_SEQ_PMG_TIMING));
> +	WREG32(MC_SEQ_PMG_CMD_MRS2_LP, RREG32(MC_PMG_CMD_MRS2));
> +
> +	ret = radeon_atom_init_mc_reg_table(rdev, module_index, table);
> +
> +        if (ret)
> +                goto init_mc_done;
> +
> +	ret = ni_copy_vbios_mc_reg_table(table, ni_table);
> +
> +        if (ret)
> +                goto init_mc_done;
> +
> +	ni_set_s0_mc_reg_index(ni_table);
> +
> +	ret = ni_set_mc_special_registers(rdev, ni_table);
> +
> +        if (ret)
> +                goto init_mc_done;
> +
> +	ni_set_valid_flag(ni_table);
> +
> +init_mc_done:
> +        kfree(table);
> +
> +	return ret;
> +}
> +
> +static void ni_populate_mc_reg_addresses(struct radeon_device *rdev,
> +					 SMC_NIslands_MCRegisters *mc_reg_table)
> +{
> +	struct ni_power_info *ni_pi = ni_get_pi(rdev);
> +	u32 i, j;
> +
> +	for (i = 0, j = 0; j < ni_pi->mc_reg_table.last; j++) {
> +		if (ni_pi->mc_reg_table.valid_flag & (1 << j)) {
> +			if (i >= SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE)
> +				break;
> +			mc_reg_table->address[i].s0 =
> +				cpu_to_be16(ni_pi->mc_reg_table.mc_reg_address[j].s0);
> +			mc_reg_table->address[i].s1 =
> +				cpu_to_be16(ni_pi->mc_reg_table.mc_reg_address[j].s1);
> +			i++;
> +		}
> +	}
> +	mc_reg_table->last = (u8)i;
> +}
> +
> +
> +static void ni_convert_mc_registers(struct ni_mc_reg_entry *entry,
> +				    SMC_NIslands_MCRegisterSet *data,
> +				    u32 num_entries, u32 valid_flag)
> +{
> +	u32 i, j;
> +
> +	for (i = 0, j = 0; j < num_entries; j++) {
> +		if (valid_flag & (1 << j)) {
> +			data->value[i] = cpu_to_be32(entry->mc_data[j]);
> +			i++;
> +		}
> +	}
> +}
> +
> +static void ni_convert_mc_reg_table_entry_to_smc(struct radeon_device *rdev,
> +						 struct rv7xx_pl *pl,
> +						 SMC_NIslands_MCRegisterSet *mc_reg_table_data)
> +{
> +	struct ni_power_info *ni_pi = ni_get_pi(rdev);
> +	u32 i = 0;
> +
> +	for (i = 0; i < ni_pi->mc_reg_table.num_entries; i++) {
> +		if (pl->mclk <= ni_pi->mc_reg_table.mc_reg_table_entry[i].mclk_max)
> +			break;
> +	}
> +
> +	if ((i == ni_pi->mc_reg_table.num_entries) && (i > 0))
> +		--i;
> +
> +	ni_convert_mc_registers(&ni_pi->mc_reg_table.mc_reg_table_entry[i],
> +				mc_reg_table_data,
> +				ni_pi->mc_reg_table.last,
> +				ni_pi->mc_reg_table.valid_flag);
> +}
> +
> +static void ni_convert_mc_reg_table_to_smc(struct radeon_device *rdev,
> +					   struct radeon_ps *radeon_state,
> +					   SMC_NIslands_MCRegisters *mc_reg_table)
> +{
> +	struct ni_ps *state = ni_get_ps(radeon_state);
> +	int i;
> +
> +	for (i = 0; i < state->performance_level_count; i++) {
> +		ni_convert_mc_reg_table_entry_to_smc(rdev,
> +						     &state->performance_levels[i],
> +						     &mc_reg_table->data[NISLANDS_MCREGISTERTABLE_FIRST_DRIVERSTATE_SLOT + i]);
> +	}
> +}
> +
> +static int ni_populate_mc_reg_table(struct radeon_device *rdev)
> +{
> +	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
> +	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
> +        struct ni_power_info *ni_pi = ni_get_pi(rdev);
> +        struct radeon_ps *radeon_boot_state = rdev->pm.dpm.boot_ps;
> +	struct ni_ps *boot_state = ni_get_ps(radeon_boot_state);
> +	SMC_NIslands_MCRegisters *mc_reg_table = &ni_pi->smc_mc_reg_table;
> +
> +	memset(mc_reg_table, 0, sizeof(SMC_NIslands_MCRegisters));
> +
> +	rv770_write_smc_soft_register(rdev, NI_SMC_SOFT_REGISTER_seq_index, 1);
> +
> +	ni_populate_mc_reg_addresses(rdev, mc_reg_table);
> +
> +	ni_convert_mc_reg_table_entry_to_smc(rdev, &boot_state->performance_levels[0],
> +					     &mc_reg_table->data[0]);
> +
> +	ni_convert_mc_registers(&ni_pi->mc_reg_table.mc_reg_table_entry[0],
> +				&mc_reg_table->data[1],
> +				ni_pi->mc_reg_table.last,
> +				ni_pi->mc_reg_table.valid_flag);
> +
> +	ni_convert_mc_reg_table_to_smc(rdev, radeon_boot_state, mc_reg_table);
> +
> +	return rv770_copy_bytes_to_smc(rdev, eg_pi->mc_reg_table_start,
> +				       (u8 *)mc_reg_table,
> +				       sizeof(SMC_NIslands_MCRegisters),
> +				       pi->sram_end);
> +}
> +
> +static int ni_upload_mc_reg_table(struct radeon_device *rdev)
> +{
> +	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
> +	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
> +        struct ni_power_info *ni_pi = ni_get_pi(rdev);
> +	struct radeon_ps *radeon_new_state = rdev->pm.dpm.requested_ps;
> +	struct ni_ps *ni_new_state = ni_get_ps(radeon_new_state);
> +	SMC_NIslands_MCRegisters *mc_reg_table = &ni_pi->smc_mc_reg_table;
> +	u16 address;
> +
> +	memset(mc_reg_table, 0, sizeof(SMC_NIslands_MCRegisters));
> +
> +	ni_convert_mc_reg_table_to_smc(rdev, radeon_new_state, mc_reg_table);
> +
> +	address = eg_pi->mc_reg_table_start +
> +		(u16)offsetof(SMC_NIslands_MCRegisters, data[NISLANDS_MCREGISTERTABLE_FIRST_DRIVERSTATE_SLOT]);
> +
> +	return rv770_copy_bytes_to_smc(rdev, address,
> +				       (u8 *)&mc_reg_table->data[NISLANDS_MCREGISTERTABLE_FIRST_DRIVERSTATE_SLOT],
> +				       sizeof(SMC_NIslands_MCRegisterSet) * ni_new_state->performance_level_count,
> +				       pi->sram_end);
> +}
> +
> +static int ni_init_driver_calculated_leakage_table(struct radeon_device *rdev,
> +						   PP_NIslands_CACTABLES *cac_tables)
> +{
> +	struct ni_power_info *ni_pi = ni_get_pi(rdev);
> +	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
> +	u32 leakage = 0;
> +	unsigned int i, j, table_size;
> +	s32 t;
> +	u32 smc_leakage, max_leakage = 0;
> +	u32 scaling_factor;
> +
> +	table_size = eg_pi->vddc_voltage_table.count;
> +
> +	if (SMC_NISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES < table_size)
> +		table_size = SMC_NISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES;
> +
> +	scaling_factor = ni_get_smc_power_scaling_factor(rdev);
> +
> +	for (i = 0; i < SMC_NISLANDS_LKGE_LUT_NUM_OF_TEMP_ENTRIES; i++) {
> +		for (j = 0; j < table_size; j++) {
> +			t = (1000 * ((i + 1) * 8));
> +
> +			if (t < ni_pi->cac_data.leakage_minimum_temperature)
> +				t = ni_pi->cac_data.leakage_minimum_temperature;
> +
> +			ni_calculate_leakage_for_v_and_t(rdev,
> +							 &ni_pi->cac_data.leakage_coefficients,
> +							 eg_pi->vddc_voltage_table.entries[j].value,
> +							 t,
> +							 ni_pi->cac_data.i_leakage,
> +							 &leakage);
> +
> +			smc_leakage = ni_scale_power_for_smc(leakage, scaling_factor) / 1000;
> +			if (smc_leakage > max_leakage)
> +				max_leakage = smc_leakage;
> +
> +			cac_tables->cac_lkge_lut[i][j] = cpu_to_be32(smc_leakage);
> +		}
> +	}
> +
> +	for (j = table_size; j < SMC_NISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES; j++) {
> +		for (i = 0; i < SMC_NISLANDS_LKGE_LUT_NUM_OF_TEMP_ENTRIES; i++)
> +			cac_tables->cac_lkge_lut[i][j] = cpu_to_be32(max_leakage);
> +	}
> +	return 0;
> +}
> +
> +static int ni_init_simplified_leakage_table(struct radeon_device *rdev,
> +					    PP_NIslands_CACTABLES *cac_tables)
> +{
> +	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
> +	struct radeon_cac_leakage_table *leakage_table =
> +		&rdev->pm.dpm.dyn_state.cac_leakage_table;
> +	u32 i, j, table_size;
> +	u32 smc_leakage, max_leakage = 0;
> +	u32 scaling_factor;
> +
> +	if (!leakage_table)
> +		return -EINVAL;
> +
> +	table_size = leakage_table->count;
> +
> +	if (eg_pi->vddc_voltage_table.count != table_size)
> +		table_size = (eg_pi->vddc_voltage_table.count < leakage_table->count) ?
> +			eg_pi->vddc_voltage_table.count : leakage_table->count;
> +
> +	if (SMC_NISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES < table_size)
> +		table_size = SMC_NISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES;
> +
> +	if (table_size == 0)
> +		return -EINVAL;
> +
> +	scaling_factor = ni_get_smc_power_scaling_factor(rdev);
> +
> +	for (j = 0; j < table_size; j++) {
> +		smc_leakage = leakage_table->entries[j].leakage;
> +
> +		if (smc_leakage > max_leakage)
> +			max_leakage = smc_leakage;
> +
> +		for (i = 0; i < SMC_NISLANDS_LKGE_LUT_NUM_OF_TEMP_ENTRIES; i++)
> +			cac_tables->cac_lkge_lut[i][j] =
> +				cpu_to_be32(ni_scale_power_for_smc(smc_leakage, scaling_factor));
> +	}
> +
> +	for (j = table_size; j < SMC_NISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES; j++) {
> +		for (i = 0; i < SMC_NISLANDS_LKGE_LUT_NUM_OF_TEMP_ENTRIES; i++)
> +			cac_tables->cac_lkge_lut[i][j] =
> +				cpu_to_be32(ni_scale_power_for_smc(max_leakage, scaling_factor));
> +	}
> +	return 0;
> +}
> +
> +static int ni_initialize_smc_cac_tables(struct radeon_device *rdev)
> +{
> +	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
> +	struct ni_power_info *ni_pi = ni_get_pi(rdev);
> +	PP_NIslands_CACTABLES *cac_tables = NULL;
> +	int i, ret;
> +        u32 reg;
> +
> +	if (ni_pi->enable_cac == false)
> +		return 0;
> +
> +	cac_tables = kzalloc(sizeof(PP_NIslands_CACTABLES), GFP_KERNEL);
> +	if (!cac_tables)
> +		return -ENOMEM;
> +
> +	reg = RREG32(CG_CAC_CTRL) & ~(TID_CNT_MASK | TID_UNIT_MASK);
> +	reg |= (TID_CNT(ni_pi->cac_weights->tid_cnt) |
> +		TID_UNIT(ni_pi->cac_weights->tid_unit));
> +	WREG32(CG_CAC_CTRL, reg);
> +
> +	for (i = 0; i < NISLANDS_DCCAC_MAX_LEVELS; i++)
> +		ni_pi->dc_cac_table[i] = ni_pi->cac_weights->dc_cac[i];
> +
> +	for (i = 0; i < SMC_NISLANDS_BIF_LUT_NUM_OF_ENTRIES; i++)
> +		cac_tables->cac_bif_lut[i] = ni_pi->cac_weights->pcie_cac[i];
> +
> +	ni_pi->cac_data.i_leakage = rdev->pm.dpm.cac_leakage;
> +	ni_pi->cac_data.pwr_const = 0;
> +	ni_pi->cac_data.dc_cac_value = ni_pi->dc_cac_table[NISLANDS_DCCAC_LEVEL_0];
> +	ni_pi->cac_data.bif_cac_value = 0;
> +	ni_pi->cac_data.mc_wr_weight = ni_pi->cac_weights->mc_write_weight;
> +	ni_pi->cac_data.mc_rd_weight = ni_pi->cac_weights->mc_read_weight;
> +	ni_pi->cac_data.allow_ovrflw = 0;
> +	ni_pi->cac_data.l2num_win_tdp = ni_pi->lta_window_size;
> +	ni_pi->cac_data.num_win_tdp = 0;
> +	ni_pi->cac_data.lts_truncate_n = ni_pi->lts_truncate;
> +
> +	if (ni_pi->driver_calculate_cac_leakage)
> +		ret = ni_init_driver_calculated_leakage_table(rdev, cac_tables);
> +	else
> +		ret = ni_init_simplified_leakage_table(rdev, cac_tables);
> +
> +	if (ret)
> +		goto done_free;
> +
> +	cac_tables->pwr_const      = cpu_to_be32(ni_pi->cac_data.pwr_const);
> +	cac_tables->dc_cacValue    = cpu_to_be32(ni_pi->cac_data.dc_cac_value);
> +	cac_tables->bif_cacValue   = cpu_to_be32(ni_pi->cac_data.bif_cac_value);
> +	cac_tables->AllowOvrflw    = ni_pi->cac_data.allow_ovrflw;
> +	cac_tables->MCWrWeight     = ni_pi->cac_data.mc_wr_weight;
> +	cac_tables->MCRdWeight     = ni_pi->cac_data.mc_rd_weight;
> +	cac_tables->numWin_TDP     = ni_pi->cac_data.num_win_tdp;
> +	cac_tables->l2numWin_TDP   = ni_pi->cac_data.l2num_win_tdp;
> +	cac_tables->lts_truncate_n = ni_pi->cac_data.lts_truncate_n;
> +
> +	ret = rv770_copy_bytes_to_smc(rdev, ni_pi->cac_table_start, (u8 *)cac_tables,
> +				      sizeof(PP_NIslands_CACTABLES), pi->sram_end);
> +
> +done_free:
> +	if (ret) {
> +		ni_pi->enable_cac = false;
> +		ni_pi->enable_power_containment = false;
> +	}
> +
> +	kfree(cac_tables);
> +
> +	return 0;
> +}
> +
> +static int ni_initialize_hardware_cac_manager(struct radeon_device *rdev)
> +{
> +	struct ni_power_info *ni_pi = ni_get_pi(rdev);
> +	u32 reg;
> +
> +	if (!ni_pi->enable_cac ||
> +	    !ni_pi->cac_configuration_required)
> +		return 0;
> +
> +	if (ni_pi->cac_weights == NULL)
> +		return -EINVAL;
> +
> +	reg = RREG32_CG(CG_CAC_REGION_1_WEIGHT_0) & ~(WEIGHT_TCP_SIG0_MASK |
> +						      WEIGHT_TCP_SIG1_MASK |
> +						      WEIGHT_TA_SIG_MASK);
> +	reg |= (WEIGHT_TCP_SIG0(ni_pi->cac_weights->weight_tcp_sig0) |
> +		WEIGHT_TCP_SIG1(ni_pi->cac_weights->weight_tcp_sig1) |
> +		WEIGHT_TA_SIG(ni_pi->cac_weights->weight_ta_sig));
> +	WREG32_CG(CG_CAC_REGION_1_WEIGHT_0, reg);
> +
> +	reg = RREG32_CG(CG_CAC_REGION_1_WEIGHT_1) & ~(WEIGHT_TCC_EN0_MASK |
> +						      WEIGHT_TCC_EN1_MASK |
> +						      WEIGHT_TCC_EN2_MASK);
> +	reg |= (WEIGHT_TCC_EN0(ni_pi->cac_weights->weight_tcc_en0) |
> +		WEIGHT_TCC_EN1(ni_pi->cac_weights->weight_tcc_en1) |
> +		WEIGHT_TCC_EN2(ni_pi->cac_weights->weight_tcc_en2));
> +	WREG32_CG(CG_CAC_REGION_1_WEIGHT_1, reg);
> +
> +	reg = RREG32_CG(CG_CAC_REGION_2_WEIGHT_0) & ~(WEIGHT_CB_EN0_MASK |
> +						      WEIGHT_CB_EN1_MASK |
> +						      WEIGHT_CB_EN2_MASK |
> +						      WEIGHT_CB_EN3_MASK);
> +	reg |= (WEIGHT_CB_EN0(ni_pi->cac_weights->weight_cb_en0) |
> +		WEIGHT_CB_EN1(ni_pi->cac_weights->weight_cb_en1) |
> +		WEIGHT_CB_EN2(ni_pi->cac_weights->weight_cb_en2) |
> +		WEIGHT_CB_EN3(ni_pi->cac_weights->weight_cb_en3));
> +	WREG32_CG(CG_CAC_REGION_2_WEIGHT_0, reg);
> +
> +	reg = RREG32_CG(CG_CAC_REGION_2_WEIGHT_1) & ~(WEIGHT_DB_SIG0_MASK |
> +						      WEIGHT_DB_SIG1_MASK |
> +						      WEIGHT_DB_SIG2_MASK |
> +						      WEIGHT_DB_SIG3_MASK);
> +	reg |= (WEIGHT_DB_SIG0(ni_pi->cac_weights->weight_db_sig0) |
> +		WEIGHT_DB_SIG1(ni_pi->cac_weights->weight_db_sig1) |
> +		WEIGHT_DB_SIG2(ni_pi->cac_weights->weight_db_sig2) |
> +		WEIGHT_DB_SIG3(ni_pi->cac_weights->weight_db_sig3));
> +	WREG32_CG(CG_CAC_REGION_2_WEIGHT_1, reg);
> +
> +	reg = RREG32_CG(CG_CAC_REGION_2_WEIGHT_2) & ~(WEIGHT_SXM_SIG0_MASK |
> +						      WEIGHT_SXM_SIG1_MASK |
> +						      WEIGHT_SXM_SIG2_MASK |
> +						      WEIGHT_SXS_SIG0_MASK |
> +						      WEIGHT_SXS_SIG1_MASK);
> +	reg |= (WEIGHT_SXM_SIG0(ni_pi->cac_weights->weight_sxm_sig0) |
> +		WEIGHT_SXM_SIG1(ni_pi->cac_weights->weight_sxm_sig1) |
> +		WEIGHT_SXM_SIG2(ni_pi->cac_weights->weight_sxm_sig2) |
> +		WEIGHT_SXS_SIG0(ni_pi->cac_weights->weight_sxs_sig0) |
> +		WEIGHT_SXS_SIG1(ni_pi->cac_weights->weight_sxs_sig1));
> +	WREG32_CG(CG_CAC_REGION_2_WEIGHT_2, reg);
> +
> +	reg = RREG32_CG(CG_CAC_REGION_3_WEIGHT_0) & ~(WEIGHT_XBR_0_MASK |
> +						      WEIGHT_XBR_1_MASK |
> +						      WEIGHT_XBR_2_MASK |
> +						      WEIGHT_SPI_SIG0_MASK);
> +	reg |= (WEIGHT_XBR_0(ni_pi->cac_weights->weight_xbr_0) |
> +		WEIGHT_XBR_1(ni_pi->cac_weights->weight_xbr_1) |
> +		WEIGHT_XBR_2(ni_pi->cac_weights->weight_xbr_2) |
> +		WEIGHT_SPI_SIG0(ni_pi->cac_weights->weight_spi_sig0));
> +	WREG32_CG(CG_CAC_REGION_3_WEIGHT_0, reg);
> +
> +	reg = RREG32_CG(CG_CAC_REGION_3_WEIGHT_1) & ~(WEIGHT_SPI_SIG1_MASK |
> +						      WEIGHT_SPI_SIG2_MASK |
> +						      WEIGHT_SPI_SIG3_MASK |
> +						      WEIGHT_SPI_SIG4_MASK |
> +						      WEIGHT_SPI_SIG5_MASK);
> +	reg |= (WEIGHT_SPI_SIG1(ni_pi->cac_weights->weight_spi_sig1) |
> +		WEIGHT_SPI_SIG2(ni_pi->cac_weights->weight_spi_sig2) |
> +		WEIGHT_SPI_SIG3(ni_pi->cac_weights->weight_spi_sig3) |
> +		WEIGHT_SPI_SIG4(ni_pi->cac_weights->weight_spi_sig4) |
> +		WEIGHT_SPI_SIG5(ni_pi->cac_weights->weight_spi_sig5));
> +	WREG32_CG(CG_CAC_REGION_3_WEIGHT_1, reg);
> +
> +	reg = RREG32_CG(CG_CAC_REGION_4_WEIGHT_0) & ~(WEIGHT_LDS_SIG0_MASK |
> +						      WEIGHT_LDS_SIG1_MASK |
> +						      WEIGHT_SC_MASK);
> +	reg |= (WEIGHT_LDS_SIG0(ni_pi->cac_weights->weight_lds_sig0) |
> +		WEIGHT_LDS_SIG1(ni_pi->cac_weights->weight_lds_sig1) |
> +		WEIGHT_SC(ni_pi->cac_weights->weight_sc));
> +	WREG32_CG(CG_CAC_REGION_4_WEIGHT_0, reg);
> +
> +	reg = RREG32_CG(CG_CAC_REGION_4_WEIGHT_1) & ~(WEIGHT_BIF_MASK |
> +						      WEIGHT_CP_MASK |
> +						      WEIGHT_PA_SIG0_MASK |
> +						      WEIGHT_PA_SIG1_MASK |
> +						      WEIGHT_VGT_SIG0_MASK);
> +	reg |= (WEIGHT_BIF(ni_pi->cac_weights->weight_bif) |
> +		WEIGHT_CP(ni_pi->cac_weights->weight_cp) |
> +		WEIGHT_PA_SIG0(ni_pi->cac_weights->weight_pa_sig0) |
> +		WEIGHT_PA_SIG1(ni_pi->cac_weights->weight_pa_sig1) |
> +		WEIGHT_VGT_SIG0(ni_pi->cac_weights->weight_vgt_sig0));
> +	WREG32_CG(CG_CAC_REGION_4_WEIGHT_1, reg);
> +
> +	reg = RREG32_CG(CG_CAC_REGION_4_WEIGHT_2) & ~(WEIGHT_VGT_SIG1_MASK |
> +						      WEIGHT_VGT_SIG2_MASK |
> +						      WEIGHT_DC_SIG0_MASK |
> +						      WEIGHT_DC_SIG1_MASK |
> +						      WEIGHT_DC_SIG2_MASK);
> +	reg |= (WEIGHT_VGT_SIG1(ni_pi->cac_weights->weight_vgt_sig1) |
> +		WEIGHT_VGT_SIG2(ni_pi->cac_weights->weight_vgt_sig2) |
> +		WEIGHT_DC_SIG0(ni_pi->cac_weights->weight_dc_sig0) |
> +		WEIGHT_DC_SIG1(ni_pi->cac_weights->weight_dc_sig1) |
> +		WEIGHT_DC_SIG2(ni_pi->cac_weights->weight_dc_sig2));
> +	WREG32_CG(CG_CAC_REGION_4_WEIGHT_2, reg);
> +
> +	reg = RREG32_CG(CG_CAC_REGION_4_WEIGHT_3) & ~(WEIGHT_DC_SIG3_MASK |
> +						      WEIGHT_UVD_SIG0_MASK |
> +						      WEIGHT_UVD_SIG1_MASK |
> +						      WEIGHT_SPARE0_MASK |
> +						      WEIGHT_SPARE1_MASK);
> +	reg |= (WEIGHT_DC_SIG3(ni_pi->cac_weights->weight_dc_sig3) |
> +		WEIGHT_UVD_SIG0(ni_pi->cac_weights->weight_uvd_sig0) |
> +		WEIGHT_UVD_SIG1(ni_pi->cac_weights->weight_uvd_sig1) |
> +		WEIGHT_SPARE0(ni_pi->cac_weights->weight_spare0) |
> +		WEIGHT_SPARE1(ni_pi->cac_weights->weight_spare1));
> +	WREG32_CG(CG_CAC_REGION_4_WEIGHT_3, reg);
> +
> +	reg = RREG32_CG(CG_CAC_REGION_5_WEIGHT_0) & ~(WEIGHT_SQ_VSP_MASK |
> +						      WEIGHT_SQ_VSP0_MASK);
> +	reg |= (WEIGHT_SQ_VSP(ni_pi->cac_weights->weight_sq_vsp) |
> +		WEIGHT_SQ_VSP0(ni_pi->cac_weights->weight_sq_vsp0));
> +	WREG32_CG(CG_CAC_REGION_5_WEIGHT_0, reg);
> +
> +	reg = RREG32_CG(CG_CAC_REGION_5_WEIGHT_1) & ~(WEIGHT_SQ_GPR_MASK);
> +	reg |= WEIGHT_SQ_GPR(ni_pi->cac_weights->weight_sq_gpr);
> +	WREG32_CG(CG_CAC_REGION_5_WEIGHT_1, reg);
> +
> +	reg = RREG32_CG(CG_CAC_REGION_4_OVERRIDE_4) & ~(OVR_MODE_SPARE_0_MASK |
> +							OVR_VAL_SPARE_0_MASK |
> +							OVR_MODE_SPARE_1_MASK |
> +							OVR_VAL_SPARE_1_MASK);
> +	reg |= (OVR_MODE_SPARE_0(ni_pi->cac_weights->ovr_mode_spare_0) |
> +		OVR_VAL_SPARE_0(ni_pi->cac_weights->ovr_val_spare_0) |
> +		OVR_MODE_SPARE_1(ni_pi->cac_weights->ovr_mode_spare_1) |
> +		OVR_VAL_SPARE_1(ni_pi->cac_weights->ovr_val_spare_1));
> +	WREG32_CG(CG_CAC_REGION_4_OVERRIDE_4, reg);
> +
> +	reg = RREG32(SQ_CAC_THRESHOLD) & ~(VSP_MASK |
> +					   VSP0_MASK |
> +					   GPR_MASK);
> +	reg |= (VSP(ni_pi->cac_weights->vsp) |
> +		VSP0(ni_pi->cac_weights->vsp0) |
> +		GPR(ni_pi->cac_weights->gpr));
> +	WREG32(SQ_CAC_THRESHOLD, reg);
> +
> +	reg = (MCDW_WR_ENABLE |
> +	       MCDX_WR_ENABLE |
> +	       MCDY_WR_ENABLE |
> +	       MCDZ_WR_ENABLE |
> +	       INDEX(0x09D4));
> +	WREG32(MC_CG_CONFIG, reg);
> +
> +	reg = (READ_WEIGHT(ni_pi->cac_weights->mc_read_weight) |
> +	       WRITE_WEIGHT(ni_pi->cac_weights->mc_write_weight) |
> +	       ALLOW_OVERFLOW);
> +	WREG32(MC_CG_DATAPORT, reg);
> +
> +	return 0;
> +}
> +
> +static int ni_enable_smc_cac(struct radeon_device *rdev, bool enable)
> +{
> +	struct ni_power_info *ni_pi = ni_get_pi(rdev);
> +	int ret = 0;
> +	PPSMC_Result smc_result;
> +
> +	if (ni_pi->enable_cac) {
> +		if (enable) {
> +			struct radeon_ps *radeon_new_state = rdev->pm.dpm.requested_ps;
> +
> +			if (!r600_is_uvd_state(radeon_new_state->class, radeon_new_state->class2)) {
> +				smc_result = rv770_send_msg_to_smc(rdev, PPSMC_MSG_CollectCAC_PowerCorreln);
> +
> +				if (ni_pi->support_cac_long_term_average) {
> +					smc_result = rv770_send_msg_to_smc(rdev, PPSMC_CACLongTermAvgEnable);
> +					if (PPSMC_Result_OK != smc_result)
> +						ni_pi->support_cac_long_term_average = false;
> +				}
> +
> +				smc_result = rv770_send_msg_to_smc(rdev, PPSMC_MSG_EnableCac);
> +				if (PPSMC_Result_OK != smc_result)
> +					ret = -EINVAL;
> +
> +				ni_pi->cac_enabled = (PPSMC_Result_OK == smc_result) ? true : false;
> +			}
> +		} else if (ni_pi->cac_enabled) {
> +			smc_result = rv770_send_msg_to_smc(rdev, PPSMC_MSG_DisableCac);
> +
> +			ni_pi->cac_enabled = false;
> +
> +			if (ni_pi->support_cac_long_term_average) {
> +				smc_result = rv770_send_msg_to_smc(rdev, PPSMC_CACLongTermAvgDisable);
> +				if (PPSMC_Result_OK != smc_result)
> +					ni_pi->support_cac_long_term_average = false;
> +			}
> +		}
> +	}
> +
> +	return ret;
> +}
> +
> +static int ni_pcie_performance_request(struct radeon_device *rdev,
> +				       u8 perf_req, bool advertise)
> +{
> +	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
> +
> +#if defined(CONFIG_ACPI)
> +	if ((perf_req == PCIE_PERF_REQ_PECI_GEN1) ||
> +            (perf_req == PCIE_PERF_REQ_PECI_GEN2)) {
> +		if (eg_pi->pcie_performance_request_registered == false)
> +			radeon_acpi_pcie_notify_device_ready(rdev);
> +		eg_pi->pcie_performance_request_registered = true;
> +		return radeon_acpi_pcie_performance_request(rdev, perf_req, advertise);
> +	} else if ((perf_req == PCIE_PERF_REQ_REMOVE_REGISTRY) &&
> +                   eg_pi->pcie_performance_request_registered) {
> +		eg_pi->pcie_performance_request_registered = false;
> +		return radeon_acpi_pcie_performance_request(rdev, perf_req, advertise);
> +	}
> +#endif
> +	return 0;
> +}
> +
> +static int ni_advertise_gen2_capability(struct radeon_device *rdev)
> +{
> +	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
> +	u32 tmp;
> +
> +        tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL);
> +
> +        if ((tmp & LC_OTHER_SIDE_EVER_SENT_GEN2) &&
> +            (tmp & LC_OTHER_SIDE_SUPPORTS_GEN2))
> +                pi->pcie_gen2 = true;
> +        else
> +		pi->pcie_gen2 = false;
> +
> +	if (!pi->pcie_gen2)
> +		ni_pcie_performance_request(rdev, PCIE_PERF_REQ_PECI_GEN2, true);
> +
> +	return 0;
> +}
> +
> +static void ni_enable_bif_dynamic_pcie_gen2(struct radeon_device *rdev,
> +					    bool enable)
> +{
> +        struct rv7xx_power_info *pi = rv770_get_pi(rdev);
> +        u32 tmp, bif;
> +
> +	tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL);
> +
> +	if ((tmp & LC_OTHER_SIDE_EVER_SENT_GEN2) &&
> +	    (tmp & LC_OTHER_SIDE_SUPPORTS_GEN2)) {
> +		if (enable) {
> +			if (!pi->boot_in_gen2) {
> +				bif = RREG32(CG_BIF_REQ_AND_RSP) & ~CG_CLIENT_REQ_MASK;
> +				bif |= CG_CLIENT_REQ(0xd);
> +				WREG32(CG_BIF_REQ_AND_RSP, bif);
> +			}
> +			tmp &= ~LC_HW_VOLTAGE_IF_CONTROL_MASK;
> +			tmp |= LC_HW_VOLTAGE_IF_CONTROL(1);
> +			tmp |= LC_GEN2_EN_STRAP;
> +
> +			tmp |= LC_CLR_FAILED_SPD_CHANGE_CNT;
> +			WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp);
> +			udelay(10);
> +			tmp &= ~LC_CLR_FAILED_SPD_CHANGE_CNT;
> +			WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp);
> +		} else {
> +			if (!pi->boot_in_gen2) {
> +				bif = RREG32(CG_BIF_REQ_AND_RSP) & ~CG_CLIENT_REQ_MASK;
> +				bif |= CG_CLIENT_REQ(0xd);
> +				WREG32(CG_BIF_REQ_AND_RSP, bif);
> +
> +				tmp &= ~LC_HW_VOLTAGE_IF_CONTROL_MASK;
> +				tmp &= ~LC_GEN2_EN_STRAP;
> +			}
> +			WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp);
> +		}
> +	}
> +}
> +
> +static void ni_enable_dynamic_pcie_gen2(struct radeon_device *rdev,
> +					bool enable)
> +{
> +	ni_enable_bif_dynamic_pcie_gen2(rdev, enable);
> +
> +	if (enable)
> +		WREG32_P(GENERAL_PWRMGT, ENABLE_GEN2PCIE, ~ENABLE_GEN2PCIE);
> +	else
> +                WREG32_P(GENERAL_PWRMGT, 0, ~ENABLE_GEN2PCIE);
> +}
> +
> +void ni_dpm_setup_asic(struct radeon_device *rdev)
> +{
> +	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
> +
> +	ni_read_clock_registers(rdev);
> +	btc_read_arb_registers(rdev);
> +	rv770_get_memory_type(rdev);
> +	if (eg_pi->pcie_performance_request)
> +		ni_advertise_gen2_capability(rdev);
> +	rv770_get_pcie_gen2_status(rdev);
> +	rv770_enable_acpi_pm(rdev);
> +}
> +
> +int ni_dpm_enable(struct radeon_device *rdev)
> +{
> +	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
> +	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
> +
> +	if (pi->gfx_clock_gating)
> +		ni_cg_clockgating_default(rdev);
> +        if (btc_dpm_enabled(rdev))
> +                return -EINVAL;
> +	if (pi->mg_clock_gating)
> +		ni_mg_clockgating_default(rdev);
> +	if (eg_pi->ls_clock_gating)
> +		ni_ls_clockgating_default(rdev);
> +	if (pi->voltage_control) {
> +		rv770_enable_voltage_control(rdev, true);
> +		cypress_construct_voltage_tables(rdev);
> +	}
> +	if (eg_pi->dynamic_ac_timing)
> +		ni_initialize_mc_reg_table(rdev);
> +	if (pi->dynamic_ss)
> +		cypress_enable_spread_spectrum(rdev, true);
> +	if (pi->thermal_protection)
> +		rv770_enable_thermal_protection(rdev, true);
> +	rv770_setup_bsp(rdev);
> +	rv770_program_git(rdev);
> +	rv770_program_tp(rdev);
> +	rv770_program_tpp(rdev);
> +	rv770_program_sstp(rdev);
> +	cypress_enable_display_gap(rdev);
> +	rv770_program_vc(rdev);
> +	if (pi->dynamic_pcie_gen2)
> +		ni_enable_dynamic_pcie_gen2(rdev, true);
> +	if (rv770_upload_firmware(rdev))
> +		return -EINVAL;
> +	ni_process_firmware_header(rdev);
> +	ni_initial_switch_from_arb_f0_to_f1(rdev);
> +	ni_init_smc_table(rdev);
> +	ni_init_smc_spll_table(rdev);
> +	ni_init_arb_table_index(rdev);
> +	if (eg_pi->dynamic_ac_timing)
> +		ni_populate_mc_reg_table(rdev);
> +	ni_initialize_smc_cac_tables(rdev);
> +	ni_initialize_hardware_cac_manager(rdev);
> +	ni_populate_smc_tdp_limits(rdev);
> +	ni_program_response_times(rdev);
> +	r7xx_start_smc(rdev);
> +	cypress_notify_smc_display_change(rdev, false);
> +	cypress_enable_sclk_control(rdev, true);
> +	if (eg_pi->memory_transition)
> +		cypress_enable_mclk_control(rdev, true);
> +	cypress_start_dpm(rdev);
> +	if (pi->gfx_clock_gating)
> +		ni_gfx_clockgating_enable(rdev, true);
> +	if (pi->mg_clock_gating)
> +		ni_mg_clockgating_enable(rdev, true);
> +	if (eg_pi->ls_clock_gating)
> +		ni_ls_clockgating_enable(rdev, true);
> +
> +	if (rdev->irq.installed &&
> +	    r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
> +		PPSMC_Result result;
> +
> +		rv770_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, 0xff * 1000);
> +		rdev->irq.dpm_thermal = true;
> +		radeon_irq_set(rdev);
> +		result = rv770_send_msg_to_smc(rdev, PPSMC_MSG_EnableThermalInterrupt);
> +
> +		if (result != PPSMC_Result_OK)
> +			DRM_DEBUG_KMS("Could not enable thermal interrupts.\n");
> +	}
> +
> +	rv770_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true);
> +
> +	return 0;
> +}
> +
> +void ni_dpm_disable(struct radeon_device *rdev)
> +{
> +	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
> +	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
> +
> +	if (!btc_dpm_enabled(rdev))
> +		return;
> +	rv770_clear_vc(rdev);
> +	if (pi->thermal_protection)
> +		rv770_enable_thermal_protection(rdev, false);
> +	ni_enable_power_containment(rdev, false);
> +	ni_enable_smc_cac(rdev, false);
> +	cypress_enable_spread_spectrum(rdev, false);
> +	rv770_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, false);
> +	if (pi->dynamic_pcie_gen2)
> +		ni_enable_dynamic_pcie_gen2(rdev, false);
> +
> +	if (rdev->irq.installed &&
> +	    r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
> +		rdev->irq.dpm_thermal = false;
> +		radeon_irq_set(rdev);
> +	}
> +
> +	if (pi->gfx_clock_gating)
> +		ni_gfx_clockgating_enable(rdev, false);
> +	if (pi->mg_clock_gating)
> +		ni_mg_clockgating_enable(rdev, false);
> +	if (eg_pi->ls_clock_gating)
> +		ni_ls_clockgating_enable(rdev, false);
> +	ni_stop_dpm(rdev);
> +	btc_reset_to_default(rdev);
> +	ni_stop_smc(rdev);
> +	ni_force_switch_to_arb_f0(rdev);
> +}
> +
> +int ni_power_control_set_level(struct radeon_device *rdev)
> +{
> +	ni_restrict_performance_levels_before_switch(rdev);
> +	rv770_halt_smc(rdev);
> +	ni_populate_smc_tdp_limits(rdev);
> +	rv770_resume_smc(rdev);
> +	rv770_set_sw_state(rdev);
> +
> +	return 0;
> +}
> +
> +int ni_dpm_set_power_state(struct radeon_device *rdev)
> +{
> +	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
> +	int ret;
> +
> +	ni_apply_state_adjust_rules(rdev);
> +
> +	ni_restrict_performance_levels_before_switch(rdev);
> +	ni_enable_power_containment(rdev, false);
> +	ni_enable_smc_cac(rdev, false);
> +	rv770_halt_smc(rdev);
> +	if (eg_pi->smu_uvd_hs)
> +		btc_notify_uvd_to_smc(rdev);
> +	ni_upload_sw_state(rdev);
> +	if (eg_pi->dynamic_ac_timing)
> +		ni_upload_mc_reg_table(rdev);
> +	ret = ni_program_memory_timing_parameters(rdev);
> +	if (ret)
> +		return ret;
> +	rv770_resume_smc(rdev);
> +	rv770_set_sw_state(rdev);
> +	ni_enable_smc_cac(rdev, true);
> +	ni_enable_power_containment(rdev, true);
> +
> +	return 0;
> +}
> +
> +void ni_dpm_reset_asic(struct radeon_device *rdev)
> +{
> +	ni_restrict_performance_levels_before_switch(rdev);
> +	rv770_set_boot_state(rdev);
> +}
> +
> +union power_info {
> +	struct _ATOM_POWERPLAY_INFO info;
> +	struct _ATOM_POWERPLAY_INFO_V2 info_2;
> +	struct _ATOM_POWERPLAY_INFO_V3 info_3;
> +	struct _ATOM_PPLIB_POWERPLAYTABLE pplib;
> +	struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2;
> +	struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3;
> +};
> +
> +union pplib_clock_info {
> +	struct _ATOM_PPLIB_R600_CLOCK_INFO r600;
> +	struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780;
> +	struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen;
> +	struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo;
> +};
> +
> +union pplib_power_state {
> +	struct _ATOM_PPLIB_STATE v1;
> +	struct _ATOM_PPLIB_STATE_V2 v2;
> +};
> +
> +static void ni_parse_pplib_non_clock_info(struct radeon_device *rdev,
> +					  struct radeon_ps *rps,
> +					  struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info,
> +					  u8 table_rev)
> +{
> +	rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings);
> +	rps->class = le16_to_cpu(non_clock_info->usClassification);
> +	rps->class2 = le16_to_cpu(non_clock_info->usClassification2);
> +
> +	if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) {
> +		rps->vclk = le32_to_cpu(non_clock_info->ulVCLK);
> +		rps->dclk = le32_to_cpu(non_clock_info->ulDCLK);
> +	} else if (r600_is_uvd_state(rps->class, rps->class2)) {
> +		rps->vclk = RV770_DEFAULT_VCLK_FREQ;
> +		rps->dclk = RV770_DEFAULT_DCLK_FREQ;
> +	} else {
> +		rps->vclk = 0;
> +		rps->dclk = 0;
> +	}
> +
> +	if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT)
> +		rdev->pm.dpm.boot_ps = rps;
> +	if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
> +		rdev->pm.dpm.uvd_ps = rps;
> +}
> +
> +static void ni_parse_pplib_clock_info(struct radeon_device *rdev,
> +				      struct radeon_ps *rps, int index,
> +				      union pplib_clock_info *clock_info)
> +{
> +	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
> +	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
> +	struct ni_ps *ps = ni_get_ps(rps);
> +	u16 vddc;
> +	struct rv7xx_pl *pl = &ps->performance_levels[index];
> +
> +	ps->performance_level_count = index + 1;
> +
> +	pl->sclk = le16_to_cpu(clock_info->evergreen.usEngineClockLow);
> +	pl->sclk |= clock_info->evergreen.ucEngineClockHigh << 16;
> +	pl->mclk = le16_to_cpu(clock_info->evergreen.usMemoryClockLow);
> +	pl->mclk |= clock_info->evergreen.ucMemoryClockHigh << 16;
> +
> +	pl->vddc = le16_to_cpu(clock_info->evergreen.usVDDC);
> +	pl->vddci = le16_to_cpu(clock_info->evergreen.usVDDCI);
> +	pl->flags = le32_to_cpu(clock_info->evergreen.ulFlags);
> +
> +	/* patch up vddc if necessary */
> +	if (pl->vddc == 0xff01) {
> +		if (radeon_atom_get_max_vddc(rdev, 0, 0, &vddc) == 0)
> +			pl->vddc = vddc;
> +	}
> +
> +	if (rps->class & ATOM_PPLIB_CLASSIFICATION_ACPI) {
> +		pi->acpi_vddc = pl->vddc;
> +		eg_pi->acpi_vddci = pl->vddci;
> +		if (ps->performance_levels[0].flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2)
> +			pi->acpi_pcie_gen2 = true;
> +		else
> +			pi->acpi_pcie_gen2 = false;
> +	}
> +
> +	if (rps->class2 & ATOM_PPLIB_CLASSIFICATION2_ULV) {
> +		eg_pi->ulv.supported = true;
> +		eg_pi->ulv.pl = pl;
> +	}
> +
> +	if (pi->min_vddc_in_table > pl->vddc)
> +		pi->min_vddc_in_table = pl->vddc;
> +
> +	if (pi->max_vddc_in_table < pl->vddc)
> +		pi->max_vddc_in_table = pl->vddc;
> +
> +	/* patch up boot state */
> +	if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) {
> +		u16 vddc, vddci;
> +		radeon_atombios_get_default_voltages(rdev, &vddc, &vddci);
> +		pl->mclk = rdev->clock.default_mclk;
> +		pl->sclk = rdev->clock.default_sclk;
> +		pl->vddc = vddc;
> +		pl->vddci = vddci;
> +	}
> +
> +	if ((rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) ==
> +	    ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE) {
> +		rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.sclk = pl->sclk;
> +		rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.mclk = pl->mclk;
> +		rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.vddc = pl->vddc;
> +		rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.vddci = pl->vddci;
> +	}
> +}
> +
> +static int ni_parse_power_table(struct radeon_device *rdev)
> +{
> +	struct radeon_mode_info *mode_info = &rdev->mode_info;
> +	struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
> +	union pplib_power_state *power_state;
> +	int i, j;
> +	union pplib_clock_info *clock_info;
> +	union power_info *power_info;
> +	int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
> +        u16 data_offset;
> +	u8 frev, crev;
> +	struct ni_ps *ps;
> +
> +	if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
> +				   &frev, &crev, &data_offset))
> +		return -EINVAL;
> +	power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
> +
> +	rdev->pm.dpm.ps = kzalloc(sizeof(struct radeon_ps) *
> +				  power_info->pplib.ucNumStates, GFP_KERNEL);
> +	if (!rdev->pm.dpm.ps)
> +		return -ENOMEM;
> +	rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps);
> +	rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime);
> +	rdev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime);
> +
> +	for (i = 0; i < power_info->pplib.ucNumStates; i++) {
> +		power_state = (union pplib_power_state *)
> +			(mode_info->atom_context->bios + data_offset +
> +			 le16_to_cpu(power_info->pplib.usStateArrayOffset) +
> +			 i * power_info->pplib.ucStateEntrySize);
> +		non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
> +			(mode_info->atom_context->bios + data_offset +
> +			 le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset) +
> +			 (power_state->v1.ucNonClockStateIndex *
> +			  power_info->pplib.ucNonClockSize));
> +		if (power_info->pplib.ucStateEntrySize - 1) {
> +			ps = kzalloc(sizeof(struct ni_ps), GFP_KERNEL);
> +			if (ps == NULL) {
> +				kfree(rdev->pm.dpm.ps);
> +				return -ENOMEM;
> +			}
> +			rdev->pm.dpm.ps[i].ps_priv = ps;
> +			ni_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i],
> +							 non_clock_info,
> +							 power_info->pplib.ucNonClockSize);
> +			for (j = 0; j < (power_info->pplib.ucStateEntrySize - 1); j++) {
> +				clock_info = (union pplib_clock_info *)
> +					(mode_info->atom_context->bios + data_offset +
> +					 le16_to_cpu(power_info->pplib.usClockInfoArrayOffset) +
> +					 (power_state->v1.ucClockStateIndices[j] *
> +					  power_info->pplib.ucClockInfoSize));
> +				ni_parse_pplib_clock_info(rdev,
> +							  &rdev->pm.dpm.ps[i], j,
> +							  clock_info);
> +			}
> +		}
> +	}
> +	rdev->pm.dpm.num_ps = power_info->pplib.ucNumStates;
> +	return 0;
> +}
> +
> +int ni_dpm_init(struct radeon_device *rdev)
> +{
> +	struct rv7xx_power_info *pi;
> +	struct evergreen_power_info *eg_pi;
> +	struct ni_power_info *ni_pi;
> +	int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info);
> +	u16 data_offset, size;
> +	u8 frev, crev;
> +	struct atom_clock_dividers dividers;
> +	int ret;
> +
> +	ni_pi = kzalloc(sizeof(struct ni_power_info), GFP_KERNEL);
> +	if (ni_pi == NULL)
> +		return -ENOMEM;
> +	rdev->pm.dpm.priv = ni_pi;
> +	eg_pi = &ni_pi->eg;
> +	pi = &eg_pi->rv7xx;
> +
> +	rv770_get_max_vddc(rdev);
> +
> +	eg_pi->ulv.supported = false;
> +	pi->acpi_vddc = 0;
> +	eg_pi->acpi_vddci = 0;
> +	pi->min_vddc_in_table = 0;
> +	pi->max_vddc_in_table = 0;
> +
> +	ret = ni_parse_power_table(rdev);
> +	if (ret)
> +		return ret;
> +	ret = r600_parse_extended_power_table(rdev);
> +	if (ret)
> +		return ret;
> +
> +	ni_patch_dependency_tables_based_on_leakage(rdev);
> +
> +	if (rdev->pm.dpm.voltage_response_time == 0)
> +		rdev->pm.dpm.voltage_response_time = R600_VOLTAGERESPONSETIME_DFLT;
> +	if (rdev->pm.dpm.backbias_response_time == 0)
> +		rdev->pm.dpm.backbias_response_time = R600_BACKBIASRESPONSETIME_DFLT;
> +
> +	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
> +					     0, false, &dividers);
> +	if (ret)
> +		pi->ref_div = dividers.ref_div + 1;
> +	else
> +		pi->ref_div = R600_REFERENCEDIVIDER_DFLT;
> +
> +	pi->rlp = RV770_RLP_DFLT;
> +	pi->rmp = RV770_RMP_DFLT;
> +	pi->lhp = RV770_LHP_DFLT;
> +	pi->lmp = RV770_LMP_DFLT;
> +
> +	eg_pi->ats[0].rlp = RV770_RLP_DFLT;
> +	eg_pi->ats[0].rmp = RV770_RMP_DFLT;
> +	eg_pi->ats[0].lhp = RV770_LHP_DFLT;
> +	eg_pi->ats[0].lmp = RV770_LMP_DFLT;
> +
> +	eg_pi->ats[1].rlp = BTC_RLP_UVD_DFLT;
> +	eg_pi->ats[1].rmp = BTC_RMP_UVD_DFLT;
> +	eg_pi->ats[1].lhp = BTC_LHP_UVD_DFLT;
> +	eg_pi->ats[1].lmp = BTC_LMP_UVD_DFLT;
> +
> +	eg_pi->smu_uvd_hs = true;
> +
> +	if (rdev->pdev->device == 0x6707) {
> +		pi->mclk_strobe_mode_threshold = 55000;
> +		pi->mclk_edc_enable_threshold = 55000;
> +		eg_pi->mclk_edc_wr_enable_threshold = 55000;
> +	} else {
> +		pi->mclk_strobe_mode_threshold = 40000;
> +		pi->mclk_edc_enable_threshold = 40000;
> +		eg_pi->mclk_edc_wr_enable_threshold = 40000;
> +	}
> +	ni_pi->mclk_rtt_mode_threshold = eg_pi->mclk_edc_wr_enable_threshold;
> +
> +	pi->voltage_control =
> +		radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC);
> +
> +	pi->mvdd_control =
> +		radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_MVDDC);
> +
> +	eg_pi->vddci_control =
> +		radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDCI);
> +
> +	if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
> +                                   &frev, &crev, &data_offset)) {
> +		pi->sclk_ss = true;
> +		pi->mclk_ss = true;
> +		pi->dynamic_ss = true;
> +	} else {
> +		pi->sclk_ss = false;
> +		pi->mclk_ss = false;
> +		pi->dynamic_ss = true;
> +	}
> +
> +	pi->asi = RV770_ASI_DFLT;
> +	pi->pasi = CYPRESS_HASI_DFLT;
> +	pi->vrc = CYPRESS_VRC_DFLT;
> +
> +	pi->power_gating = false;
> +
> +	pi->gfx_clock_gating = true;
> +
> +	pi->mg_clock_gating = true;
> +	pi->mgcgtssm = true;
> +	eg_pi->ls_clock_gating = false;
> +	eg_pi->sclk_deep_sleep = false;
> +
> +	pi->dynamic_pcie_gen2 = true;
> +
> +	if (pi->gfx_clock_gating &&
> +	    (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE))
> +		pi->thermal_protection = true;
> +	else
> +		pi->thermal_protection = false;
> +
> +	pi->display_gap = true;
> +
> +	pi->dcodt = true;
> +
> +	pi->ulps = true;
> +
> +	eg_pi->dynamic_ac_timing = true;
> +	eg_pi->abm = true;
> +	eg_pi->mcls = true;
> +	eg_pi->light_sleep = true;
> +	eg_pi->memory_transition = true;
> +#if defined(CONFIG_ACPI)
> +	eg_pi->pcie_performance_request =
> +		radeon_acpi_is_pcie_performance_request_supported(rdev);
> +#else
> +	eg_pi->pcie_performance_request = false;
> +#endif
> +
> +	eg_pi->dll_default_on = false;
> +
> +	eg_pi->sclk_deep_sleep = false;
> +
> +	pi->mclk_stutter_mode_threshold = 0;
> +
> +	pi->sram_end = SMC_RAM_END;
> +
> +	rdev->pm.dpm.dyn_state.mclk_sclk_ratio = 3;
> +	rdev->pm.dpm.dyn_state.vddc_vddci_delta = 200;
> +	rdev->pm.dpm.dyn_state.min_vddc_for_pcie_gen2 = 900;
> +	rdev->pm.dpm.dyn_state.valid_sclk_values.count = ARRAY_SIZE(btc_valid_sclk);
> +	rdev->pm.dpm.dyn_state.valid_sclk_values.values = btc_valid_sclk;
> +	rdev->pm.dpm.dyn_state.valid_mclk_values.count = 0;
> +	rdev->pm.dpm.dyn_state.valid_mclk_values.values = NULL;
> +	rdev->pm.dpm.dyn_state.sclk_mclk_delta = 12500;
> +
> +	ni_pi->cac_data.leakage_coefficients.at = 516;
> +	ni_pi->cac_data.leakage_coefficients.bt = 18;
> +	ni_pi->cac_data.leakage_coefficients.av = 51;
> +	ni_pi->cac_data.leakage_coefficients.bv = 2957;
> +
> +	switch (rdev->pdev->device) {
> +	case 0x6700:
> +	case 0x6701:
> +	case 0x6702:
> +	case 0x6703:
> +	case 0x6718:
> +		ni_pi->cac_weights = &cac_weights_cayman_xt;
> +		break;
> +	case 0x6705:
> +	case 0x6719:
> +	case 0x671D:
> +	case 0x671C:
> +	default:
> +		ni_pi->cac_weights = &cac_weights_cayman_pro;
> +		break;
> +	case 0x6704:
> +	case 0x6706:
> +	case 0x6707:
> +	case 0x6708:
> +	case 0x6709:
> +		ni_pi->cac_weights = &cac_weights_cayman_le;
> +		break;
> +	}
> +
> +	if (ni_pi->cac_weights->enable_power_containment_by_default) {
> +		ni_pi->enable_power_containment = true;
> +		ni_pi->enable_cac = true;
> +		ni_pi->enable_sq_ramping = true;
> +	} else {
> +		ni_pi->enable_power_containment = false;
> +		ni_pi->enable_cac = false;
> +		ni_pi->enable_sq_ramping = false;
> +	}
> +
> +	ni_pi->driver_calculate_cac_leakage = false;
> +	ni_pi->cac_configuration_required = true;
> +
> +	if (ni_pi->cac_configuration_required) {
> +		ni_pi->support_cac_long_term_average = true;
> +		ni_pi->lta_window_size = ni_pi->cac_weights->l2_lta_window_size;
> +		ni_pi->lts_truncate = ni_pi->cac_weights->lts_truncate;
> +	} else {
> +		ni_pi->support_cac_long_term_average = false;
> +		ni_pi->lta_window_size = 0;
> +		ni_pi->lts_truncate = 0;
> +	}
> +
> +	ni_pi->use_power_boost_limit = true;
> +
> +	return 0;
> +}
> +
> +void ni_dpm_fini(struct radeon_device *rdev)
> +{
> +	int i;
> +
> +	for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
> +		kfree(rdev->pm.dpm.ps[i].ps_priv);
> +	}
> +	kfree(rdev->pm.dpm.ps);
> +	kfree(rdev->pm.dpm.priv);
> +	r600_free_extended_power_table(rdev);
> +}
> +
> +void ni_dpm_print_power_state(struct radeon_device *rdev,
> +			      struct radeon_ps *rps)
> +{
> +	struct ni_ps *ps = ni_get_ps(rps);
> +	struct rv7xx_pl *pl;
> +	int i;
> +
> +	r600_dpm_print_class_info(rps->class, rps->class2);
> +	r600_dpm_print_cap_info(rps->caps);
> +	printk("\tuvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
> +	for (i = 0; i < ps->performance_level_count; i++) {
> +		pl = &ps->performance_levels[i];
> +		printk("\t\tpower level 0    sclk: %u mclk: %u vddc: %u vddci: %u\n",
> +		       pl->sclk, pl->mclk, pl->vddc, pl->vddci);
> +	}
> +	r600_dpm_print_ps_status(rdev, rps);
> +}
> +
> +u32 ni_dpm_get_sclk(struct radeon_device *rdev, bool low)
> +{
> +	struct ni_ps *requested_state = ni_get_ps(rdev->pm.dpm.requested_ps);
> +
> +	if (low)
> +		return requested_state->performance_levels[0].sclk;
> +	else
> +		return requested_state->performance_levels[requested_state->performance_level_count - 1].sclk;
> +}
> +
> +u32 ni_dpm_get_mclk(struct radeon_device *rdev, bool low)
> +{
> +	struct ni_ps *requested_state = ni_get_ps(rdev->pm.dpm.requested_ps);
> +
> +	if (low)
> +		return requested_state->performance_levels[0].mclk;
> +	else
> +		return requested_state->performance_levels[requested_state->performance_level_count - 1].mclk;
> +}
> +
> diff --git a/drivers/gpu/drm/radeon/ni_dpm.h b/drivers/gpu/drm/radeon/ni_dpm.h
> new file mode 100644
> index 0000000..e10f747
> --- /dev/null
> +++ b/drivers/gpu/drm/radeon/ni_dpm.h
> @@ -0,0 +1,233 @@
> +/*
> + * Copyright 2012 Advanced Micro Devices, Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + *
> + */
> +#ifndef __NI_DPM_H__
> +#define __NI_DPM_H__
> +
> +#include "cypress_dpm.h"
> +#include "btc_dpm.h"
> +#include "nislands_smc.h"
> +
> +struct ni_clock_registers {
> +	u32 cg_spll_func_cntl;
> +	u32 cg_spll_func_cntl_2;
> +	u32 cg_spll_func_cntl_3;
> +	u32 cg_spll_func_cntl_4;
> +	u32 cg_spll_spread_spectrum;
> +	u32 cg_spll_spread_spectrum_2;
> +	u32 mclk_pwrmgt_cntl;
> +	u32 dll_cntl;
> +	u32 mpll_ad_func_cntl;
> +	u32 mpll_ad_func_cntl_2;
> +	u32 mpll_dq_func_cntl;
> +	u32 mpll_dq_func_cntl_2;
> +	u32 mpll_ss1;
> +	u32 mpll_ss2;
> +};
> +
> +struct ni_mc_reg_entry {
> +	u32 mclk_max;
> +	u32 mc_data[SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE];
> +};
> +
> +struct ni_mc_reg_table {
> +	u8 last;
> +	u8 num_entries;
> +	u16 valid_flag;
> +	struct ni_mc_reg_entry mc_reg_table_entry[MAX_AC_TIMING_ENTRIES];
> +	SMC_NIslands_MCRegisterAddress mc_reg_address[SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE];
> +};
> +
> +#define NISLANDS_MCREGISTERTABLE_FIRST_DRIVERSTATE_SLOT 2
> +
> +enum ni_dc_cac_level
> +{
> +	NISLANDS_DCCAC_LEVEL_0 = 0,
> +	NISLANDS_DCCAC_LEVEL_1,
> +	NISLANDS_DCCAC_LEVEL_2,
> +	NISLANDS_DCCAC_LEVEL_3,
> +	NISLANDS_DCCAC_LEVEL_4,
> +	NISLANDS_DCCAC_LEVEL_5,
> +	NISLANDS_DCCAC_LEVEL_6,
> +	NISLANDS_DCCAC_LEVEL_7,
> +	NISLANDS_DCCAC_MAX_LEVELS
> +};
> +
> +struct ni_leakage_coeffients
> +{
> +	u32 at;
> +	u32 bt;
> +	u32 av;
> +	u32 bv;
> +	s32 t_slope;
> +	s32 t_intercept;
> +	u32 t_ref;
> +};
> +
> +struct ni_cac_data
> +{
> +	struct ni_leakage_coeffients leakage_coefficients;
> +	u32 i_leakage;
> +	s32 leakage_minimum_temperature;
> +	u32 pwr_const;
> +	u32 dc_cac_value;
> +	u32 bif_cac_value;
> +	u32 lkge_pwr;
> +	u8 mc_wr_weight;
> +	u8 mc_rd_weight;
> +	u8 allow_ovrflw;
> +	u8 num_win_tdp;
> +	u8 l2num_win_tdp;
> +	u8 lts_truncate_n;
> +};
> +
> +struct ni_cac_weights
> +{
> +	u32 weight_tcp_sig0;
> +	u32 weight_tcp_sig1;
> +	u32 weight_ta_sig;
> +	u32 weight_tcc_en0;
> +	u32 weight_tcc_en1;
> +	u32 weight_tcc_en2;
> +	u32 weight_cb_en0;
> +	u32 weight_cb_en1;
> +	u32 weight_cb_en2;
> +	u32 weight_cb_en3;
> +	u32 weight_db_sig0;
> +	u32 weight_db_sig1;
> +	u32 weight_db_sig2;
> +	u32 weight_db_sig3;
> +	u32 weight_sxm_sig0;
> +	u32 weight_sxm_sig1;
> +	u32 weight_sxm_sig2;
> +	u32 weight_sxs_sig0;
> +	u32 weight_sxs_sig1;
> +	u32 weight_xbr_0;
> +	u32 weight_xbr_1;
> +	u32 weight_xbr_2;
> +	u32 weight_spi_sig0;
> +	u32 weight_spi_sig1;
> +	u32 weight_spi_sig2;
> +	u32 weight_spi_sig3;
> +	u32 weight_spi_sig4;
> +	u32 weight_spi_sig5;
> +	u32 weight_lds_sig0;
> +	u32 weight_lds_sig1;
> +	u32 weight_sc;
> +	u32 weight_bif;
> +	u32 weight_cp;
> +	u32 weight_pa_sig0;
> +	u32 weight_pa_sig1;
> +	u32 weight_vgt_sig0;
> +	u32 weight_vgt_sig1;
> +	u32 weight_vgt_sig2;
> +	u32 weight_dc_sig0;
> +	u32 weight_dc_sig1;
> +	u32 weight_dc_sig2;
> +	u32 weight_dc_sig3;
> +	u32 weight_uvd_sig0;
> +	u32 weight_uvd_sig1;
> +	u32 weight_spare0;
> +	u32 weight_spare1;
> +	u32 weight_sq_vsp;
> +	u32 weight_sq_vsp0;
> +	u32 weight_sq_gpr;
> +	u32 ovr_mode_spare_0;
> +	u32 ovr_val_spare_0;
> +	u32 ovr_mode_spare_1;
> +	u32 ovr_val_spare_1;
> +	u32 vsp;
> +	u32 vsp0;
> +	u32 gpr;
> +	u8 mc_read_weight;
> +	u8 mc_write_weight;
> +	u32 tid_cnt;
> +	u32 tid_unit;
> +	u32 l2_lta_window_size;
> +	u32 lts_truncate;
> +	u32 dc_cac[NISLANDS_DCCAC_MAX_LEVELS];
> +	u32 pcie_cac[SMC_NISLANDS_BIF_LUT_NUM_OF_ENTRIES];
> +	bool enable_power_containment_by_default;
> +};
> +
> +struct ni_ps {
> +	u16 performance_level_count;
> +	bool dc_compatible;
> +	struct rv7xx_pl performance_levels[NISLANDS_MAX_SMC_PERFORMANCE_LEVELS_PER_SWSTATE];
> +};
> +
> +struct ni_power_info {
> +	/* must be first! */
> +	struct evergreen_power_info eg;
> +	struct ni_clock_registers clock_registers;
> +	struct ni_mc_reg_table mc_reg_table;
> +	u32 mclk_rtt_mode_threshold;
> +	/* flags */
> +	bool use_power_boost_limit;
> +	bool support_cac_long_term_average;
> +	bool cac_enabled;
> +	bool cac_configuration_required;
> +	bool driver_calculate_cac_leakage;
> +	bool pc_enabled;
> +	bool enable_power_containment;
> +	bool enable_cac;
> +	bool enable_sq_ramping;
> +	/* smc offsets */
> +	u16 arb_table_start;
> +	u16 fan_table_start;
> +	u16 cac_table_start;
> +	u16 spll_table_start;
> +	/* CAC stuff */
> +	struct ni_cac_data cac_data;
> +	u32 dc_cac_table[NISLANDS_DCCAC_MAX_LEVELS];
> +	const struct ni_cac_weights *cac_weights;
> +	u8 lta_window_size;
> +	u8 lts_truncate;
> +	struct ni_ps hw_ps;
> +	/* scratch structs */
> +	SMC_NIslands_MCRegisters smc_mc_reg_table;
> +	NISLANDS_SMC_STATETABLE smc_statetable;
> +};
> +
> +#define NISLANDS_INITIAL_STATE_ARB_INDEX    0
> +#define NISLANDS_ACPI_STATE_ARB_INDEX       1
> +#define NISLANDS_ULV_STATE_ARB_INDEX        2
> +#define NISLANDS_DRIVER_STATE_ARB_INDEX     3
> +
> +#define NISLANDS_DPM2_MAX_PULSE_SKIP        256
> +
> +#define NISLANDS_DPM2_NEAR_TDP_DEC          10
> +#define NISLANDS_DPM2_ABOVE_SAFE_INC        5
> +#define NISLANDS_DPM2_BELOW_SAFE_INC        20
> +
> +#define NISLANDS_DPM2_TDP_SAFE_LIMIT_PERCENT            80
> +
> +#define NISLANDS_DPM2_MAXPS_PERCENT_H                   90
> +#define NISLANDS_DPM2_MAXPS_PERCENT_M                   0
> +
> +#define NISLANDS_DPM2_SQ_RAMP_MAX_POWER                 0x3FFF
> +#define NISLANDS_DPM2_SQ_RAMP_MIN_POWER                 0x12
> +#define NISLANDS_DPM2_SQ_RAMP_MAX_POWER_DELTA           0x15
> +#define NISLANDS_DPM2_SQ_RAMP_STI_SIZE                  0x1E
> +#define NISLANDS_DPM2_SQ_RAMP_LTI_RATIO                 0xF
> +
> +#endif
> diff --git a/drivers/gpu/drm/radeon/nid.h b/drivers/gpu/drm/radeon/nid.h
> index 7b8da52..1775043 100644
> --- a/drivers/gpu/drm/radeon/nid.h
> +++ b/drivers/gpu/drm/radeon/nid.h
> @@ -492,6 +492,558 @@
>  /* TN SMU registers */
>  #define	TN_CURRENT_GNB_TEMP				0x1F390
>  
> +/* pm registers */
> +#define	SMC_MSG						0x20c
> +#define		HOST_SMC_MSG(x)				((x) << 0)
> +#define		HOST_SMC_MSG_MASK			(0xff << 0)
> +#define		HOST_SMC_MSG_SHIFT			0
> +#define		HOST_SMC_RESP(x)			((x) << 8)
> +#define		HOST_SMC_RESP_MASK			(0xff << 8)
> +#define		HOST_SMC_RESP_SHIFT			8
> +#define		SMC_HOST_MSG(x)				((x) << 16)
> +#define		SMC_HOST_MSG_MASK			(0xff << 16)
> +#define		SMC_HOST_MSG_SHIFT			16
> +#define		SMC_HOST_RESP(x)			((x) << 24)
> +#define		SMC_HOST_RESP_MASK			(0xff << 24)
> +#define		SMC_HOST_RESP_SHIFT			24
> +
> +#define	CG_SPLL_FUNC_CNTL				0x600
> +#define		SPLL_RESET				(1 << 0)
> +#define		SPLL_SLEEP				(1 << 1)
> +#define		SPLL_BYPASS_EN				(1 << 3)
> +#define		SPLL_REF_DIV(x)				((x) << 4)
> +#define		SPLL_REF_DIV_MASK			(0x3f << 4)
> +#define		SPLL_PDIV_A(x)				((x) << 20)
> +#define		SPLL_PDIV_A_MASK			(0x7f << 20)
> +#define		SPLL_PDIV_A_SHIFT			20
> +#define	CG_SPLL_FUNC_CNTL_2				0x604
> +#define		SCLK_MUX_SEL(x)				((x) << 0)
> +#define		SCLK_MUX_SEL_MASK			(0x1ff << 0)
> +#define	CG_SPLL_FUNC_CNTL_3				0x608
> +#define		SPLL_FB_DIV(x)				((x) << 0)
> +#define		SPLL_FB_DIV_MASK			(0x3ffffff << 0)
> +#define		SPLL_FB_DIV_SHIFT			0
> +#define		SPLL_DITHEN				(1 << 28)
> +
> +#define MPLL_CNTL_MODE                                  0x61c
> +#       define SS_SSEN                                  (1 << 24)
> +#       define SS_DSMODE_EN                             (1 << 25)
> +
> +#define	MPLL_AD_FUNC_CNTL				0x624
> +#define		CLKF(x)					((x) << 0)
> +#define		CLKF_MASK				(0x7f << 0)
> +#define		CLKR(x)					((x) << 7)
> +#define		CLKR_MASK				(0x1f << 7)
> +#define		CLKFRAC(x)				((x) << 12)
> +#define		CLKFRAC_MASK				(0x1f << 12)
> +#define		YCLK_POST_DIV(x)			((x) << 17)
> +#define		YCLK_POST_DIV_MASK			(3 << 17)
> +#define		IBIAS(x)				((x) << 20)
> +#define		IBIAS_MASK				(0x3ff << 20)
> +#define		RESET					(1 << 30)
> +#define		PDNB					(1 << 31)
> +#define	MPLL_AD_FUNC_CNTL_2				0x628
> +#define		BYPASS					(1 << 19)
> +#define		BIAS_GEN_PDNB				(1 << 24)
> +#define		RESET_EN				(1 << 25)
> +#define		VCO_MODE				(1 << 29)
> +#define	MPLL_DQ_FUNC_CNTL				0x62c
> +#define	MPLL_DQ_FUNC_CNTL_2				0x630
> +
> +#define GENERAL_PWRMGT                                  0x63c
> +#       define GLOBAL_PWRMGT_EN                         (1 << 0)
> +#       define STATIC_PM_EN                             (1 << 1)
> +#       define THERMAL_PROTECTION_DIS                   (1 << 2)
> +#       define THERMAL_PROTECTION_TYPE                  (1 << 3)
> +#       define ENABLE_GEN2PCIE                          (1 << 4)
> +#       define ENABLE_GEN2XSP                           (1 << 5)
> +#       define SW_SMIO_INDEX(x)                         ((x) << 6)
> +#       define SW_SMIO_INDEX_MASK                       (3 << 6)
> +#       define SW_SMIO_INDEX_SHIFT                      6
> +#       define LOW_VOLT_D2_ACPI                         (1 << 8)
> +#       define LOW_VOLT_D3_ACPI                         (1 << 9)
> +#       define VOLT_PWRMGT_EN                           (1 << 10)
> +#       define BACKBIAS_PAD_EN                          (1 << 18)
> +#       define BACKBIAS_VALUE                           (1 << 19)
> +#       define DYN_SPREAD_SPECTRUM_EN                   (1 << 23)
> +#       define AC_DC_SW                                 (1 << 24)
> +
> +#define SCLK_PWRMGT_CNTL                                  0x644
> +#       define SCLK_PWRMGT_OFF                            (1 << 0)
> +#       define SCLK_LOW_D1                                (1 << 1)
> +#       define FIR_RESET                                  (1 << 4)
> +#       define FIR_FORCE_TREND_SEL                        (1 << 5)
> +#       define FIR_TREND_MODE                             (1 << 6)
> +#       define DYN_GFX_CLK_OFF_EN                         (1 << 7)
> +#       define GFX_CLK_FORCE_ON                           (1 << 8)
> +#       define GFX_CLK_REQUEST_OFF                        (1 << 9)
> +#       define GFX_CLK_FORCE_OFF                          (1 << 10)
> +#       define GFX_CLK_OFF_ACPI_D1                        (1 << 11)
> +#       define GFX_CLK_OFF_ACPI_D2                        (1 << 12)
> +#       define GFX_CLK_OFF_ACPI_D3                        (1 << 13)
> +#       define DYN_LIGHT_SLEEP_EN                         (1 << 14)
> +#define	MCLK_PWRMGT_CNTL				0x648
> +#       define DLL_SPEED(x)				((x) << 0)
> +#       define DLL_SPEED_MASK				(0x1f << 0)
> +#       define MPLL_PWRMGT_OFF                          (1 << 5)
> +#       define DLL_READY                                (1 << 6)
> +#       define MC_INT_CNTL                              (1 << 7)
> +#       define MRDCKA0_PDNB                             (1 << 8)
> +#       define MRDCKA1_PDNB                             (1 << 9)
> +#       define MRDCKB0_PDNB                             (1 << 10)
> +#       define MRDCKB1_PDNB                             (1 << 11)
> +#       define MRDCKC0_PDNB                             (1 << 12)
> +#       define MRDCKC1_PDNB                             (1 << 13)
> +#       define MRDCKD0_PDNB                             (1 << 14)
> +#       define MRDCKD1_PDNB                             (1 << 15)
> +#       define MRDCKA0_RESET                            (1 << 16)
> +#       define MRDCKA1_RESET                            (1 << 17)
> +#       define MRDCKB0_RESET                            (1 << 18)
> +#       define MRDCKB1_RESET                            (1 << 19)
> +#       define MRDCKC0_RESET                            (1 << 20)
> +#       define MRDCKC1_RESET                            (1 << 21)
> +#       define MRDCKD0_RESET                            (1 << 22)
> +#       define MRDCKD1_RESET                            (1 << 23)
> +#       define DLL_READY_READ                           (1 << 24)
> +#       define USE_DISPLAY_GAP                          (1 << 25)
> +#       define USE_DISPLAY_URGENT_NORMAL                (1 << 26)
> +#       define MPLL_TURNOFF_D2                          (1 << 28)
> +#define	DLL_CNTL					0x64c
> +#       define MRDCKA0_BYPASS                           (1 << 24)
> +#       define MRDCKA1_BYPASS                           (1 << 25)
> +#       define MRDCKB0_BYPASS                           (1 << 26)
> +#       define MRDCKB1_BYPASS                           (1 << 27)
> +#       define MRDCKC0_BYPASS                           (1 << 28)
> +#       define MRDCKC1_BYPASS                           (1 << 29)
> +#       define MRDCKD0_BYPASS                           (1 << 30)
> +#       define MRDCKD1_BYPASS                           (1 << 31)
> +
> +#define CG_AT                                           0x6d4
> +#       define CG_R(x)					((x) << 0)
> +#       define CG_R_MASK				(0xffff << 0)
> +#       define CG_L(x)					((x) << 16)
> +#       define CG_L_MASK				(0xffff << 16)
> +
> +#define	CG_BIF_REQ_AND_RSP				0x7f4
> +#define		CG_CLIENT_REQ(x)			((x) << 0)
> +#define		CG_CLIENT_REQ_MASK			(0xff << 0)
> +#define		CG_CLIENT_REQ_SHIFT			0
> +#define		CG_CLIENT_RESP(x)			((x) << 8)
> +#define		CG_CLIENT_RESP_MASK			(0xff << 8)
> +#define		CG_CLIENT_RESP_SHIFT			8
> +#define		CLIENT_CG_REQ(x)			((x) << 16)
> +#define		CLIENT_CG_REQ_MASK			(0xff << 16)
> +#define		CLIENT_CG_REQ_SHIFT			16
> +#define		CLIENT_CG_RESP(x)			((x) << 24)
> +#define		CLIENT_CG_RESP_MASK			(0xff << 24)
> +#define		CLIENT_CG_RESP_SHIFT			24
> +
> +#define	CG_SPLL_SPREAD_SPECTRUM				0x790
> +#define		SSEN					(1 << 0)
> +#define		CLK_S(x)				((x) << 4)
> +#define		CLK_S_MASK				(0xfff << 4)
> +#define		CLK_S_SHIFT				4
> +#define	CG_SPLL_SPREAD_SPECTRUM_2			0x794
> +#define		CLK_V(x)				((x) << 0)
> +#define		CLK_V_MASK				(0x3ffffff << 0)
> +#define		CLK_V_SHIFT				0
> +
> +#define SMC_SCRATCH0                                    0x81c
> +
> +#define	CG_SPLL_FUNC_CNTL_4				0x850
> +
> +#define	MPLL_SS1					0x85c
> +#define		CLKV(x)					((x) << 0)
> +#define		CLKV_MASK				(0x3ffffff << 0)
> +#define	MPLL_SS2					0x860
> +#define		CLKS(x)					((x) << 0)
> +#define		CLKS_MASK				(0xfff << 0)
> +
> +#define	CG_CAC_CTRL					0x88c
> +#define		TID_CNT(x)				((x) << 0)
> +#define		TID_CNT_MASK				(0x3fff << 0)
> +#define		TID_UNIT(x)				((x) << 14)
> +#define		TID_UNIT_MASK				(0xf << 14)
> +
> +#define MC_CG_CONFIG                                    0x25bc
> +#define         MCDW_WR_ENABLE                          (1 << 0)
> +#define         MCDX_WR_ENABLE                          (1 << 1)
> +#define         MCDY_WR_ENABLE                          (1 << 2)
> +#define         MCDZ_WR_ENABLE                          (1 << 3)
> +#define		MC_RD_ENABLE(x)				((x) << 4)
> +#define		MC_RD_ENABLE_MASK			(3 << 4)
> +#define		INDEX(x)				((x) << 6)
> +#define		INDEX_MASK				(0xfff << 6)
> +#define		INDEX_SHIFT				6
> +
> +#define	MC_ARB_CAC_CNTL					0x2750
> +#define         ENABLE                                  (1 << 0)
> +#define		READ_WEIGHT(x)				((x) << 1)
> +#define		READ_WEIGHT_MASK			(0x3f << 1)
> +#define		READ_WEIGHT_SHIFT			1
> +#define		WRITE_WEIGHT(x)				((x) << 7)
> +#define		WRITE_WEIGHT_MASK			(0x3f << 7)
> +#define		WRITE_WEIGHT_SHIFT			7
> +#define         ALLOW_OVERFLOW                          (1 << 13)
> +
> +#define	MC_ARB_DRAM_TIMING				0x2774
> +#define	MC_ARB_DRAM_TIMING2				0x2778
> +
> +#define	MC_ARB_RFSH_RATE				0x27b0
> +#define		POWERMODE0(x)				((x) << 0)
> +#define		POWERMODE0_MASK				(0xff << 0)
> +#define		POWERMODE0_SHIFT			0
> +#define		POWERMODE1(x)				((x) << 8)
> +#define		POWERMODE1_MASK				(0xff << 8)
> +#define		POWERMODE1_SHIFT			8
> +#define		POWERMODE2(x)				((x) << 16)
> +#define		POWERMODE2_MASK				(0xff << 16)
> +#define		POWERMODE2_SHIFT			16
> +#define		POWERMODE3(x)				((x) << 24)
> +#define		POWERMODE3_MASK				(0xff << 24)
> +#define		POWERMODE3_SHIFT			24
> +
> +#define MC_ARB_CG                                       0x27e8
> +#define		CG_ARB_REQ(x)				((x) << 0)
> +#define		CG_ARB_REQ_MASK				(0xff << 0)
> +#define		CG_ARB_REQ_SHIFT			0
> +#define		CG_ARB_RESP(x)				((x) << 8)
> +#define		CG_ARB_RESP_MASK			(0xff << 8)
> +#define		CG_ARB_RESP_SHIFT			8
> +#define		ARB_CG_REQ(x)				((x) << 16)
> +#define		ARB_CG_REQ_MASK				(0xff << 16)
> +#define		ARB_CG_REQ_SHIFT			16
> +#define		ARB_CG_RESP(x)				((x) << 24)
> +#define		ARB_CG_RESP_MASK			(0xff << 24)
> +#define		ARB_CG_RESP_SHIFT			24
> +
> +#define	MC_ARB_DRAM_TIMING_1				0x27f0
> +#define	MC_ARB_DRAM_TIMING_2				0x27f4
> +#define	MC_ARB_DRAM_TIMING_3				0x27f8
> +#define	MC_ARB_DRAM_TIMING2_1				0x27fc
> +#define	MC_ARB_DRAM_TIMING2_2				0x2800
> +#define	MC_ARB_DRAM_TIMING2_3				0x2804
> +#define MC_ARB_BURST_TIME                               0x2808
> +#define		STATE0(x)				((x) << 0)
> +#define		STATE0_MASK				(0x1f << 0)
> +#define		STATE0_SHIFT				0
> +#define		STATE1(x)				((x) << 5)
> +#define		STATE1_MASK				(0x1f << 5)
> +#define		STATE1_SHIFT				5
> +#define		STATE2(x)				((x) << 10)
> +#define		STATE2_MASK				(0x1f << 10)
> +#define		STATE2_SHIFT				10
> +#define		STATE3(x)				((x) << 15)
> +#define		STATE3_MASK				(0x1f << 15)
> +#define		STATE3_SHIFT				15
> +
> +#define MC_CG_DATAPORT                                  0x2884
> +
> +#define MC_SEQ_RAS_TIMING                               0x28a0
> +#define MC_SEQ_CAS_TIMING                               0x28a4
> +#define MC_SEQ_MISC_TIMING                              0x28a8
> +#define MC_SEQ_MISC_TIMING2                             0x28ac
> +#define MC_SEQ_PMG_TIMING                               0x28b0
> +#define MC_SEQ_RD_CTL_D0                                0x28b4
> +#define MC_SEQ_RD_CTL_D1                                0x28b8
> +#define MC_SEQ_WR_CTL_D0                                0x28bc
> +#define MC_SEQ_WR_CTL_D1                                0x28c0
> +
> +#define MC_SEQ_MISC0                                    0x2a00
> +#define         MC_SEQ_MISC0_GDDR5_SHIFT                28
> +#define         MC_SEQ_MISC0_GDDR5_MASK                 0xf0000000
> +#define         MC_SEQ_MISC0_GDDR5_VALUE                5
> +#define MC_SEQ_MISC1                                    0x2a04
> +#define MC_SEQ_RESERVE_M                                0x2a08
> +#define MC_PMG_CMD_EMRS                                 0x2a0c
> +
> +#define MC_SEQ_MISC3                                    0x2a2c
> +
> +#define MC_SEQ_MISC5                                    0x2a54
> +#define MC_SEQ_MISC6                                    0x2a58
> +
> +#define MC_SEQ_MISC7                                    0x2a64
> +
> +#define MC_SEQ_RAS_TIMING_LP                            0x2a6c
> +#define MC_SEQ_CAS_TIMING_LP                            0x2a70
> +#define MC_SEQ_MISC_TIMING_LP                           0x2a74
> +#define MC_SEQ_MISC_TIMING2_LP                          0x2a78
> +#define MC_SEQ_WR_CTL_D0_LP                             0x2a7c
> +#define MC_SEQ_WR_CTL_D1_LP                             0x2a80
> +#define MC_SEQ_PMG_CMD_EMRS_LP                          0x2a84
> +#define MC_SEQ_PMG_CMD_MRS_LP                           0x2a88
> +
> +#define MC_PMG_CMD_MRS                                  0x2aac
> +
> +#define MC_SEQ_RD_CTL_D0_LP                             0x2b1c
> +#define MC_SEQ_RD_CTL_D1_LP                             0x2b20
> +
> +#define MC_PMG_CMD_MRS1                                 0x2b44
> +#define MC_SEQ_PMG_CMD_MRS1_LP                          0x2b48
> +#define MC_SEQ_PMG_TIMING_LP                            0x2b4c
> +
> +#define MC_PMG_CMD_MRS2                                 0x2b5c
> +#define MC_SEQ_PMG_CMD_MRS2_LP                          0x2b60
> +
> +#define	LB_SYNC_RESET_SEL				0x6b28
> +#define		LB_SYNC_RESET_SEL_MASK			(3 << 0)
> +#define		LB_SYNC_RESET_SEL_SHIFT			0
> +
> +#define	DC_STUTTER_CNTL					0x6b30
> +#define		DC_STUTTER_ENABLE_A			(1 << 0)
> +#define		DC_STUTTER_ENABLE_B			(1 << 1)
> +
> +#define SQ_CAC_THRESHOLD                                0x8e4c
> +#define		VSP(x)					((x) << 0)
> +#define		VSP_MASK				(0xff << 0)
> +#define		VSP_SHIFT				0
> +#define		VSP0(x)					((x) << 8)
> +#define		VSP0_MASK				(0xff << 8)
> +#define		VSP0_SHIFT				8
> +#define		GPR(x)					((x) << 16)
> +#define		GPR_MASK				(0xff << 16)
> +#define		GPR_SHIFT				16
> +
> +#define SQ_POWER_THROTTLE                               0x8e58
> +#define		MIN_POWER(x)				((x) << 0)
> +#define		MIN_POWER_MASK				(0x3fff << 0)
> +#define		MIN_POWER_SHIFT				0
> +#define		MAX_POWER(x)				((x) << 16)
> +#define		MAX_POWER_MASK				(0x3fff << 16)
> +#define		MAX_POWER_SHIFT				0
> +#define SQ_POWER_THROTTLE2                              0x8e5c
> +#define		MAX_POWER_DELTA(x)			((x) << 0)
> +#define		MAX_POWER_DELTA_MASK			(0x3fff << 0)
> +#define		MAX_POWER_DELTA_SHIFT			0
> +#define		STI_SIZE(x)				((x) << 16)
> +#define		STI_SIZE_MASK				(0x3ff << 16)
> +#define		STI_SIZE_SHIFT				16
> +#define		LTI_RATIO(x)				((x) << 27)
> +#define		LTI_RATIO_MASK				(0xf << 27)
> +#define		LTI_RATIO_SHIFT				27
> +
> +/* CG indirect registers */
> +#define CG_CAC_REGION_1_WEIGHT_0                        0x83
> +#define		WEIGHT_TCP_SIG0(x)			((x) << 0)
> +#define		WEIGHT_TCP_SIG0_MASK			(0x3f << 0)
> +#define		WEIGHT_TCP_SIG0_SHIFT			0
> +#define		WEIGHT_TCP_SIG1(x)			((x) << 6)
> +#define		WEIGHT_TCP_SIG1_MASK			(0x3f << 6)
> +#define		WEIGHT_TCP_SIG1_SHIFT			6
> +#define		WEIGHT_TA_SIG(x)			((x) << 12)
> +#define		WEIGHT_TA_SIG_MASK			(0x3f << 12)
> +#define		WEIGHT_TA_SIG_SHIFT			12
> +#define CG_CAC_REGION_1_WEIGHT_1                        0x84
> +#define		WEIGHT_TCC_EN0(x)			((x) << 0)
> +#define		WEIGHT_TCC_EN0_MASK			(0x3f << 0)
> +#define		WEIGHT_TCC_EN0_SHIFT			0
> +#define		WEIGHT_TCC_EN1(x)			((x) << 6)
> +#define		WEIGHT_TCC_EN1_MASK			(0x3f << 6)
> +#define		WEIGHT_TCC_EN1_SHIFT			6
> +#define		WEIGHT_TCC_EN2(x)			((x) << 12)
> +#define		WEIGHT_TCC_EN2_MASK			(0x3f << 12)
> +#define		WEIGHT_TCC_EN2_SHIFT			12
> +#define		WEIGHT_TCC_EN3(x)			((x) << 18)
> +#define		WEIGHT_TCC_EN3_MASK			(0x3f << 18)
> +#define		WEIGHT_TCC_EN3_SHIFT			18
> +#define CG_CAC_REGION_2_WEIGHT_0                        0x85
> +#define		WEIGHT_CB_EN0(x)			((x) << 0)
> +#define		WEIGHT_CB_EN0_MASK			(0x3f << 0)
> +#define		WEIGHT_CB_EN0_SHIFT			0
> +#define		WEIGHT_CB_EN1(x)			((x) << 6)
> +#define		WEIGHT_CB_EN1_MASK			(0x3f << 6)
> +#define		WEIGHT_CB_EN1_SHIFT			6
> +#define		WEIGHT_CB_EN2(x)			((x) << 12)
> +#define		WEIGHT_CB_EN2_MASK			(0x3f << 12)
> +#define		WEIGHT_CB_EN2_SHIFT			12
> +#define		WEIGHT_CB_EN3(x)			((x) << 18)
> +#define		WEIGHT_CB_EN3_MASK			(0x3f << 18)
> +#define		WEIGHT_CB_EN3_SHIFT			18
> +#define CG_CAC_REGION_2_WEIGHT_1                        0x86
> +#define		WEIGHT_DB_SIG0(x)			((x) << 0)
> +#define		WEIGHT_DB_SIG0_MASK			(0x3f << 0)
> +#define		WEIGHT_DB_SIG0_SHIFT			0
> +#define		WEIGHT_DB_SIG1(x)			((x) << 6)
> +#define		WEIGHT_DB_SIG1_MASK			(0x3f << 6)
> +#define		WEIGHT_DB_SIG1_SHIFT			6
> +#define		WEIGHT_DB_SIG2(x)			((x) << 12)
> +#define		WEIGHT_DB_SIG2_MASK			(0x3f << 12)
> +#define		WEIGHT_DB_SIG2_SHIFT			12
> +#define		WEIGHT_DB_SIG3(x)			((x) << 18)
> +#define		WEIGHT_DB_SIG3_MASK			(0x3f << 18)
> +#define		WEIGHT_DB_SIG3_SHIFT			18
> +#define CG_CAC_REGION_2_WEIGHT_2                        0x87
> +#define		WEIGHT_SXM_SIG0(x)			((x) << 0)
> +#define		WEIGHT_SXM_SIG0_MASK			(0x3f << 0)
> +#define		WEIGHT_SXM_SIG0_SHIFT			0
> +#define		WEIGHT_SXM_SIG1(x)			((x) << 6)
> +#define		WEIGHT_SXM_SIG1_MASK			(0x3f << 6)
> +#define		WEIGHT_SXM_SIG1_SHIFT			6
> +#define		WEIGHT_SXM_SIG2(x)			((x) << 12)
> +#define		WEIGHT_SXM_SIG2_MASK			(0x3f << 12)
> +#define		WEIGHT_SXM_SIG2_SHIFT			12
> +#define		WEIGHT_SXS_SIG0(x)			((x) << 18)
> +#define		WEIGHT_SXS_SIG0_MASK			(0x3f << 18)
> +#define		WEIGHT_SXS_SIG0_SHIFT			18
> +#define		WEIGHT_SXS_SIG1(x)			((x) << 24)
> +#define		WEIGHT_SXS_SIG1_MASK			(0x3f << 24)
> +#define		WEIGHT_SXS_SIG1_SHIFT			24
> +#define CG_CAC_REGION_3_WEIGHT_0                        0x88
> +#define		WEIGHT_XBR_0(x)				((x) << 0)
> +#define		WEIGHT_XBR_0_MASK			(0x3f << 0)
> +#define		WEIGHT_XBR_0_SHIFT			0
> +#define		WEIGHT_XBR_1(x)				((x) << 6)
> +#define		WEIGHT_XBR_1_MASK			(0x3f << 6)
> +#define		WEIGHT_XBR_1_SHIFT			6
> +#define		WEIGHT_XBR_2(x)				((x) << 12)
> +#define		WEIGHT_XBR_2_MASK			(0x3f << 12)
> +#define		WEIGHT_XBR_2_SHIFT			12
> +#define		WEIGHT_SPI_SIG0(x)			((x) << 18)
> +#define		WEIGHT_SPI_SIG0_MASK			(0x3f << 18)
> +#define		WEIGHT_SPI_SIG0_SHIFT			18
> +#define CG_CAC_REGION_3_WEIGHT_1                        0x89
> +#define		WEIGHT_SPI_SIG1(x)			((x) << 0)
> +#define		WEIGHT_SPI_SIG1_MASK			(0x3f << 0)
> +#define		WEIGHT_SPI_SIG1_SHIFT			0
> +#define		WEIGHT_SPI_SIG2(x)			((x) << 6)
> +#define		WEIGHT_SPI_SIG2_MASK			(0x3f << 6)
> +#define		WEIGHT_SPI_SIG2_SHIFT			6
> +#define		WEIGHT_SPI_SIG3(x)			((x) << 12)
> +#define		WEIGHT_SPI_SIG3_MASK			(0x3f << 12)
> +#define		WEIGHT_SPI_SIG3_SHIFT			12
> +#define		WEIGHT_SPI_SIG4(x)			((x) << 18)
> +#define		WEIGHT_SPI_SIG4_MASK			(0x3f << 18)
> +#define		WEIGHT_SPI_SIG4_SHIFT			18
> +#define		WEIGHT_SPI_SIG5(x)			((x) << 24)
> +#define		WEIGHT_SPI_SIG5_MASK			(0x3f << 24)
> +#define		WEIGHT_SPI_SIG5_SHIFT			24
> +#define CG_CAC_REGION_4_WEIGHT_0                        0x8a
> +#define		WEIGHT_LDS_SIG0(x)			((x) << 0)
> +#define		WEIGHT_LDS_SIG0_MASK			(0x3f << 0)
> +#define		WEIGHT_LDS_SIG0_SHIFT			0
> +#define		WEIGHT_LDS_SIG1(x)			((x) << 6)
> +#define		WEIGHT_LDS_SIG1_MASK			(0x3f << 6)
> +#define		WEIGHT_LDS_SIG1_SHIFT			6
> +#define		WEIGHT_SC(x)				((x) << 24)
> +#define		WEIGHT_SC_MASK				(0x3f << 24)
> +#define		WEIGHT_SC_SHIFT				24
> +#define CG_CAC_REGION_4_WEIGHT_1                        0x8b
> +#define		WEIGHT_BIF(x)				((x) << 0)
> +#define		WEIGHT_BIF_MASK				(0x3f << 0)
> +#define		WEIGHT_BIF_SHIFT			0
> +#define		WEIGHT_CP(x)				((x) << 6)
> +#define		WEIGHT_CP_MASK				(0x3f << 6)
> +#define		WEIGHT_CP_SHIFT				6
> +#define		WEIGHT_PA_SIG0(x)			((x) << 12)
> +#define		WEIGHT_PA_SIG0_MASK			(0x3f << 12)
> +#define		WEIGHT_PA_SIG0_SHIFT			12
> +#define		WEIGHT_PA_SIG1(x)			((x) << 18)
> +#define		WEIGHT_PA_SIG1_MASK			(0x3f << 18)
> +#define		WEIGHT_PA_SIG1_SHIFT			18
> +#define		WEIGHT_VGT_SIG0(x)			((x) << 24)
> +#define		WEIGHT_VGT_SIG0_MASK			(0x3f << 24)
> +#define		WEIGHT_VGT_SIG0_SHIFT			24
> +#define CG_CAC_REGION_4_WEIGHT_2                        0x8c
> +#define		WEIGHT_VGT_SIG1(x)			((x) << 0)
> +#define		WEIGHT_VGT_SIG1_MASK			(0x3f << 0)
> +#define		WEIGHT_VGT_SIG1_SHIFT			0
> +#define		WEIGHT_VGT_SIG2(x)			((x) << 6)
> +#define		WEIGHT_VGT_SIG2_MASK			(0x3f << 6)
> +#define		WEIGHT_VGT_SIG2_SHIFT			6
> +#define		WEIGHT_DC_SIG0(x)			((x) << 12)
> +#define		WEIGHT_DC_SIG0_MASK			(0x3f << 12)
> +#define		WEIGHT_DC_SIG0_SHIFT			12
> +#define		WEIGHT_DC_SIG1(x)			((x) << 18)
> +#define		WEIGHT_DC_SIG1_MASK			(0x3f << 18)
> +#define		WEIGHT_DC_SIG1_SHIFT			18
> +#define		WEIGHT_DC_SIG2(x)			((x) << 24)
> +#define		WEIGHT_DC_SIG2_MASK			(0x3f << 24)
> +#define		WEIGHT_DC_SIG2_SHIFT			24
> +#define CG_CAC_REGION_4_WEIGHT_3                        0x8d
> +#define		WEIGHT_DC_SIG3(x)			((x) << 0)
> +#define		WEIGHT_DC_SIG3_MASK			(0x3f << 0)
> +#define		WEIGHT_DC_SIG3_SHIFT			0
> +#define		WEIGHT_UVD_SIG0(x)			((x) << 6)
> +#define		WEIGHT_UVD_SIG0_MASK			(0x3f << 6)
> +#define		WEIGHT_UVD_SIG0_SHIFT			6
> +#define		WEIGHT_UVD_SIG1(x)			((x) << 12)
> +#define		WEIGHT_UVD_SIG1_MASK			(0x3f << 12)
> +#define		WEIGHT_UVD_SIG1_SHIFT			12
> +#define		WEIGHT_SPARE0(x)			((x) << 18)
> +#define		WEIGHT_SPARE0_MASK			(0x3f << 18)
> +#define		WEIGHT_SPARE0_SHIFT			18
> +#define		WEIGHT_SPARE1(x)			((x) << 24)
> +#define		WEIGHT_SPARE1_MASK			(0x3f << 24)
> +#define		WEIGHT_SPARE1_SHIFT			24
> +#define CG_CAC_REGION_5_WEIGHT_0                        0x8e
> +#define		WEIGHT_SQ_VSP(x)			((x) << 0)
> +#define		WEIGHT_SQ_VSP_MASK			(0x3fff << 0)
> +#define		WEIGHT_SQ_VSP_SHIFT			0
> +#define		WEIGHT_SQ_VSP0(x)			((x) << 14)
> +#define		WEIGHT_SQ_VSP0_MASK			(0x3fff << 14)
> +#define		WEIGHT_SQ_VSP0_SHIFT			14
> +#define CG_CAC_REGION_4_OVERRIDE_4                      0xab
> +#define		OVR_MODE_SPARE_0(x)			((x) << 16)
> +#define		OVR_MODE_SPARE_0_MASK			(0x1 << 16)
> +#define		OVR_MODE_SPARE_0_SHIFT			16
> +#define		OVR_VAL_SPARE_0(x)			((x) << 17)
> +#define		OVR_VAL_SPARE_0_MASK			(0x1 << 17)
> +#define		OVR_VAL_SPARE_0_SHIFT			17
> +#define		OVR_MODE_SPARE_1(x)			((x) << 18)
> +#define		OVR_MODE_SPARE_1_MASK			(0x3f << 18)
> +#define		OVR_MODE_SPARE_1_SHIFT			18
> +#define		OVR_VAL_SPARE_1(x)			((x) << 19)
> +#define		OVR_VAL_SPARE_1_MASK			(0x3f << 19)
> +#define		OVR_VAL_SPARE_1_SHIFT			19
> +#define CG_CAC_REGION_5_WEIGHT_1                        0xb7
> +#define		WEIGHT_SQ_GPR(x)			((x) << 0)
> +#define		WEIGHT_SQ_GPR_MASK			(0x3fff << 0)
> +#define		WEIGHT_SQ_GPR_SHIFT			0
> +#define		WEIGHT_SQ_LDS(x)			((x) << 14)
> +#define		WEIGHT_SQ_LDS_MASK			(0x3fff << 14)
> +#define		WEIGHT_SQ_LDS_SHIFT			14
> +
> +/* PCIE link stuff */
> +#define PCIE_LC_TRAINING_CNTL                             0xa1 /* PCIE_P */
> +#define PCIE_LC_LINK_WIDTH_CNTL                           0xa2 /* PCIE_P */
> +#       define LC_LINK_WIDTH_SHIFT                        0
> +#       define LC_LINK_WIDTH_MASK                         0x7
> +#       define LC_LINK_WIDTH_X0                           0
> +#       define LC_LINK_WIDTH_X1                           1
> +#       define LC_LINK_WIDTH_X2                           2
> +#       define LC_LINK_WIDTH_X4                           3
> +#       define LC_LINK_WIDTH_X8                           4
> +#       define LC_LINK_WIDTH_X16                          6
> +#       define LC_LINK_WIDTH_RD_SHIFT                     4
> +#       define LC_LINK_WIDTH_RD_MASK                      0x70
> +#       define LC_RECONFIG_ARC_MISSING_ESCAPE             (1 << 7)
> +#       define LC_RECONFIG_NOW                            (1 << 8)
> +#       define LC_RENEGOTIATION_SUPPORT                   (1 << 9)
> +#       define LC_RENEGOTIATE_EN                          (1 << 10)
> +#       define LC_SHORT_RECONFIG_EN                       (1 << 11)
> +#       define LC_UPCONFIGURE_SUPPORT                     (1 << 12)
> +#       define LC_UPCONFIGURE_DIS                         (1 << 13)
> +#define PCIE_LC_SPEED_CNTL                                0xa4 /* PCIE_P */
> +#       define LC_GEN2_EN_STRAP                           (1 << 0)
> +#       define LC_TARGET_LINK_SPEED_OVERRIDE_EN           (1 << 1)
> +#       define LC_FORCE_EN_HW_SPEED_CHANGE                (1 << 5)
> +#       define LC_FORCE_DIS_HW_SPEED_CHANGE               (1 << 6)
> +#       define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_MASK      (0x3 << 8)
> +#       define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_SHIFT     3
> +#       define LC_CURRENT_DATA_RATE                       (1 << 11)
> +#       define LC_HW_VOLTAGE_IF_CONTROL(x)                ((x) << 12)
> +#       define LC_HW_VOLTAGE_IF_CONTROL_MASK              (3 << 12)
> +#       define LC_HW_VOLTAGE_IF_CONTROL_SHIFT             12
> +#       define LC_VOLTAGE_TIMER_SEL_MASK                  (0xf << 14)
> +#       define LC_CLR_FAILED_SPD_CHANGE_CNT               (1 << 21)
> +#       define LC_OTHER_SIDE_EVER_SENT_GEN2               (1 << 23)
> +#       define LC_OTHER_SIDE_SUPPORTS_GEN2                (1 << 24)
> +#define MM_CFGREGS_CNTL                                   0x544c
> +#       define MM_WR_TO_CFG_EN                            (1 << 3)
> +#define LINK_CNTL2                                        0x88 /* F0 */
> +#       define TARGET_LINK_SPEED_MASK                     (0xf << 0)
> +#       define SELECTABLE_DEEMPHASIS                      (1 << 6)
> +
>  /*
>   * UVD
>   */
> diff --git a/drivers/gpu/drm/radeon/nislands_smc.h b/drivers/gpu/drm/radeon/nislands_smc.h
> new file mode 100644
> index 0000000..3cf8fc0
> --- /dev/null
> +++ b/drivers/gpu/drm/radeon/nislands_smc.h
> @@ -0,0 +1,329 @@
> +/*
> + * Copyright 2012 Advanced Micro Devices, Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + *
> + */
> +#ifndef __NISLANDS_SMC_H__
> +#define __NISLANDS_SMC_H__
> +
> +#pragma pack(push, 1)
> +
> +#define NISLANDS_MAX_SMC_PERFORMANCE_LEVELS_PER_SWSTATE 16
> +
> +struct PP_NIslands_Dpm2PerfLevel
> +{
> +    uint8_t     MaxPS;
> +    uint8_t     TgtAct;
> +    uint8_t     MaxPS_StepInc;
> +    uint8_t     MaxPS_StepDec;
> +    uint8_t     PSST;
> +    uint8_t     NearTDPDec;
> +    uint8_t     AboveSafeInc;
> +    uint8_t     BelowSafeInc;
> +    uint8_t     PSDeltaLimit;
> +    uint8_t     PSDeltaWin;
> +    uint8_t     Reserved[6];
> +};
> +
> +typedef struct PP_NIslands_Dpm2PerfLevel PP_NIslands_Dpm2PerfLevel;
> +
> +struct PP_NIslands_DPM2Parameters
> +{
> +    uint32_t    TDPLimit;
> +    uint32_t    NearTDPLimit;
> +    uint32_t    SafePowerLimit;
> +    uint32_t    PowerBoostLimit;
> +};
> +typedef struct PP_NIslands_DPM2Parameters PP_NIslands_DPM2Parameters;
> +
> +struct NISLANDS_SMC_SCLK_VALUE
> +{
> +    uint32_t        vCG_SPLL_FUNC_CNTL;
> +    uint32_t        vCG_SPLL_FUNC_CNTL_2;
> +    uint32_t        vCG_SPLL_FUNC_CNTL_3;
> +    uint32_t        vCG_SPLL_FUNC_CNTL_4;
> +    uint32_t        vCG_SPLL_SPREAD_SPECTRUM;
> +    uint32_t        vCG_SPLL_SPREAD_SPECTRUM_2;
> +    uint32_t        sclk_value;
> +};
> +
> +typedef struct NISLANDS_SMC_SCLK_VALUE NISLANDS_SMC_SCLK_VALUE;
> +
> +struct NISLANDS_SMC_MCLK_VALUE
> +{
> +    uint32_t        vMPLL_FUNC_CNTL;
> +    uint32_t        vMPLL_FUNC_CNTL_1;
> +    uint32_t        vMPLL_FUNC_CNTL_2;
> +    uint32_t        vMPLL_AD_FUNC_CNTL;
> +    uint32_t        vMPLL_AD_FUNC_CNTL_2;
> +    uint32_t        vMPLL_DQ_FUNC_CNTL;
> +    uint32_t        vMPLL_DQ_FUNC_CNTL_2;
> +    uint32_t        vMCLK_PWRMGT_CNTL;
> +    uint32_t        vDLL_CNTL;
> +    uint32_t        vMPLL_SS;
> +    uint32_t        vMPLL_SS2;
> +    uint32_t        mclk_value;
> +};
> +
> +typedef struct NISLANDS_SMC_MCLK_VALUE NISLANDS_SMC_MCLK_VALUE;
> +
> +struct NISLANDS_SMC_VOLTAGE_VALUE
> +{
> +    uint16_t             value;
> +    uint8_t              index;
> +    uint8_t              padding;
> +};
> +
> +typedef struct NISLANDS_SMC_VOLTAGE_VALUE NISLANDS_SMC_VOLTAGE_VALUE;
> +
> +struct NISLANDS_SMC_HW_PERFORMANCE_LEVEL
> +{
> +    uint8_t                     arbValue;
> +    uint8_t                     ACIndex;
> +    uint8_t                     displayWatermark;
> +    uint8_t                     gen2PCIE;
> +    uint8_t                     reserved1;
> +    uint8_t                     reserved2;
> +    uint8_t                     strobeMode;
> +    uint8_t                     mcFlags;
> +    uint32_t                    aT;
> +    uint32_t                    bSP;
> +    NISLANDS_SMC_SCLK_VALUE     sclk;
> +    NISLANDS_SMC_MCLK_VALUE     mclk;
> +    NISLANDS_SMC_VOLTAGE_VALUE  vddc;
> +    NISLANDS_SMC_VOLTAGE_VALUE  mvdd;
> +    NISLANDS_SMC_VOLTAGE_VALUE  vddci;
> +    NISLANDS_SMC_VOLTAGE_VALUE  std_vddc;
> +    uint32_t                    powergate_en;
> +    uint8_t                     hUp;
> +    uint8_t                     hDown;
> +    uint8_t                     stateFlags;
> +    uint8_t                     arbRefreshState;
> +    uint32_t                    SQPowerThrottle;
> +    uint32_t                    SQPowerThrottle_2;
> +    uint32_t                    reserved[2];
> +    PP_NIslands_Dpm2PerfLevel   dpm2;
> +};
> +
> +#define NISLANDS_SMC_STROBE_RATIO    0x0F
> +#define NISLANDS_SMC_STROBE_ENABLE   0x10
> +
> +#define NISLANDS_SMC_MC_EDC_RD_FLAG  0x01
> +#define NISLANDS_SMC_MC_EDC_WR_FLAG  0x02
> +#define NISLANDS_SMC_MC_RTT_ENABLE   0x04
> +#define NISLANDS_SMC_MC_STUTTER_EN   0x08
> +
> +typedef struct NISLANDS_SMC_HW_PERFORMANCE_LEVEL NISLANDS_SMC_HW_PERFORMANCE_LEVEL;
> +
> +struct NISLANDS_SMC_SWSTATE
> +{
> +    uint8_t                             flags;
> +    uint8_t                             levelCount;
> +    uint8_t                             padding2;
> +    uint8_t                             padding3;
> +    NISLANDS_SMC_HW_PERFORMANCE_LEVEL   levels[1];
> +};
> +
> +typedef struct NISLANDS_SMC_SWSTATE NISLANDS_SMC_SWSTATE;
> +
> +#define NISLANDS_SMC_VOLTAGEMASK_VDDC  0
> +#define NISLANDS_SMC_VOLTAGEMASK_MVDD  1
> +#define NISLANDS_SMC_VOLTAGEMASK_VDDCI 2
> +#define NISLANDS_SMC_VOLTAGEMASK_MAX   4
> +
> +struct NISLANDS_SMC_VOLTAGEMASKTABLE
> +{
> +    uint8_t  highMask[NISLANDS_SMC_VOLTAGEMASK_MAX];
> +    uint32_t lowMask[NISLANDS_SMC_VOLTAGEMASK_MAX];
> +};
> +
> +typedef struct NISLANDS_SMC_VOLTAGEMASKTABLE NISLANDS_SMC_VOLTAGEMASKTABLE;
> +
> +#define NISLANDS_MAX_NO_VREG_STEPS 32
> +
> +struct NISLANDS_SMC_STATETABLE
> +{
> +    uint8_t                             thermalProtectType;
> +    uint8_t                             systemFlags;
> +    uint8_t                             maxVDDCIndexInPPTable;
> +    uint8_t                             extraFlags;
> +    uint8_t                             highSMIO[NISLANDS_MAX_NO_VREG_STEPS];
> +    uint32_t                            lowSMIO[NISLANDS_MAX_NO_VREG_STEPS];
> +    NISLANDS_SMC_VOLTAGEMASKTABLE       voltageMaskTable;
> +    PP_NIslands_DPM2Parameters          dpm2Params;
> +    NISLANDS_SMC_SWSTATE                initialState;
> +    NISLANDS_SMC_SWSTATE                ACPIState;
> +    NISLANDS_SMC_SWSTATE                ULVState;
> +    NISLANDS_SMC_SWSTATE                driverState;
> +    NISLANDS_SMC_HW_PERFORMANCE_LEVEL   dpmLevels[NISLANDS_MAX_SMC_PERFORMANCE_LEVELS_PER_SWSTATE - 1];
> +};
> +
> +typedef struct NISLANDS_SMC_STATETABLE NISLANDS_SMC_STATETABLE;
> +
> +#define NI_SMC_SOFT_REGISTERS_START        0x108
> +
> +#define NI_SMC_SOFT_REGISTER_mclk_chg_timeout        0x0
> +#define NI_SMC_SOFT_REGISTER_delay_bbias             0xC
> +#define NI_SMC_SOFT_REGISTER_delay_vreg              0x10
> +#define NI_SMC_SOFT_REGISTER_delay_acpi              0x2C
> +#define NI_SMC_SOFT_REGISTER_seq_index               0x64
> +#define NI_SMC_SOFT_REGISTER_mvdd_chg_time           0x68
> +#define NI_SMC_SOFT_REGISTER_mclk_switch_lim         0x78
> +#define NI_SMC_SOFT_REGISTER_watermark_threshold     0x80
> +#define NI_SMC_SOFT_REGISTER_mc_block_delay          0x84
> +#define NI_SMC_SOFT_REGISTER_uvd_enabled             0x98
> +
> +#define SMC_NISLANDS_MC_TPP_CAC_NUM_OF_ENTRIES 16
> +#define SMC_NISLANDS_LKGE_LUT_NUM_OF_TEMP_ENTRIES 16
> +#define SMC_NISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES 16
> +#define SMC_NISLANDS_BIF_LUT_NUM_OF_ENTRIES 4
> +
> +struct SMC_NISLANDS_MC_TPP_CAC_TABLE
> +{
> +    uint32_t    tpp[SMC_NISLANDS_MC_TPP_CAC_NUM_OF_ENTRIES];
> +    uint32_t    cacValue[SMC_NISLANDS_MC_TPP_CAC_NUM_OF_ENTRIES];
> +};
> +
> +typedef struct SMC_NISLANDS_MC_TPP_CAC_TABLE SMC_NISLANDS_MC_TPP_CAC_TABLE;
> +
> +
> +struct PP_NIslands_CACTABLES
> +{
> +    uint32_t                cac_bif_lut[SMC_NISLANDS_BIF_LUT_NUM_OF_ENTRIES];
> +    uint32_t                cac_lkge_lut[SMC_NISLANDS_LKGE_LUT_NUM_OF_TEMP_ENTRIES][SMC_NISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES];
> +
> +    uint32_t                pwr_const;
> +
> +    uint32_t                dc_cacValue;
> +    uint32_t                bif_cacValue;
> +    uint32_t                lkge_pwr;
> +
> +    uint8_t                 cac_width;
> +    uint8_t                 window_size_p2;
> +
> +    uint8_t                 num_drop_lsb;
> +    uint8_t                 padding_0;
> +
> +    uint32_t                last_power;
> +
> +    uint8_t                 AllowOvrflw;
> +    uint8_t                 MCWrWeight;
> +    uint8_t                 MCRdWeight;
> +    uint8_t                 padding_1[9];
> +
> +    uint8_t                 enableWinAvg;
> +    uint8_t                 numWin_TDP;
> +    uint8_t                 l2numWin_TDP;
> +    uint8_t                 WinIndex;
> +
> +    uint32_t                dynPwr_TDP[4];
> +    uint32_t                lkgePwr_TDP[4];
> +    uint32_t                power_TDP[4];
> +    uint32_t                avg_dynPwr_TDP;
> +    uint32_t                avg_lkgePwr_TDP;
> +    uint32_t                avg_power_TDP;
> +    uint32_t                lts_power_TDP;
> +    uint8_t                 lts_truncate_n;
> +    uint8_t                 padding_2[7];
> +};
> +
> +typedef struct PP_NIslands_CACTABLES PP_NIslands_CACTABLES;
> +
> +#define SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE 32
> +#define SMC_NISLANDS_MC_REGISTER_ARRAY_SET_COUNT 20
> +
> +struct SMC_NIslands_MCRegisterAddress
> +{
> +    uint16_t s0;
> +    uint16_t s1;
> +};
> +
> +typedef struct SMC_NIslands_MCRegisterAddress SMC_NIslands_MCRegisterAddress;
> +
> +
> +struct SMC_NIslands_MCRegisterSet
> +{
> +    uint32_t value[SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE];
> +};
> +
> +typedef struct SMC_NIslands_MCRegisterSet SMC_NIslands_MCRegisterSet;
> +
> +struct SMC_NIslands_MCRegisters
> +{
> +    uint8_t                             last;
> +    uint8_t                             reserved[3];
> +    SMC_NIslands_MCRegisterAddress      address[SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE];
> +    SMC_NIslands_MCRegisterSet          data[SMC_NISLANDS_MC_REGISTER_ARRAY_SET_COUNT];
> +};
> +
> +typedef struct SMC_NIslands_MCRegisters SMC_NIslands_MCRegisters;
> +
> +struct SMC_NIslands_MCArbDramTimingRegisterSet
> +{
> +    uint32_t mc_arb_dram_timing;
> +    uint32_t mc_arb_dram_timing2;
> +    uint8_t  mc_arb_rfsh_rate;
> +    uint8_t  padding[3];
> +};
> +
> +typedef struct SMC_NIslands_MCArbDramTimingRegisterSet SMC_NIslands_MCArbDramTimingRegisterSet;
> +
> +struct SMC_NIslands_MCArbDramTimingRegisters
> +{
> +    uint8_t                                     arb_current;
> +    uint8_t                                     reserved[3];
> +    SMC_NIslands_MCArbDramTimingRegisterSet     data[20];
> +};
> +
> +typedef struct SMC_NIslands_MCArbDramTimingRegisters SMC_NIslands_MCArbDramTimingRegisters;
> +
> +struct SMC_NISLANDS_SPLL_DIV_TABLE
> +{
> +    uint32_t    freq[256];
> +    uint32_t    ss[256];
> +};
> +
> +#define SMC_NISLANDS_SPLL_DIV_TABLE_FBDIV_MASK  0x01ffffff
> +#define SMC_NISLANDS_SPLL_DIV_TABLE_FBDIV_SHIFT 0
> +#define SMC_NISLANDS_SPLL_DIV_TABLE_PDIV_MASK   0xfe000000
> +#define SMC_NISLANDS_SPLL_DIV_TABLE_PDIV_SHIFT  25
> +#define SMC_NISLANDS_SPLL_DIV_TABLE_CLKV_MASK   0x000fffff
> +#define SMC_NISLANDS_SPLL_DIV_TABLE_CLKV_SHIFT  0
> +#define SMC_NISLANDS_SPLL_DIV_TABLE_CLKS_MASK   0xfff00000
> +#define SMC_NISLANDS_SPLL_DIV_TABLE_CLKS_SHIFT  20
> +
> +typedef struct SMC_NISLANDS_SPLL_DIV_TABLE SMC_NISLANDS_SPLL_DIV_TABLE;
> +
> +#define NISLANDS_SMC_FIRMWARE_HEADER_LOCATION 0x100
> +
> +#define NISLANDS_SMC_FIRMWARE_HEADER_version                   0x0
> +#define NISLANDS_SMC_FIRMWARE_HEADER_flags                     0x4
> +#define NISLANDS_SMC_FIRMWARE_HEADER_softRegisters             0x8
> +#define NISLANDS_SMC_FIRMWARE_HEADER_stateTable                0xC
> +#define NISLANDS_SMC_FIRMWARE_HEADER_fanTable                  0x10
> +#define NISLANDS_SMC_FIRMWARE_HEADER_cacTable                  0x14
> +#define NISLANDS_SMC_FIRMWARE_HEADER_mcRegisterTable           0x20
> +#define NISLANDS_SMC_FIRMWARE_HEADER_mcArbDramAutoRefreshTable 0x2C
> +#define NISLANDS_SMC_FIRMWARE_HEADER_spllTable                 0x30
> +
> +#pragma pack(pop)
> +
> +#endif
> +
> diff --git a/drivers/gpu/drm/radeon/ppsmc.h b/drivers/gpu/drm/radeon/ppsmc.h
> index 3d0786f..607982a 100644
> --- a/drivers/gpu/drm/radeon/ppsmc.h
> +++ b/drivers/gpu/drm/radeon/ppsmc.h
> @@ -46,6 +46,7 @@
>  #define PPSMC_DISPLAY_WATERMARK_HIGH                    1
>  
>  #define PPSMC_STATEFLAG_AUTO_PULSE_SKIP    0x01
> +#define PPSMC_STATEFLAG_POWERBOOST         0x02
>  
>  #define PPSMC_Result_OK             ((uint8_t)0x01)
>  #define PPSMC_Result_Failed         ((uint8_t)0xFF)
> @@ -56,17 +57,28 @@ typedef uint8_t PPSMC_Result;
>  #define PPSMC_MSG_Resume                    ((uint8_t)0x11)
>  #define PPSMC_MSG_TwoLevelsDisabled         ((uint8_t)0x15)
>  #define PPSMC_MSG_EnableThermalInterrupt    ((uint8_t)0x16)
> +#define PPSMC_MSG_RunningOnAC               ((uint8_t)0x17)
>  #define PPSMC_MSG_SwitchToSwState           ((uint8_t)0x20)
>  #define PPSMC_MSG_SwitchToInitialState      ((uint8_t)0x40)
>  #define PPSMC_MSG_NoForcedLevel             ((uint8_t)0x41)
>  #define PPSMC_MSG_SwitchToMinimumPower      ((uint8_t)0x51)
>  #define PPSMC_MSG_ResumeFromMinimumPower    ((uint8_t)0x52)
> +#define PPSMC_MSG_EnableCac                 ((uint8_t)0x53)
> +#define PPSMC_MSG_DisableCac                ((uint8_t)0x54)
> +#define PPSMC_TDPClampingActive             ((uint8_t)0x59)
> +#define PPSMC_TDPClampingInactive           ((uint8_t)0x5A)
>  #define PPSMC_MSG_NoDisplay                 ((uint8_t)0x5D)
>  #define PPSMC_MSG_HasDisplay                ((uint8_t)0x5E)
> +#define PPSMC_MSG_UVDPowerOFF               ((uint8_t)0x60)
> +#define PPSMC_MSG_UVDPowerON                ((uint8_t)0x61)
>  #define PPSMC_MSG_EnableULV                 ((uint8_t)0x62)
>  #define PPSMC_MSG_DisableULV                ((uint8_t)0x63)
>  #define PPSMC_MSG_EnterULV                  ((uint8_t)0x64)
>  #define PPSMC_MSG_ExitULV                   ((uint8_t)0x65)
> +#define PPSMC_CACLongTermAvgEnable          ((uint8_t)0x6E)
> +#define PPSMC_CACLongTermAvgDisable         ((uint8_t)0x6F)
> +#define PPSMC_MSG_CollectCAC_PowerCorreln   ((uint8_t)0x7A)
> +#define PPSMC_MSG_SetEnabledLevels          ((uint8_t)0x82)
>  #define PPSMC_MSG_ResetToDefaults           ((uint8_t)0x84)
>  
>  /* TN */
> diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c
> index 5dcbb28..e6703ef 100644
> --- a/drivers/gpu/drm/radeon/radeon_asic.c
> +++ b/drivers/gpu/drm/radeon/radeon_asic.c
> @@ -1804,6 +1804,18 @@ static struct radeon_asic cayman_asic = {
>  		.set_uvd_clocks = &evergreen_set_uvd_clocks,
>  		.get_temperature = &evergreen_get_temp,
>  	},
> +	.dpm = {
> +		.init = &ni_dpm_init,
> +		.setup_asic = &ni_dpm_setup_asic,
> +		.enable = &ni_dpm_enable,
> +		.disable = &ni_dpm_disable,
> +		.set_power_state = &ni_dpm_set_power_state,
> +		.display_configuration_changed = &cypress_dpm_display_configuration_changed,
> +		.fini = &ni_dpm_fini,
> +		.get_sclk = &ni_dpm_get_sclk,
> +		.get_mclk = &ni_dpm_get_mclk,
> +		.print_power_state = &ni_dpm_print_power_state,
> +	},
>  	.pflip = {
>  		.pre_page_flip = &evergreen_pre_page_flip,
>  		.page_flip = &evergreen_page_flip,
> diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
> index 4d3f93d..2fef64d 100644
> --- a/drivers/gpu/drm/radeon/radeon_asic.h
> +++ b/drivers/gpu/drm/radeon/radeon_asic.h
> @@ -581,6 +581,16 @@ bool cayman_gfx_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring);
>  bool cayman_dma_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring);
>  void cayman_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm);
>  
> +int ni_dpm_init(struct radeon_device *rdev);
> +void ni_dpm_setup_asic(struct radeon_device *rdev);
> +int ni_dpm_enable(struct radeon_device *rdev);
> +void ni_dpm_disable(struct radeon_device *rdev);
> +int ni_dpm_set_power_state(struct radeon_device *rdev);
> +void ni_dpm_fini(struct radeon_device *rdev);
> +u32 ni_dpm_get_sclk(struct radeon_device *rdev, bool low);
> +u32 ni_dpm_get_mclk(struct radeon_device *rdev, bool low);
> +void ni_dpm_print_power_state(struct radeon_device *rdev,
> +			      struct radeon_ps *ps);
>  int trinity_dpm_init(struct radeon_device *rdev);
>  int trinity_dpm_enable(struct radeon_device *rdev);
>  void trinity_dpm_disable(struct radeon_device *rdev);
> diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
> index 2eb41be..01ff18b 100644
> --- a/drivers/gpu/drm/radeon/radeon_pm.c
> +++ b/drivers/gpu/drm/radeon/radeon_pm.c
> @@ -1100,6 +1100,7 @@ int radeon_pm_init(struct radeon_device *rdev)
>  	case CHIP_BARTS:
>  	case CHIP_TURKS:
>  	case CHIP_CAICOS:
> +	case CHIP_CAYMAN:
>  	case CHIP_ARUBA:
>  		if (radeon_dpm == 1)
>  			rdev->pm.pm_method = PM_METHOD_DPM;
> diff --git a/drivers/gpu/drm/radeon/radeon_ucode.h b/drivers/gpu/drm/radeon/radeon_ucode.h
> index e592e27..51beb4c 100644
> --- a/drivers/gpu/drm/radeon/radeon_ucode.h
> +++ b/drivers/gpu/drm/radeon/radeon_ucode.h
> @@ -100,4 +100,9 @@
>  #define CAICOS_SMC_INT_VECTOR_START  0xffc0
>  #define CAICOS_SMC_INT_VECTOR_SIZE   0x0040
>  
> +#define CAYMAN_SMC_UCODE_START       0x0100
> +#define CAYMAN_SMC_UCODE_SIZE        0x79ec
> +#define CAYMAN_SMC_INT_VECTOR_START  0xffc0
> +#define CAYMAN_SMC_INT_VECTOR_SIZE   0x0040
> +
>  #endif
> diff --git a/drivers/gpu/drm/radeon/rv770_smc.c b/drivers/gpu/drm/radeon/rv770_smc.c
> index 0078c59..ab95da5 100644
> --- a/drivers/gpu/drm/radeon/rv770_smc.c
> +++ b/drivers/gpu/drm/radeon/rv770_smc.c
> @@ -254,6 +254,26 @@ static const u8 caicos_smc_int_vectors[] =
>  	0x05, 0x0A, 0x05, 0x0A
>  };
>  
> +static const u8 cayman_smc_int_vectors[] =
> +{
> +	0x12, 0x05, 0x12, 0x05,
> +	0x12, 0x05, 0x12, 0x05,
> +	0x12, 0x05, 0x12, 0x05,
> +	0x12, 0x05, 0x12, 0x05,
> +	0x12, 0x05, 0x12, 0x05,
> +	0x12, 0x05, 0x12, 0x05,
> +	0x12, 0x05, 0x12, 0x05,
> +	0x12, 0x05, 0x12, 0x05,
> +	0x12, 0x05, 0x12, 0x05,
> +	0x12, 0x05, 0x12, 0x05,
> +	0x12, 0x05, 0x12, 0x05,
> +	0x12, 0x05, 0x12, 0x05,
> +	0x12, 0x05, 0x18, 0xEA,
> +	0x12, 0x20, 0x1C, 0x34,
> +	0x1C, 0x34, 0x08, 0x72,
> +	0x08, 0x72, 0x08, 0x72
> +};
> +
>  int rv770_set_smc_sram_address(struct radeon_device *rdev,
>  			       u16 smc_address, u16 limit)
>  {
> @@ -544,6 +564,13 @@ int rv770_load_smc_ucode(struct radeon_device *rdev,
>  		int_vect_start_address = CAICOS_SMC_INT_VECTOR_START;
>  		int_vect_size = CAICOS_SMC_INT_VECTOR_SIZE;
>  		break;
> +	case CHIP_CAYMAN:
> +		ucode_start_address = CAYMAN_SMC_UCODE_START;
> +		ucode_size = CAYMAN_SMC_UCODE_SIZE;
> +		int_vect = (const u8 *)&cayman_smc_int_vectors;
> +		int_vect_start_address = CAYMAN_SMC_INT_VECTOR_START;
> +		int_vect_size = CAYMAN_SMC_INT_VECTOR_SIZE;
> +		break;
>  	default:
>  		DRM_ERROR("unknown asic in smc ucode loader\n");
>  		BUG();
> -- 
> 1.7.7.5
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 000/165] radeon drm-next patches
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
@ 2013-06-26 12:55 ` Jerome Glisse
  2013-06-26 13:21 ` [PATCH 001/165] drm/radeon: fix AVI infoframe generation alexdeucher
                   ` (112 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: Jerome Glisse @ 2013-06-26 12:55 UTC (permalink / raw)
  To: alexdeucher; +Cc: Alex Deucher, dri-devel

On Wed, Jun 26, 2013 at 09:21:20AM -0400, alexdeucher@gmail.com wrote:
> From: Alex Deucher <alexander.deucher@amd.com>
> 
> These are the radeon patches for 3.11.  Some of these patches
> are huge so, it might be easier to review things here:
> http://cgit.freedesktop.org/~agd5f/linux/log/?h=drm-next-3.11-wip
> 
> I'll send a formal pull in request in the next day or two.
> 
> Highlights of this series:
> - DPM support (Dynamic Power Management) for r6xx-SI
> - Support for CIK (Sea Islands): modesetting, 3D, compute, UVD
> - ASPM support for R6xx-SI
> 
> Since this is the initial public DPM code, it's still disabled by default
> until we get more community testing.  Pass dpm=1 to the radeon module to
> enable it.

So for the serie (except one i replied to) got my :

Reviewed-by: Jerome Glisse <jglisse@redhat.com>

I mostly checked the logic behind function ie what function is supose to do
and does it do it properly. I didn't do any tedious check like is it using
proper define for this generation.

I wish more of the acronym related to power management were documented. There
is so many magic name that it's often hard to understand the logic of the
code, what it's doing and what is it that it's computing.

Regarding CIK i fear that the hsa addition doesn't fit very well with our ring
stuff, we probably don't want a ring struct for each of the 32 or 64 queues.
But as right now we are only using few queues, that's probably alright.

Cheers,
Jerome

> 
> Alex Deucher (164):
>   drm/radeon: fix AVI infoframe generation
>   drm/radeon: add backlight quirk for hybrid mac
>   drm/radeon: add a reset work handler
>   drm/radeon: add CIK chip families
>   drm/radeon: add DCE8 macro for CIK
>   drm/radeon: adapt to PCI BAR changes on CIK
>   drm/radeon: add gpu init support for CIK (v9)
>   drm/radeon: Add support for CIK GPU reset (v2)
>   drm/radeon: add support for MC/VM setup on CIK (v6)
>   drm/radeon/cik: stop page faults from hanging the system (v2)
>   drm/radeon: add initial ucode loading for CIK (v5)
>   drm/radeon: add support mc ucode loading on CIK (v2)
>   drm/radeon: Add CP init for CIK (v7)
>   drm/radeon: add IB and fence dispatch functions for CIK gfx (v7)
>   drm/radeon: add ring and IB tests for CIK (v3)
>   drm/radeon: implement async vm_flush for the CP (v7)
>   drm/radeon: Add support for RLC init on CIK (v4)
>   drm/radeon: add support for interrupts on CIK (v5)
>   drm/radeon/cik: log and handle VM page fault interrupts
>   drm/radeon/cik: add support for sDMA dma engines (v8)
>   drm/radeon: implement async vm_flush for the sDMA (v6)
>   drm/radeon/cik: add support for doing async VM pt updates (v5)
>   drm/radeon/cik: fill in startup/shutdown callbacks (v4)
>   drm/radeon: upstream ObjectID.h updates (v2)
>   drm/radeon: upstream atombios.h updates (v2)
>   drm/radeon: atombios power table updates (v2)
>   drm/radeon: handle the integrated thermal controller on CI
>   drm/radeon: update power state parsing for CI
>   drm/radeon/dce8: add support for display watermark setup
>   drm/radeon/cik: add hw cursor support (v2)
>   drm/radeon/dce8: properly handle interlaced timing
>   drm/radeon/dce8: crtc_set_base updates
>   drm/radeon/atom: add DCE8 encoder support
>   drm/radeon/atom: add support for new DVO tables
>   drm/radeon: update DISPCLK programming for DCE8
>   drm/radeon: add support pll selection for DCE8 (v4)
>   drm/radeon: Handle PPLL0 powerdown on DCE8
>   drm/radeon: use frac fb div on DCE8
>   drm/radeon: add SS override support for KB/KV
>   drm/radeon: Update radeon_info_ioctl for CIK (v2)
>   drm/radeon: add get_gpu_clock_counter() callback for cik
>   drm/radeon: update CIK soft reset
>   drm/radeon: add indirect register accessors for SMC registers
>   drm/radeon: add get_xclk() callback for CIK
>   drm/radeon/cik: add pcie_port indirect register accessors
>   drm/radeon: update radeon_atom_get_clock_dividers() for SI
>   drm/radeon: update radeon_atom_get_clock_dividers for CIK
>   drm/radeon/cik: add srbm_select function
>   drm/radeon: use callbacks for ring pointer handling
>   drm/radeon: implement simple doorbell page allocator
>   drm/radeon/cik: Add support for compute queues (v2)
>   drm/radeon/cik: switch to type3 nop packet for compute rings
>   drm/radeon: fix up ring functions for compute rings
>   drm/radeon/cik: add support for compute interrupts
>   drm/radeon/cik: add support for golden register init
>   drm/radeon: add radeon_asic struct for CIK (v11)
>   drm/radeon: add cik tile mode array query
>   drm/radeon: add current Bonaire PCI ids
>   drm/radeon: add current KB pci ids
>   drm/radeon/kms: add accessors for RCU indirect space
>   drm/radeon/evergreen: add indirect register accessors for CG
>     registers
>   drm/radeon: make get_temperature functions a callback
>   drm/radeon: add support for thermal sensor on tn
>   drm/radeon/kms: move ucode defines to a separate header
>   drm/radeon: properly set up the RLC on ON/LN/TN (v3)
>   drm/radeon/kms: add atom helper functions for dpm (v3)
>   drm/radeon/kms: add new asic struct for rv6xx (v3)
>   drm/radeon/kms: add common dpm infrastructure
>   drm/radeon/kms: fix up rs780/rs880 display watermark calc for dpm
>   drm/radeon/kms: fix up 6xx/7xx display watermark calc for dpm
>   drm/radeon/kms: fix up dce4/5 display watermark calc for dpm
>   drm/radeon/kms: fix up dce6 display watermark calc for dpm
>   drm/radeon/kms: add common r600 dpm functions
>   drm/radeon/kms: add dpm support for rs780/rs880
>   drm/radeon/kms: add dpm support for rv6xx
>   drm/radeon/kms: add dpm support for rv7xx (v2)
>   drm/radeon/kms: add dpm support for evergreen (v2)
>   drm/radeon/kms: add dpm support for btc (v2)
>   drm/radeon/kms: add dpm support for sumo asics
>   drm/radeon/kms: add dpm support for trinity asics
>   drm/radeon/dpm: let atom control display phy powergating
>   drm/radeon: add dpm UVD handling for r7xx asics
>   drm/radeon: add dpm UVD handling for evergreen/btc asics
>   drm/radeon: add dpm UVD handling for sumo asics
>   drm/radeon: add dpm UVD handling for TN asics (v2)
>   drm/radeon/kms: enable UVD as needed (v9)
>   drm/radeon/dpm: add helpers for extended power tables (v2)
>   drm/radeon/dpm: track whether we are on AC or battery
>   drm/radeon/dpm: fixup dynamic state adjust for sumo
>   drm/radeon/dpm: fixup dynamic state adjust for TN
>   drm/radeon/dpm: fixup dynamic state adjust for btc (v2)
>   drm/radeon/kms: add dpm support for cayman
>   drm/radeon/cayman: update tdp limits in set_power_state
>   drm/radeon/dpm/rs780: restructure code
>   drm/radeon/dpm/rv6xx: restructure code
>   drm/radeon/dpm/rv7xx: restructure code
>   drm/radeon/dpm/evergreen: restructure code
>   drm/radeon/dpm/btc: restructure code
>   drm/radeon/dpm/cayman: restructure code
>   drm/radeon/dpm/sumo: restructure code
>   drm/radeon/dpm/tn: restructure code
>   drm/radeon/dpm: add new pre/post_set_power_state callbacks
>   drm/radeon/dpm: add pre/post_set_power_state callbacks (6xx-eg)
>   drm/radeon/dpm: add pre/post_set_power_state callback (sumo)
>   drm/radeon/dpm: add pre/post_set_power_state callback (TN)
>   drm/radeon/dpm: add pre/post_set_power_state callback (BTC)
>   drm/radeon/dpm: add pre/post_set_power_state callback (cayman)
>   drm/radeon/dpm: remove broken dyn state remnants
>   drm/radeon: add missing UVD clock set in cayman dpm code
>   drm/radeon/dpm: remove local sumo_get_xclk()
>   drm/radeon: implement apci perf request
>   drm/radeon/atom: add helper to calcuate mpll params
>   drm/radeon: update radeon_atom_is_voltage_gpio() for SI
>   drm/radeon: update radeon_atom_get_voltage_table() for SI
>   drm/radeon: implement pcie gen2/3 support for SI
>   drm/radeon: add accessors of pif_phy indirect register space
>   drm/radeon: add support for ASPM on evergreen asics
>   drm/radeon: add support for ASPM on SI asics (v2)
>   drm/radeon: enable additional power gating features on trinity
>   drm/radeon: update rlc programming sequence on SI
>   drm/radeon: add atom get leakage vddc function
>   drm/radeon: add indirect accessors for UVD CTX registers
>   drm/radeon: initialize save/restore buffer for pg on verde
>   drm/radeon: add clearstate init for verde power gating
>   drm/radeon: implement clock and power gating for SI
>   drm/radeon/dpm: add an enum for pcie gen selection
>   drm/radeon/dpm: pull in phase shedding limits from atom
>   drm/radeon/dpm: endian fixes for extended power tables
>   drm/radeon/dpm: pull in ppm info from atom
>   drm/radeon/dpm: save some display parameters for DPM
>   drm/radeon: minor sid.h cleanup
>   drm: add some additional fixed point helpers (v2)
>   drm/radeon/dpm/cayman: use new fixed point functions
>   drm/radeon: fix some memory leaks in extended table parsing
>   drm/radeon/dpm: validate voltages against dispclk requirements
>   drm/radeon: update radeon_atombios_get_default_voltages for mvdd
>   drm/radeon/dpm: add pcie gen helper function
>   drm/radeon: fix typo in atom voltage table handling (6xx-ni)
>   drm/radeon: fix typo in atom voltage table handling (si+)
>   drm/radeon/atom: fix voltage table parsing
>   drm/radeon/dpm/ni: properly catch errors in dpm setup
>   drm/radeon/dpm/btc: properly catch errors in dpm setup
>   drm/radeon/dpm/evergreen: properly catch errors in dpm setup
>   drm/radeon/dpm/sumo: properly catch errors in dpm setup
>   drm/radeon/dpm/trinity: properly catch errors in dpm setup
>   drm/radeon/dpm/r7xx: properly catch errors in dpm setup
>   drm/radeon/dpm/r6xx: properly catch errors in dpm setup
>   drm/radeon/dpm/rs780: properly catch errors in dpm setup
>   drm/radeon: add SI to r600_is_internal_thermal_sensor()
>   drm/radeon: switch SI to use radeon_ucode.h
>   drm/radeon/kms: add dpm support for SI (v3)
>   drm/radeon/dpm: add dpm_enable failure output (7xx-ni)
>   drm/radeon/dpm: add dpm_enable failure output (si)
>   drm/radeon/dpm: add dpm_set_power_state failure output (7xx-ni)
>   drm/radeon/dpm: add dpm_set_power_state failure output (si)
>   drm/radeon/dpm: fix typo in setting uvd clock
>   drm/radeon/si: fix typo in function name
>   drm/radeon: fix typo in cik_select_se_sh()
>   drm/radeon: fix typo in ni_print_power_state
>   drm/radeon/dpm: add support for setting UVD clock on rs780
>   drm/radeon/dpm: add support for setting UVD clock on rv6xx
>   drm/radeon/dpm: fix UVD clock setting on cayman
>   drm/radeon/dpm: fix UVD clock setting on SI
>   drm/radeon: fix endian issues in atombios dpm code
> 
> Christian König (1):
>   drm/radeon: add UVD support for CIK (v3)
> 
>  drivers/gpu/drm/radeon/Makefile               |    5 +-
>  drivers/gpu/drm/radeon/ObjectID.h             |   40 +
>  drivers/gpu/drm/radeon/atombios.h             |  547 ++-
>  drivers/gpu/drm/radeon/atombios_crtc.c        |   88 +-
>  drivers/gpu/drm/radeon/atombios_encoders.c    |   51 +-
>  drivers/gpu/drm/radeon/btc_dpm.c              | 2731 ++++++++++
>  drivers/gpu/drm/radeon/btc_dpm.h              |   57 +
>  drivers/gpu/drm/radeon/btcd.h                 |  181 +
>  drivers/gpu/drm/radeon/cik.c                  | 6995 +++++++++++++++++++++++++
>  drivers/gpu/drm/radeon/cik_blit_shaders.c     |  246 +
>  drivers/gpu/drm/radeon/cik_blit_shaders.h     |   32 +
>  drivers/gpu/drm/radeon/cik_reg.h              |  147 +
>  drivers/gpu/drm/radeon/cikd.h                 | 1297 +++++
>  drivers/gpu/drm/radeon/clearstate_cayman.h    | 1081 ++++
>  drivers/gpu/drm/radeon/clearstate_defs.h      |   44 +
>  drivers/gpu/drm/radeon/clearstate_evergreen.h | 1080 ++++
>  drivers/gpu/drm/radeon/clearstate_si.h        |  941 ++++
>  drivers/gpu/drm/radeon/cypress_dpm.c          | 2170 ++++++++
>  drivers/gpu/drm/radeon/cypress_dpm.h          |  160 +
>  drivers/gpu/drm/radeon/evergreen.c            |  644 +++-
>  drivers/gpu/drm/radeon/evergreen_hdmi.c       |   11 +-
>  drivers/gpu/drm/radeon/evergreen_reg.h        |   12 +
>  drivers/gpu/drm/radeon/evergreen_smc.h        |   67 +
>  drivers/gpu/drm/radeon/evergreend.h           |  389 ++-
>  drivers/gpu/drm/radeon/ni.c                   |  198 +-
>  drivers/gpu/drm/radeon/ni_dpm.c               | 4288 +++++++++++++++
>  drivers/gpu/drm/radeon/ni_dpm.h               |  248 +
>  drivers/gpu/drm/radeon/nid.h                  |  561 ++
>  drivers/gpu/drm/radeon/nislands_smc.h         |  329 ++
>  drivers/gpu/drm/radeon/ppsmc.h                |  110 +
>  drivers/gpu/drm/radeon/r600.c                 |  147 +-
>  drivers/gpu/drm/radeon/r600_dpm.c             | 1024 ++++
>  drivers/gpu/drm/radeon/r600_dpm.h             |  226 +
>  drivers/gpu/drm/radeon/r600_hdmi.c            |   11 +-
>  drivers/gpu/drm/radeon/r600_reg.h             |    6 +
>  drivers/gpu/drm/radeon/r600d.h                |  232 +-
>  drivers/gpu/drm/radeon/radeon.h               |  517 ++-
>  drivers/gpu/drm/radeon/radeon_acpi.c          |  145 +
>  drivers/gpu/drm/radeon/radeon_asic.c          |  524 ++-
>  drivers/gpu/drm/radeon/radeon_asic.h          |  166 +
>  drivers/gpu/drm/radeon/radeon_atombios.c      |  880 +++-
>  drivers/gpu/drm/radeon/radeon_cs.c            |    1 +
>  drivers/gpu/drm/radeon/radeon_cursor.c        |   10 +-
>  drivers/gpu/drm/radeon/radeon_device.c        |  106 +-
>  drivers/gpu/drm/radeon/radeon_display.c       |   21 +-
>  drivers/gpu/drm/radeon/radeon_drv.c           |    7 +-
>  drivers/gpu/drm/radeon/radeon_family.h        |    3 +
>  drivers/gpu/drm/radeon/radeon_irq_kms.c       |   20 +
>  drivers/gpu/drm/radeon/radeon_kms.c           |   41 +-
>  drivers/gpu/drm/radeon/radeon_mode.h          |   93 +
>  drivers/gpu/drm/radeon/radeon_pm.c            |  610 ++-
>  drivers/gpu/drm/radeon/radeon_reg.h           |    1 +
>  drivers/gpu/drm/radeon/radeon_ring.c          |   55 +-
>  drivers/gpu/drm/radeon/radeon_ucode.h         |  129 +
>  drivers/gpu/drm/radeon/radeon_uvd.c           |   32 +-
>  drivers/gpu/drm/radeon/rs690.c                |  291 +-
>  drivers/gpu/drm/radeon/rs780_dpm.c            |  963 ++++
>  drivers/gpu/drm/radeon/rs780_dpm.h            |  109 +
>  drivers/gpu/drm/radeon/rs780d.h               |  168 +
>  drivers/gpu/drm/radeon/rv515.c                |  224 +-
>  drivers/gpu/drm/radeon/rv6xx_dpm.c            | 2059 ++++++++
>  drivers/gpu/drm/radeon/rv6xx_dpm.h            |   95 +
>  drivers/gpu/drm/radeon/rv6xxd.h               |  246 +
>  drivers/gpu/drm/radeon/rv730_dpm.c            |  508 ++
>  drivers/gpu/drm/radeon/rv730d.h               |  165 +
>  drivers/gpu/drm/radeon/rv740_dpm.c            |  416 ++
>  drivers/gpu/drm/radeon/rv740d.h               |  117 +
>  drivers/gpu/drm/radeon/rv770_dpm.c            | 2446 +++++++++
>  drivers/gpu/drm/radeon/rv770_dpm.h            |  287 +
>  drivers/gpu/drm/radeon/rv770_smc.c            |  621 +++
>  drivers/gpu/drm/radeon/rv770_smc.h            |  209 +
>  drivers/gpu/drm/radeon/rv770d.h               |  279 +-
>  drivers/gpu/drm/radeon/si.c                   | 1337 +++++-
>  drivers/gpu/drm/radeon/si_dpm.c               | 6369 ++++++++++++++++++++++
>  drivers/gpu/drm/radeon/si_dpm.h               |  227 +
>  drivers/gpu/drm/radeon/si_smc.c               |  284 +
>  drivers/gpu/drm/radeon/sid.h                  |  599 ++-
>  drivers/gpu/drm/radeon/sislands_smc.h         |  397 ++
>  drivers/gpu/drm/radeon/sumo_dpm.c             | 1801 +++++++
>  drivers/gpu/drm/radeon/sumo_dpm.h             |  220 +
>  drivers/gpu/drm/radeon/sumo_smc.c             |  222 +
>  drivers/gpu/drm/radeon/sumod.h                |  372 ++
>  drivers/gpu/drm/radeon/trinity_dpm.c          | 1887 +++++++
>  drivers/gpu/drm/radeon/trinity_dpm.h          |  131 +
>  drivers/gpu/drm/radeon/trinity_smc.c          |  115 +
>  drivers/gpu/drm/radeon/trinityd.h             |  228 +
>  include/drm/drm_fixed.h                       |   96 +
>  include/drm/drm_pciids.h                      |   24 +
>  88 files changed, 52708 insertions(+), 561 deletions(-)
>  create mode 100644 drivers/gpu/drm/radeon/btc_dpm.c
>  create mode 100644 drivers/gpu/drm/radeon/btc_dpm.h
>  create mode 100644 drivers/gpu/drm/radeon/btcd.h
>  create mode 100644 drivers/gpu/drm/radeon/cik.c
>  create mode 100644 drivers/gpu/drm/radeon/cik_blit_shaders.c
>  create mode 100644 drivers/gpu/drm/radeon/cik_blit_shaders.h
>  create mode 100644 drivers/gpu/drm/radeon/cik_reg.h
>  create mode 100644 drivers/gpu/drm/radeon/cikd.h
>  create mode 100644 drivers/gpu/drm/radeon/clearstate_cayman.h
>  create mode 100644 drivers/gpu/drm/radeon/clearstate_defs.h
>  create mode 100644 drivers/gpu/drm/radeon/clearstate_evergreen.h
>  create mode 100644 drivers/gpu/drm/radeon/clearstate_si.h
>  create mode 100644 drivers/gpu/drm/radeon/cypress_dpm.c
>  create mode 100644 drivers/gpu/drm/radeon/cypress_dpm.h
>  create mode 100644 drivers/gpu/drm/radeon/evergreen_smc.h
>  create mode 100644 drivers/gpu/drm/radeon/ni_dpm.c
>  create mode 100644 drivers/gpu/drm/radeon/ni_dpm.h
>  create mode 100644 drivers/gpu/drm/radeon/nislands_smc.h
>  create mode 100644 drivers/gpu/drm/radeon/ppsmc.h
>  create mode 100644 drivers/gpu/drm/radeon/r600_dpm.c
>  create mode 100644 drivers/gpu/drm/radeon/r600_dpm.h
>  create mode 100644 drivers/gpu/drm/radeon/radeon_ucode.h
>  create mode 100644 drivers/gpu/drm/radeon/rs780_dpm.c
>  create mode 100644 drivers/gpu/drm/radeon/rs780_dpm.h
>  create mode 100644 drivers/gpu/drm/radeon/rs780d.h
>  create mode 100644 drivers/gpu/drm/radeon/rv6xx_dpm.c
>  create mode 100644 drivers/gpu/drm/radeon/rv6xx_dpm.h
>  create mode 100644 drivers/gpu/drm/radeon/rv6xxd.h
>  create mode 100644 drivers/gpu/drm/radeon/rv730_dpm.c
>  create mode 100644 drivers/gpu/drm/radeon/rv730d.h
>  create mode 100644 drivers/gpu/drm/radeon/rv740_dpm.c
>  create mode 100644 drivers/gpu/drm/radeon/rv740d.h
>  create mode 100644 drivers/gpu/drm/radeon/rv770_dpm.c
>  create mode 100644 drivers/gpu/drm/radeon/rv770_dpm.h
>  create mode 100644 drivers/gpu/drm/radeon/rv770_smc.c
>  create mode 100644 drivers/gpu/drm/radeon/rv770_smc.h
>  create mode 100644 drivers/gpu/drm/radeon/si_dpm.c
>  create mode 100644 drivers/gpu/drm/radeon/si_dpm.h
>  create mode 100644 drivers/gpu/drm/radeon/si_smc.c
>  create mode 100644 drivers/gpu/drm/radeon/sislands_smc.h
>  create mode 100644 drivers/gpu/drm/radeon/sumo_dpm.c
>  create mode 100644 drivers/gpu/drm/radeon/sumo_dpm.h
>  create mode 100644 drivers/gpu/drm/radeon/sumo_smc.c
>  create mode 100644 drivers/gpu/drm/radeon/sumod.h
>  create mode 100644 drivers/gpu/drm/radeon/trinity_dpm.c
>  create mode 100644 drivers/gpu/drm/radeon/trinity_dpm.h
>  create mode 100644 drivers/gpu/drm/radeon/trinity_smc.c
>  create mode 100644 drivers/gpu/drm/radeon/trinityd.h
> 
> -- 
> 1.7.7.5
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 051/165] drm/radeon: implement simple doorbell page allocator
  2013-06-26 13:22 ` [PATCH 051/165] drm/radeon: implement simple doorbell page allocator alexdeucher
@ 2013-06-26 12:57   ` Jerome Glisse
  2013-06-26 18:38     ` Alex Deucher
  0 siblings, 1 reply; 142+ messages in thread
From: Jerome Glisse @ 2013-06-26 12:57 UTC (permalink / raw)
  To: alexdeucher; +Cc: Alex Deucher, dri-devel

On Wed, Jun 26, 2013 at 09:22:11AM -0400, alexdeucher@gmail.com wrote:
> From: Alex Deucher <alexander.deucher@amd.com>
> 
> The doorbell aperture is a PCI BAR whose pages can be
> mapped to compute resources for things like wptrs
> for userspace queues.
> 
> This patch maps the BAR and sets up a simple allocator
> to allocate pages from the BAR.

This doorbell stuff is cryptic, is that some memory on the GPU ? Or is it
more like a register file ? ie what is backing the pci bar.

Also probably want to use bitmap as i dont think gcc will turn bool array
into a bitmap.

Cheers,
Jerome

> 
> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
> ---
>  drivers/gpu/drm/radeon/cik.c           |   38 +++++++++++++
>  drivers/gpu/drm/radeon/radeon.h        |   21 +++++++
>  drivers/gpu/drm/radeon/radeon_device.c |   94 ++++++++++++++++++++++++++++++++
>  3 files changed, 153 insertions(+), 0 deletions(-)
> 
> diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
> index bb7dbc4..5c28fa5 100644
> --- a/drivers/gpu/drm/radeon/cik.c
> +++ b/drivers/gpu/drm/radeon/cik.c
> @@ -121,6 +121,44 @@ u32 cik_get_xclk(struct radeon_device *rdev)
>  	return reference_clock;
>  }
>  
> +/**
> + * cik_mm_rdoorbell - read a doorbell dword
> + *
> + * @rdev: radeon_device pointer
> + * @offset: byte offset into the aperture
> + *
> + * Returns the value in the doorbell aperture at the
> + * requested offset (CIK).
> + */
> +u32 cik_mm_rdoorbell(struct radeon_device *rdev, u32 offset)
> +{
> +	if (offset < rdev->doorbell.size) {
> +		return readl(((void __iomem *)rdev->doorbell.ptr) + offset);
> +	} else {
> +		DRM_ERROR("reading beyond doorbell aperture: 0x%08x!\n", offset);
> +		return 0;
> +	}
> +}
> +
> +/**
> + * cik_mm_wdoorbell - write a doorbell dword
> + *
> + * @rdev: radeon_device pointer
> + * @offset: byte offset into the aperture
> + * @v: value to write
> + *
> + * Writes @v to the doorbell aperture at the
> + * requested offset (CIK).
> + */
> +void cik_mm_wdoorbell(struct radeon_device *rdev, u32 offset, u32 v)
> +{
> +	if (offset < rdev->doorbell.size) {
> +		writel(v, ((void __iomem *)rdev->doorbell.ptr) + offset);
> +	} else {
> +		DRM_ERROR("writing beyond doorbell aperture: 0x%08x!\n", offset);
> +	}
> +}
> +
>  #define BONAIRE_IO_MC_REGS_SIZE 36
>  
>  static const u32 bonaire_io_mc_regs[BONAIRE_IO_MC_REGS_SIZE][2] =
> diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
> index ad4e68a..a2a3430 100644
> --- a/drivers/gpu/drm/radeon/radeon.h
> +++ b/drivers/gpu/drm/radeon/radeon.h
> @@ -556,6 +556,20 @@ struct radeon_scratch {
>  int radeon_scratch_get(struct radeon_device *rdev, uint32_t *reg);
>  void radeon_scratch_free(struct radeon_device *rdev, uint32_t reg);
>  
> +/*
> + * GPU doorbell structures, functions & helpers
> + */
> +struct radeon_doorbell {
> +	u32			num_pages;
> +	bool			free[1024];
> +	/* doorbell mmio */
> +	resource_size_t			base;
> +	resource_size_t			size;
> +	void __iomem			*ptr;
> +};
> +
> +int radeon_doorbell_get(struct radeon_device *rdev, u32 *page);
> +void radeon_doorbell_free(struct radeon_device *rdev, u32 doorbell);
>  
>  /*
>   * IRQS.
> @@ -1711,6 +1725,7 @@ struct radeon_device {
>  	struct radeon_gart		gart;
>  	struct radeon_mode_info		mode_info;
>  	struct radeon_scratch		scratch;
> +	struct radeon_doorbell		doorbell;
>  	struct radeon_mman		mman;
>  	struct radeon_fence_driver	fence_drv[RADEON_NUM_RINGS];
>  	wait_queue_head_t		fence_queue;
> @@ -1784,6 +1799,9 @@ void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v,
>  u32 r100_io_rreg(struct radeon_device *rdev, u32 reg);
>  void r100_io_wreg(struct radeon_device *rdev, u32 reg, u32 v);
>  
> +u32 cik_mm_rdoorbell(struct radeon_device *rdev, u32 offset);
> +void cik_mm_wdoorbell(struct radeon_device *rdev, u32 offset, u32 v);
> +
>  /*
>   * Cast helper
>   */
> @@ -1833,6 +1851,9 @@ void r100_io_wreg(struct radeon_device *rdev, u32 reg, u32 v);
>  #define RREG32_IO(reg) r100_io_rreg(rdev, (reg))
>  #define WREG32_IO(reg, v) r100_io_wreg(rdev, (reg), (v))
>  
> +#define RDOORBELL32(offset) cik_mm_rdoorbell(rdev, (offset))
> +#define WDOORBELL32(offset, v) cik_mm_wdoorbell(rdev, (offset), (v))
> +
>  /*
>   * Indirect registers accessor
>   */
> diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
> index 4e97ff7..82335e3 100644
> --- a/drivers/gpu/drm/radeon/radeon_device.c
> +++ b/drivers/gpu/drm/radeon/radeon_device.c
> @@ -232,6 +232,94 @@ void radeon_scratch_free(struct radeon_device *rdev, uint32_t reg)
>  }
>  
>  /*
> + * GPU doorbell aperture helpers function.
> + */
> +/**
> + * radeon_doorbell_init - Init doorbell driver information.
> + *
> + * @rdev: radeon_device pointer
> + *
> + * Init doorbell driver information (CIK)
> + * Returns 0 on success, error on failure.
> + */
> +int radeon_doorbell_init(struct radeon_device *rdev)
> +{
> +	int i;
> +
> +	/* doorbell bar mapping */
> +	rdev->doorbell.base = pci_resource_start(rdev->pdev, 2);
> +	rdev->doorbell.size = pci_resource_len(rdev->pdev, 2);
> +
> +	/* limit to 4 MB for now */
> +	if (rdev->doorbell.size > (4 * 1024 * 1024))
> +		rdev->doorbell.size = 4 * 1024 * 1024;
> +
> +	rdev->doorbell.ptr = ioremap(rdev->doorbell.base, rdev->doorbell.size);
> +	if (rdev->doorbell.ptr == NULL) {
> +		return -ENOMEM;
> +	}
> +	DRM_INFO("doorbell mmio base: 0x%08X\n", (uint32_t)rdev->doorbell.base);
> +	DRM_INFO("doorbell mmio size: %u\n", (unsigned)rdev->doorbell.size);
> +
> +	rdev->doorbell.num_pages = rdev->doorbell.size / PAGE_SIZE;
> +
> +	for (i = 0; i < rdev->doorbell.num_pages; i++) {
> +		rdev->doorbell.free[i] = true;
> +	}
> +	return 0;
> +}
> +
> +/**
> + * radeon_doorbell_fini - Tear down doorbell driver information.
> + *
> + * @rdev: radeon_device pointer
> + *
> + * Tear down doorbell driver information (CIK)
> + */
> +void radeon_doorbell_fini(struct radeon_device *rdev)
> +{
> +	iounmap(rdev->doorbell.ptr);
> +	rdev->doorbell.ptr = NULL;
> +}
> +
> +/**
> + * radeon_doorbell_get - Allocate a doorbell page
> + *
> + * @rdev: radeon_device pointer
> + * @doorbell: doorbell page number
> + *
> + * Allocate a doorbell page for use by the driver (all asics).
> + * Returns 0 on success or -EINVAL on failure.
> + */
> +int radeon_doorbell_get(struct radeon_device *rdev, u32 *doorbell)
> +{
> +	int i;
> +
> +	for (i = 0; i < rdev->doorbell.num_pages; i++) {
> +		if (rdev->doorbell.free[i]) {
> +			rdev->doorbell.free[i] = false;
> +			*doorbell = i;
> +			return 0;
> +		}
> +	}
> +	return -EINVAL;
> +}
> +
> +/**
> + * radeon_doorbell_free - Free a doorbell page
> + *
> + * @rdev: radeon_device pointer
> + * @doorbell: doorbell page number
> + *
> + * Free a doorbell page allocated for use by the driver (all asics)
> + */
> +void radeon_doorbell_free(struct radeon_device *rdev, u32 doorbell)
> +{
> +	if (doorbell < rdev->doorbell.num_pages)
> +		rdev->doorbell.free[doorbell] = true;
> +}
> +
> +/*
>   * radeon_wb_*()
>   * Writeback is the the method by which the the GPU updates special pages
>   * in memory with the status of certain GPU events (fences, ring pointers,
> @@ -1162,6 +1250,10 @@ int radeon_device_init(struct radeon_device *rdev,
>  	DRM_INFO("register mmio base: 0x%08X\n", (uint32_t)rdev->rmmio_base);
>  	DRM_INFO("register mmio size: %u\n", (unsigned)rdev->rmmio_size);
>  
> +	/* doorbell bar mapping */
> +	if (rdev->family >= CHIP_BONAIRE)
> +		radeon_doorbell_init(rdev);
> +
>  	/* io port mapping */
>  	for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
>  		if (pci_resource_flags(rdev->pdev, i) & IORESOURCE_IO) {
> @@ -1239,6 +1331,8 @@ void radeon_device_fini(struct radeon_device *rdev)
>  	rdev->rio_mem = NULL;
>  	iounmap(rdev->rmmio);
>  	rdev->rmmio = NULL;
> +	if (rdev->family >= CHIP_BONAIRE)
> +		radeon_doorbell_fini(rdev);
>  	radeon_debugfs_remove_files(rdev);
>  }
>  
> -- 
> 1.7.7.5
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 075/165] drm/radeon/kms: add dpm support for rs780/rs880
  2013-06-26 18:19     ` Alex Deucher
@ 2013-06-26 13:18       ` Jerome Glisse
  2013-06-26 18:41         ` Alex Deucher
  0 siblings, 1 reply; 142+ messages in thread
From: Jerome Glisse @ 2013-06-26 13:18 UTC (permalink / raw)
  To: Alex Deucher; +Cc: Alex Deucher, dri-devel

On Wed, Jun 26, 2013 at 02:19:23PM -0400, Alex Deucher wrote:
> On Wed, Jun 26, 2013 at 6:46 AM, Jerome Glisse <j.glisse@gmail.com> wrote:
> > On Wed, Jun 26, 2013 at 09:22:35AM -0400, alexdeucher@gmail.com wrote:
> >> From: Alex Deucher <alexander.deucher@amd.com>
> >>
> >> This adds dpm support for rs780/rs880 asics.  This includes:
> >> - clockgating
> >> - dynamic engine clock scaling
> >> - dynamic voltage scaling
> >>
> >> set radeon.dpm=1 to enable it.
> >>
> >> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
> >
> > Depending on the answer to inline question :
> >
> > Reviewed-by: Jerome Glisse <jglisse@redhat.com>
> >
> >> ---
> >>  drivers/gpu/drm/radeon/Makefile      |    2 +-
> >>  drivers/gpu/drm/radeon/radeon_asic.c |   12 +
> >>  drivers/gpu/drm/radeon/radeon_asic.h |   12 +
> >>  drivers/gpu/drm/radeon/radeon_pm.c   |    7 +
> >>  drivers/gpu/drm/radeon/rs780_dpm.c   |  894 ++++++++++++++++++++++++++++++++++
> >>  drivers/gpu/drm/radeon/rs780_dpm.h   |  109 ++++
> >>  drivers/gpu/drm/radeon/rs780d.h      |  168 +++++++
> >>  7 files changed, 1203 insertions(+), 1 deletions(-)
> >>  create mode 100644 drivers/gpu/drm/radeon/rs780_dpm.c
> >>  create mode 100644 drivers/gpu/drm/radeon/rs780_dpm.h
> >>  create mode 100644 drivers/gpu/drm/radeon/rs780d.h
> >>
> >> diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile
> >> index a131a13..e44b046 100644
> >> --- a/drivers/gpu/drm/radeon/Makefile
> >> +++ b/drivers/gpu/drm/radeon/Makefile
> >> @@ -77,7 +77,7 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \
> >>       evergreen_hdmi.o radeon_trace_points.o ni.o cayman_blit_shaders.o \
> >>       atombios_encoders.o radeon_semaphore.o radeon_sa.o atombios_i2c.o si.o \
> >>       si_blit_shaders.o radeon_prime.o radeon_uvd.o cik.o cik_blit_shaders.o \
> >> -     r600_dpm.o
> >> +     r600_dpm.o rs780_dpm.o
> >>
> >>  radeon-$(CONFIG_COMPAT) += radeon_ioc32.o
> >>  radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o
> >> diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c
> >> index d9c8e9a..db3c930 100644
> >> --- a/drivers/gpu/drm/radeon/radeon_asic.c
> >> +++ b/drivers/gpu/drm/radeon/radeon_asic.c
> >> @@ -1194,6 +1194,18 @@ static struct radeon_asic rs780_asic = {
> >>               .set_clock_gating = NULL,
> >>               .get_temperature = &rv6xx_get_temp,
> >>       },
> >> +     .dpm = {
> >> +             .init = &rs780_dpm_init,
> >> +             .setup_asic = &rs780_dpm_setup_asic,
> >> +             .enable = &rs780_dpm_enable,
> >> +             .disable = &rs780_dpm_disable,
> >> +             .set_power_state = &rs780_dpm_set_power_state,
> >> +             .display_configuration_changed = &rs780_dpm_display_configuration_changed,
> >> +             .fini = &rs780_dpm_fini,
> >> +             .get_sclk = &rs780_dpm_get_sclk,
> >> +             .get_mclk = &rs780_dpm_get_mclk,
> >> +             .print_power_state = &rs780_dpm_print_power_state,
> >> +     },
> >>       .pflip = {
> >>               .pre_page_flip = &rs600_pre_page_flip,
> >>               .page_flip = &rs600_page_flip,
> >> diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
> >> index 8507cae..134bf57 100644
> >> --- a/drivers/gpu/drm/radeon/radeon_asic.h
> >> +++ b/drivers/gpu/drm/radeon/radeon_asic.h
> >> @@ -396,6 +396,18 @@ int r600_mc_wait_for_idle(struct radeon_device *rdev);
> >>  u32 r600_get_xclk(struct radeon_device *rdev);
> >>  uint64_t r600_get_gpu_clock_counter(struct radeon_device *rdev);
> >>  int rv6xx_get_temp(struct radeon_device *rdev);
> >> +/* rs780 dpm */
> >> +int rs780_dpm_init(struct radeon_device *rdev);
> >> +int rs780_dpm_enable(struct radeon_device *rdev);
> >> +void rs780_dpm_disable(struct radeon_device *rdev);
> >> +int rs780_dpm_set_power_state(struct radeon_device *rdev);
> >> +void rs780_dpm_setup_asic(struct radeon_device *rdev);
> >> +void rs780_dpm_display_configuration_changed(struct radeon_device *rdev);
> >> +void rs780_dpm_fini(struct radeon_device *rdev);
> >> +u32 rs780_dpm_get_sclk(struct radeon_device *rdev, bool low);
> >> +u32 rs780_dpm_get_mclk(struct radeon_device *rdev, bool low);
> >> +void rs780_dpm_print_power_state(struct radeon_device *rdev,
> >> +                              struct radeon_ps *ps);
> >>
> >>  /* uvd */
> >>  int r600_uvd_init(struct radeon_device *rdev);
> >> diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
> >> index 4f5422e..853a8a2 100644
> >> --- a/drivers/gpu/drm/radeon/radeon_pm.c
> >> +++ b/drivers/gpu/drm/radeon/radeon_pm.c
> >> @@ -1030,6 +1030,13 @@ int radeon_pm_init(struct radeon_device *rdev)
> >>  {
> >>       /* enable dpm on rv6xx+ */
> >>       switch (rdev->family) {
> >> +     case CHIP_RS780:
> >> +     case CHIP_RS880:
> >> +             if (radeon_dpm == 1)
> >> +                     rdev->pm.pm_method = PM_METHOD_DPM;
> >> +             else
> >> +                     rdev->pm.pm_method = PM_METHOD_PROFILE;
> >> +             break;
> >>       default:
> >>               /* default to profile method */
> >>               rdev->pm.pm_method = PM_METHOD_PROFILE;
> >> diff --git a/drivers/gpu/drm/radeon/rs780_dpm.c b/drivers/gpu/drm/radeon/rs780_dpm.c
> >> new file mode 100644
> >> index 0000000..f594900
> >> --- /dev/null
> >> +++ b/drivers/gpu/drm/radeon/rs780_dpm.c
> >> @@ -0,0 +1,894 @@
> >> +/*
> >> + * Copyright 2011 Advanced Micro Devices, Inc.
> >> + *
> >> + * Permission is hereby granted, free of charge, to any person obtaining a
> >> + * copy of this software and associated documentation files (the "Software"),
> >> + * to deal in the Software without restriction, including without limitation
> >> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> >> + * and/or sell copies of the Software, and to permit persons to whom the
> >> + * Software is furnished to do so, subject to the following conditions:
> >> + *
> >> + * The above copyright notice and this permission notice shall be included in
> >> + * all copies or substantial portions of the Software.
> >> + *
> >> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> >> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> >> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> >> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> >> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> >> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> >> + * OTHER DEALINGS IN THE SOFTWARE.
> >> + *
> >> + * Authors: Alex Deucher
> >> + */
> >> +
> >> +#include "drmP.h"
> >> +#include "radeon.h"
> >> +#include "rs780d.h"
> >> +#include "r600_dpm.h"
> >> +#include "rs780_dpm.h"
> >> +#include "atom.h"
> >> +
> >> +static struct igp_ps *rs780_get_ps(struct radeon_ps *rps)
> >> +{
> >> +     struct igp_ps *ps = rps->ps_priv;
> >> +
> >> +     return ps;
> >> +}
> >> +
> >> +static struct igp_power_info *rs780_get_pi(struct radeon_device *rdev)
> >> +{
> >> +     struct igp_power_info *pi = rdev->pm.dpm.priv;
> >> +
> >> +     return pi;
> >> +}
> >> +
> >> +static void rs780_get_pm_mode_parameters(struct radeon_device *rdev)
> >> +{
> >> +     struct igp_power_info *pi = rs780_get_pi(rdev);
> >> +     struct radeon_mode_info *minfo = &rdev->mode_info;
> >> +     struct drm_crtc *crtc;
> >> +     struct radeon_crtc *radeon_crtc;
> >> +     int i;
> >> +
> >> +     /* defaults */
> >> +     pi->crtc_id = 0;
> >> +     pi->refresh_rate = 60;
> >> +
> >> +     for (i = 0; i < rdev->num_crtc; i++) {
> >> +             crtc = (struct drm_crtc *)minfo->crtcs[i];
> >> +             if (crtc && crtc->enabled) {
> >> +                     radeon_crtc = to_radeon_crtc(crtc);
> >> +                     pi->crtc_id = radeon_crtc->crtc_id;
> >> +                     if (crtc->mode.htotal && crtc->mode.vtotal)
> >> +                             pi->refresh_rate =
> >> +                                     (crtc->mode.clock * 1000) /
> >> +                                     (crtc->mode.htotal * crtc->mode.vtotal);
> >> +                     break;
> >> +             }
> >> +     }
> >
> > Ok this looks wrong to me you look for the first enabled crtc but on those iirc
> > there could be 2 so first one might be a low refresh rate and second one an higher
> > one. Thus returning the first one might lead to PM decision that are wrong.
> >

So what happens when 2 are active ? Flickering on the unsync one ?

Cheers,
Jerome

> 
> On RS780/RS880, the hardware can only synchronize with a single crtc,
> so it doesn't really matter which one we pick as long as it's active.
> 
> 
> >> +}
> >> +
> >> +static void rs780_voltage_scaling_enable(struct radeon_device *rdev, bool enable);
> >> +
> >> +static int rs780_initialize_dpm_power_state(struct radeon_device *rdev)
> >> +{
> >> +     struct atom_clock_dividers dividers;
> >> +     struct igp_ps *default_state = rs780_get_ps(rdev->pm.dpm.boot_ps);
> >> +     int i, ret;
> >> +
> >> +     ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
> >> +                                          default_state->sclk_low, false, &dividers);
> >> +     if (ret)
> >> +             return ret;
> >> +
> >> +     r600_engine_clock_entry_set_reference_divider(rdev, 0, dividers.ref_div);
> >> +     r600_engine_clock_entry_set_feedback_divider(rdev, 0, dividers.fb_div);
> >> +     r600_engine_clock_entry_set_post_divider(rdev, 0, dividers.post_div);
> >> +
> >> +     if (dividers.enable_post_div)
> >> +             r600_engine_clock_entry_enable_post_divider(rdev, 0, true);
> >> +     else
> >> +             r600_engine_clock_entry_enable_post_divider(rdev, 0, false);
> >> +
> >> +     r600_engine_clock_entry_set_step_time(rdev, 0, R600_SST_DFLT);
> >> +     r600_engine_clock_entry_enable_pulse_skipping(rdev, 0, false);
> >> +
> >> +     r600_engine_clock_entry_enable(rdev, 0, true);
> >> +     for (i = 1; i < R600_PM_NUMBER_OF_SCLKS; i++)
> >> +             r600_engine_clock_entry_enable(rdev, i, false);
> >> +
> >> +     r600_enable_mclk_control(rdev, false);
> >> +     r600_voltage_control_enable_pins(rdev, 0);
> >> +
> >> +     return 0;
> >> +}
> >> +
> >> +static int rs780_initialize_dpm_parameters(struct radeon_device *rdev)
> >> +{
> >> +     int ret = 0;
> >> +     int i;
> >> +
> >> +     r600_set_bsp(rdev, R600_BSU_DFLT, R600_BSP_DFLT);
> >> +
> >> +     r600_set_at(rdev, 0, 0, 0, 0);
> >> +
> >> +     r600_set_git(rdev, R600_GICST_DFLT);
> >> +
> >> +     for (i = 0; i < R600_PM_NUMBER_OF_TC; i++)
> >> +             r600_set_tc(rdev, i, 0, 0);
> >> +
> >> +     r600_select_td(rdev, R600_TD_DFLT);
> >> +     r600_set_vrc(rdev, 0);
> >> +
> >> +     r600_set_tpu(rdev, R600_TPU_DFLT);
> >> +     r600_set_tpc(rdev, R600_TPC_DFLT);
> >> +
> >> +     r600_set_sstu(rdev, R600_SSTU_DFLT);
> >> +     r600_set_sst(rdev, R600_SST_DFLT);
> >> +
> >> +     r600_set_fctu(rdev, R600_FCTU_DFLT);
> >> +     r600_set_fct(rdev, R600_FCT_DFLT);
> >> +
> >> +     r600_set_vddc3d_oorsu(rdev, R600_VDDC3DOORSU_DFLT);
> >> +     r600_set_vddc3d_oorphc(rdev, R600_VDDC3DOORPHC_DFLT);
> >> +     r600_set_vddc3d_oorsdc(rdev, R600_VDDC3DOORSDC_DFLT);
> >> +     r600_set_ctxcgtt3d_rphc(rdev, R600_CTXCGTT3DRPHC_DFLT);
> >> +     r600_set_ctxcgtt3d_rsdc(rdev, R600_CTXCGTT3DRSDC_DFLT);
> >> +
> >> +     r600_vid_rt_set_vru(rdev, R600_VRU_DFLT);
> >> +     r600_vid_rt_set_vrt(rdev, R600_VOLTAGERESPONSETIME_DFLT);
> >> +     r600_vid_rt_set_ssu(rdev, R600_SPLLSTEPUNIT_DFLT);
> >> +
> >> +     ret = rs780_initialize_dpm_power_state(rdev);
> >> +
> >> +     r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_LOW,     0);
> >> +     r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_MEDIUM,  0);
> >> +     r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_HIGH,    0);
> >> +
> >> +     r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_LOW,    0);
> >> +     r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_MEDIUM, 0);
> >> +     r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_HIGH,   0);
> >> +
> >> +     r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_LOW,    0);
> >> +     r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_MEDIUM, 0);
> >> +     r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_HIGH,   0);
> >> +
> >> +     r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_LOW,    R600_DISPLAY_WATERMARK_HIGH);
> >> +     r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_MEDIUM, R600_DISPLAY_WATERMARK_HIGH);
> >> +     r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_HIGH,   R600_DISPLAY_WATERMARK_HIGH);
> >> +
> >> +     r600_power_level_enable(rdev, R600_POWER_LEVEL_CTXSW, false);
> >> +     r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, false);
> >> +     r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, false);
> >> +     r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true);
> >> +
> >> +     r600_power_level_set_enter_index(rdev, R600_POWER_LEVEL_LOW);
> >> +
> >> +     r600_set_vrc(rdev, RS780_CGFTV_DFLT);
> >> +
> >> +     return ret;
> >> +}
> >> +
> >> +static void rs780_start_dpm(struct radeon_device *rdev)
> >> +{
> >> +     r600_enable_sclk_control(rdev, false);
> >> +     r600_enable_mclk_control(rdev, false);
> >> +
> >> +     r600_dynamicpm_enable(rdev, true);
> >> +
> >> +     radeon_wait_for_vblank(rdev, 0);
> >> +     radeon_wait_for_vblank(rdev, 1);
> >> +
> >> +     r600_enable_spll_bypass(rdev, true);
> >> +     r600_wait_for_spll_change(rdev);
> >> +     r600_enable_spll_bypass(rdev, false);
> >> +     r600_wait_for_spll_change(rdev);
> >> +
> >> +     r600_enable_spll_bypass(rdev, true);
> >> +     r600_wait_for_spll_change(rdev);
> >> +     r600_enable_spll_bypass(rdev, false);
> >> +     r600_wait_for_spll_change(rdev);
> >> +
> >> +     r600_enable_sclk_control(rdev, true);
> >> +}
> >> +
> >> +
> >> +static void rs780_preset_ranges_slow_clk_fbdiv_en(struct radeon_device *rdev)
> >> +{
> >> +     WREG32_P(FVTHROT_SLOW_CLK_FEEDBACK_DIV_REG1, RANGE_SLOW_CLK_FEEDBACK_DIV_EN,
> >> +              ~RANGE_SLOW_CLK_FEEDBACK_DIV_EN);
> >> +
> >> +     WREG32_P(FVTHROT_SLOW_CLK_FEEDBACK_DIV_REG1,
> >> +              RANGE0_SLOW_CLK_FEEDBACK_DIV(RS780_SLOWCLKFEEDBACKDIV_DFLT),
> >> +              ~RANGE0_SLOW_CLK_FEEDBACK_DIV_MASK);
> >> +}
> >> +
> >> +static void rs780_preset_starting_fbdiv(struct radeon_device *rdev)
> >> +{
> >> +     u32 fbdiv = (RREG32(CG_SPLL_FUNC_CNTL) & SPLL_FB_DIV_MASK) >> SPLL_FB_DIV_SHIFT;
> >> +
> >> +     WREG32_P(FVTHROT_FBDIV_REG1, STARTING_FEEDBACK_DIV(fbdiv),
> >> +              ~STARTING_FEEDBACK_DIV_MASK);
> >> +
> >> +     WREG32_P(FVTHROT_FBDIV_REG2, FORCED_FEEDBACK_DIV(fbdiv),
> >> +              ~FORCED_FEEDBACK_DIV_MASK);
> >> +
> >> +     WREG32_P(FVTHROT_FBDIV_REG1, FORCE_FEEDBACK_DIV, ~FORCE_FEEDBACK_DIV);
> >> +}
> >> +
> >> +static void rs780_voltage_scaling_init(struct radeon_device *rdev)
> >> +{
> >> +     struct igp_power_info *pi = rs780_get_pi(rdev);
> >> +     struct drm_device *dev = rdev->ddev;
> >> +     u32 fv_throt_pwm_fb_div_range[3];
> >> +     u32 fv_throt_pwm_range[4];
> >> +
> >> +     if (dev->pdev->device == 0x9614) {
> >> +             fv_throt_pwm_fb_div_range[0] = RS780D_FVTHROTPWMFBDIVRANGEREG0_DFLT;
> >> +             fv_throt_pwm_fb_div_range[1] = RS780D_FVTHROTPWMFBDIVRANGEREG1_DFLT;
> >> +             fv_throt_pwm_fb_div_range[2] = RS780D_FVTHROTPWMFBDIVRANGEREG2_DFLT;
> >> +     } else if ((dev->pdev->device == 0x9714) ||
> >> +                (dev->pdev->device == 0x9715)) {
> >> +             fv_throt_pwm_fb_div_range[0] = RS880D_FVTHROTPWMFBDIVRANGEREG0_DFLT;
> >> +             fv_throt_pwm_fb_div_range[1] = RS880D_FVTHROTPWMFBDIVRANGEREG1_DFLT;
> >> +             fv_throt_pwm_fb_div_range[2] = RS880D_FVTHROTPWMFBDIVRANGEREG2_DFLT;
> >> +     } else {
> >> +             fv_throt_pwm_fb_div_range[0] = RS780_FVTHROTPWMFBDIVRANGEREG0_DFLT;
> >> +             fv_throt_pwm_fb_div_range[1] = RS780_FVTHROTPWMFBDIVRANGEREG1_DFLT;
> >> +             fv_throt_pwm_fb_div_range[2] = RS780_FVTHROTPWMFBDIVRANGEREG2_DFLT;
> >> +     }
> >> +
> >> +     if (pi->pwm_voltage_control) {
> >> +             fv_throt_pwm_range[0] = pi->min_voltage;
> >> +             fv_throt_pwm_range[1] = pi->min_voltage;
> >> +             fv_throt_pwm_range[2] = pi->max_voltage;
> >> +             fv_throt_pwm_range[3] = pi->max_voltage;
> >> +     } else {
> >> +             fv_throt_pwm_range[0] = pi->invert_pwm_required ?
> >> +                     RS780_FVTHROTPWMRANGE3_GPIO_DFLT : RS780_FVTHROTPWMRANGE0_GPIO_DFLT;
> >> +             fv_throt_pwm_range[1] = pi->invert_pwm_required ?
> >> +                     RS780_FVTHROTPWMRANGE2_GPIO_DFLT : RS780_FVTHROTPWMRANGE1_GPIO_DFLT;
> >> +             fv_throt_pwm_range[2] = pi->invert_pwm_required ?
> >> +                     RS780_FVTHROTPWMRANGE1_GPIO_DFLT : RS780_FVTHROTPWMRANGE2_GPIO_DFLT;
> >> +             fv_throt_pwm_range[3] = pi->invert_pwm_required ?
> >> +                     RS780_FVTHROTPWMRANGE0_GPIO_DFLT : RS780_FVTHROTPWMRANGE3_GPIO_DFLT;
> >> +     }
> >> +
> >> +     WREG32_P(FVTHROT_PWM_CTRL_REG0,
> >> +              STARTING_PWM_HIGHTIME(pi->max_voltage),
> >> +              ~STARTING_PWM_HIGHTIME_MASK);
> >> +
> >> +     WREG32_P(FVTHROT_PWM_CTRL_REG0,
> >> +              NUMBER_OF_CYCLES_IN_PERIOD(pi->num_of_cycles_in_period),
> >> +              ~NUMBER_OF_CYCLES_IN_PERIOD_MASK);
> >> +
> >> +     WREG32_P(FVTHROT_PWM_CTRL_REG0, FORCE_STARTING_PWM_HIGHTIME,
> >> +              ~FORCE_STARTING_PWM_HIGHTIME);
> >> +
> >> +     if (pi->invert_pwm_required)
> >> +             WREG32_P(FVTHROT_PWM_CTRL_REG0, INVERT_PWM_WAVEFORM, ~INVERT_PWM_WAVEFORM);
> >> +     else
> >> +             WREG32_P(FVTHROT_PWM_CTRL_REG0, 0, ~INVERT_PWM_WAVEFORM);
> >> +
> >> +     rs780_voltage_scaling_enable(rdev, true);
> >> +
> >> +     WREG32(FVTHROT_PWM_CTRL_REG1,
> >> +            (MIN_PWM_HIGHTIME(pi->min_voltage) |
> >> +             MAX_PWM_HIGHTIME(pi->max_voltage)));
> >> +
> >> +     WREG32(FVTHROT_PWM_US_REG0, RS780_FVTHROTPWMUSREG0_DFLT);
> >> +     WREG32(FVTHROT_PWM_US_REG1, RS780_FVTHROTPWMUSREG1_DFLT);
> >> +     WREG32(FVTHROT_PWM_DS_REG0, RS780_FVTHROTPWMDSREG0_DFLT);
> >> +     WREG32(FVTHROT_PWM_DS_REG1, RS780_FVTHROTPWMDSREG1_DFLT);
> >> +
> >> +     WREG32_P(FVTHROT_PWM_FEEDBACK_DIV_REG1,
> >> +              RANGE0_PWM_FEEDBACK_DIV(fv_throt_pwm_fb_div_range[0]),
> >> +              ~RANGE0_PWM_FEEDBACK_DIV_MASK);
> >> +
> >> +     WREG32(FVTHROT_PWM_FEEDBACK_DIV_REG2,
> >> +            (RANGE1_PWM_FEEDBACK_DIV(fv_throt_pwm_fb_div_range[1]) |
> >> +             RANGE2_PWM_FEEDBACK_DIV(fv_throt_pwm_fb_div_range[2])));
> >> +
> >> +     WREG32(FVTHROT_PWM_FEEDBACK_DIV_REG3,
> >> +            (RANGE0_PWM(fv_throt_pwm_range[1]) |
> >> +             RANGE1_PWM(fv_throt_pwm_range[2])));
> >> +     WREG32(FVTHROT_PWM_FEEDBACK_DIV_REG4,
> >> +            (RANGE2_PWM(fv_throt_pwm_range[1]) |
> >> +             RANGE3_PWM(fv_throt_pwm_range[2])));
> >> +}
> >> +
> >> +static void rs780_clk_scaling_enable(struct radeon_device *rdev, bool enable)
> >> +{
> >> +     if (enable)
> >> +             WREG32_P(FVTHROT_CNTRL_REG, ENABLE_FV_THROT | ENABLE_FV_UPDATE,
> >> +                      ~(ENABLE_FV_THROT | ENABLE_FV_UPDATE));
> >> +     else
> >> +             WREG32_P(FVTHROT_CNTRL_REG, 0,
> >> +                      ~(ENABLE_FV_THROT | ENABLE_FV_UPDATE));
> >> +}
> >> +
> >> +static void rs780_voltage_scaling_enable(struct radeon_device *rdev, bool enable)
> >> +{
> >> +     if (enable)
> >> +             WREG32_P(FVTHROT_CNTRL_REG, ENABLE_FV_THROT_IO, ~ENABLE_FV_THROT_IO);
> >> +     else
> >> +             WREG32_P(FVTHROT_CNTRL_REG, 0, ~ENABLE_FV_THROT_IO);
> >> +}
> >> +
> >> +static void rs780_set_engine_clock_wfc(struct radeon_device *rdev)
> >> +{
> >> +     WREG32(FVTHROT_UTC0, RS780_FVTHROTUTC0_DFLT);
> >> +     WREG32(FVTHROT_UTC1, RS780_FVTHROTUTC1_DFLT);
> >> +     WREG32(FVTHROT_UTC2, RS780_FVTHROTUTC2_DFLT);
> >> +     WREG32(FVTHROT_UTC3, RS780_FVTHROTUTC3_DFLT);
> >> +     WREG32(FVTHROT_UTC4, RS780_FVTHROTUTC4_DFLT);
> >> +
> >> +     WREG32(FVTHROT_DTC0, RS780_FVTHROTDTC0_DFLT);
> >> +     WREG32(FVTHROT_DTC1, RS780_FVTHROTDTC1_DFLT);
> >> +     WREG32(FVTHROT_DTC2, RS780_FVTHROTDTC2_DFLT);
> >> +     WREG32(FVTHROT_DTC3, RS780_FVTHROTDTC3_DFLT);
> >> +     WREG32(FVTHROT_DTC4, RS780_FVTHROTDTC4_DFLT);
> >> +}
> >> +
> >> +static void rs780_set_engine_clock_sc(struct radeon_device *rdev)
> >> +{
> >> +     WREG32_P(FVTHROT_FBDIV_REG2,
> >> +              FB_DIV_TIMER_VAL(RS780_FBDIVTIMERVAL_DFLT),
> >> +              ~FB_DIV_TIMER_VAL_MASK);
> >> +
> >> +     WREG32_P(FVTHROT_CNTRL_REG,
> >> +              REFRESH_RATE_DIVISOR(0) | MINIMUM_CIP(0xf),
> >> +              ~(REFRESH_RATE_DIVISOR_MASK | MINIMUM_CIP_MASK));
> >> +}
> >> +
> >> +static void rs780_set_engine_clock_tdc(struct radeon_device *rdev)
> >> +{
> >> +     WREG32_P(FVTHROT_CNTRL_REG, 0, ~(FORCE_TREND_SEL | TREND_SEL_MODE));
> >> +}
> >> +
> >> +static void rs780_set_engine_clock_ssc(struct radeon_device *rdev)
> >> +{
> >> +     WREG32(FVTHROT_FB_US_REG0, RS780_FVTHROTFBUSREG0_DFLT);
> >> +     WREG32(FVTHROT_FB_US_REG1, RS780_FVTHROTFBUSREG1_DFLT);
> >> +     WREG32(FVTHROT_FB_DS_REG0, RS780_FVTHROTFBDSREG0_DFLT);
> >> +     WREG32(FVTHROT_FB_DS_REG1, RS780_FVTHROTFBDSREG1_DFLT);
> >> +
> >> +     WREG32_P(FVTHROT_FBDIV_REG1, MAX_FEEDBACK_STEP(1), ~MAX_FEEDBACK_STEP_MASK);
> >> +}
> >> +
> >> +static void rs780_program_at(struct radeon_device *rdev)
> >> +{
> >> +     struct igp_power_info *pi = rs780_get_pi(rdev);
> >> +
> >> +     WREG32(FVTHROT_TARGET_REG, 30000000 / pi->refresh_rate);
> >> +     WREG32(FVTHROT_CB1, 1000000 * 5 / pi->refresh_rate);
> >> +     WREG32(FVTHROT_CB2, 1000000 * 10 / pi->refresh_rate);
> >> +     WREG32(FVTHROT_CB3, 1000000 * 30 / pi->refresh_rate);
> >> +     WREG32(FVTHROT_CB4, 1000000 * 50 / pi->refresh_rate);
> >> +}
> >> +
> >> +static void rs780_disable_vbios_powersaving(struct radeon_device *rdev)
> >> +{
> >> +     WREG32_P(CG_INTGFX_MISC, 0, ~0xFFF00000);
> >> +}
> >> +
> >> +static void rs780_force_voltage_to_high(struct radeon_device *rdev)
> >> +{
> >> +     struct igp_power_info *pi = rs780_get_pi(rdev);
> >> +     struct igp_ps *current_state = rs780_get_ps(rdev->pm.dpm.current_ps);
> >> +
> >> +     if ((current_state->max_voltage == RS780_VDDC_LEVEL_HIGH) &&
> >> +         (current_state->min_voltage == RS780_VDDC_LEVEL_HIGH))
> >> +             return;
> >> +
> >> +     WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL);
> >> +
> >> +     udelay(1);
> >> +
> >> +     WREG32_P(FVTHROT_PWM_CTRL_REG0,
> >> +              STARTING_PWM_HIGHTIME(pi->max_voltage),
> >> +              ~STARTING_PWM_HIGHTIME_MASK);
> >> +
> >> +     WREG32_P(FVTHROT_PWM_CTRL_REG0,
> >> +              FORCE_STARTING_PWM_HIGHTIME, ~FORCE_STARTING_PWM_HIGHTIME);
> >> +
> >> +     WREG32_P(FVTHROT_PWM_FEEDBACK_DIV_REG1, 0,
> >> +             ~RANGE_PWM_FEEDBACK_DIV_EN);
> >> +
> >> +     udelay(1);
> >> +
> >> +     WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
> >> +}
> >> +
> >> +static int rs780_set_engine_clock_scaling(struct radeon_device *rdev)
> >> +{
> >> +     struct atom_clock_dividers min_dividers, max_dividers, current_max_dividers;
> >> +     struct igp_ps *new_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
> >> +     struct igp_ps *old_state = rs780_get_ps(rdev->pm.dpm.current_ps);
> >> +     int ret;
> >> +
> >> +     if ((new_state->sclk_high == old_state->sclk_high) &&
> >> +         (new_state->sclk_low == old_state->sclk_low))
> >> +             return 0;
> >> +
> >> +     ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
> >> +                                          new_state->sclk_low, false, &min_dividers);
> >> +     if (ret)
> >> +             return ret;
> >> +
> >> +     ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
> >> +                                          new_state->sclk_high, false, &max_dividers);
> >> +     if (ret)
> >> +             return ret;
> >> +
> >> +     ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
> >> +                                          old_state->sclk_high, false, &current_max_dividers);
> >> +     if (ret)
> >> +             return ret;
> >> +
> >> +     WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL);
> >> +
> >> +     WREG32_P(FVTHROT_FBDIV_REG2, FORCED_FEEDBACK_DIV(max_dividers.fb_div),
> >> +              ~FORCED_FEEDBACK_DIV_MASK);
> >> +     WREG32_P(FVTHROT_FBDIV_REG1, STARTING_FEEDBACK_DIV(max_dividers.fb_div),
> >> +              ~STARTING_FEEDBACK_DIV_MASK);
> >> +     WREG32_P(FVTHROT_FBDIV_REG1, FORCE_FEEDBACK_DIV, ~FORCE_FEEDBACK_DIV);
> >> +
> >> +     udelay(100);
> >> +
> >> +     WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
> >> +
> >> +     if (max_dividers.fb_div > min_dividers.fb_div) {
> >> +             WREG32_P(FVTHROT_FBDIV_REG0,
> >> +                      MIN_FEEDBACK_DIV(min_dividers.fb_div) |
> >> +                      MAX_FEEDBACK_DIV(max_dividers.fb_div),
> >> +                      ~(MIN_FEEDBACK_DIV_MASK | MAX_FEEDBACK_DIV_MASK));
> >> +
> >> +             WREG32_P(FVTHROT_FBDIV_REG1, 0, ~FORCE_FEEDBACK_DIV);
> >> +     }
> >> +
> >> +     return 0;
> >> +}
> >> +
> >> +static void rs780_set_engine_clock_spc(struct radeon_device *rdev)
> >> +{
> >> +     struct igp_ps *new_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
> >> +     struct igp_ps *old_state = rs780_get_ps(rdev->pm.dpm.current_ps);
> >> +     struct igp_power_info *pi = rs780_get_pi(rdev);
> >> +
> >> +     if ((new_state->sclk_high == old_state->sclk_high) &&
> >> +         (new_state->sclk_low == old_state->sclk_low))
> >> +             return;
> >> +
> >> +     if (pi->crtc_id == 0)
> >> +             WREG32_P(CG_INTGFX_MISC, 0, ~FVTHROT_VBLANK_SEL);
> >> +     else
> >> +             WREG32_P(CG_INTGFX_MISC, FVTHROT_VBLANK_SEL, ~FVTHROT_VBLANK_SEL);
> >> +
> >> +}
> >> +
> >> +static void rs780_activate_engine_clk_scaling(struct radeon_device *rdev)
> >> +{
> >> +     struct igp_ps *new_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
> >> +     struct igp_ps *old_state = rs780_get_ps(rdev->pm.dpm.current_ps);
> >> +
> >> +     if ((new_state->sclk_high == old_state->sclk_high) &&
> >> +         (new_state->sclk_low == old_state->sclk_low))
> >> +             return;
> >> +
> >> +     rs780_clk_scaling_enable(rdev, true);
> >> +}
> >> +
> >> +static u32 rs780_get_voltage_for_vddc_level(struct radeon_device *rdev,
> >> +                                         enum rs780_vddc_level vddc)
> >> +{
> >> +     struct igp_power_info *pi = rs780_get_pi(rdev);
> >> +
> >> +     if (vddc == RS780_VDDC_LEVEL_HIGH)
> >> +             return pi->max_voltage;
> >> +     else if (vddc == RS780_VDDC_LEVEL_LOW)
> >> +             return pi->min_voltage;
> >> +     else
> >> +             return pi->max_voltage;
> >> +}
> >> +
> >> +static void rs780_enable_voltage_scaling(struct radeon_device *rdev)
> >> +{
> >> +     struct igp_ps *new_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
> >> +     struct igp_power_info *pi = rs780_get_pi(rdev);
> >> +     enum rs780_vddc_level vddc_high, vddc_low;
> >> +
> >> +     udelay(100);
> >> +
> >> +     if ((new_state->max_voltage == RS780_VDDC_LEVEL_HIGH) &&
> >> +         (new_state->min_voltage == RS780_VDDC_LEVEL_HIGH))
> >> +             return;
> >> +
> >> +     vddc_high = rs780_get_voltage_for_vddc_level(rdev,
> >> +                                                  new_state->max_voltage);
> >> +     vddc_low = rs780_get_voltage_for_vddc_level(rdev,
> >> +                                                 new_state->min_voltage);
> >> +
> >> +     WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL);
> >> +
> >> +     udelay(1);
> >> +     if (vddc_high > vddc_low) {
> >> +             WREG32_P(FVTHROT_PWM_FEEDBACK_DIV_REG1,
> >> +                      RANGE_PWM_FEEDBACK_DIV_EN, ~RANGE_PWM_FEEDBACK_DIV_EN);
> >> +
> >> +             WREG32_P(FVTHROT_PWM_CTRL_REG0, 0, ~FORCE_STARTING_PWM_HIGHTIME);
> >> +     } else if (vddc_high == vddc_low) {
> >> +             if (pi->max_voltage != vddc_high) {
> >> +                     WREG32_P(FVTHROT_PWM_CTRL_REG0,
> >> +                              STARTING_PWM_HIGHTIME(vddc_high),
> >> +                              ~STARTING_PWM_HIGHTIME_MASK);
> >> +
> >> +                     WREG32_P(FVTHROT_PWM_CTRL_REG0,
> >> +                              FORCE_STARTING_PWM_HIGHTIME,
> >> +                              ~FORCE_STARTING_PWM_HIGHTIME);
> >> +             }
> >> +     }
> >> +
> >> +     WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
> >> +}
> >> +
> >> +int rs780_dpm_enable(struct radeon_device *rdev)
> >> +{
> >> +     struct igp_power_info *pi = rs780_get_pi(rdev);
> >> +
> >> +     rs780_get_pm_mode_parameters(rdev);
> >> +     rs780_disable_vbios_powersaving(rdev);
> >> +
> >> +     if (r600_dynamicpm_enabled(rdev))
> >> +             return -EINVAL;
> >> +     if (rs780_initialize_dpm_parameters(rdev))
> >> +             return -EINVAL;
> >> +     rs780_start_dpm(rdev);
> >> +
> >> +     rs780_preset_ranges_slow_clk_fbdiv_en(rdev);
> >> +     rs780_preset_starting_fbdiv(rdev);
> >> +     if (pi->voltage_control)
> >> +             rs780_voltage_scaling_init(rdev);
> >> +     rs780_clk_scaling_enable(rdev, true);
> >> +     rs780_set_engine_clock_sc(rdev);
> >> +     rs780_set_engine_clock_wfc(rdev);
> >> +     rs780_program_at(rdev);
> >> +     rs780_set_engine_clock_tdc(rdev);
> >> +     rs780_set_engine_clock_ssc(rdev);
> >> +
> >> +     if (pi->gfx_clock_gating)
> >> +             r600_gfx_clockgating_enable(rdev, true);
> >> +
> >> +     return 0;
> >> +}
> >> +
> >> +void rs780_dpm_disable(struct radeon_device *rdev)
> >> +{
> >> +     struct igp_power_info *pi = rs780_get_pi(rdev);
> >> +
> >> +     r600_dynamicpm_enable(rdev, false);
> >> +
> >> +     rs780_clk_scaling_enable(rdev, false);
> >> +     rs780_voltage_scaling_enable(rdev, false);
> >> +
> >> +     if (pi->gfx_clock_gating)
> >> +             r600_gfx_clockgating_enable(rdev, false);
> >> +}
> >> +
> >> +int rs780_dpm_set_power_state(struct radeon_device *rdev)
> >> +{
> >> +     struct igp_power_info *pi = rs780_get_pi(rdev);
> >> +
> >> +     rs780_get_pm_mode_parameters(rdev);
> >> +
> >> +     if (pi->voltage_control) {
> >> +             rs780_force_voltage_to_high(rdev);
> >> +             mdelay(5);
> >> +     }
> >> +
> >> +     rs780_set_engine_clock_scaling(rdev);
> >> +     rs780_set_engine_clock_spc(rdev);
> >> +
> >> +     rs780_activate_engine_clk_scaling(rdev);
> >> +
> >> +     if (pi->voltage_control)
> >> +             rs780_enable_voltage_scaling(rdev);
> >> +
> >> +     return 0;
> >> +}
> >> +
> >> +void rs780_dpm_setup_asic(struct radeon_device *rdev)
> >> +{
> >> +
> >> +}
> >> +
> >> +void rs780_dpm_display_configuration_changed(struct radeon_device *rdev)
> >> +{
> >> +     rs780_get_pm_mode_parameters(rdev);
> >> +     rs780_program_at(rdev);
> >> +}
> >> +
> >> +union igp_info {
> >> +     struct _ATOM_INTEGRATED_SYSTEM_INFO info;
> >> +     struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2;
> >> +};
> >> +
> >> +union power_info {
> >> +     struct _ATOM_POWERPLAY_INFO info;
> >> +     struct _ATOM_POWERPLAY_INFO_V2 info_2;
> >> +     struct _ATOM_POWERPLAY_INFO_V3 info_3;
> >> +     struct _ATOM_PPLIB_POWERPLAYTABLE pplib;
> >> +     struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2;
> >> +     struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3;
> >> +};
> >> +
> >> +union pplib_clock_info {
> >> +     struct _ATOM_PPLIB_R600_CLOCK_INFO r600;
> >> +     struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780;
> >> +     struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen;
> >> +     struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo;
> >> +};
> >> +
> >> +union pplib_power_state {
> >> +     struct _ATOM_PPLIB_STATE v1;
> >> +     struct _ATOM_PPLIB_STATE_V2 v2;
> >> +};
> >> +
> >> +static void rs780_parse_pplib_non_clock_info(struct radeon_device *rdev,
> >> +                                          struct radeon_ps *rps,
> >> +                                          struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info,
> >> +                                          u8 table_rev)
> >> +{
> >> +     rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings);
> >> +     rps->class = le16_to_cpu(non_clock_info->usClassification);
> >> +     rps->class2 = le16_to_cpu(non_clock_info->usClassification2);
> >> +
> >> +     if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) {
> >> +             rps->vclk = le32_to_cpu(non_clock_info->ulVCLK);
> >> +             rps->dclk = le32_to_cpu(non_clock_info->ulDCLK);
> >> +     } else if (r600_is_uvd_state(rps->class, rps->class2)) {
> >> +             rps->vclk = RS780_DEFAULT_VCLK_FREQ;
> >> +             rps->dclk = RS780_DEFAULT_DCLK_FREQ;
> >> +     } else {
> >> +             rps->vclk = 0;
> >> +             rps->dclk = 0;
> >> +     }
> >> +
> >> +     if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT)
> >> +             rdev->pm.dpm.boot_ps = rps;
> >> +     if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
> >> +             rdev->pm.dpm.uvd_ps = rps;
> >> +}
> >> +
> >> +static void rs780_parse_pplib_clock_info(struct radeon_device *rdev,
> >> +                                      struct radeon_ps *rps,
> >> +                                      union pplib_clock_info *clock_info)
> >> +{
> >> +     struct igp_ps *ps = rs780_get_ps(rps);
> >> +     u32 sclk;
> >> +
> >> +     sclk = le16_to_cpu(clock_info->rs780.usLowEngineClockLow);
> >> +     sclk |= clock_info->rs780.ucLowEngineClockHigh << 16;
> >> +     ps->sclk_low = sclk;
> >> +     sclk = le16_to_cpu(clock_info->rs780.usHighEngineClockLow);
> >> +     sclk |= clock_info->rs780.ucHighEngineClockHigh << 16;
> >> +     ps->sclk_high = sclk;
> >> +     switch (le16_to_cpu(clock_info->rs780.usVDDC)) {
> >> +     case ATOM_PPLIB_RS780_VOLTAGE_NONE:
> >> +     default:
> >> +             ps->min_voltage = RS780_VDDC_LEVEL_UNKNOWN;
> >> +             ps->max_voltage = RS780_VDDC_LEVEL_UNKNOWN;
> >> +             break;
> >> +     case ATOM_PPLIB_RS780_VOLTAGE_LOW:
> >> +             ps->min_voltage = RS780_VDDC_LEVEL_LOW;
> >> +             ps->max_voltage = RS780_VDDC_LEVEL_LOW;
> >> +             break;
> >> +     case ATOM_PPLIB_RS780_VOLTAGE_HIGH:
> >> +             ps->min_voltage = RS780_VDDC_LEVEL_HIGH;
> >> +             ps->max_voltage = RS780_VDDC_LEVEL_HIGH;
> >> +             break;
> >> +     case ATOM_PPLIB_RS780_VOLTAGE_VARIABLE:
> >> +             ps->min_voltage = RS780_VDDC_LEVEL_LOW;
> >> +             ps->max_voltage = RS780_VDDC_LEVEL_HIGH;
> >> +             break;
> >> +     }
> >> +     ps->flags = le32_to_cpu(clock_info->rs780.ulFlags);
> >> +
> >> +     if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) {
> >> +             ps->sclk_low = rdev->clock.default_sclk;
> >> +             ps->sclk_high = rdev->clock.default_sclk;
> >> +             ps->min_voltage = RS780_VDDC_LEVEL_HIGH;
> >> +             ps->max_voltage = RS780_VDDC_LEVEL_HIGH;
> >> +     }
> >> +}
> >> +
> >> +static int rs780_parse_power_table(struct radeon_device *rdev)
> >> +{
> >> +     struct radeon_mode_info *mode_info = &rdev->mode_info;
> >> +     struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
> >> +     union pplib_power_state *power_state;
> >> +     int i;
> >> +     union pplib_clock_info *clock_info;
> >> +     union power_info *power_info;
> >> +     int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
> >> +        u16 data_offset;
> >> +     u8 frev, crev;
> >> +     struct igp_ps *ps;
> >> +
> >> +     if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
> >> +                                &frev, &crev, &data_offset))
> >> +             return -EINVAL;
> >> +     power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
> >> +
> >> +     rdev->pm.dpm.ps = kzalloc(sizeof(struct radeon_ps) *
> >> +                               power_info->pplib.ucNumStates, GFP_KERNEL);
> >> +     if (!rdev->pm.dpm.ps)
> >> +             return -ENOMEM;
> >> +     rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps);
> >> +     rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime);
> >> +     rdev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime);
> >> +
> >> +     for (i = 0; i < power_info->pplib.ucNumStates; i++) {
> >> +             power_state = (union pplib_power_state *)
> >> +                     (mode_info->atom_context->bios + data_offset +
> >> +                      le16_to_cpu(power_info->pplib.usStateArrayOffset) +
> >> +                      i * power_info->pplib.ucStateEntrySize);
> >> +             non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
> >> +                     (mode_info->atom_context->bios + data_offset +
> >> +                      le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset) +
> >> +                      (power_state->v1.ucNonClockStateIndex *
> >> +                       power_info->pplib.ucNonClockSize));
> >> +             if (power_info->pplib.ucStateEntrySize - 1) {
> >> +                     clock_info = (union pplib_clock_info *)
> >> +                             (mode_info->atom_context->bios + data_offset +
> >> +                              le16_to_cpu(power_info->pplib.usClockInfoArrayOffset) +
> >> +                              (power_state->v1.ucClockStateIndices[0] *
> >> +                               power_info->pplib.ucClockInfoSize));
> >> +                     ps = kzalloc(sizeof(struct igp_ps), GFP_KERNEL);
> >> +                     if (ps == NULL) {
> >> +                             kfree(rdev->pm.dpm.ps);
> >> +                             return -ENOMEM;
> >> +                     }
> >> +                     rdev->pm.dpm.ps[i].ps_priv = ps;
> >> +                     rs780_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i],
> >> +                                                      non_clock_info,
> >> +                                                      power_info->pplib.ucNonClockSize);
> >> +                     rs780_parse_pplib_clock_info(rdev,
> >> +                                                  &rdev->pm.dpm.ps[i],
> >> +                                                  clock_info);
> >> +             }
> >> +     }
> >> +     rdev->pm.dpm.num_ps = power_info->pplib.ucNumStates;
> >> +     return 0;
> >> +}
> >> +
> >> +int rs780_dpm_init(struct radeon_device *rdev)
> >> +{
> >> +     struct igp_power_info *pi;
> >> +     int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);
> >> +     union igp_info *info;
> >> +     u16 data_offset;
> >> +     u8 frev, crev;
> >> +     int ret;
> >> +
> >> +     pi = kzalloc(sizeof(struct igp_power_info), GFP_KERNEL);
> >> +     if (pi == NULL)
> >> +             return -ENOMEM;
> >> +     rdev->pm.dpm.priv = pi;
> >> +
> >> +     ret = rs780_parse_power_table(rdev);
> >> +     if (ret)
> >> +             return ret;
> >> +
> >> +     pi->voltage_control = false;
> >> +     pi->gfx_clock_gating = true;
> >> +
> >> +     if (atom_parse_data_header(rdev->mode_info.atom_context, index, NULL,
> >> +                                &frev, &crev, &data_offset)) {
> >> +             info = (union igp_info *)(rdev->mode_info.atom_context->bios + data_offset);
> >> +
> >> +             /* Get various system informations from bios */
> >> +             switch (crev) {
> >> +             case 1:
> >> +                     pi->num_of_cycles_in_period =
> >> +                             info->info.ucNumberOfCyclesInPeriod;
> >> +                     pi->num_of_cycles_in_period |=
> >> +                             info->info.ucNumberOfCyclesInPeriodHi << 8;
> >> +                     pi->invert_pwm_required =
> >> +                             (pi->num_of_cycles_in_period & 0x8000) ? true : false;
> >> +                     pi->boot_voltage = info->info.ucStartingPWM_HighTime;
> >> +                     pi->max_voltage = info->info.ucMaxNBVoltage;
> >> +                     pi->max_voltage |= info->info.ucMaxNBVoltageHigh << 8;
> >> +                     pi->min_voltage = info->info.ucMinNBVoltage;
> >> +                     pi->min_voltage |= info->info.ucMinNBVoltageHigh << 8;
> >> +                     pi->inter_voltage_low =
> >> +                             le16_to_cpu(info->info.usInterNBVoltageLow);
> >> +                     pi->inter_voltage_high =
> >> +                             le16_to_cpu(info->info.usInterNBVoltageHigh);
> >> +                     pi->voltage_control = true;
> >> +                     pi->bootup_uma_clk = info->info.usK8MemoryClock * 100;
> >> +                     break;
> >> +             case 2:
> >> +                     pi->num_of_cycles_in_period =
> >> +                             le16_to_cpu(info->info_2.usNumberOfCyclesInPeriod);
> >> +                     pi->invert_pwm_required =
> >> +                             (pi->num_of_cycles_in_period & 0x8000) ? true : false;
> >> +                     pi->boot_voltage =
> >> +                             le16_to_cpu(info->info_2.usBootUpNBVoltage);
> >> +                     pi->max_voltage =
> >> +                             le16_to_cpu(info->info_2.usMaxNBVoltage);
> >> +                     pi->min_voltage =
> >> +                             le16_to_cpu(info->info_2.usMinNBVoltage);
> >> +                     pi->system_config =
> >> +                             le32_to_cpu(info->info_2.ulSystemConfig);
> >> +                     pi->pwm_voltage_control =
> >> +                             (pi->system_config & 0x4) ? true : false;
> >> +                     pi->voltage_control = true;
> >> +                     pi->bootup_uma_clk = le32_to_cpu(info->info_2.ulBootUpUMAClock);
> >> +                     break;
> >> +             default:
> >> +                     DRM_ERROR("No integrated system info for your GPU\n");
> >> +                     return -EINVAL;
> >> +             }
> >> +             if (pi->min_voltage > pi->max_voltage)
> >> +                     pi->voltage_control = false;
> >> +             if (pi->pwm_voltage_control) {
> >> +                     if ((pi->num_of_cycles_in_period == 0) ||
> >> +                         (pi->max_voltage == 0) ||
> >> +                         (pi->min_voltage == 0))
> >> +                             pi->voltage_control = false;
> >> +             } else {
> >> +                     if ((pi->num_of_cycles_in_period == 0) ||
> >> +                         (pi->max_voltage == 0))
> >> +                             pi->voltage_control = false;
> >> +             }
> >> +
> >> +             return 0;
> >> +     }
> >> +     radeon_dpm_fini(rdev);
> >> +     return -EINVAL;
> >> +}
> >> +
> >> +void rs780_dpm_print_power_state(struct radeon_device *rdev,
> >> +                              struct radeon_ps *rps)
> >> +{
> >> +     struct igp_ps *ps = rs780_get_ps(rps);
> >> +
> >> +     r600_dpm_print_class_info(rps->class, rps->class2);
> >> +     r600_dpm_print_cap_info(rps->caps);
> >> +     printk("\tuvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
> >> +     printk("\t\tpower level 0    sclk: %u vddc_index: %d\n",
> >> +            ps->sclk_low, ps->min_voltage);
> >> +     printk("\t\tpower level 1    sclk: %u vddc_index: %d\n",
> >> +            ps->sclk_high, ps->max_voltage);
> >> +     r600_dpm_print_ps_status(rdev, rps);
> >> +}
> >> +
> >> +void rs780_dpm_fini(struct radeon_device *rdev)
> >> +{
> >> +     int i;
> >> +
> >> +     for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
> >> +             kfree(rdev->pm.dpm.ps[i].ps_priv);
> >> +     }
> >> +     kfree(rdev->pm.dpm.ps);
> >> +     kfree(rdev->pm.dpm.priv);
> >> +}
> >> +
> >> +u32 rs780_dpm_get_sclk(struct radeon_device *rdev, bool low)
> >> +{
> >> +     struct igp_ps *requested_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
> >> +
> >> +     if (low)
> >> +             return requested_state->sclk_low;
> >> +     else
> >> +             return requested_state->sclk_high;
> >> +}
> >> +
> >> +u32 rs780_dpm_get_mclk(struct radeon_device *rdev, bool low)
> >> +{
> >> +     struct igp_power_info *pi = rs780_get_pi(rdev);
> >> +
> >> +     return pi->bootup_uma_clk;
> >> +}
> >> diff --git a/drivers/gpu/drm/radeon/rs780_dpm.h b/drivers/gpu/drm/radeon/rs780_dpm.h
> >> new file mode 100644
> >> index 0000000..47a40b1
> >> --- /dev/null
> >> +++ b/drivers/gpu/drm/radeon/rs780_dpm.h
> >> @@ -0,0 +1,109 @@
> >> +/*
> >> + * Copyright 2011 Advanced Micro Devices, Inc.
> >> + *
> >> + * Permission is hereby granted, free of charge, to any person obtaining a
> >> + * copy of this software and associated documentation files (the "Software"),
> >> + * to deal in the Software without restriction, including without limitation
> >> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> >> + * and/or sell copies of the Software, and to permit persons to whom the
> >> + * Software is furnished to do so, subject to the following conditions:
> >> + *
> >> + * The above copyright notice and this permission notice shall be included in
> >> + * all copies or substantial portions of the Software.
> >> + *
> >> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> >> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> >> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> >> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> >> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> >> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> >> + * OTHER DEALINGS IN THE SOFTWARE.
> >> + *
> >> + */
> >> +#ifndef __RS780_DPM_H__
> >> +#define __RS780_DPM_H__
> >> +
> >> +enum rs780_vddc_level {
> >> +     RS780_VDDC_LEVEL_UNKNOWN = 0,
> >> +     RS780_VDDC_LEVEL_LOW = 1,
> >> +     RS780_VDDC_LEVEL_HIGH = 2,
> >> +};
> >> +
> >> +struct igp_power_info {
> >> +     /* flags */
> >> +     bool invert_pwm_required;
> >> +     bool pwm_voltage_control;
> >> +     bool voltage_control;
> >> +     bool gfx_clock_gating;
> >> +     /* stored values */
> >> +     u32 system_config;
> >> +     u32 bootup_uma_clk;
> >> +     u16 max_voltage;
> >> +     u16 min_voltage;
> >> +     u16 boot_voltage;
> >> +     u16 inter_voltage_low;
> >> +     u16 inter_voltage_high;
> >> +     u16 num_of_cycles_in_period;
> >> +     /* variable */
> >> +     int crtc_id;
> >> +     int refresh_rate;
> >> +};
> >> +
> >> +struct igp_ps {
> >> +     enum rs780_vddc_level min_voltage;
> >> +     enum rs780_vddc_level max_voltage;
> >> +     u32 sclk_low;
> >> +     u32 sclk_high;
> >> +     u32 flags;
> >> +};
> >> +
> >> +#define RS780_CGFTV_DFLT                 0x0303000f
> >> +#define RS780_FBDIVTIMERVAL_DFLT         0x2710
> >> +
> >> +#define RS780_FVTHROTUTC0_DFLT   0x04010040
> >> +#define RS780_FVTHROTUTC1_DFLT   0x04010040
> >> +#define RS780_FVTHROTUTC2_DFLT   0x04010040
> >> +#define RS780_FVTHROTUTC3_DFLT   0x04010040
> >> +#define RS780_FVTHROTUTC4_DFLT   0x04010040
> >> +
> >> +#define RS780_FVTHROTDTC0_DFLT 0x04010040
> >> +#define RS780_FVTHROTDTC1_DFLT 0x04010040
> >> +#define RS780_FVTHROTDTC2_DFLT 0x04010040
> >> +#define RS780_FVTHROTDTC3_DFLT 0x04010040
> >> +#define RS780_FVTHROTDTC4_DFLT 0x04010040
> >> +
> >> +#define RS780_FVTHROTFBUSREG0_DFLT       0x00001001
> >> +#define RS780_FVTHROTFBUSREG1_DFLT       0x00002002
> >> +#define RS780_FVTHROTFBDSREG0_DFLT       0x00004001
> >> +#define RS780_FVTHROTFBDSREG1_DFLT       0x00020010
> >> +
> >> +#define RS780_FVTHROTPWMUSREG0_DFLT      0x00002001
> >> +#define RS780_FVTHROTPWMUSREG1_DFLT      0x00004003
> >> +#define RS780_FVTHROTPWMDSREG0_DFLT      0x00002001
> >> +#define RS780_FVTHROTPWMDSREG1_DFLT      0x00004003
> >> +
> >> +#define RS780_FVTHROTPWMFBDIVRANGEREG0_DFLT  0x37
> >> +#define RS780_FVTHROTPWMFBDIVRANGEREG1_DFLT  0x4b
> >> +#define RS780_FVTHROTPWMFBDIVRANGEREG2_DFLT  0x8b
> >> +
> >> +#define RS780D_FVTHROTPWMFBDIVRANGEREG0_DFLT  0x8b
> >> +#define RS780D_FVTHROTPWMFBDIVRANGEREG1_DFLT  0x8c
> >> +#define RS780D_FVTHROTPWMFBDIVRANGEREG2_DFLT  0xb5
> >> +
> >> +#define RS880D_FVTHROTPWMFBDIVRANGEREG0_DFLT  0x8d
> >> +#define RS880D_FVTHROTPWMFBDIVRANGEREG1_DFLT  0x8e
> >> +#define RS880D_FVTHROTPWMFBDIVRANGEREG2_DFLT  0xBa
> >> +
> >> +#define RS780_FVTHROTPWMRANGE0_GPIO_DFLT  0x1a
> >> +#define RS780_FVTHROTPWMRANGE1_GPIO_DFLT  0x1a
> >> +#define RS780_FVTHROTPWMRANGE2_GPIO_DFLT  0x0
> >> +#define RS780_FVTHROTPWMRANGE3_GPIO_DFLT  0x0
> >> +
> >> +#define RS780_SLOWCLKFEEDBACKDIV_DFLT 110
> >> +
> >> +#define RS780_CGCLKGATING_DFLT           0x0000E204
> >> +
> >> +#define RS780_DEFAULT_VCLK_FREQ  53300 /* 10 khz */
> >> +#define RS780_DEFAULT_DCLK_FREQ  40000 /* 10 khz */
> >> +
> >> +#endif
> >> diff --git a/drivers/gpu/drm/radeon/rs780d.h b/drivers/gpu/drm/radeon/rs780d.h
> >> new file mode 100644
> >> index 0000000..b1142ed
> >> --- /dev/null
> >> +++ b/drivers/gpu/drm/radeon/rs780d.h
> >> @@ -0,0 +1,168 @@
> >> +/*
> >> + * Copyright 2011 Advanced Micro Devices, Inc.
> >> + *
> >> + * Permission is hereby granted, free of charge, to any person obtaining a
> >> + * copy of this software and associated documentation files (the "Software"),
> >> + * to deal in the Software without restriction, including without limitation
> >> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> >> + * and/or sell copies of the Software, and to permit persons to whom the
> >> + * Software is furnished to do so, subject to the following conditions:
> >> + *
> >> + * The above copyright notice and this permission notice shall be included in
> >> + * all copies or substantial portions of the Software.
> >> + *
> >> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> >> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> >> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> >> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> >> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> >> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> >> + * OTHER DEALINGS IN THE SOFTWARE.
> >> + *
> >> + */
> >> +#ifndef __RS780D_H__
> >> +#define __RS780D_H__
> >> +
> >> +#define CG_SPLL_FUNC_CNTL                                 0x600
> >> +#       define SPLL_RESET                                (1 << 0)
> >> +#       define SPLL_SLEEP                                (1 << 1)
> >> +#       define SPLL_REF_DIV(x)                           ((x) << 2)
> >> +#       define SPLL_REF_DIV_MASK                         (7 << 2)
> >> +#       define SPLL_FB_DIV(x)                            ((x) << 5)
> >> +#       define SPLL_FB_DIV_MASK                          (0xff << 2)
> >> +#       define SPLL_FB_DIV_SHIFT                         2
> >> +#       define SPLL_PULSEEN                              (1 << 13)
> >> +#       define SPLL_PULSENUM(x)                          ((x) << 14)
> >> +#       define SPLL_PULSENUM_MASK                        (3 << 14)
> >> +#       define SPLL_SW_HILEN(x)                          ((x) << 16)
> >> +#       define SPLL_SW_HILEN_MASK                        (0xf << 16)
> >> +#       define SPLL_SW_LOLEN(x)                          ((x) << 20)
> >> +#       define SPLL_SW_LOLEN_MASK                        (0xf << 20)
> >> +#       define SPLL_DIVEN                                (1 << 24)
> >> +#       define SPLL_BYPASS_EN                            (1 << 25)
> >> +#       define SPLL_CHG_STATUS                           (1 << 29)
> >> +#       define SPLL_CTLREQ                               (1 << 30)
> >> +#       define SPLL_CTLACK                               (1 << 31)
> >> +
> >> +/* RS780/RS880 PM */
> >> +#define      FVTHROT_CNTRL_REG                               0x3000
> >> +#define              DONT_WAIT_FOR_FBDIV_WRAP                (1 << 0)
> >> +#define              MINIMUM_CIP(x)                          ((x) << 1)
> >> +#define              MINIMUM_CIP_SHIFT                       1
> >> +#define              MINIMUM_CIP_MASK                        0x1fffffe
> >> +#define              REFRESH_RATE_DIVISOR(x)                 ((x) << 25)
> >> +#define              REFRESH_RATE_DIVISOR_SHIFT              25
> >> +#define              REFRESH_RATE_DIVISOR_MASK               (0x3 << 25)
> >> +#define              ENABLE_FV_THROT                         (1 << 27)
> >> +#define              ENABLE_FV_UPDATE                        (1 << 28)
> >> +#define              TREND_SEL_MODE                          (1 << 29)
> >> +#define              FORCE_TREND_SEL                         (1 << 30)
> >> +#define              ENABLE_FV_THROT_IO                      (1 << 31)
> >> +#define      FVTHROT_TARGET_REG                              0x3004
> >> +#define              TARGET_IDLE_COUNT(x)                    ((x) << 0)
> >> +#define              TARGET_IDLE_COUNT_MASK                  0xffffff
> >> +#define              TARGET_IDLE_COUNT_SHIFT                 0
> >> +#define      FVTHROT_CB1                                     0x3008
> >> +#define      FVTHROT_CB2                                     0x300c
> >> +#define      FVTHROT_CB3                                     0x3010
> >> +#define      FVTHROT_CB4                                     0x3014
> >> +#define      FVTHROT_UTC0                                    0x3018
> >> +#define      FVTHROT_UTC1                                    0x301c
> >> +#define      FVTHROT_UTC2                                    0x3020
> >> +#define      FVTHROT_UTC3                                    0x3024
> >> +#define      FVTHROT_UTC4                                    0x3028
> >> +#define      FVTHROT_DTC0                                    0x302c
> >> +#define      FVTHROT_DTC1                                    0x3030
> >> +#define      FVTHROT_DTC2                                    0x3034
> >> +#define      FVTHROT_DTC3                                    0x3038
> >> +#define      FVTHROT_DTC4                                    0x303c
> >> +#define      FVTHROT_FBDIV_REG0                              0x3040
> >> +#define              MIN_FEEDBACK_DIV(x)                     ((x) << 0)
> >> +#define              MIN_FEEDBACK_DIV_MASK                   0xfff
> >> +#define              MIN_FEEDBACK_DIV_SHIFT                  0
> >> +#define              MAX_FEEDBACK_DIV(x)                     ((x) << 12)
> >> +#define              MAX_FEEDBACK_DIV_MASK                   (0xfff << 12)
> >> +#define              MAX_FEEDBACK_DIV_SHIFT                  12
> >> +#define      FVTHROT_FBDIV_REG1                              0x3044
> >> +#define              MAX_FEEDBACK_STEP(x)                    ((x) << 0)
> >> +#define              MAX_FEEDBACK_STEP_MASK                  0xfff
> >> +#define              MAX_FEEDBACK_STEP_SHIFT                 0
> >> +#define              STARTING_FEEDBACK_DIV(x)                ((x) << 12)
> >> +#define              STARTING_FEEDBACK_DIV_MASK              (0xfff << 12)
> >> +#define              STARTING_FEEDBACK_DIV_SHIFT             12
> >> +#define              FORCE_FEEDBACK_DIV                      (1 << 24)
> >> +#define      FVTHROT_FBDIV_REG2                              0x3048
> >> +#define              FORCED_FEEDBACK_DIV(x)                  ((x) << 0)
> >> +#define              FORCED_FEEDBACK_DIV_MASK                0xfff
> >> +#define              FORCED_FEEDBACK_DIV_SHIFT               0
> >> +#define              FB_DIV_TIMER_VAL(x)                     ((x) << 12)
> >> +#define              FB_DIV_TIMER_VAL_MASK                   (0xffff << 12)
> >> +#define              FB_DIV_TIMER_VAL_SHIFT                  12
> >> +#define      FVTHROT_FB_US_REG0                              0x304c
> >> +#define      FVTHROT_FB_US_REG1                              0x3050
> >> +#define      FVTHROT_FB_DS_REG0                              0x3054
> >> +#define      FVTHROT_FB_DS_REG1                              0x3058
> >> +#define      FVTHROT_PWM_CTRL_REG0                           0x305c
> >> +#define              STARTING_PWM_HIGHTIME(x)                ((x) << 0)
> >> +#define              STARTING_PWM_HIGHTIME_MASK              0xfff
> >> +#define              STARTING_PWM_HIGHTIME_SHIFT             0
> >> +#define              NUMBER_OF_CYCLES_IN_PERIOD(x)           ((x) << 12)
> >> +#define              NUMBER_OF_CYCLES_IN_PERIOD_MASK         (0xfff << 12)
> >> +#define              NUMBER_OF_CYCLES_IN_PERIOD_SHIFT        12
> >> +#define              FORCE_STARTING_PWM_HIGHTIME             (1 << 24)
> >> +#define              INVERT_PWM_WAVEFORM                     (1 << 25)
> >> +#define      FVTHROT_PWM_CTRL_REG1                           0x3060
> >> +#define              MIN_PWM_HIGHTIME(x)                     ((x) << 0)
> >> +#define              MIN_PWM_HIGHTIME_MASK                   0xfff
> >> +#define              MIN_PWM_HIGHTIME_SHIFT                  0
> >> +#define              MAX_PWM_HIGHTIME(x)                     ((x) << 12)
> >> +#define              MAX_PWM_HIGHTIME_MASK                   (0xfff << 12)
> >> +#define              MAX_PWM_HIGHTIME_SHIFT                  12
> >> +#define      FVTHROT_PWM_US_REG0                             0x3064
> >> +#define      FVTHROT_PWM_US_REG1                             0x3068
> >> +#define      FVTHROT_PWM_DS_REG0                             0x306c
> >> +#define      FVTHROT_PWM_DS_REG1                             0x3070
> >> +#define      FVTHROT_STATUS_REG0                             0x3074
> >> +#define              CURRENT_FEEDBACK_DIV_MASK               0xfff
> >> +#define              CURRENT_FEEDBACK_DIV_SHIFT              0
> >> +#define      FVTHROT_STATUS_REG1                             0x3078
> >> +#define      FVTHROT_STATUS_REG2                             0x307c
> >> +#define      CG_INTGFX_MISC                                  0x3080
> >> +#define              FVTHROT_VBLANK_SEL                      (1 << 9)
> >> +#define      FVTHROT_PWM_FEEDBACK_DIV_REG1                   0x308c
> >> +#define              RANGE0_PWM_FEEDBACK_DIV(x)              ((x) << 0)
> >> +#define              RANGE0_PWM_FEEDBACK_DIV_MASK            0xfff
> >> +#define              RANGE0_PWM_FEEDBACK_DIV_SHIFT           0
> >> +#define              RANGE_PWM_FEEDBACK_DIV_EN               (1 << 12)
> >> +#define      FVTHROT_PWM_FEEDBACK_DIV_REG2                   0x3090
> >> +#define              RANGE1_PWM_FEEDBACK_DIV(x)              ((x) << 0)
> >> +#define              RANGE1_PWM_FEEDBACK_DIV_MASK            0xfff
> >> +#define              RANGE1_PWM_FEEDBACK_DIV_SHIFT           0
> >> +#define              RANGE2_PWM_FEEDBACK_DIV(x)              ((x) << 12)
> >> +#define              RANGE2_PWM_FEEDBACK_DIV_MASK            (0xfff << 12)
> >> +#define              RANGE2_PWM_FEEDBACK_DIV_SHIFT           12
> >> +#define      FVTHROT_PWM_FEEDBACK_DIV_REG3                   0x3094
> >> +#define              RANGE0_PWM(x)                           ((x) << 0)
> >> +#define              RANGE0_PWM_MASK                         0xfff
> >> +#define              RANGE0_PWM_SHIFT                        0
> >> +#define              RANGE1_PWM(x)                           ((x) << 12)
> >> +#define              RANGE1_PWM_MASK                         (0xfff << 12)
> >> +#define              RANGE1_PWM_SHIFT                        12
> >> +#define      FVTHROT_PWM_FEEDBACK_DIV_REG4                   0x3098
> >> +#define              RANGE2_PWM(x)                           ((x) << 0)
> >> +#define              RANGE2_PWM_MASK                         0xfff
> >> +#define              RANGE2_PWM_SHIFT                        0
> >> +#define              RANGE3_PWM(x)                           ((x) << 12)
> >> +#define              RANGE3_PWM_MASK                         (0xfff << 12)
> >> +#define              RANGE3_PWM_SHIFT                        12
> >> +#define      FVTHROT_SLOW_CLK_FEEDBACK_DIV_REG1              0x30ac
> >> +#define              RANGE0_SLOW_CLK_FEEDBACK_DIV(x)         ((x) << 0)
> >> +#define              RANGE0_SLOW_CLK_FEEDBACK_DIV_MASK       0xfff
> >> +#define              RANGE0_SLOW_CLK_FEEDBACK_DIV_SHIFT      0
> >> +#define              RANGE_SLOW_CLK_FEEDBACK_DIV_EN          (1 << 12)
> >> +
> >> +#define      GFX_MACRO_BYPASS_CNTL                           0x30c0
> >> +#define              SPLL_BYPASS_CNTL                        (1 << 0)
> >> +#define              UPLL_BYPASS_CNTL                        (1 << 1)
> >> +
> >> +#endif
> >> --
> >> 1.7.7.5
> >>
> >> _______________________________________________
> >> dri-devel mailing list
> >> dri-devel@lists.freedesktop.org
> >> http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 000/165] radeon drm-next patches
@ 2013-06-26 13:21 alexdeucher
  2013-06-26 12:55 ` Jerome Glisse
                   ` (113 more replies)
  0 siblings, 114 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:21 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

These are the radeon patches for 3.11.  Some of these patches
are huge so, it might be easier to review things here:
http://cgit.freedesktop.org/~agd5f/linux/log/?h=drm-next-3.11-wip

I'll send a formal pull in request in the next day or two.

Highlights of this series:
- DPM support (Dynamic Power Management) for r6xx-SI
- Support for CIK (Sea Islands): modesetting, 3D, compute, UVD
- ASPM support for R6xx-SI

Since this is the initial public DPM code, it's still disabled by default
until we get more community testing.  Pass dpm=1 to the radeon module to
enable it.

Alex Deucher (164):
  drm/radeon: fix AVI infoframe generation
  drm/radeon: add backlight quirk for hybrid mac
  drm/radeon: add a reset work handler
  drm/radeon: add CIK chip families
  drm/radeon: add DCE8 macro for CIK
  drm/radeon: adapt to PCI BAR changes on CIK
  drm/radeon: add gpu init support for CIK (v9)
  drm/radeon: Add support for CIK GPU reset (v2)
  drm/radeon: add support for MC/VM setup on CIK (v6)
  drm/radeon/cik: stop page faults from hanging the system (v2)
  drm/radeon: add initial ucode loading for CIK (v5)
  drm/radeon: add support mc ucode loading on CIK (v2)
  drm/radeon: Add CP init for CIK (v7)
  drm/radeon: add IB and fence dispatch functions for CIK gfx (v7)
  drm/radeon: add ring and IB tests for CIK (v3)
  drm/radeon: implement async vm_flush for the CP (v7)
  drm/radeon: Add support for RLC init on CIK (v4)
  drm/radeon: add support for interrupts on CIK (v5)
  drm/radeon/cik: log and handle VM page fault interrupts
  drm/radeon/cik: add support for sDMA dma engines (v8)
  drm/radeon: implement async vm_flush for the sDMA (v6)
  drm/radeon/cik: add support for doing async VM pt updates (v5)
  drm/radeon/cik: fill in startup/shutdown callbacks (v4)
  drm/radeon: upstream ObjectID.h updates (v2)
  drm/radeon: upstream atombios.h updates (v2)
  drm/radeon: atombios power table updates (v2)
  drm/radeon: handle the integrated thermal controller on CI
  drm/radeon: update power state parsing for CI
  drm/radeon/dce8: add support for display watermark setup
  drm/radeon/cik: add hw cursor support (v2)
  drm/radeon/dce8: properly handle interlaced timing
  drm/radeon/dce8: crtc_set_base updates
  drm/radeon/atom: add DCE8 encoder support
  drm/radeon/atom: add support for new DVO tables
  drm/radeon: update DISPCLK programming for DCE8
  drm/radeon: add support pll selection for DCE8 (v4)
  drm/radeon: Handle PPLL0 powerdown on DCE8
  drm/radeon: use frac fb div on DCE8
  drm/radeon: add SS override support for KB/KV
  drm/radeon: Update radeon_info_ioctl for CIK (v2)
  drm/radeon: add get_gpu_clock_counter() callback for cik
  drm/radeon: update CIK soft reset
  drm/radeon: add indirect register accessors for SMC registers
  drm/radeon: add get_xclk() callback for CIK
  drm/radeon/cik: add pcie_port indirect register accessors
  drm/radeon: update radeon_atom_get_clock_dividers() for SI
  drm/radeon: update radeon_atom_get_clock_dividers for CIK
  drm/radeon/cik: add srbm_select function
  drm/radeon: use callbacks for ring pointer handling
  drm/radeon: implement simple doorbell page allocator
  drm/radeon/cik: Add support for compute queues (v2)
  drm/radeon/cik: switch to type3 nop packet for compute rings
  drm/radeon: fix up ring functions for compute rings
  drm/radeon/cik: add support for compute interrupts
  drm/radeon/cik: add support for golden register init
  drm/radeon: add radeon_asic struct for CIK (v11)
  drm/radeon: add cik tile mode array query
  drm/radeon: add current Bonaire PCI ids
  drm/radeon: add current KB pci ids
  drm/radeon/kms: add accessors for RCU indirect space
  drm/radeon/evergreen: add indirect register accessors for CG
    registers
  drm/radeon: make get_temperature functions a callback
  drm/radeon: add support for thermal sensor on tn
  drm/radeon/kms: move ucode defines to a separate header
  drm/radeon: properly set up the RLC on ON/LN/TN (v3)
  drm/radeon/kms: add atom helper functions for dpm (v3)
  drm/radeon/kms: add new asic struct for rv6xx (v3)
  drm/radeon/kms: add common dpm infrastructure
  drm/radeon/kms: fix up rs780/rs880 display watermark calc for dpm
  drm/radeon/kms: fix up 6xx/7xx display watermark calc for dpm
  drm/radeon/kms: fix up dce4/5 display watermark calc for dpm
  drm/radeon/kms: fix up dce6 display watermark calc for dpm
  drm/radeon/kms: add common r600 dpm functions
  drm/radeon/kms: add dpm support for rs780/rs880
  drm/radeon/kms: add dpm support for rv6xx
  drm/radeon/kms: add dpm support for rv7xx (v2)
  drm/radeon/kms: add dpm support for evergreen (v2)
  drm/radeon/kms: add dpm support for btc (v2)
  drm/radeon/kms: add dpm support for sumo asics
  drm/radeon/kms: add dpm support for trinity asics
  drm/radeon/dpm: let atom control display phy powergating
  drm/radeon: add dpm UVD handling for r7xx asics
  drm/radeon: add dpm UVD handling for evergreen/btc asics
  drm/radeon: add dpm UVD handling for sumo asics
  drm/radeon: add dpm UVD handling for TN asics (v2)
  drm/radeon/kms: enable UVD as needed (v9)
  drm/radeon/dpm: add helpers for extended power tables (v2)
  drm/radeon/dpm: track whether we are on AC or battery
  drm/radeon/dpm: fixup dynamic state adjust for sumo
  drm/radeon/dpm: fixup dynamic state adjust for TN
  drm/radeon/dpm: fixup dynamic state adjust for btc (v2)
  drm/radeon/kms: add dpm support for cayman
  drm/radeon/cayman: update tdp limits in set_power_state
  drm/radeon/dpm/rs780: restructure code
  drm/radeon/dpm/rv6xx: restructure code
  drm/radeon/dpm/rv7xx: restructure code
  drm/radeon/dpm/evergreen: restructure code
  drm/radeon/dpm/btc: restructure code
  drm/radeon/dpm/cayman: restructure code
  drm/radeon/dpm/sumo: restructure code
  drm/radeon/dpm/tn: restructure code
  drm/radeon/dpm: add new pre/post_set_power_state callbacks
  drm/radeon/dpm: add pre/post_set_power_state callbacks (6xx-eg)
  drm/radeon/dpm: add pre/post_set_power_state callback (sumo)
  drm/radeon/dpm: add pre/post_set_power_state callback (TN)
  drm/radeon/dpm: add pre/post_set_power_state callback (BTC)
  drm/radeon/dpm: add pre/post_set_power_state callback (cayman)
  drm/radeon/dpm: remove broken dyn state remnants
  drm/radeon: add missing UVD clock set in cayman dpm code
  drm/radeon/dpm: remove local sumo_get_xclk()
  drm/radeon: implement apci perf request
  drm/radeon/atom: add helper to calcuate mpll params
  drm/radeon: update radeon_atom_is_voltage_gpio() for SI
  drm/radeon: update radeon_atom_get_voltage_table() for SI
  drm/radeon: implement pcie gen2/3 support for SI
  drm/radeon: add accessors of pif_phy indirect register space
  drm/radeon: add support for ASPM on evergreen asics
  drm/radeon: add support for ASPM on SI asics (v2)
  drm/radeon: enable additional power gating features on trinity
  drm/radeon: update rlc programming sequence on SI
  drm/radeon: add atom get leakage vddc function
  drm/radeon: add indirect accessors for UVD CTX registers
  drm/radeon: initialize save/restore buffer for pg on verde
  drm/radeon: add clearstate init for verde power gating
  drm/radeon: implement clock and power gating for SI
  drm/radeon/dpm: add an enum for pcie gen selection
  drm/radeon/dpm: pull in phase shedding limits from atom
  drm/radeon/dpm: endian fixes for extended power tables
  drm/radeon/dpm: pull in ppm info from atom
  drm/radeon/dpm: save some display parameters for DPM
  drm/radeon: minor sid.h cleanup
  drm: add some additional fixed point helpers (v2)
  drm/radeon/dpm/cayman: use new fixed point functions
  drm/radeon: fix some memory leaks in extended table parsing
  drm/radeon/dpm: validate voltages against dispclk requirements
  drm/radeon: update radeon_atombios_get_default_voltages for mvdd
  drm/radeon/dpm: add pcie gen helper function
  drm/radeon: fix typo in atom voltage table handling (6xx-ni)
  drm/radeon: fix typo in atom voltage table handling (si+)
  drm/radeon/atom: fix voltage table parsing
  drm/radeon/dpm/ni: properly catch errors in dpm setup
  drm/radeon/dpm/btc: properly catch errors in dpm setup
  drm/radeon/dpm/evergreen: properly catch errors in dpm setup
  drm/radeon/dpm/sumo: properly catch errors in dpm setup
  drm/radeon/dpm/trinity: properly catch errors in dpm setup
  drm/radeon/dpm/r7xx: properly catch errors in dpm setup
  drm/radeon/dpm/r6xx: properly catch errors in dpm setup
  drm/radeon/dpm/rs780: properly catch errors in dpm setup
  drm/radeon: add SI to r600_is_internal_thermal_sensor()
  drm/radeon: switch SI to use radeon_ucode.h
  drm/radeon/kms: add dpm support for SI (v3)
  drm/radeon/dpm: add dpm_enable failure output (7xx-ni)
  drm/radeon/dpm: add dpm_enable failure output (si)
  drm/radeon/dpm: add dpm_set_power_state failure output (7xx-ni)
  drm/radeon/dpm: add dpm_set_power_state failure output (si)
  drm/radeon/dpm: fix typo in setting uvd clock
  drm/radeon/si: fix typo in function name
  drm/radeon: fix typo in cik_select_se_sh()
  drm/radeon: fix typo in ni_print_power_state
  drm/radeon/dpm: add support for setting UVD clock on rs780
  drm/radeon/dpm: add support for setting UVD clock on rv6xx
  drm/radeon/dpm: fix UVD clock setting on cayman
  drm/radeon/dpm: fix UVD clock setting on SI
  drm/radeon: fix endian issues in atombios dpm code

Christian König (1):
  drm/radeon: add UVD support for CIK (v3)

 drivers/gpu/drm/radeon/Makefile               |    5 +-
 drivers/gpu/drm/radeon/ObjectID.h             |   40 +
 drivers/gpu/drm/radeon/atombios.h             |  547 ++-
 drivers/gpu/drm/radeon/atombios_crtc.c        |   88 +-
 drivers/gpu/drm/radeon/atombios_encoders.c    |   51 +-
 drivers/gpu/drm/radeon/btc_dpm.c              | 2731 ++++++++++
 drivers/gpu/drm/radeon/btc_dpm.h              |   57 +
 drivers/gpu/drm/radeon/btcd.h                 |  181 +
 drivers/gpu/drm/radeon/cik.c                  | 6995 +++++++++++++++++++++++++
 drivers/gpu/drm/radeon/cik_blit_shaders.c     |  246 +
 drivers/gpu/drm/radeon/cik_blit_shaders.h     |   32 +
 drivers/gpu/drm/radeon/cik_reg.h              |  147 +
 drivers/gpu/drm/radeon/cikd.h                 | 1297 +++++
 drivers/gpu/drm/radeon/clearstate_cayman.h    | 1081 ++++
 drivers/gpu/drm/radeon/clearstate_defs.h      |   44 +
 drivers/gpu/drm/radeon/clearstate_evergreen.h | 1080 ++++
 drivers/gpu/drm/radeon/clearstate_si.h        |  941 ++++
 drivers/gpu/drm/radeon/cypress_dpm.c          | 2170 ++++++++
 drivers/gpu/drm/radeon/cypress_dpm.h          |  160 +
 drivers/gpu/drm/radeon/evergreen.c            |  644 +++-
 drivers/gpu/drm/radeon/evergreen_hdmi.c       |   11 +-
 drivers/gpu/drm/radeon/evergreen_reg.h        |   12 +
 drivers/gpu/drm/radeon/evergreen_smc.h        |   67 +
 drivers/gpu/drm/radeon/evergreend.h           |  389 ++-
 drivers/gpu/drm/radeon/ni.c                   |  198 +-
 drivers/gpu/drm/radeon/ni_dpm.c               | 4288 +++++++++++++++
 drivers/gpu/drm/radeon/ni_dpm.h               |  248 +
 drivers/gpu/drm/radeon/nid.h                  |  561 ++
 drivers/gpu/drm/radeon/nislands_smc.h         |  329 ++
 drivers/gpu/drm/radeon/ppsmc.h                |  110 +
 drivers/gpu/drm/radeon/r600.c                 |  147 +-
 drivers/gpu/drm/radeon/r600_dpm.c             | 1024 ++++
 drivers/gpu/drm/radeon/r600_dpm.h             |  226 +
 drivers/gpu/drm/radeon/r600_hdmi.c            |   11 +-
 drivers/gpu/drm/radeon/r600_reg.h             |    6 +
 drivers/gpu/drm/radeon/r600d.h                |  232 +-
 drivers/gpu/drm/radeon/radeon.h               |  517 ++-
 drivers/gpu/drm/radeon/radeon_acpi.c          |  145 +
 drivers/gpu/drm/radeon/radeon_asic.c          |  524 ++-
 drivers/gpu/drm/radeon/radeon_asic.h          |  166 +
 drivers/gpu/drm/radeon/radeon_atombios.c      |  880 +++-
 drivers/gpu/drm/radeon/radeon_cs.c            |    1 +
 drivers/gpu/drm/radeon/radeon_cursor.c        |   10 +-
 drivers/gpu/drm/radeon/radeon_device.c        |  106 +-
 drivers/gpu/drm/radeon/radeon_display.c       |   21 +-
 drivers/gpu/drm/radeon/radeon_drv.c           |    7 +-
 drivers/gpu/drm/radeon/radeon_family.h        |    3 +
 drivers/gpu/drm/radeon/radeon_irq_kms.c       |   20 +
 drivers/gpu/drm/radeon/radeon_kms.c           |   41 +-
 drivers/gpu/drm/radeon/radeon_mode.h          |   93 +
 drivers/gpu/drm/radeon/radeon_pm.c            |  610 ++-
 drivers/gpu/drm/radeon/radeon_reg.h           |    1 +
 drivers/gpu/drm/radeon/radeon_ring.c          |   55 +-
 drivers/gpu/drm/radeon/radeon_ucode.h         |  129 +
 drivers/gpu/drm/radeon/radeon_uvd.c           |   32 +-
 drivers/gpu/drm/radeon/rs690.c                |  291 +-
 drivers/gpu/drm/radeon/rs780_dpm.c            |  963 ++++
 drivers/gpu/drm/radeon/rs780_dpm.h            |  109 +
 drivers/gpu/drm/radeon/rs780d.h               |  168 +
 drivers/gpu/drm/radeon/rv515.c                |  224 +-
 drivers/gpu/drm/radeon/rv6xx_dpm.c            | 2059 ++++++++
 drivers/gpu/drm/radeon/rv6xx_dpm.h            |   95 +
 drivers/gpu/drm/radeon/rv6xxd.h               |  246 +
 drivers/gpu/drm/radeon/rv730_dpm.c            |  508 ++
 drivers/gpu/drm/radeon/rv730d.h               |  165 +
 drivers/gpu/drm/radeon/rv740_dpm.c            |  416 ++
 drivers/gpu/drm/radeon/rv740d.h               |  117 +
 drivers/gpu/drm/radeon/rv770_dpm.c            | 2446 +++++++++
 drivers/gpu/drm/radeon/rv770_dpm.h            |  287 +
 drivers/gpu/drm/radeon/rv770_smc.c            |  621 +++
 drivers/gpu/drm/radeon/rv770_smc.h            |  209 +
 drivers/gpu/drm/radeon/rv770d.h               |  279 +-
 drivers/gpu/drm/radeon/si.c                   | 1337 +++++-
 drivers/gpu/drm/radeon/si_dpm.c               | 6369 ++++++++++++++++++++++
 drivers/gpu/drm/radeon/si_dpm.h               |  227 +
 drivers/gpu/drm/radeon/si_smc.c               |  284 +
 drivers/gpu/drm/radeon/sid.h                  |  599 ++-
 drivers/gpu/drm/radeon/sislands_smc.h         |  397 ++
 drivers/gpu/drm/radeon/sumo_dpm.c             | 1801 +++++++
 drivers/gpu/drm/radeon/sumo_dpm.h             |  220 +
 drivers/gpu/drm/radeon/sumo_smc.c             |  222 +
 drivers/gpu/drm/radeon/sumod.h                |  372 ++
 drivers/gpu/drm/radeon/trinity_dpm.c          | 1887 +++++++
 drivers/gpu/drm/radeon/trinity_dpm.h          |  131 +
 drivers/gpu/drm/radeon/trinity_smc.c          |  115 +
 drivers/gpu/drm/radeon/trinityd.h             |  228 +
 include/drm/drm_fixed.h                       |   96 +
 include/drm/drm_pciids.h                      |   24 +
 88 files changed, 52708 insertions(+), 561 deletions(-)
 create mode 100644 drivers/gpu/drm/radeon/btc_dpm.c
 create mode 100644 drivers/gpu/drm/radeon/btc_dpm.h
 create mode 100644 drivers/gpu/drm/radeon/btcd.h
 create mode 100644 drivers/gpu/drm/radeon/cik.c
 create mode 100644 drivers/gpu/drm/radeon/cik_blit_shaders.c
 create mode 100644 drivers/gpu/drm/radeon/cik_blit_shaders.h
 create mode 100644 drivers/gpu/drm/radeon/cik_reg.h
 create mode 100644 drivers/gpu/drm/radeon/cikd.h
 create mode 100644 drivers/gpu/drm/radeon/clearstate_cayman.h
 create mode 100644 drivers/gpu/drm/radeon/clearstate_defs.h
 create mode 100644 drivers/gpu/drm/radeon/clearstate_evergreen.h
 create mode 100644 drivers/gpu/drm/radeon/clearstate_si.h
 create mode 100644 drivers/gpu/drm/radeon/cypress_dpm.c
 create mode 100644 drivers/gpu/drm/radeon/cypress_dpm.h
 create mode 100644 drivers/gpu/drm/radeon/evergreen_smc.h
 create mode 100644 drivers/gpu/drm/radeon/ni_dpm.c
 create mode 100644 drivers/gpu/drm/radeon/ni_dpm.h
 create mode 100644 drivers/gpu/drm/radeon/nislands_smc.h
 create mode 100644 drivers/gpu/drm/radeon/ppsmc.h
 create mode 100644 drivers/gpu/drm/radeon/r600_dpm.c
 create mode 100644 drivers/gpu/drm/radeon/r600_dpm.h
 create mode 100644 drivers/gpu/drm/radeon/radeon_ucode.h
 create mode 100644 drivers/gpu/drm/radeon/rs780_dpm.c
 create mode 100644 drivers/gpu/drm/radeon/rs780_dpm.h
 create mode 100644 drivers/gpu/drm/radeon/rs780d.h
 create mode 100644 drivers/gpu/drm/radeon/rv6xx_dpm.c
 create mode 100644 drivers/gpu/drm/radeon/rv6xx_dpm.h
 create mode 100644 drivers/gpu/drm/radeon/rv6xxd.h
 create mode 100644 drivers/gpu/drm/radeon/rv730_dpm.c
 create mode 100644 drivers/gpu/drm/radeon/rv730d.h
 create mode 100644 drivers/gpu/drm/radeon/rv740_dpm.c
 create mode 100644 drivers/gpu/drm/radeon/rv740d.h
 create mode 100644 drivers/gpu/drm/radeon/rv770_dpm.c
 create mode 100644 drivers/gpu/drm/radeon/rv770_dpm.h
 create mode 100644 drivers/gpu/drm/radeon/rv770_smc.c
 create mode 100644 drivers/gpu/drm/radeon/rv770_smc.h
 create mode 100644 drivers/gpu/drm/radeon/si_dpm.c
 create mode 100644 drivers/gpu/drm/radeon/si_dpm.h
 create mode 100644 drivers/gpu/drm/radeon/si_smc.c
 create mode 100644 drivers/gpu/drm/radeon/sislands_smc.h
 create mode 100644 drivers/gpu/drm/radeon/sumo_dpm.c
 create mode 100644 drivers/gpu/drm/radeon/sumo_dpm.h
 create mode 100644 drivers/gpu/drm/radeon/sumo_smc.c
 create mode 100644 drivers/gpu/drm/radeon/sumod.h
 create mode 100644 drivers/gpu/drm/radeon/trinity_dpm.c
 create mode 100644 drivers/gpu/drm/radeon/trinity_dpm.h
 create mode 100644 drivers/gpu/drm/radeon/trinity_smc.c
 create mode 100644 drivers/gpu/drm/radeon/trinityd.h

-- 
1.7.7.5

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 001/165] drm/radeon: fix AVI infoframe generation
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
  2013-06-26 12:55 ` Jerome Glisse
@ 2013-06-26 13:21 ` alexdeucher
  2013-06-26 13:21 ` [PATCH 002/165] drm/radeon: add backlight quirk for hybrid mac alexdeucher
                   ` (111 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:21 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher, stable, Rafał Miłecki

From: Alex Deucher <alexander.deucher@amd.com>

- remove adding 2 to checksum, this is incorrect.

This was incorrectly introduced in:
92db7f6c860b8190571a9dc1fcbc16d003422fe8
http://lists.freedesktop.org/archives/dri-devel/2011-December/017717.html
However, the off by 2 was due to adding the version twice.
From the examples in the URL above:

[Rafał Miłecki][RV620] fglrx:
0x7454: 00 A8 5E 79     R600_HDMI_VIDEOINFOFRAME_0
0x7458: 00 28 00 10     R600_HDMI_VIDEOINFOFRAME_1
0x745C: 00 48 00 28     R600_HDMI_VIDEOINFOFRAME_2
0x7460: 02 00 00 48     R600_HDMI_VIDEOINFOFRAME_3
===================
(0x82 + 0x2 + 0xD) + 0x1F8 = 0x289
-0x289 = 0x77

However, the payload sum is not 0x1f8, it's 0x1f6.
00 + A8 + 5E + 00 +
00 + 28 + 00 + 10 +
00 + 48 + 00 + 28 +
00 + 48 =
0x1f6

Bits 25:24 of HDMI_VIDEOINFOFRAME_3 are the packet version, not part
of the payload.  So the total would be:
(0x82 + 0x2 + 0xD) + 0x1f6 = 0x287
-0x287 = 0x79

- properly emit the AVI infoframe version.  This was not being
emitted previous which is probably what caused the issue above.

This should fix blank screen when HDMI audio is enabled on
certain monitors.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Cc: stable@vger.kernel.org
Cc: Rafał Miłecki <zajec5@gmail.com>
---
 drivers/gpu/drm/radeon/evergreen_hdmi.c |   11 ++---------
 drivers/gpu/drm/radeon/r600_hdmi.c      |   11 ++---------
 2 files changed, 4 insertions(+), 18 deletions(-)

diff --git a/drivers/gpu/drm/radeon/evergreen_hdmi.c b/drivers/gpu/drm/radeon/evergreen_hdmi.c
index ed7c8a7..b9c6f76 100644
--- a/drivers/gpu/drm/radeon/evergreen_hdmi.c
+++ b/drivers/gpu/drm/radeon/evergreen_hdmi.c
@@ -128,14 +128,7 @@ static void evergreen_hdmi_update_avi_infoframe(struct drm_encoder *encoder,
 	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
 	uint32_t offset = dig->afmt->offset;
 	uint8_t *frame = buffer + 3;
-
-	/* Our header values (type, version, length) should be alright, Intel
-	 * is using the same. Checksum function also seems to be OK, it works
-	 * fine for audio infoframe. However calculated value is always lower
-	 * by 2 in comparison to fglrx. It breaks displaying anything in case
-	 * of TVs that strictly check the checksum. Hack it manually here to
-	 * workaround this issue. */
-	frame[0x0] += 2;
+	uint8_t *header = buffer;
 
 	WREG32(AFMT_AVI_INFO0 + offset,
 		frame[0x0] | (frame[0x1] << 8) | (frame[0x2] << 16) | (frame[0x3] << 24));
@@ -144,7 +137,7 @@ static void evergreen_hdmi_update_avi_infoframe(struct drm_encoder *encoder,
 	WREG32(AFMT_AVI_INFO2 + offset,
 		frame[0x8] | (frame[0x9] << 8) | (frame[0xA] << 16) | (frame[0xB] << 24));
 	WREG32(AFMT_AVI_INFO3 + offset,
-		frame[0xC] | (frame[0xD] << 8));
+		frame[0xC] | (frame[0xD] << 8) | (header[1] << 24));
 }
 
 static void evergreen_audio_set_dto(struct drm_encoder *encoder, u32 clock)
diff --git a/drivers/gpu/drm/radeon/r600_hdmi.c b/drivers/gpu/drm/radeon/r600_hdmi.c
index 456750a..e73b2a7 100644
--- a/drivers/gpu/drm/radeon/r600_hdmi.c
+++ b/drivers/gpu/drm/radeon/r600_hdmi.c
@@ -133,14 +133,7 @@ static void r600_hdmi_update_avi_infoframe(struct drm_encoder *encoder,
 	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
 	uint32_t offset = dig->afmt->offset;
 	uint8_t *frame = buffer + 3;
-
-	/* Our header values (type, version, length) should be alright, Intel
-	 * is using the same. Checksum function also seems to be OK, it works
-	 * fine for audio infoframe. However calculated value is always lower
-	 * by 2 in comparison to fglrx. It breaks displaying anything in case
-	 * of TVs that strictly check the checksum. Hack it manually here to
-	 * workaround this issue. */
-	frame[0x0] += 2;
+	uint8_t *header = buffer;
 
 	WREG32(HDMI0_AVI_INFO0 + offset,
 		frame[0x0] | (frame[0x1] << 8) | (frame[0x2] << 16) | (frame[0x3] << 24));
@@ -149,7 +142,7 @@ static void r600_hdmi_update_avi_infoframe(struct drm_encoder *encoder,
 	WREG32(HDMI0_AVI_INFO2 + offset,
 		frame[0x8] | (frame[0x9] << 8) | (frame[0xA] << 16) | (frame[0xB] << 24));
 	WREG32(HDMI0_AVI_INFO3 + offset,
-		frame[0xC] | (frame[0xD] << 8));
+		frame[0xC] | (frame[0xD] << 8) | (header[1] << 24));
 }
 
 /*
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 002/165] drm/radeon: add backlight quirk for hybrid mac
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
  2013-06-26 12:55 ` Jerome Glisse
  2013-06-26 13:21 ` [PATCH 001/165] drm/radeon: fix AVI infoframe generation alexdeucher
@ 2013-06-26 13:21 ` alexdeucher
  2013-06-26 13:21 ` [PATCH 003/165] drm/radeon: add a reset work handler alexdeucher
                   ` (110 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:21 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher, stable

From: Alex Deucher <alexander.deucher@amd.com>

Mac laptops with multiple GPUs apparently use the gmux
driver for backlight control.  Don't register a radeon
backlight interface.  We may need to add other pci ids
for other hybrid mac laptops.

Fixes:
https://bugs.freedesktop.org/show_bug.cgi?id=65377

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Cc: stable@vger.kernel.org
---
 drivers/gpu/drm/radeon/atombios_encoders.c |    7 +++++++
 1 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c
index 8406c82..4120d35 100644
--- a/drivers/gpu/drm/radeon/atombios_encoders.c
+++ b/drivers/gpu/drm/radeon/atombios_encoders.c
@@ -186,6 +186,13 @@ void radeon_atom_backlight_init(struct radeon_encoder *radeon_encoder,
 	u8 backlight_level;
 	char bl_name[16];
 
+	/* Mac laptops with multiple GPUs use the gmux driver for backlight
+	 * so don't register a backlight device
+	 */
+	if ((rdev->pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE) &&
+	    (rdev->pdev->device == 0x6741))
+		return;
+
 	if (!radeon_encoder->enc_priv)
 		return;
 
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 003/165] drm/radeon: add a reset work handler
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (2 preceding siblings ...)
  2013-06-26 13:21 ` [PATCH 002/165] drm/radeon: add backlight quirk for hybrid mac alexdeucher
@ 2013-06-26 13:21 ` alexdeucher
  2013-06-26 13:21 ` [PATCH 004/165] drm/radeon: add CIK chip families alexdeucher
                   ` (109 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:21 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

New asics support non-privileged IBs.  This allows us
to skip IB checking in the driver since the hardware
will check the command buffers for us.  When using
non-privileged IBs, if the CP encounters an illegal
register in the command stream, it will halt and generate
an interrupt.  The CP needs to be reset to continue.  For now
just do a full GPU reset when this happens.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/radeon.h         |    1 +
 drivers/gpu/drm/radeon/radeon_irq_kms.c |   18 ++++++++++++++++++
 2 files changed, 19 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 142ce6c..f5fccbb 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -1691,6 +1691,7 @@ struct radeon_device {
 	struct si_rlc rlc;
 	struct work_struct hotplug_work;
 	struct work_struct audio_work;
+	struct work_struct reset_work;
 	int num_crtc; /* number of crtcs */
 	struct mutex dc_hw_i2c_mutex; /* display controller hw i2c mutex */
 	bool audio_enabled;
diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c
index 5a99d43..dbffeca 100644
--- a/drivers/gpu/drm/radeon/radeon_irq_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c
@@ -82,6 +82,23 @@ static void radeon_hotplug_work_func(struct work_struct *work)
 }
 
 /**
+ * radeon_irq_reset_work_func - execute gpu reset
+ *
+ * @work: work struct
+ *
+ * Execute scheduled gpu reset (cayman+).
+ * This function is called when the irq handler
+ * thinks we need a gpu reset.
+ */
+static void radeon_irq_reset_work_func(struct work_struct *work)
+{
+	struct radeon_device *rdev = container_of(work, struct radeon_device,
+						  reset_work);
+
+	radeon_gpu_reset(rdev);
+}
+
+/**
  * radeon_driver_irq_preinstall_kms - drm irq preinstall callback
  *
  * @dev: drm dev pointer
@@ -243,6 +260,7 @@ int radeon_irq_kms_init(struct radeon_device *rdev)
 
 	INIT_WORK(&rdev->hotplug_work, radeon_hotplug_work_func);
 	INIT_WORK(&rdev->audio_work, r600_audio_update_hdmi);
+	INIT_WORK(&rdev->reset_work, radeon_irq_reset_work_func);
 
 	spin_lock_init(&rdev->irq.lock);
 	r = drm_vblank_init(rdev->ddev, rdev->num_crtc);
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 004/165] drm/radeon: add CIK chip families
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (3 preceding siblings ...)
  2013-06-26 13:21 ` [PATCH 003/165] drm/radeon: add a reset work handler alexdeucher
@ 2013-06-26 13:21 ` alexdeucher
  2013-06-26 13:21 ` [PATCH 005/165] drm/radeon: add DCE8 macro for CIK alexdeucher
                   ` (108 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:21 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/radeon_device.c |    3 +++
 drivers/gpu/drm/radeon/radeon_family.h |    3 +++
 2 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
index b0dc0b6..c24056b 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -95,6 +95,9 @@ static const char radeon_family_name[][16] = {
 	"VERDE",
 	"OLAND",
 	"HAINAN",
+	"BONAIRE",
+	"KAVERI",
+	"KABINI",
 	"LAST",
 };
 
diff --git a/drivers/gpu/drm/radeon/radeon_family.h b/drivers/gpu/drm/radeon/radeon_family.h
index 36e9803..3c82890 100644
--- a/drivers/gpu/drm/radeon/radeon_family.h
+++ b/drivers/gpu/drm/radeon/radeon_family.h
@@ -93,6 +93,9 @@ enum radeon_family {
 	CHIP_VERDE,
 	CHIP_OLAND,
 	CHIP_HAINAN,
+	CHIP_BONAIRE,
+	CHIP_KAVERI,
+	CHIP_KABINI,
 	CHIP_LAST,
 };
 
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 005/165] drm/radeon: add DCE8 macro for CIK
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (4 preceding siblings ...)
  2013-06-26 13:21 ` [PATCH 004/165] drm/radeon: add CIK chip families alexdeucher
@ 2013-06-26 13:21 ` alexdeucher
  2013-06-26 13:21 ` [PATCH 006/165] drm/radeon: adapt to PCI BAR changes on CIK alexdeucher
                   ` (107 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:21 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/radeon.h |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index f5fccbb..b50a786 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -1841,6 +1841,7 @@ void r100_pll_errata_after_index(struct radeon_device *rdev);
 			     (rdev->flags & RADEON_IS_IGP))
 #define ASIC_IS_DCE64(rdev) ((rdev->family == CHIP_OLAND))
 #define ASIC_IS_NODCE(rdev) ((rdev->family == CHIP_HAINAN))
+#define ASIC_IS_DCE8(rdev) ((rdev->family >= CHIP_BONAIRE))
 
 /*
  * BIOS helpers.
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 006/165] drm/radeon: adapt to PCI BAR changes on CIK
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (5 preceding siblings ...)
  2013-06-26 13:21 ` [PATCH 005/165] drm/radeon: add DCE8 macro for CIK alexdeucher
@ 2013-06-26 13:21 ` alexdeucher
  2013-06-26 13:21 ` [PATCH 007/165] drm/radeon: add gpu init support for CIK (v9) alexdeucher
                   ` (106 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:21 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

register BAR is now at PCI BAR 5.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/radeon_device.c |    9 +++++++--
 1 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
index c24056b..4e97ff7 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -1148,8 +1148,13 @@ int radeon_device_init(struct radeon_device *rdev,
 	/* Registers mapping */
 	/* TODO: block userspace mapping of io register */
 	spin_lock_init(&rdev->mmio_idx_lock);
-	rdev->rmmio_base = pci_resource_start(rdev->pdev, 2);
-	rdev->rmmio_size = pci_resource_len(rdev->pdev, 2);
+	if (rdev->family >= CHIP_BONAIRE) {
+		rdev->rmmio_base = pci_resource_start(rdev->pdev, 5);
+		rdev->rmmio_size = pci_resource_len(rdev->pdev, 5);
+	} else {
+		rdev->rmmio_base = pci_resource_start(rdev->pdev, 2);
+		rdev->rmmio_size = pci_resource_len(rdev->pdev, 2);
+	}
 	rdev->rmmio = ioremap(rdev->rmmio_base, rdev->rmmio_size);
 	if (rdev->rmmio == NULL) {
 		return -ENOMEM;
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 007/165] drm/radeon: add gpu init support for CIK (v9)
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (6 preceding siblings ...)
  2013-06-26 13:21 ` [PATCH 006/165] drm/radeon: adapt to PCI BAR changes on CIK alexdeucher
@ 2013-06-26 13:21 ` alexdeucher
  2013-06-26 13:21 ` [PATCH 008/165] drm/radeon: Add support for CIK GPU reset (v2) alexdeucher
                   ` (105 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:21 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

v2: tiling fixes
v3: more tiling fixes
v4: more tiling fixes
v5: additional register init
v6: rebase
v7: fix gb_addr_config for KV/KB
v8: drop wip KV bits for now, add missing config reg
v9: fix cu count on Bonaire

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/Makefile |    2 +-
 drivers/gpu/drm/radeon/cik.c    | 1192 +++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/radeon/cikd.h   |  253 +++++++++
 drivers/gpu/drm/radeon/radeon.h |   30 +
 4 files changed, 1476 insertions(+), 1 deletions(-)
 create mode 100644 drivers/gpu/drm/radeon/cik.c
 create mode 100644 drivers/gpu/drm/radeon/cikd.h

diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile
index 86c5e36..88d0601 100644
--- a/drivers/gpu/drm/radeon/Makefile
+++ b/drivers/gpu/drm/radeon/Makefile
@@ -76,7 +76,7 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \
 	evergreen.o evergreen_cs.o evergreen_blit_shaders.o evergreen_blit_kms.o \
 	evergreen_hdmi.o radeon_trace_points.o ni.o cayman_blit_shaders.o \
 	atombios_encoders.o radeon_semaphore.o radeon_sa.o atombios_i2c.o si.o \
-	si_blit_shaders.o radeon_prime.o radeon_uvd.o
+	si_blit_shaders.o radeon_prime.o radeon_uvd.o cik.o
 
 radeon-$(CONFIG_COMPAT) += radeon_ioc32.o
 radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o
diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
new file mode 100644
index 0000000..28f68dc
--- /dev/null
+++ b/drivers/gpu/drm/radeon/cik.c
@@ -0,0 +1,1192 @@
+/*
+ * Copyright 2012 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Alex Deucher
+ */
+#include <linux/firmware.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include "drmP.h"
+#include "radeon.h"
+#include "cikd.h"
+#include "atom.h"
+
+/*
+ * Core functions
+ */
+/**
+ * cik_tiling_mode_table_init - init the hw tiling table
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Starting with SI, the tiling setup is done globally in a
+ * set of 32 tiling modes.  Rather than selecting each set of
+ * parameters per surface as on older asics, we just select
+ * which index in the tiling table we want to use, and the
+ * surface uses those parameters (CIK).
+ */
+static void cik_tiling_mode_table_init(struct radeon_device *rdev)
+{
+	const u32 num_tile_mode_states = 32;
+	const u32 num_secondary_tile_mode_states = 16;
+	u32 reg_offset, gb_tile_moden, split_equal_to_row_size;
+	u32 num_pipe_configs;
+	u32 num_rbs = rdev->config.cik.max_backends_per_se *
+		rdev->config.cik.max_shader_engines;
+
+	switch (rdev->config.cik.mem_row_size_in_kb) {
+	case 1:
+		split_equal_to_row_size = ADDR_SURF_TILE_SPLIT_1KB;
+		break;
+	case 2:
+	default:
+		split_equal_to_row_size = ADDR_SURF_TILE_SPLIT_2KB;
+		break;
+	case 4:
+		split_equal_to_row_size = ADDR_SURF_TILE_SPLIT_4KB;
+		break;
+	}
+
+	num_pipe_configs = rdev->config.cik.max_tile_pipes;
+	if (num_pipe_configs > 8)
+		num_pipe_configs = 8; /* ??? */
+
+	if (num_pipe_configs == 8) {
+		for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++) {
+			switch (reg_offset) {
+			case 0:
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B));
+				break;
+			case 1:
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B));
+				break;
+			case 2:
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B));
+				break;
+			case 3:
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B));
+				break;
+			case 4:
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+						 TILE_SPLIT(split_equal_to_row_size));
+				break;
+			case 5:
+				gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+						 MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+				break;
+			case 6:
+				gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B));
+				break;
+			case 7:
+				gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+						 TILE_SPLIT(split_equal_to_row_size));
+				break;
+			case 8:
+				gb_tile_moden = (ARRAY_MODE(ARRAY_LINEAR_ALIGNED) |
+						 PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16));
+				break;
+			case 9:
+				gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+						 MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING));
+				break;
+			case 10:
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+						 SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+				break;
+			case 11:
+				gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+						 MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+						 SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+				break;
+			case 12:
+				gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+						 SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+				break;
+			case 13:
+				gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+						 MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING));
+				break;
+			case 14:
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+						 SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+				break;
+			case 16:
+				gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+						 MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+						 SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+				break;
+			case 17:
+				gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+						 SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+				break;
+			case 27:
+				gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+						 MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING));
+				break;
+			case 28:
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+						 SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+				break;
+			case 29:
+				gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+						 MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+						 SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+				break;
+			case 30:
+				gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+						 SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+				break;
+			default:
+				gb_tile_moden = 0;
+				break;
+			}
+			WREG32(GB_TILE_MODE0 + (reg_offset * 4), gb_tile_moden);
+		}
+		for (reg_offset = 0; reg_offset < num_secondary_tile_mode_states; reg_offset++) {
+			switch (reg_offset) {
+			case 0:
+				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+						 NUM_BANKS(ADDR_SURF_16_BANK));
+				break;
+			case 1:
+				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+						 NUM_BANKS(ADDR_SURF_16_BANK));
+				break;
+			case 2:
+				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+						 NUM_BANKS(ADDR_SURF_16_BANK));
+				break;
+			case 3:
+				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+						 NUM_BANKS(ADDR_SURF_16_BANK));
+				break;
+			case 4:
+				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
+						 NUM_BANKS(ADDR_SURF_8_BANK));
+				break;
+			case 5:
+				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
+						 NUM_BANKS(ADDR_SURF_4_BANK));
+				break;
+			case 6:
+				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
+						 NUM_BANKS(ADDR_SURF_2_BANK));
+				break;
+			case 8:
+				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_8) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+						 NUM_BANKS(ADDR_SURF_16_BANK));
+				break;
+			case 9:
+				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+						 NUM_BANKS(ADDR_SURF_16_BANK));
+				break;
+			case 10:
+				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+						 NUM_BANKS(ADDR_SURF_16_BANK));
+				break;
+			case 11:
+				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+						 NUM_BANKS(ADDR_SURF_16_BANK));
+				break;
+			case 12:
+				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
+						 NUM_BANKS(ADDR_SURF_8_BANK));
+				break;
+			case 13:
+				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
+						 NUM_BANKS(ADDR_SURF_4_BANK));
+				break;
+			case 14:
+				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
+						 NUM_BANKS(ADDR_SURF_2_BANK));
+				break;
+			default:
+				gb_tile_moden = 0;
+				break;
+			}
+			WREG32(GB_MACROTILE_MODE0 + (reg_offset * 4), gb_tile_moden);
+		}
+	} else if (num_pipe_configs == 4) {
+		if (num_rbs == 4) {
+			for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++) {
+				switch (reg_offset) {
+				case 0:
+					gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+							 MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+							 PIPE_CONFIG(ADDR_SURF_P4_16x16) |
+							 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B));
+					break;
+				case 1:
+					gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+							 MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+							 PIPE_CONFIG(ADDR_SURF_P4_16x16) |
+							 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B));
+					break;
+				case 2:
+					gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+							 MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+							 PIPE_CONFIG(ADDR_SURF_P4_16x16) |
+							 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B));
+					break;
+				case 3:
+					gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+							 MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+							 PIPE_CONFIG(ADDR_SURF_P4_16x16) |
+							 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B));
+					break;
+				case 4:
+					gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+							 MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+							 PIPE_CONFIG(ADDR_SURF_P4_16x16) |
+							 TILE_SPLIT(split_equal_to_row_size));
+					break;
+				case 5:
+					gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+							 MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+					break;
+				case 6:
+					gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+							 MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+							 PIPE_CONFIG(ADDR_SURF_P4_16x16) |
+							 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B));
+					break;
+				case 7:
+					gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+							 MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+							 PIPE_CONFIG(ADDR_SURF_P4_16x16) |
+							 TILE_SPLIT(split_equal_to_row_size));
+					break;
+				case 8:
+					gb_tile_moden = (ARRAY_MODE(ARRAY_LINEAR_ALIGNED) |
+							 PIPE_CONFIG(ADDR_SURF_P4_16x16));
+					break;
+				case 9:
+					gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+							 MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING));
+					break;
+				case 10:
+					gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+							 MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+							 PIPE_CONFIG(ADDR_SURF_P4_16x16) |
+							 SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+					break;
+				case 11:
+					gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+							 MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+							 PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+							 SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+					break;
+				case 12:
+					gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+							 MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+							 PIPE_CONFIG(ADDR_SURF_P4_16x16) |
+							 SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+					break;
+				case 13:
+					gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+							 MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING));
+					break;
+				case 14:
+					gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+							 MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+							 PIPE_CONFIG(ADDR_SURF_P4_16x16) |
+							 SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+					break;
+				case 16:
+					gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+							 MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+							 PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+							 SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+					break;
+				case 17:
+					gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+							 MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+							 PIPE_CONFIG(ADDR_SURF_P4_16x16) |
+							 SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+					break;
+				case 27:
+					gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+							 MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING));
+					break;
+				case 28:
+					gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+							 MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+							 PIPE_CONFIG(ADDR_SURF_P4_16x16) |
+							 SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+					break;
+				case 29:
+					gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+							 MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+							 PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+							 SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+					break;
+				case 30:
+					gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+							 MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+							 PIPE_CONFIG(ADDR_SURF_P4_16x16) |
+							 SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+					break;
+				default:
+					gb_tile_moden = 0;
+					break;
+				}
+				WREG32(GB_TILE_MODE0 + (reg_offset * 4), gb_tile_moden);
+			}
+		} else if (num_rbs < 4) {
+			for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++) {
+				switch (reg_offset) {
+				case 0:
+					gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+							 MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+							 PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+							 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B));
+					break;
+				case 1:
+					gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+							 MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+							 PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+							 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B));
+					break;
+				case 2:
+					gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+							 MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+							 PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+							 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B));
+					break;
+				case 3:
+					gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+							 MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+							 PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+							 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B));
+					break;
+				case 4:
+					gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+							 MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+							 PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+							 TILE_SPLIT(split_equal_to_row_size));
+					break;
+				case 5:
+					gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+							 MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+					break;
+				case 6:
+					gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+							 MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+							 PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+							 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B));
+					break;
+				case 7:
+					gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+							 MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+							 PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+							 TILE_SPLIT(split_equal_to_row_size));
+					break;
+				case 8:
+					gb_tile_moden = (ARRAY_MODE(ARRAY_LINEAR_ALIGNED) |
+						 PIPE_CONFIG(ADDR_SURF_P4_8x16));
+					break;
+				case 9:
+					gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+							 MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING));
+					break;
+				case 10:
+					gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+							 MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+							 PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+							 SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+					break;
+				case 11:
+					gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+							 MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+							 PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+							 SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+					break;
+				case 12:
+					gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+							 MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+							 PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+							 SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+					break;
+				case 13:
+					gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+							 MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING));
+					break;
+				case 14:
+					gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+							 MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+							 PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+							 SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+					break;
+				case 16:
+					gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+							 MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+							 PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+							 SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+					break;
+				case 17:
+					gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+							 MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+							 PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+							 SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+					break;
+				case 27:
+					gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+							 MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING));
+					break;
+				case 28:
+					gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+							 MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+							 PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+							 SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+					break;
+				case 29:
+					gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+							 MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+							 PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+							 SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+					break;
+				case 30:
+					gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+							 MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+							 PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+							 SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+					break;
+				default:
+					gb_tile_moden = 0;
+					break;
+				}
+				WREG32(GB_TILE_MODE0 + (reg_offset * 4), gb_tile_moden);
+			}
+		}
+		for (reg_offset = 0; reg_offset < num_secondary_tile_mode_states; reg_offset++) {
+			switch (reg_offset) {
+			case 0:
+				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+						 NUM_BANKS(ADDR_SURF_16_BANK));
+				break;
+			case 1:
+				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+						 NUM_BANKS(ADDR_SURF_16_BANK));
+				break;
+			case 2:
+				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+						 NUM_BANKS(ADDR_SURF_16_BANK));
+				break;
+			case 3:
+				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+						 NUM_BANKS(ADDR_SURF_16_BANK));
+				break;
+			case 4:
+				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+						 NUM_BANKS(ADDR_SURF_16_BANK));
+				break;
+			case 5:
+				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+						 NUM_BANKS(ADDR_SURF_8_BANK));
+				break;
+			case 6:
+				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
+						 NUM_BANKS(ADDR_SURF_4_BANK));
+				break;
+			case 8:
+				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_8) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+						 NUM_BANKS(ADDR_SURF_16_BANK));
+				break;
+			case 9:
+				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+						 NUM_BANKS(ADDR_SURF_16_BANK));
+				break;
+			case 10:
+				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+						 NUM_BANKS(ADDR_SURF_16_BANK));
+				break;
+			case 11:
+				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+						 NUM_BANKS(ADDR_SURF_16_BANK));
+				break;
+			case 12:
+				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+						 NUM_BANKS(ADDR_SURF_16_BANK));
+				break;
+			case 13:
+				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+						 NUM_BANKS(ADDR_SURF_8_BANK));
+				break;
+			case 14:
+				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
+						 NUM_BANKS(ADDR_SURF_4_BANK));
+				break;
+			default:
+				gb_tile_moden = 0;
+				break;
+			}
+			WREG32(GB_MACROTILE_MODE0 + (reg_offset * 4), gb_tile_moden);
+		}
+	} else if (num_pipe_configs == 2) {
+		for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++) {
+			switch (reg_offset) {
+			case 0:
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P2) |
+						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B));
+				break;
+			case 1:
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P2) |
+						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B));
+				break;
+			case 2:
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P2) |
+						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B));
+				break;
+			case 3:
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P2) |
+						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B));
+				break;
+			case 4:
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P2) |
+						 TILE_SPLIT(split_equal_to_row_size));
+				break;
+			case 5:
+				gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+						 MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+				break;
+			case 6:
+				gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P2) |
+						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B));
+				break;
+			case 7:
+				gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P2) |
+						 TILE_SPLIT(split_equal_to_row_size));
+				break;
+			case 8:
+				gb_tile_moden = ARRAY_MODE(ARRAY_LINEAR_ALIGNED);
+				break;
+			case 9:
+				gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+						 MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING));
+				break;
+			case 10:
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P2) |
+						 SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+				break;
+			case 11:
+				gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+						 MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P2) |
+						 SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+				break;
+			case 12:
+				gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P2) |
+						 SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+				break;
+			case 13:
+				gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+						 MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING));
+				break;
+			case 14:
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P2) |
+						 SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+				break;
+			case 16:
+				gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+						 MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P2) |
+						 SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+				break;
+			case 17:
+				gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P2) |
+						 SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+				break;
+			case 27:
+				gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+						 MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING));
+				break;
+			case 28:
+				gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P2) |
+						 SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+				break;
+			case 29:
+				gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+						 MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P2) |
+						 SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+				break;
+			case 30:
+				gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P2) |
+						 SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+				break;
+			default:
+				gb_tile_moden = 0;
+				break;
+			}
+			WREG32(GB_TILE_MODE0 + (reg_offset * 4), gb_tile_moden);
+		}
+		for (reg_offset = 0; reg_offset < num_secondary_tile_mode_states; reg_offset++) {
+			switch (reg_offset) {
+			case 0:
+				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+						 NUM_BANKS(ADDR_SURF_16_BANK));
+				break;
+			case 1:
+				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+						 NUM_BANKS(ADDR_SURF_16_BANK));
+				break;
+			case 2:
+				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+						 NUM_BANKS(ADDR_SURF_16_BANK));
+				break;
+			case 3:
+				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+						 NUM_BANKS(ADDR_SURF_16_BANK));
+				break;
+			case 4:
+				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+						 NUM_BANKS(ADDR_SURF_16_BANK));
+				break;
+			case 5:
+				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+						 NUM_BANKS(ADDR_SURF_16_BANK));
+				break;
+			case 6:
+				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+						 NUM_BANKS(ADDR_SURF_8_BANK));
+				break;
+			case 8:
+				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_4) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_8) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+						 NUM_BANKS(ADDR_SURF_16_BANK));
+				break;
+			case 9:
+				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_4) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+						 NUM_BANKS(ADDR_SURF_16_BANK));
+				break;
+			case 10:
+				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+						 NUM_BANKS(ADDR_SURF_16_BANK));
+				break;
+			case 11:
+				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+						 NUM_BANKS(ADDR_SURF_16_BANK));
+				break;
+			case 12:
+				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+						 NUM_BANKS(ADDR_SURF_16_BANK));
+				break;
+			case 13:
+				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+						 NUM_BANKS(ADDR_SURF_16_BANK));
+				break;
+			case 14:
+				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+						 NUM_BANKS(ADDR_SURF_8_BANK));
+				break;
+			default:
+				gb_tile_moden = 0;
+				break;
+			}
+			WREG32(GB_MACROTILE_MODE0 + (reg_offset * 4), gb_tile_moden);
+		}
+	} else
+		DRM_ERROR("unknown num pipe config: 0x%x\n", num_pipe_configs);
+}
+
+/**
+ * cik_select_se_sh - select which SE, SH to address
+ *
+ * @rdev: radeon_device pointer
+ * @se_num: shader engine to address
+ * @sh_num: sh block to address
+ *
+ * Select which SE, SH combinations to address. Certain
+ * registers are instanced per SE or SH.  0xffffffff means
+ * broadcast to all SEs or SHs (CIK).
+ */
+static void cik_select_se_sh(struct radeon_device *rdev,
+			     u32 se_num, u32 sh_num)
+{
+	u32 data = INSTANCE_BROADCAST_WRITES;
+
+	if ((se_num == 0xffffffff) && (sh_num == 0xffffffff))
+		data = SH_BROADCAST_WRITES | SE_BROADCAST_WRITES;
+	else if (se_num == 0xffffffff)
+		data |= SE_BROADCAST_WRITES | SH_INDEX(sh_num);
+	else if (sh_num == 0xffffffff)
+		data |= SH_BROADCAST_WRITES | SE_INDEX(se_num);
+	else
+		data |= SH_INDEX(sh_num) | SE_INDEX(se_num);
+	WREG32(GRBM_GFX_INDEX, data);
+}
+
+/**
+ * cik_create_bitmask - create a bitmask
+ *
+ * @bit_width: length of the mask
+ *
+ * create a variable length bit mask (CIK).
+ * Returns the bitmask.
+ */
+static u32 cik_create_bitmask(u32 bit_width)
+{
+	u32 i, mask = 0;
+
+	for (i = 0; i < bit_width; i++) {
+		mask <<= 1;
+		mask |= 1;
+	}
+	return mask;
+}
+
+/**
+ * cik_select_se_sh - select which SE, SH to address
+ *
+ * @rdev: radeon_device pointer
+ * @max_rb_num: max RBs (render backends) for the asic
+ * @se_num: number of SEs (shader engines) for the asic
+ * @sh_per_se: number of SH blocks per SE for the asic
+ *
+ * Calculates the bitmask of disabled RBs (CIK).
+ * Returns the disabled RB bitmask.
+ */
+static u32 cik_get_rb_disabled(struct radeon_device *rdev,
+			      u32 max_rb_num, u32 se_num,
+			      u32 sh_per_se)
+{
+	u32 data, mask;
+
+	data = RREG32(CC_RB_BACKEND_DISABLE);
+	if (data & 1)
+		data &= BACKEND_DISABLE_MASK;
+	else
+		data = 0;
+	data |= RREG32(GC_USER_RB_BACKEND_DISABLE);
+
+	data >>= BACKEND_DISABLE_SHIFT;
+
+	mask = cik_create_bitmask(max_rb_num / se_num / sh_per_se);
+
+	return data & mask;
+}
+
+/**
+ * cik_setup_rb - setup the RBs on the asic
+ *
+ * @rdev: radeon_device pointer
+ * @se_num: number of SEs (shader engines) for the asic
+ * @sh_per_se: number of SH blocks per SE for the asic
+ * @max_rb_num: max RBs (render backends) for the asic
+ *
+ * Configures per-SE/SH RB registers (CIK).
+ */
+static void cik_setup_rb(struct radeon_device *rdev,
+			 u32 se_num, u32 sh_per_se,
+			 u32 max_rb_num)
+{
+	int i, j;
+	u32 data, mask;
+	u32 disabled_rbs = 0;
+	u32 enabled_rbs = 0;
+
+	for (i = 0; i < se_num; i++) {
+		for (j = 0; j < sh_per_se; j++) {
+			cik_select_se_sh(rdev, i, j);
+			data = cik_get_rb_disabled(rdev, max_rb_num, se_num, sh_per_se);
+			disabled_rbs |= data << ((i * sh_per_se + j) * CIK_RB_BITMAP_WIDTH_PER_SH);
+		}
+	}
+	cik_select_se_sh(rdev, 0xffffffff, 0xffffffff);
+
+	mask = 1;
+	for (i = 0; i < max_rb_num; i++) {
+		if (!(disabled_rbs & mask))
+			enabled_rbs |= mask;
+		mask <<= 1;
+	}
+
+	for (i = 0; i < se_num; i++) {
+		cik_select_se_sh(rdev, i, 0xffffffff);
+		data = 0;
+		for (j = 0; j < sh_per_se; j++) {
+			switch (enabled_rbs & 3) {
+			case 1:
+				data |= (RASTER_CONFIG_RB_MAP_0 << (i * sh_per_se + j) * 2);
+				break;
+			case 2:
+				data |= (RASTER_CONFIG_RB_MAP_3 << (i * sh_per_se + j) * 2);
+				break;
+			case 3:
+			default:
+				data |= (RASTER_CONFIG_RB_MAP_2 << (i * sh_per_se + j) * 2);
+				break;
+			}
+			enabled_rbs >>= 2;
+		}
+		WREG32(PA_SC_RASTER_CONFIG, data);
+	}
+	cik_select_se_sh(rdev, 0xffffffff, 0xffffffff);
+}
+
+/**
+ * cik_gpu_init - setup the 3D engine
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Configures the 3D engine and tiling configuration
+ * registers so that the 3D engine is usable.
+ */
+static void cik_gpu_init(struct radeon_device *rdev)
+{
+	u32 gb_addr_config = RREG32(GB_ADDR_CONFIG);
+	u32 mc_shared_chmap, mc_arb_ramcfg;
+	u32 hdp_host_path_cntl;
+	u32 tmp;
+	int i, j;
+
+	switch (rdev->family) {
+	case CHIP_BONAIRE:
+		rdev->config.cik.max_shader_engines = 2;
+		rdev->config.cik.max_tile_pipes = 4;
+		rdev->config.cik.max_cu_per_sh = 7;
+		rdev->config.cik.max_sh_per_se = 1;
+		rdev->config.cik.max_backends_per_se = 2;
+		rdev->config.cik.max_texture_channel_caches = 4;
+		rdev->config.cik.max_gprs = 256;
+		rdev->config.cik.max_gs_threads = 32;
+		rdev->config.cik.max_hw_contexts = 8;
+
+		rdev->config.cik.sc_prim_fifo_size_frontend = 0x20;
+		rdev->config.cik.sc_prim_fifo_size_backend = 0x100;
+		rdev->config.cik.sc_hiz_tile_fifo_size = 0x30;
+		rdev->config.cik.sc_earlyz_tile_fifo_size = 0x130;
+		gb_addr_config = BONAIRE_GB_ADDR_CONFIG_GOLDEN;
+		break;
+	case CHIP_KAVERI:
+		/* TODO */
+		break;
+	case CHIP_KABINI:
+	default:
+		rdev->config.cik.max_shader_engines = 1;
+		rdev->config.cik.max_tile_pipes = 2;
+		rdev->config.cik.max_cu_per_sh = 2;
+		rdev->config.cik.max_sh_per_se = 1;
+		rdev->config.cik.max_backends_per_se = 1;
+		rdev->config.cik.max_texture_channel_caches = 2;
+		rdev->config.cik.max_gprs = 256;
+		rdev->config.cik.max_gs_threads = 16;
+		rdev->config.cik.max_hw_contexts = 8;
+
+		rdev->config.cik.sc_prim_fifo_size_frontend = 0x20;
+		rdev->config.cik.sc_prim_fifo_size_backend = 0x100;
+		rdev->config.cik.sc_hiz_tile_fifo_size = 0x30;
+		rdev->config.cik.sc_earlyz_tile_fifo_size = 0x130;
+		gb_addr_config = BONAIRE_GB_ADDR_CONFIG_GOLDEN;
+		break;
+	}
+
+	/* Initialize HDP */
+	for (i = 0, j = 0; i < 32; i++, j += 0x18) {
+		WREG32((0x2c14 + j), 0x00000000);
+		WREG32((0x2c18 + j), 0x00000000);
+		WREG32((0x2c1c + j), 0x00000000);
+		WREG32((0x2c20 + j), 0x00000000);
+		WREG32((0x2c24 + j), 0x00000000);
+	}
+
+	WREG32(GRBM_CNTL, GRBM_READ_TIMEOUT(0xff));
+
+	WREG32(BIF_FB_EN, FB_READ_EN | FB_WRITE_EN);
+
+	mc_shared_chmap = RREG32(MC_SHARED_CHMAP);
+	mc_arb_ramcfg = RREG32(MC_ARB_RAMCFG);
+
+	rdev->config.cik.num_tile_pipes = rdev->config.cik.max_tile_pipes;
+	rdev->config.cik.mem_max_burst_length_bytes = 256;
+	tmp = (mc_arb_ramcfg & NOOFCOLS_MASK) >> NOOFCOLS_SHIFT;
+	rdev->config.cik.mem_row_size_in_kb = (4 * (1 << (8 + tmp))) / 1024;
+	if (rdev->config.cik.mem_row_size_in_kb > 4)
+		rdev->config.cik.mem_row_size_in_kb = 4;
+	/* XXX use MC settings? */
+	rdev->config.cik.shader_engine_tile_size = 32;
+	rdev->config.cik.num_gpus = 1;
+	rdev->config.cik.multi_gpu_tile_size = 64;
+
+	/* fix up row size */
+	gb_addr_config &= ~ROW_SIZE_MASK;
+	switch (rdev->config.cik.mem_row_size_in_kb) {
+	case 1:
+	default:
+		gb_addr_config |= ROW_SIZE(0);
+		break;
+	case 2:
+		gb_addr_config |= ROW_SIZE(1);
+		break;
+	case 4:
+		gb_addr_config |= ROW_SIZE(2);
+		break;
+	}
+
+	/* setup tiling info dword.  gb_addr_config is not adequate since it does
+	 * not have bank info, so create a custom tiling dword.
+	 * bits 3:0   num_pipes
+	 * bits 7:4   num_banks
+	 * bits 11:8  group_size
+	 * bits 15:12 row_size
+	 */
+	rdev->config.cik.tile_config = 0;
+	switch (rdev->config.cik.num_tile_pipes) {
+	case 1:
+		rdev->config.cik.tile_config |= (0 << 0);
+		break;
+	case 2:
+		rdev->config.cik.tile_config |= (1 << 0);
+		break;
+	case 4:
+		rdev->config.cik.tile_config |= (2 << 0);
+		break;
+	case 8:
+	default:
+		/* XXX what about 12? */
+		rdev->config.cik.tile_config |= (3 << 0);
+		break;
+	}
+	if ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT)
+		rdev->config.cik.tile_config |= 1 << 4;
+	else
+		rdev->config.cik.tile_config |= 0 << 4;
+	rdev->config.cik.tile_config |=
+		((gb_addr_config & PIPE_INTERLEAVE_SIZE_MASK) >> PIPE_INTERLEAVE_SIZE_SHIFT) << 8;
+	rdev->config.cik.tile_config |=
+		((gb_addr_config & ROW_SIZE_MASK) >> ROW_SIZE_SHIFT) << 12;
+
+	WREG32(GB_ADDR_CONFIG, gb_addr_config);
+	WREG32(HDP_ADDR_CONFIG, gb_addr_config);
+	WREG32(DMIF_ADDR_CALC, gb_addr_config);
+
+	cik_tiling_mode_table_init(rdev);
+
+	cik_setup_rb(rdev, rdev->config.cik.max_shader_engines,
+		     rdev->config.cik.max_sh_per_se,
+		     rdev->config.cik.max_backends_per_se);
+
+	/* set HW defaults for 3D engine */
+	WREG32(CP_MEQ_THRESHOLDS, MEQ1_START(0x30) | MEQ2_START(0x60));
+
+	WREG32(SX_DEBUG_1, 0x20);
+
+	WREG32(TA_CNTL_AUX, 0x00010000);
+
+	tmp = RREG32(SPI_CONFIG_CNTL);
+	tmp |= 0x03000000;
+	WREG32(SPI_CONFIG_CNTL, tmp);
+
+	WREG32(SQ_CONFIG, 1);
+
+	WREG32(DB_DEBUG, 0);
+
+	tmp = RREG32(DB_DEBUG2) & ~0xf00fffff;
+	tmp |= 0x00000400;
+	WREG32(DB_DEBUG2, tmp);
+
+	tmp = RREG32(DB_DEBUG3) & ~0x0002021c;
+	tmp |= 0x00020200;
+	WREG32(DB_DEBUG3, tmp);
+
+	tmp = RREG32(CB_HW_CONTROL) & ~0x00010000;
+	tmp |= 0x00018208;
+	WREG32(CB_HW_CONTROL, tmp);
+
+	WREG32(SPI_CONFIG_CNTL_1, VTX_DONE_DELAY(4));
+
+	WREG32(PA_SC_FIFO_SIZE, (SC_FRONTEND_PRIM_FIFO_SIZE(rdev->config.cik.sc_prim_fifo_size_frontend) |
+				 SC_BACKEND_PRIM_FIFO_SIZE(rdev->config.cik.sc_prim_fifo_size_backend) |
+				 SC_HIZ_TILE_FIFO_SIZE(rdev->config.cik.sc_hiz_tile_fifo_size) |
+				 SC_EARLYZ_TILE_FIFO_SIZE(rdev->config.cik.sc_earlyz_tile_fifo_size)));
+
+	WREG32(VGT_NUM_INSTANCES, 1);
+
+	WREG32(CP_PERFMON_CNTL, 0);
+
+	WREG32(SQ_CONFIG, 0);
+
+	WREG32(PA_SC_FORCE_EOV_MAX_CNTS, (FORCE_EOV_MAX_CLK_CNT(4095) |
+					  FORCE_EOV_MAX_REZ_CNT(255)));
+
+	WREG32(VGT_CACHE_INVALIDATION, CACHE_INVALIDATION(VC_AND_TC) |
+	       AUTO_INVLD_EN(ES_AND_GS_AUTO));
+
+	WREG32(VGT_GS_VERTEX_REUSE, 16);
+	WREG32(PA_SC_LINE_STIPPLE_STATE, 0);
+
+	tmp = RREG32(HDP_MISC_CNTL);
+	tmp |= HDP_FLUSH_INVALIDATE_CACHE;
+	WREG32(HDP_MISC_CNTL, tmp);
+
+	hdp_host_path_cntl = RREG32(HDP_HOST_PATH_CNTL);
+	WREG32(HDP_HOST_PATH_CNTL, hdp_host_path_cntl);
+
+	WREG32(PA_CL_ENHANCE, CLIP_VTX_REORDER_ENA | NUM_CLIP_SEQ(3));
+	WREG32(PA_SC_ENHANCE, ENABLE_PA_SC_OUT_OF_ORDER);
+
+	udelay(50);
+}
+
diff --git a/drivers/gpu/drm/radeon/cikd.h b/drivers/gpu/drm/radeon/cikd.h
new file mode 100644
index 0000000..e51fb41
--- /dev/null
+++ b/drivers/gpu/drm/radeon/cikd.h
@@ -0,0 +1,253 @@
+/*
+ * Copyright 2012 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Alex Deucher
+ */
+#ifndef CIK_H
+#define CIK_H
+
+#define BONAIRE_GB_ADDR_CONFIG_GOLDEN        0x12010001
+
+#define CIK_RB_BITMAP_WIDTH_PER_SH  2
+
+#define DMIF_ADDR_CALC  				0xC00
+
+#define MC_SHARED_CHMAP						0x2004
+#define		NOOFCHAN_SHIFT					12
+#define		NOOFCHAN_MASK					0x0000f000
+#define MC_SHARED_CHREMAP					0x2008
+
+#define	MC_ARB_RAMCFG					0x2760
+#define		NOOFBANK_SHIFT					0
+#define		NOOFBANK_MASK					0x00000003
+#define		NOOFRANK_SHIFT					2
+#define		NOOFRANK_MASK					0x00000004
+#define		NOOFROWS_SHIFT					3
+#define		NOOFROWS_MASK					0x00000038
+#define		NOOFCOLS_SHIFT					6
+#define		NOOFCOLS_MASK					0x000000C0
+#define		CHANSIZE_SHIFT					8
+#define		CHANSIZE_MASK					0x00000100
+#define		NOOFGROUPS_SHIFT				12
+#define		NOOFGROUPS_MASK					0x00001000
+
+#define	HDP_HOST_PATH_CNTL				0x2C00
+#define	HDP_NONSURFACE_BASE				0x2C04
+#define	HDP_NONSURFACE_INFO				0x2C08
+#define	HDP_NONSURFACE_SIZE				0x2C0C
+
+#define HDP_ADDR_CONFIG  				0x2F48
+#define HDP_MISC_CNTL					0x2F4C
+#define 	HDP_FLUSH_INVALIDATE_CACHE			(1 << 0)
+
+#define	BIF_FB_EN						0x5490
+#define		FB_READ_EN					(1 << 0)
+#define		FB_WRITE_EN					(1 << 1)
+
+#define	GRBM_CNTL					0x8000
+#define		GRBM_READ_TIMEOUT(x)				((x) << 0)
+
+#define CP_MEQ_THRESHOLDS				0x8764
+#define		MEQ1_START(x)				((x) << 0)
+#define		MEQ2_START(x)				((x) << 8)
+
+#define	VGT_VTX_VECT_EJECT_REG				0x88B0
+
+#define	VGT_CACHE_INVALIDATION				0x88C4
+#define		CACHE_INVALIDATION(x)				((x) << 0)
+#define			VC_ONLY						0
+#define			TC_ONLY						1
+#define			VC_AND_TC					2
+#define		AUTO_INVLD_EN(x)				((x) << 6)
+#define			NO_AUTO						0
+#define			ES_AUTO						1
+#define			GS_AUTO						2
+#define			ES_AND_GS_AUTO					3
+
+#define	VGT_GS_VERTEX_REUSE				0x88D4
+
+#define CC_GC_SHADER_ARRAY_CONFIG			0x89bc
+#define		INACTIVE_CUS_MASK			0xFFFF0000
+#define		INACTIVE_CUS_SHIFT			16
+#define GC_USER_SHADER_ARRAY_CONFIG			0x89c0
+
+#define	PA_CL_ENHANCE					0x8A14
+#define		CLIP_VTX_REORDER_ENA				(1 << 0)
+#define		NUM_CLIP_SEQ(x)					((x) << 1)
+
+#define	PA_SC_FORCE_EOV_MAX_CNTS			0x8B24
+#define		FORCE_EOV_MAX_CLK_CNT(x)			((x) << 0)
+#define		FORCE_EOV_MAX_REZ_CNT(x)			((x) << 16)
+
+#define	PA_SC_FIFO_SIZE					0x8BCC
+#define		SC_FRONTEND_PRIM_FIFO_SIZE(x)			((x) << 0)
+#define		SC_BACKEND_PRIM_FIFO_SIZE(x)			((x) << 6)
+#define		SC_HIZ_TILE_FIFO_SIZE(x)			((x) << 15)
+#define		SC_EARLYZ_TILE_FIFO_SIZE(x)			((x) << 23)
+
+#define	PA_SC_ENHANCE					0x8BF0
+#define		ENABLE_PA_SC_OUT_OF_ORDER			(1 << 0)
+#define		DISABLE_PA_SC_GUIDANCE				(1 << 13)
+
+#define	SQ_CONFIG					0x8C00
+
+#define	SX_DEBUG_1					0x9060
+
+#define	SPI_CONFIG_CNTL					0x9100
+
+#define	SPI_CONFIG_CNTL_1				0x913C
+#define		VTX_DONE_DELAY(x)				((x) << 0)
+#define		INTERP_ONE_PRIM_PER_ROW				(1 << 4)
+
+#define	TA_CNTL_AUX					0x9508
+
+#define DB_DEBUG					0x9830
+#define DB_DEBUG2					0x9834
+#define DB_DEBUG3					0x9838
+
+#define CC_RB_BACKEND_DISABLE				0x98F4
+#define		BACKEND_DISABLE(x)     			((x) << 16)
+#define GB_ADDR_CONFIG  				0x98F8
+#define		NUM_PIPES(x)				((x) << 0)
+#define		NUM_PIPES_MASK				0x00000007
+#define		NUM_PIPES_SHIFT				0
+#define		PIPE_INTERLEAVE_SIZE(x)			((x) << 4)
+#define		PIPE_INTERLEAVE_SIZE_MASK		0x00000070
+#define		PIPE_INTERLEAVE_SIZE_SHIFT		4
+#define		NUM_SHADER_ENGINES(x)			((x) << 12)
+#define		NUM_SHADER_ENGINES_MASK			0x00003000
+#define		NUM_SHADER_ENGINES_SHIFT		12
+#define		SHADER_ENGINE_TILE_SIZE(x)     		((x) << 16)
+#define		SHADER_ENGINE_TILE_SIZE_MASK		0x00070000
+#define		SHADER_ENGINE_TILE_SIZE_SHIFT		16
+#define		ROW_SIZE(x)             		((x) << 28)
+#define		ROW_SIZE_MASK				0x30000000
+#define		ROW_SIZE_SHIFT				28
+
+#define	GB_TILE_MODE0					0x9910
+#       define ARRAY_MODE(x)					((x) << 2)
+#              define	ARRAY_LINEAR_GENERAL			0
+#              define	ARRAY_LINEAR_ALIGNED			1
+#              define	ARRAY_1D_TILED_THIN1			2
+#              define	ARRAY_2D_TILED_THIN1			4
+#              define	ARRAY_PRT_TILED_THIN1			5
+#              define	ARRAY_PRT_2D_TILED_THIN1		6
+#       define PIPE_CONFIG(x)					((x) << 6)
+#              define	ADDR_SURF_P2				0
+#              define	ADDR_SURF_P4_8x16			4
+#              define	ADDR_SURF_P4_16x16			5
+#              define	ADDR_SURF_P4_16x32			6
+#              define	ADDR_SURF_P4_32x32			7
+#              define	ADDR_SURF_P8_16x16_8x16			8
+#              define	ADDR_SURF_P8_16x32_8x16			9
+#              define	ADDR_SURF_P8_32x32_8x16			10
+#              define	ADDR_SURF_P8_16x32_16x16		11
+#              define	ADDR_SURF_P8_32x32_16x16		12
+#              define	ADDR_SURF_P8_32x32_16x32		13
+#              define	ADDR_SURF_P8_32x64_32x32		14
+#       define TILE_SPLIT(x)					((x) << 11)
+#              define	ADDR_SURF_TILE_SPLIT_64B		0
+#              define	ADDR_SURF_TILE_SPLIT_128B		1
+#              define	ADDR_SURF_TILE_SPLIT_256B		2
+#              define	ADDR_SURF_TILE_SPLIT_512B		3
+#              define	ADDR_SURF_TILE_SPLIT_1KB		4
+#              define	ADDR_SURF_TILE_SPLIT_2KB		5
+#              define	ADDR_SURF_TILE_SPLIT_4KB		6
+#       define MICRO_TILE_MODE_NEW(x)				((x) << 22)
+#              define	ADDR_SURF_DISPLAY_MICRO_TILING		0
+#              define	ADDR_SURF_THIN_MICRO_TILING		1
+#              define	ADDR_SURF_DEPTH_MICRO_TILING		2
+#              define	ADDR_SURF_ROTATED_MICRO_TILING		3
+#       define SAMPLE_SPLIT(x)					((x) << 25)
+#              define	ADDR_SURF_SAMPLE_SPLIT_1		0
+#              define	ADDR_SURF_SAMPLE_SPLIT_2		1
+#              define	ADDR_SURF_SAMPLE_SPLIT_4		2
+#              define	ADDR_SURF_SAMPLE_SPLIT_8		3
+
+#define	GB_MACROTILE_MODE0					0x9990
+#       define BANK_WIDTH(x)					((x) << 0)
+#              define	ADDR_SURF_BANK_WIDTH_1			0
+#              define	ADDR_SURF_BANK_WIDTH_2			1
+#              define	ADDR_SURF_BANK_WIDTH_4			2
+#              define	ADDR_SURF_BANK_WIDTH_8			3
+#       define BANK_HEIGHT(x)					((x) << 2)
+#              define	ADDR_SURF_BANK_HEIGHT_1			0
+#              define	ADDR_SURF_BANK_HEIGHT_2			1
+#              define	ADDR_SURF_BANK_HEIGHT_4			2
+#              define	ADDR_SURF_BANK_HEIGHT_8			3
+#       define MACRO_TILE_ASPECT(x)				((x) << 4)
+#              define	ADDR_SURF_MACRO_ASPECT_1		0
+#              define	ADDR_SURF_MACRO_ASPECT_2		1
+#              define	ADDR_SURF_MACRO_ASPECT_4		2
+#              define	ADDR_SURF_MACRO_ASPECT_8		3
+#       define NUM_BANKS(x)					((x) << 6)
+#              define	ADDR_SURF_2_BANK			0
+#              define	ADDR_SURF_4_BANK			1
+#              define	ADDR_SURF_8_BANK			2
+#              define	ADDR_SURF_16_BANK			3
+
+#define	CB_HW_CONTROL					0x9A10
+
+#define	GC_USER_RB_BACKEND_DISABLE			0x9B7C
+#define		BACKEND_DISABLE_MASK			0x00FF0000
+#define		BACKEND_DISABLE_SHIFT			16
+
+#define	TCP_CHAN_STEER_LO				0xac0c
+#define	TCP_CHAN_STEER_HI				0xac10
+
+#define PA_SC_RASTER_CONFIG                             0x28350
+#       define RASTER_CONFIG_RB_MAP_0                   0
+#       define RASTER_CONFIG_RB_MAP_1                   1
+#       define RASTER_CONFIG_RB_MAP_2                   2
+#       define RASTER_CONFIG_RB_MAP_3                   3
+
+#define GRBM_GFX_INDEX          			0x30800
+#define		INSTANCE_INDEX(x)			((x) << 0)
+#define		SH_INDEX(x)     			((x) << 8)
+#define		SE_INDEX(x)     			((x) << 16)
+#define		SH_BROADCAST_WRITES      		(1 << 29)
+#define		INSTANCE_BROADCAST_WRITES      		(1 << 30)
+#define		SE_BROADCAST_WRITES      		(1 << 31)
+
+#define	VGT_ESGS_RING_SIZE				0x30900
+#define	VGT_GSVS_RING_SIZE				0x30904
+#define	VGT_PRIMITIVE_TYPE				0x30908
+#define	VGT_INDEX_TYPE					0x3090C
+
+#define	VGT_NUM_INDICES					0x30930
+#define	VGT_NUM_INSTANCES				0x30934
+#define	VGT_TF_RING_SIZE				0x30938
+#define	VGT_HS_OFFCHIP_PARAM				0x3093C
+#define	VGT_TF_MEMORY_BASE				0x30940
+
+#define	PA_SU_LINE_STIPPLE_VALUE			0x30a00
+#define	PA_SC_LINE_STIPPLE_STATE			0x30a04
+
+#define	SQC_CACHES					0x30d20
+
+#define	CP_PERFMON_CNTL					0x36020
+
+#define	CGTS_TCC_DISABLE				0x3c00c
+#define	CGTS_USER_TCC_DISABLE				0x3c010
+#define		TCC_DISABLE_MASK				0xFFFF0000
+#define		TCC_DISABLE_SHIFT				16
+
+#endif
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index b50a786..b1a2230 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -1505,6 +1505,35 @@ struct si_asic {
 	uint32_t tile_mode_array[32];
 };
 
+struct cik_asic {
+	unsigned max_shader_engines;
+	unsigned max_tile_pipes;
+	unsigned max_cu_per_sh;
+	unsigned max_sh_per_se;
+	unsigned max_backends_per_se;
+	unsigned max_texture_channel_caches;
+	unsigned max_gprs;
+	unsigned max_gs_threads;
+	unsigned max_hw_contexts;
+	unsigned sc_prim_fifo_size_frontend;
+	unsigned sc_prim_fifo_size_backend;
+	unsigned sc_hiz_tile_fifo_size;
+	unsigned sc_earlyz_tile_fifo_size;
+
+	unsigned num_tile_pipes;
+	unsigned num_backends_per_se;
+	unsigned backend_disable_mask_per_asic;
+	unsigned backend_map;
+	unsigned num_texture_channel_caches;
+	unsigned mem_max_burst_length_bytes;
+	unsigned mem_row_size_in_kb;
+	unsigned shader_engine_tile_size;
+	unsigned num_gpus;
+	unsigned multi_gpu_tile_size;
+
+	unsigned tile_config;
+};
+
 union radeon_asic_config {
 	struct r300_asic	r300;
 	struct r100_asic	r100;
@@ -1513,6 +1542,7 @@ union radeon_asic_config {
 	struct evergreen_asic	evergreen;
 	struct cayman_asic	cayman;
 	struct si_asic		si;
+	struct cik_asic		cik;
 };
 
 /*
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 008/165] drm/radeon: Add support for CIK GPU reset (v2)
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (7 preceding siblings ...)
  2013-06-26 13:21 ` [PATCH 007/165] drm/radeon: add gpu init support for CIK (v9) alexdeucher
@ 2013-06-26 13:21 ` alexdeucher
  2013-06-26 13:21 ` [PATCH 009/165] drm/radeon: add support for MC/VM setup on CIK (v6) alexdeucher
                   ` (104 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:21 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

v2: split soft reset into compute and gfx.  Still need
to make reset more fine grained, but this should be a
start.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/cik.c  |  197 +++++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/radeon/cikd.h |   80 +++++++++++++++++
 2 files changed, 277 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
index 28f68dc..e448ae2 100644
--- a/drivers/gpu/drm/radeon/cik.c
+++ b/drivers/gpu/drm/radeon/cik.c
@@ -27,9 +27,13 @@
 #include <linux/module.h>
 #include "drmP.h"
 #include "radeon.h"
+#include "radeon_asic.h"
 #include "cikd.h"
 #include "atom.h"
 
+extern void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save);
+extern void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save);
+
 /*
  * Core functions
  */
@@ -1190,3 +1194,196 @@ static void cik_gpu_init(struct radeon_device *rdev)
 	udelay(50);
 }
 
+/**
+ * cik_gpu_is_lockup - check if the 3D engine is locked up
+ *
+ * @rdev: radeon_device pointer
+ * @ring: radeon_ring structure holding ring information
+ *
+ * Check if the 3D engine is locked up (CIK).
+ * Returns true if the engine is locked, false if not.
+ */
+bool cik_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)
+{
+	u32 srbm_status, srbm_status2;
+	u32 grbm_status, grbm_status2;
+	u32 grbm_status_se0, grbm_status_se1, grbm_status_se2, grbm_status_se3;
+
+	srbm_status = RREG32(SRBM_STATUS);
+	srbm_status2 = RREG32(SRBM_STATUS2);
+	grbm_status = RREG32(GRBM_STATUS);
+	grbm_status2 = RREG32(GRBM_STATUS2);
+	grbm_status_se0 = RREG32(GRBM_STATUS_SE0);
+	grbm_status_se1 = RREG32(GRBM_STATUS_SE1);
+	grbm_status_se2 = RREG32(GRBM_STATUS_SE2);
+	grbm_status_se3 = RREG32(GRBM_STATUS_SE3);
+	if (!(grbm_status & GUI_ACTIVE)) {
+		radeon_ring_lockup_update(ring);
+		return false;
+	}
+	/* force CP activities */
+	radeon_ring_force_activity(rdev, ring);
+	return radeon_ring_test_lockup(rdev, ring);
+}
+
+/**
+ * cik_gfx_gpu_soft_reset - soft reset the 3D engine and CPG
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Soft reset the GFX engine and CPG blocks (CIK).
+ * XXX: deal with reseting RLC and CPF
+ * Returns 0 for success.
+ */
+static int cik_gfx_gpu_soft_reset(struct radeon_device *rdev)
+{
+	struct evergreen_mc_save save;
+	u32 grbm_reset = 0;
+
+	if (!(RREG32(GRBM_STATUS) & GUI_ACTIVE))
+		return 0;
+
+	dev_info(rdev->dev, "GPU GFX softreset \n");
+	dev_info(rdev->dev, "  GRBM_STATUS=0x%08X\n",
+		RREG32(GRBM_STATUS));
+	dev_info(rdev->dev, "  GRBM_STATUS2=0x%08X\n",
+		RREG32(GRBM_STATUS2));
+	dev_info(rdev->dev, "  GRBM_STATUS_SE0=0x%08X\n",
+		RREG32(GRBM_STATUS_SE0));
+	dev_info(rdev->dev, "  GRBM_STATUS_SE1=0x%08X\n",
+		RREG32(GRBM_STATUS_SE1));
+	dev_info(rdev->dev, "  GRBM_STATUS_SE2=0x%08X\n",
+		RREG32(GRBM_STATUS_SE2));
+	dev_info(rdev->dev, "  GRBM_STATUS_SE3=0x%08X\n",
+		RREG32(GRBM_STATUS_SE3));
+	dev_info(rdev->dev, "  SRBM_STATUS=0x%08X\n",
+		RREG32(SRBM_STATUS));
+	dev_info(rdev->dev, "  SRBM_STATUS2=0x%08X\n",
+		RREG32(SRBM_STATUS2));
+	evergreen_mc_stop(rdev, &save);
+	if (radeon_mc_wait_for_idle(rdev)) {
+		dev_warn(rdev->dev, "Wait for MC idle timedout !\n");
+	}
+	/* Disable CP parsing/prefetching */
+	WREG32(CP_ME_CNTL, CP_ME_HALT | CP_PFP_HALT | CP_CE_HALT);
+
+	/* reset all the gfx block and all CPG blocks */
+	grbm_reset = SOFT_RESET_CPG | SOFT_RESET_GFX;
+
+	dev_info(rdev->dev, "  GRBM_SOFT_RESET=0x%08X\n", grbm_reset);
+	WREG32(GRBM_SOFT_RESET, grbm_reset);
+	(void)RREG32(GRBM_SOFT_RESET);
+	udelay(50);
+	WREG32(GRBM_SOFT_RESET, 0);
+	(void)RREG32(GRBM_SOFT_RESET);
+	/* Wait a little for things to settle down */
+	udelay(50);
+	dev_info(rdev->dev, "  GRBM_STATUS=0x%08X\n",
+		RREG32(GRBM_STATUS));
+	dev_info(rdev->dev, "  GRBM_STATUS2=0x%08X\n",
+		RREG32(GRBM_STATUS2));
+	dev_info(rdev->dev, "  GRBM_STATUS_SE0=0x%08X\n",
+		RREG32(GRBM_STATUS_SE0));
+	dev_info(rdev->dev, "  GRBM_STATUS_SE1=0x%08X\n",
+		RREG32(GRBM_STATUS_SE1));
+	dev_info(rdev->dev, "  GRBM_STATUS_SE2=0x%08X\n",
+		RREG32(GRBM_STATUS_SE2));
+	dev_info(rdev->dev, "  GRBM_STATUS_SE3=0x%08X\n",
+		RREG32(GRBM_STATUS_SE3));
+	dev_info(rdev->dev, "  SRBM_STATUS=0x%08X\n",
+		RREG32(SRBM_STATUS));
+	dev_info(rdev->dev, "  SRBM_STATUS2=0x%08X\n",
+		RREG32(SRBM_STATUS2));
+	evergreen_mc_resume(rdev, &save);
+	return 0;
+}
+
+/**
+ * cik_compute_gpu_soft_reset - soft reset CPC
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Soft reset the CPC blocks (CIK).
+ * XXX: deal with reseting RLC and CPF
+ * Returns 0 for success.
+ */
+static int cik_compute_gpu_soft_reset(struct radeon_device *rdev)
+{
+	struct evergreen_mc_save save;
+	u32 grbm_reset = 0;
+
+	dev_info(rdev->dev, "GPU compute softreset \n");
+	dev_info(rdev->dev, "  GRBM_STATUS=0x%08X\n",
+		RREG32(GRBM_STATUS));
+	dev_info(rdev->dev, "  GRBM_STATUS2=0x%08X\n",
+		RREG32(GRBM_STATUS2));
+	dev_info(rdev->dev, "  GRBM_STATUS_SE0=0x%08X\n",
+		RREG32(GRBM_STATUS_SE0));
+	dev_info(rdev->dev, "  GRBM_STATUS_SE1=0x%08X\n",
+		RREG32(GRBM_STATUS_SE1));
+	dev_info(rdev->dev, "  GRBM_STATUS_SE2=0x%08X\n",
+		RREG32(GRBM_STATUS_SE2));
+	dev_info(rdev->dev, "  GRBM_STATUS_SE3=0x%08X\n",
+		RREG32(GRBM_STATUS_SE3));
+	dev_info(rdev->dev, "  SRBM_STATUS=0x%08X\n",
+		RREG32(SRBM_STATUS));
+	dev_info(rdev->dev, "  SRBM_STATUS2=0x%08X\n",
+		RREG32(SRBM_STATUS2));
+	evergreen_mc_stop(rdev, &save);
+	if (radeon_mc_wait_for_idle(rdev)) {
+		dev_warn(rdev->dev, "Wait for MC idle timedout !\n");
+	}
+	/* Disable CP parsing/prefetching */
+	WREG32(CP_MEC_CNTL, MEC_ME1_HALT | MEC_ME2_HALT);
+
+	/* reset all the CPC blocks */
+	grbm_reset = SOFT_RESET_CPG;
+
+	dev_info(rdev->dev, "  GRBM_SOFT_RESET=0x%08X\n", grbm_reset);
+	WREG32(GRBM_SOFT_RESET, grbm_reset);
+	(void)RREG32(GRBM_SOFT_RESET);
+	udelay(50);
+	WREG32(GRBM_SOFT_RESET, 0);
+	(void)RREG32(GRBM_SOFT_RESET);
+	/* Wait a little for things to settle down */
+	udelay(50);
+	dev_info(rdev->dev, "  GRBM_STATUS=0x%08X\n",
+		RREG32(GRBM_STATUS));
+	dev_info(rdev->dev, "  GRBM_STATUS2=0x%08X\n",
+		RREG32(GRBM_STATUS2));
+	dev_info(rdev->dev, "  GRBM_STATUS_SE0=0x%08X\n",
+		RREG32(GRBM_STATUS_SE0));
+	dev_info(rdev->dev, "  GRBM_STATUS_SE1=0x%08X\n",
+		RREG32(GRBM_STATUS_SE1));
+	dev_info(rdev->dev, "  GRBM_STATUS_SE2=0x%08X\n",
+		RREG32(GRBM_STATUS_SE2));
+	dev_info(rdev->dev, "  GRBM_STATUS_SE3=0x%08X\n",
+		RREG32(GRBM_STATUS_SE3));
+	dev_info(rdev->dev, "  SRBM_STATUS=0x%08X\n",
+		RREG32(SRBM_STATUS));
+	dev_info(rdev->dev, "  SRBM_STATUS2=0x%08X\n",
+		RREG32(SRBM_STATUS2));
+	evergreen_mc_resume(rdev, &save);
+	return 0;
+}
+
+/**
+ * cik_asic_reset - soft reset compute and gfx
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Soft reset the CPC blocks (CIK).
+ * XXX: make this more fine grained and only reset
+ * what is necessary.
+ * Returns 0 for success.
+ */
+int cik_asic_reset(struct radeon_device *rdev)
+{
+	int r;
+
+	r = cik_compute_gpu_soft_reset(rdev);
+	if (r)
+		dev_info(rdev->dev, "Compute reset failed!\n");
+
+	return cik_gfx_gpu_soft_reset(rdev);
+}
diff --git a/drivers/gpu/drm/radeon/cikd.h b/drivers/gpu/drm/radeon/cikd.h
index e51fb41..41b2316 100644
--- a/drivers/gpu/drm/radeon/cikd.h
+++ b/drivers/gpu/drm/radeon/cikd.h
@@ -30,6 +30,9 @@
 
 #define DMIF_ADDR_CALC  				0xC00
 
+#define	SRBM_STATUS2				        0xE4C
+#define	SRBM_STATUS				        0xE50
+
 #define MC_SHARED_CHMAP						0x2004
 #define		NOOFCHAN_SHIFT					12
 #define		NOOFCHAN_MASK					0x0000f000
@@ -65,6 +68,83 @@
 #define	GRBM_CNTL					0x8000
 #define		GRBM_READ_TIMEOUT(x)				((x) << 0)
 
+#define	GRBM_STATUS2					0x8008
+#define		ME0PIPE1_CMDFIFO_AVAIL_MASK			0x0000000F
+#define		ME0PIPE1_CF_RQ_PENDING				(1 << 4)
+#define		ME0PIPE1_PF_RQ_PENDING				(1 << 5)
+#define		ME1PIPE0_RQ_PENDING				(1 << 6)
+#define		ME1PIPE1_RQ_PENDING				(1 << 7)
+#define		ME1PIPE2_RQ_PENDING				(1 << 8)
+#define		ME1PIPE3_RQ_PENDING				(1 << 9)
+#define		ME2PIPE0_RQ_PENDING				(1 << 10)
+#define		ME2PIPE1_RQ_PENDING				(1 << 11)
+#define		ME2PIPE2_RQ_PENDING				(1 << 12)
+#define		ME2PIPE3_RQ_PENDING				(1 << 13)
+#define		RLC_RQ_PENDING 					(1 << 14)
+#define		RLC_BUSY 					(1 << 24)
+#define		TC_BUSY 					(1 << 25)
+#define		CPF_BUSY 					(1 << 28)
+#define		CPC_BUSY 					(1 << 29)
+#define		CPG_BUSY 					(1 << 30)
+
+#define	GRBM_STATUS					0x8010
+#define		ME0PIPE0_CMDFIFO_AVAIL_MASK			0x0000000F
+#define		SRBM_RQ_PENDING					(1 << 5)
+#define		ME0PIPE0_CF_RQ_PENDING				(1 << 7)
+#define		ME0PIPE0_PF_RQ_PENDING				(1 << 8)
+#define		GDS_DMA_RQ_PENDING				(1 << 9)
+#define		DB_CLEAN					(1 << 12)
+#define		CB_CLEAN					(1 << 13)
+#define		TA_BUSY 					(1 << 14)
+#define		GDS_BUSY 					(1 << 15)
+#define		WD_BUSY_NO_DMA 					(1 << 16)
+#define		VGT_BUSY					(1 << 17)
+#define		IA_BUSY_NO_DMA					(1 << 18)
+#define		IA_BUSY						(1 << 19)
+#define		SX_BUSY 					(1 << 20)
+#define		WD_BUSY 					(1 << 21)
+#define		SPI_BUSY					(1 << 22)
+#define		BCI_BUSY					(1 << 23)
+#define		SC_BUSY 					(1 << 24)
+#define		PA_BUSY 					(1 << 25)
+#define		DB_BUSY 					(1 << 26)
+#define		CP_COHERENCY_BUSY      				(1 << 28)
+#define		CP_BUSY 					(1 << 29)
+#define		CB_BUSY 					(1 << 30)
+#define		GUI_ACTIVE					(1 << 31)
+#define	GRBM_STATUS_SE0					0x8014
+#define	GRBM_STATUS_SE1					0x8018
+#define	GRBM_STATUS_SE2					0x8038
+#define	GRBM_STATUS_SE3					0x803C
+#define		SE_DB_CLEAN					(1 << 1)
+#define		SE_CB_CLEAN					(1 << 2)
+#define		SE_BCI_BUSY					(1 << 22)
+#define		SE_VGT_BUSY					(1 << 23)
+#define		SE_PA_BUSY					(1 << 24)
+#define		SE_TA_BUSY					(1 << 25)
+#define		SE_SX_BUSY					(1 << 26)
+#define		SE_SPI_BUSY					(1 << 27)
+#define		SE_SC_BUSY					(1 << 29)
+#define		SE_DB_BUSY					(1 << 30)
+#define		SE_CB_BUSY					(1 << 31)
+
+#define	GRBM_SOFT_RESET					0x8020
+#define		SOFT_RESET_CP					(1 << 0)  /* All CP blocks */
+#define		SOFT_RESET_RLC					(1 << 2)  /* RLC */
+#define		SOFT_RESET_GFX					(1 << 16) /* GFX */
+#define		SOFT_RESET_CPF					(1 << 17) /* CP fetcher shared by gfx and compute */
+#define		SOFT_RESET_CPC					(1 << 18) /* CP Compute (MEC1/2) */
+#define		SOFT_RESET_CPG					(1 << 19) /* CP GFX (PFP, ME, CE) */
+
+#define CP_MEC_CNTL					0x8234
+#define		MEC_ME2_HALT					(1 << 28)
+#define		MEC_ME1_HALT					(1 << 30)
+
+#define CP_ME_CNTL					0x86D8
+#define		CP_CE_HALT					(1 << 24)
+#define		CP_PFP_HALT					(1 << 26)
+#define		CP_ME_HALT					(1 << 28)
+
 #define CP_MEQ_THRESHOLDS				0x8764
 #define		MEQ1_START(x)				((x) << 0)
 #define		MEQ2_START(x)				((x) << 8)
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 009/165] drm/radeon: add support for MC/VM setup on CIK (v6)
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (8 preceding siblings ...)
  2013-06-26 13:21 ` [PATCH 008/165] drm/radeon: Add support for CIK GPU reset (v2) alexdeucher
@ 2013-06-26 13:21 ` alexdeucher
  2013-06-26 13:21 ` [PATCH 010/165] drm/radeon/cik: stop page faults from hanging the system (v2) alexdeucher
                   ` (103 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:21 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

The vm callbacks are the same as the SI ones right now
(same regs and bits). We could share the SI variants, and
I may yet do that, but I figured I would add CIK specific
ones for now in case we need to change anything.

V2: add documentation, minor fixes.
V3: integrate vram offset fixes for APUs
V4: enable 2 level VM PTs
V5: index SH_MEM_* regs properly
V6: add ib_parse()

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/cik.c  |  361 +++++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/radeon/cikd.h |  125 ++++++++++++++
 drivers/gpu/drm/radeon/si.c   |    4 +-
 3 files changed, 488 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
index e448ae2..a4e1b95 100644
--- a/drivers/gpu/drm/radeon/cik.c
+++ b/drivers/gpu/drm/radeon/cik.c
@@ -33,6 +33,7 @@
 
 extern void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save);
 extern void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save);
+extern void si_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc);
 
 /*
  * Core functions
@@ -1387,3 +1388,363 @@ int cik_asic_reset(struct radeon_device *rdev)
 
 	return cik_gfx_gpu_soft_reset(rdev);
 }
+
+/* MC */
+/**
+ * cik_mc_program - program the GPU memory controller
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Set the location of vram, gart, and AGP in the GPU's
+ * physical address space (CIK).
+ */
+static void cik_mc_program(struct radeon_device *rdev)
+{
+	struct evergreen_mc_save save;
+	u32 tmp;
+	int i, j;
+
+	/* Initialize HDP */
+	for (i = 0, j = 0; i < 32; i++, j += 0x18) {
+		WREG32((0x2c14 + j), 0x00000000);
+		WREG32((0x2c18 + j), 0x00000000);
+		WREG32((0x2c1c + j), 0x00000000);
+		WREG32((0x2c20 + j), 0x00000000);
+		WREG32((0x2c24 + j), 0x00000000);
+	}
+	WREG32(HDP_REG_COHERENCY_FLUSH_CNTL, 0);
+
+	evergreen_mc_stop(rdev, &save);
+	if (radeon_mc_wait_for_idle(rdev)) {
+		dev_warn(rdev->dev, "Wait for MC idle timedout !\n");
+	}
+	/* Lockout access through VGA aperture*/
+	WREG32(VGA_HDP_CONTROL, VGA_MEMORY_DISABLE);
+	/* Update configuration */
+	WREG32(MC_VM_SYSTEM_APERTURE_LOW_ADDR,
+	       rdev->mc.vram_start >> 12);
+	WREG32(MC_VM_SYSTEM_APERTURE_HIGH_ADDR,
+	       rdev->mc.vram_end >> 12);
+	WREG32(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR,
+	       rdev->vram_scratch.gpu_addr >> 12);
+	tmp = ((rdev->mc.vram_end >> 24) & 0xFFFF) << 16;
+	tmp |= ((rdev->mc.vram_start >> 24) & 0xFFFF);
+	WREG32(MC_VM_FB_LOCATION, tmp);
+	/* XXX double check these! */
+	WREG32(HDP_NONSURFACE_BASE, (rdev->mc.vram_start >> 8));
+	WREG32(HDP_NONSURFACE_INFO, (2 << 7) | (1 << 30));
+	WREG32(HDP_NONSURFACE_SIZE, 0x3FFFFFFF);
+	WREG32(MC_VM_AGP_BASE, 0);
+	WREG32(MC_VM_AGP_TOP, 0x0FFFFFFF);
+	WREG32(MC_VM_AGP_BOT, 0x0FFFFFFF);
+	if (radeon_mc_wait_for_idle(rdev)) {
+		dev_warn(rdev->dev, "Wait for MC idle timedout !\n");
+	}
+	evergreen_mc_resume(rdev, &save);
+	/* we need to own VRAM, so turn off the VGA renderer here
+	 * to stop it overwriting our objects */
+	rv515_vga_render_disable(rdev);
+}
+
+/**
+ * cik_mc_init - initialize the memory controller driver params
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Look up the amount of vram, vram width, and decide how to place
+ * vram and gart within the GPU's physical address space (CIK).
+ * Returns 0 for success.
+ */
+static int cik_mc_init(struct radeon_device *rdev)
+{
+	u32 tmp;
+	int chansize, numchan;
+
+	/* Get VRAM informations */
+	rdev->mc.vram_is_ddr = true;
+	tmp = RREG32(MC_ARB_RAMCFG);
+	if (tmp & CHANSIZE_MASK) {
+		chansize = 64;
+	} else {
+		chansize = 32;
+	}
+	tmp = RREG32(MC_SHARED_CHMAP);
+	switch ((tmp & NOOFCHAN_MASK) >> NOOFCHAN_SHIFT) {
+	case 0:
+	default:
+		numchan = 1;
+		break;
+	case 1:
+		numchan = 2;
+		break;
+	case 2:
+		numchan = 4;
+		break;
+	case 3:
+		numchan = 8;
+		break;
+	case 4:
+		numchan = 3;
+		break;
+	case 5:
+		numchan = 6;
+		break;
+	case 6:
+		numchan = 10;
+		break;
+	case 7:
+		numchan = 12;
+		break;
+	case 8:
+		numchan = 16;
+		break;
+	}
+	rdev->mc.vram_width = numchan * chansize;
+	/* Could aper size report 0 ? */
+	rdev->mc.aper_base = pci_resource_start(rdev->pdev, 0);
+	rdev->mc.aper_size = pci_resource_len(rdev->pdev, 0);
+	/* size in MB on si */
+	rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE) * 1024 * 1024;
+	rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE) * 1024 * 1024;
+	rdev->mc.visible_vram_size = rdev->mc.aper_size;
+	si_vram_gtt_location(rdev, &rdev->mc);
+	radeon_update_bandwidth_info(rdev);
+
+	return 0;
+}
+
+/*
+ * GART
+ * VMID 0 is the physical GPU addresses as used by the kernel.
+ * VMIDs 1-15 are used for userspace clients and are handled
+ * by the radeon vm/hsa code.
+ */
+/**
+ * cik_pcie_gart_tlb_flush - gart tlb flush callback
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Flush the TLB for the VMID 0 page table (CIK).
+ */
+void cik_pcie_gart_tlb_flush(struct radeon_device *rdev)
+{
+	/* flush hdp cache */
+	WREG32(HDP_MEM_COHERENCY_FLUSH_CNTL, 0);
+
+	/* bits 0-15 are the VM contexts0-15 */
+	WREG32(VM_INVALIDATE_REQUEST, 0x1);
+}
+
+/**
+ * cik_pcie_gart_enable - gart enable
+ *
+ * @rdev: radeon_device pointer
+ *
+ * This sets up the TLBs, programs the page tables for VMID0,
+ * sets up the hw for VMIDs 1-15 which are allocated on
+ * demand, and sets up the global locations for the LDS, GDS,
+ * and GPUVM for FSA64 clients (CIK).
+ * Returns 0 for success, errors for failure.
+ */
+static int cik_pcie_gart_enable(struct radeon_device *rdev)
+{
+	int r, i;
+
+	if (rdev->gart.robj == NULL) {
+		dev_err(rdev->dev, "No VRAM object for PCIE GART.\n");
+		return -EINVAL;
+	}
+	r = radeon_gart_table_vram_pin(rdev);
+	if (r)
+		return r;
+	radeon_gart_restore(rdev);
+	/* Setup TLB control */
+	WREG32(MC_VM_MX_L1_TLB_CNTL,
+	       (0xA << 7) |
+	       ENABLE_L1_TLB |
+	       SYSTEM_ACCESS_MODE_NOT_IN_SYS |
+	       ENABLE_ADVANCED_DRIVER_MODEL |
+	       SYSTEM_APERTURE_UNMAPPED_ACCESS_PASS_THRU);
+	/* Setup L2 cache */
+	WREG32(VM_L2_CNTL, ENABLE_L2_CACHE |
+	       ENABLE_L2_FRAGMENT_PROCESSING |
+	       ENABLE_L2_PTE_CACHE_LRU_UPDATE_BY_WRITE |
+	       ENABLE_L2_PDE0_CACHE_LRU_UPDATE_BY_WRITE |
+	       EFFECTIVE_L2_QUEUE_SIZE(7) |
+	       CONTEXT1_IDENTITY_ACCESS_MODE(1));
+	WREG32(VM_L2_CNTL2, INVALIDATE_ALL_L1_TLBS | INVALIDATE_L2_CACHE);
+	WREG32(VM_L2_CNTL3, L2_CACHE_BIGK_ASSOCIATIVITY |
+	       L2_CACHE_BIGK_FRAGMENT_SIZE(6));
+	/* setup context0 */
+	WREG32(VM_CONTEXT0_PAGE_TABLE_START_ADDR, rdev->mc.gtt_start >> 12);
+	WREG32(VM_CONTEXT0_PAGE_TABLE_END_ADDR, rdev->mc.gtt_end >> 12);
+	WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR, rdev->gart.table_addr >> 12);
+	WREG32(VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR,
+			(u32)(rdev->dummy_page.addr >> 12));
+	WREG32(VM_CONTEXT0_CNTL2, 0);
+	WREG32(VM_CONTEXT0_CNTL, (ENABLE_CONTEXT | PAGE_TABLE_DEPTH(0) |
+				  RANGE_PROTECTION_FAULT_ENABLE_DEFAULT));
+
+	WREG32(0x15D4, 0);
+	WREG32(0x15D8, 0);
+	WREG32(0x15DC, 0);
+
+	/* empty context1-15 */
+	/* FIXME start with 4G, once using 2 level pt switch to full
+	 * vm size space
+	 */
+	/* set vm size, must be a multiple of 4 */
+	WREG32(VM_CONTEXT1_PAGE_TABLE_START_ADDR, 0);
+	WREG32(VM_CONTEXT1_PAGE_TABLE_END_ADDR, rdev->vm_manager.max_pfn);
+	for (i = 1; i < 16; i++) {
+		if (i < 8)
+			WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (i << 2),
+			       rdev->gart.table_addr >> 12);
+		else
+			WREG32(VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((i - 8) << 2),
+			       rdev->gart.table_addr >> 12);
+	}
+
+	/* enable context1-15 */
+	WREG32(VM_CONTEXT1_PROTECTION_FAULT_DEFAULT_ADDR,
+	       (u32)(rdev->dummy_page.addr >> 12));
+	WREG32(VM_CONTEXT1_CNTL2, 0);
+	WREG32(VM_CONTEXT1_CNTL, ENABLE_CONTEXT | PAGE_TABLE_DEPTH(1) |
+				RANGE_PROTECTION_FAULT_ENABLE_DEFAULT);
+
+	/* TC cache setup ??? */
+	WREG32(TC_CFG_L1_LOAD_POLICY0, 0);
+	WREG32(TC_CFG_L1_LOAD_POLICY1, 0);
+	WREG32(TC_CFG_L1_STORE_POLICY, 0);
+
+	WREG32(TC_CFG_L2_LOAD_POLICY0, 0);
+	WREG32(TC_CFG_L2_LOAD_POLICY1, 0);
+	WREG32(TC_CFG_L2_STORE_POLICY0, 0);
+	WREG32(TC_CFG_L2_STORE_POLICY1, 0);
+	WREG32(TC_CFG_L2_ATOMIC_POLICY, 0);
+
+	WREG32(TC_CFG_L1_VOLATILE, 0);
+	WREG32(TC_CFG_L2_VOLATILE, 0);
+
+	if (rdev->family == CHIP_KAVERI) {
+		u32 tmp = RREG32(CHUB_CONTROL);
+		tmp &= ~BYPASS_VM;
+		WREG32(CHUB_CONTROL, tmp);
+	}
+
+	/* XXX SH_MEM regs */
+	/* where to put LDS, scratch, GPUVM in FSA64 space */
+	for (i = 0; i < 16; i++) {
+		WREG32(SRBM_GFX_CNTL, VMID(i));
+		WREG32(SH_MEM_CONFIG, 0);
+		WREG32(SH_MEM_APE1_BASE, 1);
+		WREG32(SH_MEM_APE1_LIMIT, 0);
+		WREG32(SH_MEM_BASES, 0);
+	}
+	WREG32(SRBM_GFX_CNTL, 0);
+
+	cik_pcie_gart_tlb_flush(rdev);
+	DRM_INFO("PCIE GART of %uM enabled (table at 0x%016llX).\n",
+		 (unsigned)(rdev->mc.gtt_size >> 20),
+		 (unsigned long long)rdev->gart.table_addr);
+	rdev->gart.ready = true;
+	return 0;
+}
+
+/**
+ * cik_pcie_gart_disable - gart disable
+ *
+ * @rdev: radeon_device pointer
+ *
+ * This disables all VM page table (CIK).
+ */
+static void cik_pcie_gart_disable(struct radeon_device *rdev)
+{
+	/* Disable all tables */
+	WREG32(VM_CONTEXT0_CNTL, 0);
+	WREG32(VM_CONTEXT1_CNTL, 0);
+	/* Setup TLB control */
+	WREG32(MC_VM_MX_L1_TLB_CNTL, SYSTEM_ACCESS_MODE_NOT_IN_SYS |
+	       SYSTEM_APERTURE_UNMAPPED_ACCESS_PASS_THRU);
+	/* Setup L2 cache */
+	WREG32(VM_L2_CNTL,
+	       ENABLE_L2_FRAGMENT_PROCESSING |
+	       ENABLE_L2_PTE_CACHE_LRU_UPDATE_BY_WRITE |
+	       ENABLE_L2_PDE0_CACHE_LRU_UPDATE_BY_WRITE |
+	       EFFECTIVE_L2_QUEUE_SIZE(7) |
+	       CONTEXT1_IDENTITY_ACCESS_MODE(1));
+	WREG32(VM_L2_CNTL2, 0);
+	WREG32(VM_L2_CNTL3, L2_CACHE_BIGK_ASSOCIATIVITY |
+	       L2_CACHE_BIGK_FRAGMENT_SIZE(6));
+	radeon_gart_table_vram_unpin(rdev);
+}
+
+/**
+ * cik_pcie_gart_fini - vm fini callback
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Tears down the driver GART/VM setup (CIK).
+ */
+static void cik_pcie_gart_fini(struct radeon_device *rdev)
+{
+	cik_pcie_gart_disable(rdev);
+	radeon_gart_table_vram_free(rdev);
+	radeon_gart_fini(rdev);
+}
+
+/* vm parser */
+/**
+ * cik_ib_parse - vm ib_parse callback
+ *
+ * @rdev: radeon_device pointer
+ * @ib: indirect buffer pointer
+ *
+ * CIK uses hw IB checking so this is a nop (CIK).
+ */
+int cik_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib)
+{
+	return 0;
+}
+
+/*
+ * vm
+ * VMID 0 is the physical GPU addresses as used by the kernel.
+ * VMIDs 1-15 are used for userspace clients and are handled
+ * by the radeon vm/hsa code.
+ */
+/**
+ * cik_vm_init - cik vm init callback
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Inits cik specific vm parameters (number of VMs, base of vram for
+ * VMIDs 1-15) (CIK).
+ * Returns 0 for success.
+ */
+int cik_vm_init(struct radeon_device *rdev)
+{
+	/* number of VMs */
+	rdev->vm_manager.nvm = 16;
+	/* base offset of vram pages */
+	if (rdev->flags & RADEON_IS_IGP) {
+		u64 tmp = RREG32(MC_VM_FB_OFFSET);
+		tmp <<= 22;
+		rdev->vm_manager.vram_base_offset = tmp;
+	} else
+		rdev->vm_manager.vram_base_offset = 0;
+
+	return 0;
+}
+
+/**
+ * cik_vm_fini - cik vm fini callback
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Tear down any asic specific VM setup (CIK).
+ */
+void cik_vm_fini(struct radeon_device *rdev)
+{
+}
+
diff --git a/drivers/gpu/drm/radeon/cikd.h b/drivers/gpu/drm/radeon/cikd.h
index 41b2316..071a781 100644
--- a/drivers/gpu/drm/radeon/cikd.h
+++ b/drivers/gpu/drm/radeon/cikd.h
@@ -28,16 +28,106 @@
 
 #define CIK_RB_BITMAP_WIDTH_PER_SH  2
 
+#define VGA_HDP_CONTROL  				0x328
+#define		VGA_MEMORY_DISABLE				(1 << 4)
+
 #define DMIF_ADDR_CALC  				0xC00
 
+#define	SRBM_GFX_CNTL				        0xE44
+#define		PIPEID(x)					((x) << 0)
+#define		MEID(x)						((x) << 2)
+#define		VMID(x)						((x) << 4)
+#define		QUEUEID(x)					((x) << 8)
+
 #define	SRBM_STATUS2				        0xE4C
 #define	SRBM_STATUS				        0xE50
 
+#define VM_L2_CNTL					0x1400
+#define		ENABLE_L2_CACHE					(1 << 0)
+#define		ENABLE_L2_FRAGMENT_PROCESSING			(1 << 1)
+#define		L2_CACHE_PTE_ENDIAN_SWAP_MODE(x)		((x) << 2)
+#define		L2_CACHE_PDE_ENDIAN_SWAP_MODE(x)		((x) << 4)
+#define		ENABLE_L2_PTE_CACHE_LRU_UPDATE_BY_WRITE		(1 << 9)
+#define		ENABLE_L2_PDE0_CACHE_LRU_UPDATE_BY_WRITE	(1 << 10)
+#define		EFFECTIVE_L2_QUEUE_SIZE(x)			(((x) & 7) << 15)
+#define		CONTEXT1_IDENTITY_ACCESS_MODE(x)		(((x) & 3) << 19)
+#define VM_L2_CNTL2					0x1404
+#define		INVALIDATE_ALL_L1_TLBS				(1 << 0)
+#define		INVALIDATE_L2_CACHE				(1 << 1)
+#define		INVALIDATE_CACHE_MODE(x)			((x) << 26)
+#define			INVALIDATE_PTE_AND_PDE_CACHES		0
+#define			INVALIDATE_ONLY_PTE_CACHES		1
+#define			INVALIDATE_ONLY_PDE_CACHES		2
+#define VM_L2_CNTL3					0x1408
+#define		BANK_SELECT(x)					((x) << 0)
+#define		L2_CACHE_UPDATE_MODE(x)				((x) << 6)
+#define		L2_CACHE_BIGK_FRAGMENT_SIZE(x)			((x) << 15)
+#define		L2_CACHE_BIGK_ASSOCIATIVITY			(1 << 20)
+#define	VM_L2_STATUS					0x140C
+#define		L2_BUSY						(1 << 0)
+#define VM_CONTEXT0_CNTL				0x1410
+#define		ENABLE_CONTEXT					(1 << 0)
+#define		PAGE_TABLE_DEPTH(x)				(((x) & 3) << 1)
+#define		RANGE_PROTECTION_FAULT_ENABLE_DEFAULT		(1 << 4)
+#define VM_CONTEXT1_CNTL				0x1414
+#define VM_CONTEXT0_CNTL2				0x1430
+#define VM_CONTEXT1_CNTL2				0x1434
+#define	VM_CONTEXT8_PAGE_TABLE_BASE_ADDR		0x1438
+#define	VM_CONTEXT9_PAGE_TABLE_BASE_ADDR		0x143c
+#define	VM_CONTEXT10_PAGE_TABLE_BASE_ADDR		0x1440
+#define	VM_CONTEXT11_PAGE_TABLE_BASE_ADDR		0x1444
+#define	VM_CONTEXT12_PAGE_TABLE_BASE_ADDR		0x1448
+#define	VM_CONTEXT13_PAGE_TABLE_BASE_ADDR		0x144c
+#define	VM_CONTEXT14_PAGE_TABLE_BASE_ADDR		0x1450
+#define	VM_CONTEXT15_PAGE_TABLE_BASE_ADDR		0x1454
+
+#define VM_INVALIDATE_REQUEST				0x1478
+#define VM_INVALIDATE_RESPONSE				0x147c
+
+#define VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR	0x1518
+#define VM_CONTEXT1_PROTECTION_FAULT_DEFAULT_ADDR	0x151c
+
+#define	VM_CONTEXT0_PAGE_TABLE_BASE_ADDR		0x153c
+#define	VM_CONTEXT1_PAGE_TABLE_BASE_ADDR		0x1540
+#define	VM_CONTEXT2_PAGE_TABLE_BASE_ADDR		0x1544
+#define	VM_CONTEXT3_PAGE_TABLE_BASE_ADDR		0x1548
+#define	VM_CONTEXT4_PAGE_TABLE_BASE_ADDR		0x154c
+#define	VM_CONTEXT5_PAGE_TABLE_BASE_ADDR		0x1550
+#define	VM_CONTEXT6_PAGE_TABLE_BASE_ADDR		0x1554
+#define	VM_CONTEXT7_PAGE_TABLE_BASE_ADDR		0x1558
+#define	VM_CONTEXT0_PAGE_TABLE_START_ADDR		0x155c
+#define	VM_CONTEXT1_PAGE_TABLE_START_ADDR		0x1560
+
+#define	VM_CONTEXT0_PAGE_TABLE_END_ADDR			0x157C
+#define	VM_CONTEXT1_PAGE_TABLE_END_ADDR			0x1580
+
 #define MC_SHARED_CHMAP						0x2004
 #define		NOOFCHAN_SHIFT					12
 #define		NOOFCHAN_MASK					0x0000f000
 #define MC_SHARED_CHREMAP					0x2008
 
+#define CHUB_CONTROL					0x1864
+#define		BYPASS_VM					(1 << 0)
+
+#define	MC_VM_FB_LOCATION				0x2024
+#define	MC_VM_AGP_TOP					0x2028
+#define	MC_VM_AGP_BOT					0x202C
+#define	MC_VM_AGP_BASE					0x2030
+#define	MC_VM_SYSTEM_APERTURE_LOW_ADDR			0x2034
+#define	MC_VM_SYSTEM_APERTURE_HIGH_ADDR			0x2038
+#define	MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR		0x203C
+
+#define	MC_VM_MX_L1_TLB_CNTL				0x2064
+#define		ENABLE_L1_TLB					(1 << 0)
+#define		ENABLE_L1_FRAGMENT_PROCESSING			(1 << 1)
+#define		SYSTEM_ACCESS_MODE_PA_ONLY			(0 << 3)
+#define		SYSTEM_ACCESS_MODE_USE_SYS_MAP			(1 << 3)
+#define		SYSTEM_ACCESS_MODE_IN_SYS			(2 << 3)
+#define		SYSTEM_ACCESS_MODE_NOT_IN_SYS			(3 << 3)
+#define		SYSTEM_APERTURE_UNMAPPED_ACCESS_PASS_THRU	(0 << 5)
+#define		ENABLE_ADVANCED_DRIVER_MODEL			(1 << 6)
+#define	MC_VM_FB_OFFSET					0x2068
+
 #define	MC_ARB_RAMCFG					0x2760
 #define		NOOFBANK_SHIFT					0
 #define		NOOFBANK_MASK					0x00000003
@@ -61,10 +151,16 @@
 #define HDP_MISC_CNTL					0x2F4C
 #define 	HDP_FLUSH_INVALIDATE_CACHE			(1 << 0)
 
+#define	CONFIG_MEMSIZE					0x5428
+
+#define HDP_MEM_COHERENCY_FLUSH_CNTL			0x5480
+
 #define	BIF_FB_EN						0x5490
 #define		FB_READ_EN					(1 << 0)
 #define		FB_WRITE_EN					(1 << 1)
 
+#define HDP_REG_COHERENCY_FLUSH_CNTL			0x54A0
+
 #define	GRBM_CNTL					0x8000
 #define		GRBM_READ_TIMEOUT(x)				((x) << 0)
 
@@ -189,6 +285,24 @@
 
 #define	SQ_CONFIG					0x8C00
 
+#define	SH_MEM_BASES					0x8C28
+/* if PTR32, these are the bases for scratch and lds */
+#define		PRIVATE_BASE(x)					((x) << 0) /* scratch */
+#define		SHARED_BASE(x)					((x) << 16) /* LDS */
+#define	SH_MEM_APE1_BASE				0x8C2C
+/* if PTR32, this is the base location of GPUVM */
+#define	SH_MEM_APE1_LIMIT				0x8C30
+/* if PTR32, this is the upper limit of GPUVM */
+#define	SH_MEM_CONFIG					0x8C34
+#define		PTR32						(1 << 0)
+#define		ALIGNMENT_MODE(x)				((x) << 2)
+#define			SH_MEM_ALIGNMENT_MODE_DWORD			0
+#define			SH_MEM_ALIGNMENT_MODE_DWORD_STRICT		1
+#define			SH_MEM_ALIGNMENT_MODE_STRICT			2
+#define			SH_MEM_ALIGNMENT_MODE_UNALIGNED			3
+#define		DEFAULT_MTYPE(x)				((x) << 4)
+#define		APE1_MTYPE(x)					((x) << 7)
+
 #define	SX_DEBUG_1					0x9060
 
 #define	SPI_CONFIG_CNTL					0x9100
@@ -293,6 +407,17 @@
 #define	TCP_CHAN_STEER_LO				0xac0c
 #define	TCP_CHAN_STEER_HI				0xac10
 
+#define	TC_CFG_L1_LOAD_POLICY0				0xAC68
+#define	TC_CFG_L1_LOAD_POLICY1				0xAC6C
+#define	TC_CFG_L1_STORE_POLICY				0xAC70
+#define	TC_CFG_L2_LOAD_POLICY0				0xAC74
+#define	TC_CFG_L2_LOAD_POLICY1				0xAC78
+#define	TC_CFG_L2_STORE_POLICY0				0xAC7C
+#define	TC_CFG_L2_STORE_POLICY1				0xAC80
+#define	TC_CFG_L2_ATOMIC_POLICY				0xAC84
+#define	TC_CFG_L1_VOLATILE				0xAC88
+#define	TC_CFG_L2_VOLATILE				0xAC8C
+
 #define PA_SC_RASTER_CONFIG                             0x28350
 #       define RASTER_CONFIG_RB_MAP_0                   0
 #       define RASTER_CONFIG_RB_MAP_1                   1
diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c
index a1b0da6..813a8a9 100644
--- a/drivers/gpu/drm/radeon/si.c
+++ b/drivers/gpu/drm/radeon/si.c
@@ -3535,8 +3535,8 @@ static void si_mc_program(struct radeon_device *rdev)
 	}
 }
 
-static void si_vram_gtt_location(struct radeon_device *rdev,
-				 struct radeon_mc *mc)
+void si_vram_gtt_location(struct radeon_device *rdev,
+			  struct radeon_mc *mc)
 {
 	if (mc->mc_vram_size > 0xFFC0000000ULL) {
 		/* leave room for at least 1024M GTT */
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 010/165] drm/radeon/cik: stop page faults from hanging the system (v2)
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (9 preceding siblings ...)
  2013-06-26 13:21 ` [PATCH 009/165] drm/radeon: add support for MC/VM setup on CIK (v6) alexdeucher
@ 2013-06-26 13:21 ` alexdeucher
  2013-06-26 13:21 ` [PATCH 011/165] drm/radeon: add initial ucode loading for CIK (v5) alexdeucher
                   ` (102 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:21 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Redirect invalid memory accesses to the default page
instead of locking up the memory controller.

v2: rebase on top of 2 level PTs

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/cik.c  |   15 +++++++++++++--
 drivers/gpu/drm/radeon/cikd.h |   11 +++++++++++
 2 files changed, 24 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
index a4e1b95..28a7531 100644
--- a/drivers/gpu/drm/radeon/cik.c
+++ b/drivers/gpu/drm/radeon/cik.c
@@ -1608,9 +1608,20 @@ static int cik_pcie_gart_enable(struct radeon_device *rdev)
 	/* enable context1-15 */
 	WREG32(VM_CONTEXT1_PROTECTION_FAULT_DEFAULT_ADDR,
 	       (u32)(rdev->dummy_page.addr >> 12));
-	WREG32(VM_CONTEXT1_CNTL2, 0);
+	WREG32(VM_CONTEXT1_CNTL2, 4);
 	WREG32(VM_CONTEXT1_CNTL, ENABLE_CONTEXT | PAGE_TABLE_DEPTH(1) |
-				RANGE_PROTECTION_FAULT_ENABLE_DEFAULT);
+				RANGE_PROTECTION_FAULT_ENABLE_INTERRUPT |
+				RANGE_PROTECTION_FAULT_ENABLE_DEFAULT |
+				DUMMY_PAGE_PROTECTION_FAULT_ENABLE_INTERRUPT |
+				DUMMY_PAGE_PROTECTION_FAULT_ENABLE_DEFAULT |
+				PDE0_PROTECTION_FAULT_ENABLE_INTERRUPT |
+				PDE0_PROTECTION_FAULT_ENABLE_DEFAULT |
+				VALID_PROTECTION_FAULT_ENABLE_INTERRUPT |
+				VALID_PROTECTION_FAULT_ENABLE_DEFAULT |
+				READ_PROTECTION_FAULT_ENABLE_INTERRUPT |
+				READ_PROTECTION_FAULT_ENABLE_DEFAULT |
+				WRITE_PROTECTION_FAULT_ENABLE_INTERRUPT |
+				WRITE_PROTECTION_FAULT_ENABLE_DEFAULT);
 
 	/* TC cache setup ??? */
 	WREG32(TC_CFG_L1_LOAD_POLICY0, 0);
diff --git a/drivers/gpu/drm/radeon/cikd.h b/drivers/gpu/drm/radeon/cikd.h
index 071a781..0dab9c5 100644
--- a/drivers/gpu/drm/radeon/cikd.h
+++ b/drivers/gpu/drm/radeon/cikd.h
@@ -68,7 +68,18 @@
 #define VM_CONTEXT0_CNTL				0x1410
 #define		ENABLE_CONTEXT					(1 << 0)
 #define		PAGE_TABLE_DEPTH(x)				(((x) & 3) << 1)
+#define		RANGE_PROTECTION_FAULT_ENABLE_INTERRUPT		(1 << 3)
 #define		RANGE_PROTECTION_FAULT_ENABLE_DEFAULT		(1 << 4)
+#define		DUMMY_PAGE_PROTECTION_FAULT_ENABLE_INTERRUPT	(1 << 6)
+#define		DUMMY_PAGE_PROTECTION_FAULT_ENABLE_DEFAULT	(1 << 7)
+#define		PDE0_PROTECTION_FAULT_ENABLE_INTERRUPT		(1 << 9)
+#define		PDE0_PROTECTION_FAULT_ENABLE_DEFAULT		(1 << 10)
+#define		VALID_PROTECTION_FAULT_ENABLE_INTERRUPT		(1 << 12)
+#define		VALID_PROTECTION_FAULT_ENABLE_DEFAULT		(1 << 13)
+#define		READ_PROTECTION_FAULT_ENABLE_INTERRUPT		(1 << 15)
+#define		READ_PROTECTION_FAULT_ENABLE_DEFAULT		(1 << 16)
+#define		WRITE_PROTECTION_FAULT_ENABLE_INTERRUPT		(1 << 18)
+#define		WRITE_PROTECTION_FAULT_ENABLE_DEFAULT		(1 << 19)
 #define VM_CONTEXT1_CNTL				0x1414
 #define VM_CONTEXT0_CNTL2				0x1430
 #define VM_CONTEXT1_CNTL2				0x1434
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 011/165] drm/radeon: add initial ucode loading for CIK (v5)
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (10 preceding siblings ...)
  2013-06-26 13:21 ` [PATCH 010/165] drm/radeon/cik: stop page faults from hanging the system (v2) alexdeucher
@ 2013-06-26 13:21 ` alexdeucher
  2013-06-26 13:21 ` [PATCH 012/165] drm/radeon: add support mc ucode loading on CIK (v2) alexdeucher
                   ` (101 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:21 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Currently the driver required 6 sets of ucode:
1. pfp - pre-fetch parser, part of the GFX CP
2. me - micro engine, part of the GFX CP
3. ce - constant engine, part of the GFX CP
4. rlc - interrupt, etc. controller
5. mc - memory controller (discrete cards only)
6. mec - compute engines, part of Compute CP

V2: add documentation
V3: update MC ucode
V4: rebase
V5: update mc ucode

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/cik.c    |  180 +++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/radeon/radeon.h |    1 +
 2 files changed, 181 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
index 28a7531..36e0fc9 100644
--- a/drivers/gpu/drm/radeon/cik.c
+++ b/drivers/gpu/drm/radeon/cik.c
@@ -31,10 +31,190 @@
 #include "cikd.h"
 #include "atom.h"
 
+/* GFX */
+#define CIK_PFP_UCODE_SIZE 2144
+#define CIK_ME_UCODE_SIZE 2144
+#define CIK_CE_UCODE_SIZE 2144
+/* compute */
+#define CIK_MEC_UCODE_SIZE 4192
+/* interrupts */
+#define BONAIRE_RLC_UCODE_SIZE 2048
+#define KB_RLC_UCODE_SIZE 2560
+#define KV_RLC_UCODE_SIZE 2560
+/* gddr controller */
+#define CIK_MC_UCODE_SIZE 7866
+
+MODULE_FIRMWARE("radeon/BONAIRE_pfp.bin");
+MODULE_FIRMWARE("radeon/BONAIRE_me.bin");
+MODULE_FIRMWARE("radeon/BONAIRE_ce.bin");
+MODULE_FIRMWARE("radeon/BONAIRE_mec.bin");
+MODULE_FIRMWARE("radeon/BONAIRE_mc.bin");
+MODULE_FIRMWARE("radeon/BONAIRE_rlc.bin");
+MODULE_FIRMWARE("radeon/KAVERI_pfp.bin");
+MODULE_FIRMWARE("radeon/KAVERI_me.bin");
+MODULE_FIRMWARE("radeon/KAVERI_ce.bin");
+MODULE_FIRMWARE("radeon/KAVERI_mec.bin");
+MODULE_FIRMWARE("radeon/KAVERI_rlc.bin");
+MODULE_FIRMWARE("radeon/KABINI_pfp.bin");
+MODULE_FIRMWARE("radeon/KABINI_me.bin");
+MODULE_FIRMWARE("radeon/KABINI_ce.bin");
+MODULE_FIRMWARE("radeon/KABINI_mec.bin");
+MODULE_FIRMWARE("radeon/KABINI_rlc.bin");
+
 extern void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save);
 extern void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save);
 extern void si_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc);
 
+/**
+ * cik_init_microcode - load ucode images from disk
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Use the firmware interface to load the ucode images into
+ * the driver (not loaded into hw).
+ * Returns 0 on success, error on failure.
+ */
+static int cik_init_microcode(struct radeon_device *rdev)
+{
+	struct platform_device *pdev;
+	const char *chip_name;
+	size_t pfp_req_size, me_req_size, ce_req_size,
+		mec_req_size, rlc_req_size, mc_req_size;
+	char fw_name[30];
+	int err;
+
+	DRM_DEBUG("\n");
+
+	pdev = platform_device_register_simple("radeon_cp", 0, NULL, 0);
+	err = IS_ERR(pdev);
+	if (err) {
+		printk(KERN_ERR "radeon_cp: Failed to register firmware\n");
+		return -EINVAL;
+	}
+
+	switch (rdev->family) {
+	case CHIP_BONAIRE:
+		chip_name = "BONAIRE";
+		pfp_req_size = CIK_PFP_UCODE_SIZE * 4;
+		me_req_size = CIK_ME_UCODE_SIZE * 4;
+		ce_req_size = CIK_CE_UCODE_SIZE * 4;
+		mec_req_size = CIK_MEC_UCODE_SIZE * 4;
+		rlc_req_size = BONAIRE_RLC_UCODE_SIZE * 4;
+		mc_req_size = CIK_MC_UCODE_SIZE * 4;
+		break;
+	case CHIP_KAVERI:
+		chip_name = "KAVERI";
+		pfp_req_size = CIK_PFP_UCODE_SIZE * 4;
+		me_req_size = CIK_ME_UCODE_SIZE * 4;
+		ce_req_size = CIK_CE_UCODE_SIZE * 4;
+		mec_req_size = CIK_MEC_UCODE_SIZE * 4;
+		rlc_req_size = KV_RLC_UCODE_SIZE * 4;
+		break;
+	case CHIP_KABINI:
+		chip_name = "KABINI";
+		pfp_req_size = CIK_PFP_UCODE_SIZE * 4;
+		me_req_size = CIK_ME_UCODE_SIZE * 4;
+		ce_req_size = CIK_CE_UCODE_SIZE * 4;
+		mec_req_size = CIK_MEC_UCODE_SIZE * 4;
+		rlc_req_size = KB_RLC_UCODE_SIZE * 4;
+		break;
+	default: BUG();
+	}
+
+	DRM_INFO("Loading %s Microcode\n", chip_name);
+
+	snprintf(fw_name, sizeof(fw_name), "radeon/%s_pfp.bin", chip_name);
+	err = request_firmware(&rdev->pfp_fw, fw_name, &pdev->dev);
+	if (err)
+		goto out;
+	if (rdev->pfp_fw->size != pfp_req_size) {
+		printk(KERN_ERR
+		       "cik_cp: Bogus length %zu in firmware \"%s\"\n",
+		       rdev->pfp_fw->size, fw_name);
+		err = -EINVAL;
+		goto out;
+	}
+
+	snprintf(fw_name, sizeof(fw_name), "radeon/%s_me.bin", chip_name);
+	err = request_firmware(&rdev->me_fw, fw_name, &pdev->dev);
+	if (err)
+		goto out;
+	if (rdev->me_fw->size != me_req_size) {
+		printk(KERN_ERR
+		       "cik_cp: Bogus length %zu in firmware \"%s\"\n",
+		       rdev->me_fw->size, fw_name);
+		err = -EINVAL;
+	}
+
+	snprintf(fw_name, sizeof(fw_name), "radeon/%s_ce.bin", chip_name);
+	err = request_firmware(&rdev->ce_fw, fw_name, &pdev->dev);
+	if (err)
+		goto out;
+	if (rdev->ce_fw->size != ce_req_size) {
+		printk(KERN_ERR
+		       "cik_cp: Bogus length %zu in firmware \"%s\"\n",
+		       rdev->ce_fw->size, fw_name);
+		err = -EINVAL;
+	}
+
+	snprintf(fw_name, sizeof(fw_name), "radeon/%s_mec.bin", chip_name);
+	err = request_firmware(&rdev->mec_fw, fw_name, &pdev->dev);
+	if (err)
+		goto out;
+	if (rdev->mec_fw->size != mec_req_size) {
+		printk(KERN_ERR
+		       "cik_cp: Bogus length %zu in firmware \"%s\"\n",
+		       rdev->mec_fw->size, fw_name);
+		err = -EINVAL;
+	}
+
+	snprintf(fw_name, sizeof(fw_name), "radeon/%s_rlc.bin", chip_name);
+	err = request_firmware(&rdev->rlc_fw, fw_name, &pdev->dev);
+	if (err)
+		goto out;
+	if (rdev->rlc_fw->size != rlc_req_size) {
+		printk(KERN_ERR
+		       "cik_rlc: Bogus length %zu in firmware \"%s\"\n",
+		       rdev->rlc_fw->size, fw_name);
+		err = -EINVAL;
+	}
+
+	/* No MC ucode on APUs */
+	if (!(rdev->flags & RADEON_IS_IGP)) {
+		snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name);
+		err = request_firmware(&rdev->mc_fw, fw_name, &pdev->dev);
+		if (err)
+			goto out;
+		if (rdev->mc_fw->size != mc_req_size) {
+			printk(KERN_ERR
+			       "cik_mc: Bogus length %zu in firmware \"%s\"\n",
+			       rdev->mc_fw->size, fw_name);
+			err = -EINVAL;
+		}
+	}
+
+out:
+	platform_device_unregister(pdev);
+
+	if (err) {
+		if (err != -EINVAL)
+			printk(KERN_ERR
+			       "cik_cp: Failed to load firmware \"%s\"\n",
+			       fw_name);
+		release_firmware(rdev->pfp_fw);
+		rdev->pfp_fw = NULL;
+		release_firmware(rdev->me_fw);
+		rdev->me_fw = NULL;
+		release_firmware(rdev->ce_fw);
+		rdev->ce_fw = NULL;
+		release_firmware(rdev->rlc_fw);
+		rdev->rlc_fw = NULL;
+		release_firmware(rdev->mc_fw);
+		rdev->mc_fw = NULL;
+	}
+	return err;
+}
+
 /*
  * Core functions
  */
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index b1a2230..1c06c47 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -1714,6 +1714,7 @@ struct radeon_device {
 	const struct firmware *mc_fw;	/* NI MC firmware */
 	const struct firmware *ce_fw;	/* SI CE firmware */
 	const struct firmware *uvd_fw;	/* UVD firmware */
+	const struct firmware *mec_fw;	/* CIK MEC firmware */
 	struct r600_blit r600_blit;
 	struct r600_vram_scratch vram_scratch;
 	int msi_enabled; /* msi enabled */
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 012/165] drm/radeon: add support mc ucode loading on CIK (v2)
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (11 preceding siblings ...)
  2013-06-26 13:21 ` [PATCH 011/165] drm/radeon: add initial ucode loading for CIK (v5) alexdeucher
@ 2013-06-26 13:21 ` alexdeucher
  2013-06-26 13:21 ` [PATCH 013/165] drm/radeon: Add CP init for CIK (v7) alexdeucher
                   ` (100 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:21 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Load the GDDR5 ucode and train the links.

v2: update ucode

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/cik.c  |  116 +++++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/radeon/cikd.h |   16 ++++++
 2 files changed, 132 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
index 36e0fc9..8eec582 100644
--- a/drivers/gpu/drm/radeon/cik.c
+++ b/drivers/gpu/drm/radeon/cik.c
@@ -65,6 +65,122 @@ extern void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_sa
 extern void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save);
 extern void si_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc);
 
+#define BONAIRE_IO_MC_REGS_SIZE 36
+
+static const u32 bonaire_io_mc_regs[BONAIRE_IO_MC_REGS_SIZE][2] =
+{
+	{0x00000070, 0x04400000},
+	{0x00000071, 0x80c01803},
+	{0x00000072, 0x00004004},
+	{0x00000073, 0x00000100},
+	{0x00000074, 0x00ff0000},
+	{0x00000075, 0x34000000},
+	{0x00000076, 0x08000014},
+	{0x00000077, 0x00cc08ec},
+	{0x00000078, 0x00000400},
+	{0x00000079, 0x00000000},
+	{0x0000007a, 0x04090000},
+	{0x0000007c, 0x00000000},
+	{0x0000007e, 0x4408a8e8},
+	{0x0000007f, 0x00000304},
+	{0x00000080, 0x00000000},
+	{0x00000082, 0x00000001},
+	{0x00000083, 0x00000002},
+	{0x00000084, 0xf3e4f400},
+	{0x00000085, 0x052024e3},
+	{0x00000087, 0x00000000},
+	{0x00000088, 0x01000000},
+	{0x0000008a, 0x1c0a0000},
+	{0x0000008b, 0xff010000},
+	{0x0000008d, 0xffffefff},
+	{0x0000008e, 0xfff3efff},
+	{0x0000008f, 0xfff3efbf},
+	{0x00000092, 0xf7ffffff},
+	{0x00000093, 0xffffff7f},
+	{0x00000095, 0x00101101},
+	{0x00000096, 0x00000fff},
+	{0x00000097, 0x00116fff},
+	{0x00000098, 0x60010000},
+	{0x00000099, 0x10010000},
+	{0x0000009a, 0x00006000},
+	{0x0000009b, 0x00001000},
+	{0x0000009f, 0x00b48000}
+};
+
+/* ucode loading */
+/**
+ * ci_mc_load_microcode - load MC ucode into the hw
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Load the GDDR MC ucode into the hw (CIK).
+ * Returns 0 on success, error on failure.
+ */
+static int ci_mc_load_microcode(struct radeon_device *rdev)
+{
+	const __be32 *fw_data;
+	u32 running, blackout = 0;
+	u32 *io_mc_regs;
+	int i, ucode_size, regs_size;
+
+	if (!rdev->mc_fw)
+		return -EINVAL;
+
+	switch (rdev->family) {
+	case CHIP_BONAIRE:
+	default:
+		io_mc_regs = (u32 *)&bonaire_io_mc_regs;
+		ucode_size = CIK_MC_UCODE_SIZE;
+		regs_size = BONAIRE_IO_MC_REGS_SIZE;
+		break;
+	}
+
+	running = RREG32(MC_SEQ_SUP_CNTL) & RUN_MASK;
+
+	if (running == 0) {
+		if (running) {
+			blackout = RREG32(MC_SHARED_BLACKOUT_CNTL);
+			WREG32(MC_SHARED_BLACKOUT_CNTL, blackout | 1);
+		}
+
+		/* reset the engine and set to writable */
+		WREG32(MC_SEQ_SUP_CNTL, 0x00000008);
+		WREG32(MC_SEQ_SUP_CNTL, 0x00000010);
+
+		/* load mc io regs */
+		for (i = 0; i < regs_size; i++) {
+			WREG32(MC_SEQ_IO_DEBUG_INDEX, io_mc_regs[(i << 1)]);
+			WREG32(MC_SEQ_IO_DEBUG_DATA, io_mc_regs[(i << 1) + 1]);
+		}
+		/* load the MC ucode */
+		fw_data = (const __be32 *)rdev->mc_fw->data;
+		for (i = 0; i < ucode_size; i++)
+			WREG32(MC_SEQ_SUP_PGM, be32_to_cpup(fw_data++));
+
+		/* put the engine back into the active state */
+		WREG32(MC_SEQ_SUP_CNTL, 0x00000008);
+		WREG32(MC_SEQ_SUP_CNTL, 0x00000004);
+		WREG32(MC_SEQ_SUP_CNTL, 0x00000001);
+
+		/* wait for training to complete */
+		for (i = 0; i < rdev->usec_timeout; i++) {
+			if (RREG32(MC_SEQ_TRAIN_WAKEUP_CNTL) & TRAIN_DONE_D0)
+				break;
+			udelay(1);
+		}
+		for (i = 0; i < rdev->usec_timeout; i++) {
+			if (RREG32(MC_SEQ_TRAIN_WAKEUP_CNTL) & TRAIN_DONE_D1)
+				break;
+			udelay(1);
+		}
+
+		if (running)
+			WREG32(MC_SHARED_BLACKOUT_CNTL, blackout);
+	}
+
+	return 0;
+}
+
 /**
  * cik_init_microcode - load ucode images from disk
  *
diff --git a/drivers/gpu/drm/radeon/cikd.h b/drivers/gpu/drm/radeon/cikd.h
index 0dab9c5..2300ae0 100644
--- a/drivers/gpu/drm/radeon/cikd.h
+++ b/drivers/gpu/drm/radeon/cikd.h
@@ -139,6 +139,8 @@
 #define		ENABLE_ADVANCED_DRIVER_MODEL			(1 << 6)
 #define	MC_VM_FB_OFFSET					0x2068
 
+#define MC_SHARED_BLACKOUT_CNTL           		0x20ac
+
 #define	MC_ARB_RAMCFG					0x2760
 #define		NOOFBANK_SHIFT					0
 #define		NOOFBANK_MASK					0x00000003
@@ -153,6 +155,20 @@
 #define		NOOFGROUPS_SHIFT				12
 #define		NOOFGROUPS_MASK					0x00001000
 
+#define MC_SEQ_SUP_CNTL           			0x28c8
+#define		RUN_MASK      				(1 << 0)
+#define MC_SEQ_SUP_PGM           			0x28cc
+
+#define	MC_SEQ_TRAIN_WAKEUP_CNTL			0x28e8
+#define		TRAIN_DONE_D0      			(1 << 30)
+#define		TRAIN_DONE_D1      			(1 << 31)
+
+#define MC_IO_PAD_CNTL_D0           			0x29d0
+#define		MEM_FALL_OUT_CMD      			(1 << 8)
+
+#define MC_SEQ_IO_DEBUG_INDEX           		0x2a44
+#define MC_SEQ_IO_DEBUG_DATA           			0x2a48
+
 #define	HDP_HOST_PATH_CNTL				0x2C00
 #define	HDP_NONSURFACE_BASE				0x2C04
 #define	HDP_NONSURFACE_INFO				0x2C08
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 013/165] drm/radeon: Add CP init for CIK (v7)
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (12 preceding siblings ...)
  2013-06-26 13:21 ` [PATCH 012/165] drm/radeon: add support mc ucode loading on CIK (v2) alexdeucher
@ 2013-06-26 13:21 ` alexdeucher
  2013-06-26 13:21 ` [PATCH 014/165] drm/radeon: add IB and fence dispatch functions for CIK gfx (v7) alexdeucher
                   ` (99 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:21 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Sets up the GFX ring and loads ucode for GFX and Compute.

Todo:
- handle compute queue setup.

v2: add documentation
v3: integrate with latest reset changes
v4: additional init fixes
v5: scratch reg write back no longer supported on CIK
v6: properly set CP_RB0_BASE_HI
v7: rebase

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/Makefile           |    2 +-
 drivers/gpu/drm/radeon/cik.c              |  395 +++++++++++++++++++++++++++++
 drivers/gpu/drm/radeon/cik_blit_shaders.c |  246 ++++++++++++++++++
 drivers/gpu/drm/radeon/cik_blit_shaders.h |   32 +++
 drivers/gpu/drm/radeon/cikd.h             |  222 ++++++++++++++++
 drivers/gpu/drm/radeon/radeon_cs.c        |    4 +-
 6 files changed, 899 insertions(+), 2 deletions(-)
 create mode 100644 drivers/gpu/drm/radeon/cik_blit_shaders.c
 create mode 100644 drivers/gpu/drm/radeon/cik_blit_shaders.h

diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile
index 88d0601..292fd25 100644
--- a/drivers/gpu/drm/radeon/Makefile
+++ b/drivers/gpu/drm/radeon/Makefile
@@ -76,7 +76,7 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \
 	evergreen.o evergreen_cs.o evergreen_blit_shaders.o evergreen_blit_kms.o \
 	evergreen_hdmi.o radeon_trace_points.o ni.o cayman_blit_shaders.o \
 	atombios_encoders.o radeon_semaphore.o radeon_sa.o atombios_i2c.o si.o \
-	si_blit_shaders.o radeon_prime.o radeon_uvd.o cik.o
+	si_blit_shaders.o radeon_prime.o radeon_uvd.o cik.o cik_blit_shaders.o
 
 radeon-$(CONFIG_COMPAT) += radeon_ioc32.o
 radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o
diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
index 8eec582..5712526 100644
--- a/drivers/gpu/drm/radeon/cik.c
+++ b/drivers/gpu/drm/radeon/cik.c
@@ -30,6 +30,7 @@
 #include "radeon_asic.h"
 #include "cikd.h"
 #include "atom.h"
+#include "cik_blit_shaders.h"
 
 /* GFX */
 #define CIK_PFP_UCODE_SIZE 2144
@@ -1491,6 +1492,400 @@ static void cik_gpu_init(struct radeon_device *rdev)
 	udelay(50);
 }
 
+/*
+ * CP.
+ * On CIK, gfx and compute now have independant command processors.
+ *
+ * GFX
+ * Gfx consists of a single ring and can process both gfx jobs and
+ * compute jobs.  The gfx CP consists of three microengines (ME):
+ * PFP - Pre-Fetch Parser
+ * ME - Micro Engine
+ * CE - Constant Engine
+ * The PFP and ME make up what is considered the Drawing Engine (DE).
+ * The CE is an asynchronous engine used for updating buffer desciptors
+ * used by the DE so that they can be loaded into cache in parallel
+ * while the DE is processing state update packets.
+ *
+ * Compute
+ * The compute CP consists of two microengines (ME):
+ * MEC1 - Compute MicroEngine 1
+ * MEC2 - Compute MicroEngine 2
+ * Each MEC supports 4 compute pipes and each pipe supports 8 queues.
+ * The queues are exposed to userspace and are programmed directly
+ * by the compute runtime.
+ */
+/**
+ * cik_cp_gfx_enable - enable/disable the gfx CP MEs
+ *
+ * @rdev: radeon_device pointer
+ * @enable: enable or disable the MEs
+ *
+ * Halts or unhalts the gfx MEs.
+ */
+static void cik_cp_gfx_enable(struct radeon_device *rdev, bool enable)
+{
+	if (enable)
+		WREG32(CP_ME_CNTL, 0);
+	else {
+		WREG32(CP_ME_CNTL, (CP_ME_HALT | CP_PFP_HALT | CP_CE_HALT));
+		rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ready = false;
+	}
+	udelay(50);
+}
+
+/**
+ * cik_cp_gfx_load_microcode - load the gfx CP ME ucode
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Loads the gfx PFP, ME, and CE ucode.
+ * Returns 0 for success, -EINVAL if the ucode is not available.
+ */
+static int cik_cp_gfx_load_microcode(struct radeon_device *rdev)
+{
+	const __be32 *fw_data;
+	int i;
+
+	if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw)
+		return -EINVAL;
+
+	cik_cp_gfx_enable(rdev, false);
+
+	/* PFP */
+	fw_data = (const __be32 *)rdev->pfp_fw->data;
+	WREG32(CP_PFP_UCODE_ADDR, 0);
+	for (i = 0; i < CIK_PFP_UCODE_SIZE; i++)
+		WREG32(CP_PFP_UCODE_DATA, be32_to_cpup(fw_data++));
+	WREG32(CP_PFP_UCODE_ADDR, 0);
+
+	/* CE */
+	fw_data = (const __be32 *)rdev->ce_fw->data;
+	WREG32(CP_CE_UCODE_ADDR, 0);
+	for (i = 0; i < CIK_CE_UCODE_SIZE; i++)
+		WREG32(CP_CE_UCODE_DATA, be32_to_cpup(fw_data++));
+	WREG32(CP_CE_UCODE_ADDR, 0);
+
+	/* ME */
+	fw_data = (const __be32 *)rdev->me_fw->data;
+	WREG32(CP_ME_RAM_WADDR, 0);
+	for (i = 0; i < CIK_ME_UCODE_SIZE; i++)
+		WREG32(CP_ME_RAM_DATA, be32_to_cpup(fw_data++));
+	WREG32(CP_ME_RAM_WADDR, 0);
+
+	WREG32(CP_PFP_UCODE_ADDR, 0);
+	WREG32(CP_CE_UCODE_ADDR, 0);
+	WREG32(CP_ME_RAM_WADDR, 0);
+	WREG32(CP_ME_RAM_RADDR, 0);
+	return 0;
+}
+
+/**
+ * cik_cp_gfx_start - start the gfx ring
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Enables the ring and loads the clear state context and other
+ * packets required to init the ring.
+ * Returns 0 for success, error for failure.
+ */
+static int cik_cp_gfx_start(struct radeon_device *rdev)
+{
+	struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
+	int r, i;
+
+	/* init the CP */
+	WREG32(CP_MAX_CONTEXT, rdev->config.cik.max_hw_contexts - 1);
+	WREG32(CP_ENDIAN_SWAP, 0);
+	WREG32(CP_DEVICE_ID, 1);
+
+	cik_cp_gfx_enable(rdev, true);
+
+	r = radeon_ring_lock(rdev, ring, cik_default_size + 17);
+	if (r) {
+		DRM_ERROR("radeon: cp failed to lock ring (%d).\n", r);
+		return r;
+	}
+
+	/* init the CE partitions.  CE only used for gfx on CIK */
+	radeon_ring_write(ring, PACKET3(PACKET3_SET_BASE, 2));
+	radeon_ring_write(ring, PACKET3_BASE_INDEX(CE_PARTITION_BASE));
+	radeon_ring_write(ring, 0xc000);
+	radeon_ring_write(ring, 0xc000);
+
+	/* setup clear context state */
+	radeon_ring_write(ring, PACKET3(PACKET3_PREAMBLE_CNTL, 0));
+	radeon_ring_write(ring, PACKET3_PREAMBLE_BEGIN_CLEAR_STATE);
+
+	radeon_ring_write(ring, PACKET3(PACKET3_CONTEXT_CONTROL, 1));
+	radeon_ring_write(ring, 0x80000000);
+	radeon_ring_write(ring, 0x80000000);
+
+	for (i = 0; i < cik_default_size; i++)
+		radeon_ring_write(ring, cik_default_state[i]);
+
+	radeon_ring_write(ring, PACKET3(PACKET3_PREAMBLE_CNTL, 0));
+	radeon_ring_write(ring, PACKET3_PREAMBLE_END_CLEAR_STATE);
+
+	/* set clear context state */
+	radeon_ring_write(ring, PACKET3(PACKET3_CLEAR_STATE, 0));
+	radeon_ring_write(ring, 0);
+
+	radeon_ring_write(ring, PACKET3(PACKET3_SET_CONTEXT_REG, 2));
+	radeon_ring_write(ring, 0x00000316);
+	radeon_ring_write(ring, 0x0000000e); /* VGT_VERTEX_REUSE_BLOCK_CNTL */
+	radeon_ring_write(ring, 0x00000010); /* VGT_OUT_DEALLOC_CNTL */
+
+	radeon_ring_unlock_commit(rdev, ring);
+
+	return 0;
+}
+
+/**
+ * cik_cp_gfx_fini - stop the gfx ring
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Stop the gfx ring and tear down the driver ring
+ * info.
+ */
+static void cik_cp_gfx_fini(struct radeon_device *rdev)
+{
+	cik_cp_gfx_enable(rdev, false);
+	radeon_ring_fini(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
+}
+
+/**
+ * cik_cp_gfx_resume - setup the gfx ring buffer registers
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Program the location and size of the gfx ring buffer
+ * and test it to make sure it's working.
+ * Returns 0 for success, error for failure.
+ */
+static int cik_cp_gfx_resume(struct radeon_device *rdev)
+{
+	struct radeon_ring *ring;
+	u32 tmp;
+	u32 rb_bufsz;
+	u64 rb_addr;
+	int r;
+
+	WREG32(CP_SEM_WAIT_TIMER, 0x0);
+	WREG32(CP_SEM_INCOMPLETE_TIMER_CNTL, 0x0);
+
+	/* Set the write pointer delay */
+	WREG32(CP_RB_WPTR_DELAY, 0);
+
+	/* set the RB to use vmid 0 */
+	WREG32(CP_RB_VMID, 0);
+
+	WREG32(SCRATCH_ADDR, ((rdev->wb.gpu_addr + RADEON_WB_SCRATCH_OFFSET) >> 8) & 0xFFFFFFFF);
+
+	/* ring 0 - compute and gfx */
+	/* Set ring buffer size */
+	ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
+	rb_bufsz = drm_order(ring->ring_size / 8);
+	tmp = (drm_order(RADEON_GPU_PAGE_SIZE/8) << 8) | rb_bufsz;
+#ifdef __BIG_ENDIAN
+	tmp |= BUF_SWAP_32BIT;
+#endif
+	WREG32(CP_RB0_CNTL, tmp);
+
+	/* Initialize the ring buffer's read and write pointers */
+	WREG32(CP_RB0_CNTL, tmp | RB_RPTR_WR_ENA);
+	ring->wptr = 0;
+	WREG32(CP_RB0_WPTR, ring->wptr);
+
+	/* set the wb address wether it's enabled or not */
+	WREG32(CP_RB0_RPTR_ADDR, (rdev->wb.gpu_addr + RADEON_WB_CP_RPTR_OFFSET) & 0xFFFFFFFC);
+	WREG32(CP_RB0_RPTR_ADDR_HI, upper_32_bits(rdev->wb.gpu_addr + RADEON_WB_CP_RPTR_OFFSET) & 0xFF);
+
+	/* scratch register shadowing is no longer supported */
+	WREG32(SCRATCH_UMSK, 0);
+
+	if (!rdev->wb.enabled)
+		tmp |= RB_NO_UPDATE;
+
+	mdelay(1);
+	WREG32(CP_RB0_CNTL, tmp);
+
+	rb_addr = ring->gpu_addr >> 8;
+	WREG32(CP_RB0_BASE, rb_addr);
+	WREG32(CP_RB0_BASE_HI, upper_32_bits(rb_addr));
+
+	ring->rptr = RREG32(CP_RB0_RPTR);
+
+	/* start the ring */
+	cik_cp_gfx_start(rdev);
+	rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ready = true;
+	r = radeon_ring_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
+	if (r) {
+		rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ready = false;
+		return r;
+	}
+	return 0;
+}
+
+/**
+ * cik_cp_compute_enable - enable/disable the compute CP MEs
+ *
+ * @rdev: radeon_device pointer
+ * @enable: enable or disable the MEs
+ *
+ * Halts or unhalts the compute MEs.
+ */
+static void cik_cp_compute_enable(struct radeon_device *rdev, bool enable)
+{
+	if (enable)
+		WREG32(CP_MEC_CNTL, 0);
+	else
+		WREG32(CP_MEC_CNTL, (MEC_ME1_HALT | MEC_ME2_HALT));
+	udelay(50);
+}
+
+/**
+ * cik_cp_compute_load_microcode - load the compute CP ME ucode
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Loads the compute MEC1&2 ucode.
+ * Returns 0 for success, -EINVAL if the ucode is not available.
+ */
+static int cik_cp_compute_load_microcode(struct radeon_device *rdev)
+{
+	const __be32 *fw_data;
+	int i;
+
+	if (!rdev->mec_fw)
+		return -EINVAL;
+
+	cik_cp_compute_enable(rdev, false);
+
+	/* MEC1 */
+	fw_data = (const __be32 *)rdev->mec_fw->data;
+	WREG32(CP_MEC_ME1_UCODE_ADDR, 0);
+	for (i = 0; i < CIK_MEC_UCODE_SIZE; i++)
+		WREG32(CP_MEC_ME1_UCODE_DATA, be32_to_cpup(fw_data++));
+	WREG32(CP_MEC_ME1_UCODE_ADDR, 0);
+
+	if (rdev->family == CHIP_KAVERI) {
+		/* MEC2 */
+		fw_data = (const __be32 *)rdev->mec_fw->data;
+		WREG32(CP_MEC_ME2_UCODE_ADDR, 0);
+		for (i = 0; i < CIK_MEC_UCODE_SIZE; i++)
+			WREG32(CP_MEC_ME2_UCODE_DATA, be32_to_cpup(fw_data++));
+		WREG32(CP_MEC_ME2_UCODE_ADDR, 0);
+	}
+
+	return 0;
+}
+
+/**
+ * cik_cp_compute_start - start the compute queues
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Enable the compute queues.
+ * Returns 0 for success, error for failure.
+ */
+static int cik_cp_compute_start(struct radeon_device *rdev)
+{
+	//todo
+	return 0;
+}
+
+/**
+ * cik_cp_compute_fini - stop the compute queues
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Stop the compute queues and tear down the driver queue
+ * info.
+ */
+static void cik_cp_compute_fini(struct radeon_device *rdev)
+{
+	cik_cp_compute_enable(rdev, false);
+	//todo
+}
+
+/**
+ * cik_cp_compute_resume - setup the compute queue registers
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Program the compute queues and test them to make sure they
+ * are working.
+ * Returns 0 for success, error for failure.
+ */
+static int cik_cp_compute_resume(struct radeon_device *rdev)
+{
+	int r;
+
+	//todo
+	r = cik_cp_compute_start(rdev);
+	if (r)
+		return r;
+	return 0;
+}
+
+/* XXX temporary wrappers to handle both compute and gfx */
+/* XXX */
+static void cik_cp_enable(struct radeon_device *rdev, bool enable)
+{
+	cik_cp_gfx_enable(rdev, enable);
+	cik_cp_compute_enable(rdev, enable);
+}
+
+/* XXX */
+static int cik_cp_load_microcode(struct radeon_device *rdev)
+{
+	int r;
+
+	r = cik_cp_gfx_load_microcode(rdev);
+	if (r)
+		return r;
+	r = cik_cp_compute_load_microcode(rdev);
+	if (r)
+		return r;
+
+	return 0;
+}
+
+/* XXX */
+static void cik_cp_fini(struct radeon_device *rdev)
+{
+	cik_cp_gfx_fini(rdev);
+	cik_cp_compute_fini(rdev);
+}
+
+/* XXX */
+static int cik_cp_resume(struct radeon_device *rdev)
+{
+	int r;
+
+	/* Reset all cp blocks */
+	WREG32(GRBM_SOFT_RESET, SOFT_RESET_CP);
+	RREG32(GRBM_SOFT_RESET);
+	mdelay(15);
+	WREG32(GRBM_SOFT_RESET, 0);
+	RREG32(GRBM_SOFT_RESET);
+
+	r = cik_cp_load_microcode(rdev);
+	if (r)
+		return r;
+
+	r = cik_cp_gfx_resume(rdev);
+	if (r)
+		return r;
+	r = cik_cp_compute_resume(rdev);
+	if (r)
+		return r;
+
+	return 0;
+}
+
 /**
  * cik_gpu_is_lockup - check if the 3D engine is locked up
  *
diff --git a/drivers/gpu/drm/radeon/cik_blit_shaders.c b/drivers/gpu/drm/radeon/cik_blit_shaders.c
new file mode 100644
index 0000000..ff13118
--- /dev/null
+++ b/drivers/gpu/drm/radeon/cik_blit_shaders.c
@@ -0,0 +1,246 @@
+/*
+ * Copyright 2012 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *     Alex Deucher <alexander.deucher@amd.com>
+ */
+
+#include <linux/types.h>
+#include <linux/bug.h>
+#include <linux/kernel.h>
+
+const u32 cik_default_state[] =
+{
+	0xc0066900,
+	0x00000000,
+	0x00000060, /* DB_RENDER_CONTROL */
+	0x00000000, /* DB_COUNT_CONTROL */
+	0x00000000, /* DB_DEPTH_VIEW */
+	0x0000002a, /* DB_RENDER_OVERRIDE */
+	0x00000000, /* DB_RENDER_OVERRIDE2 */
+	0x00000000, /* DB_HTILE_DATA_BASE */
+
+	0xc0046900,
+	0x00000008,
+	0x00000000, /* DB_DEPTH_BOUNDS_MIN */
+	0x00000000, /* DB_DEPTH_BOUNDS_MAX */
+	0x00000000, /* DB_STENCIL_CLEAR */
+	0x00000000, /* DB_DEPTH_CLEAR */
+
+	0xc0036900,
+	0x0000000f,
+	0x00000000, /* DB_DEPTH_INFO */
+	0x00000000, /* DB_Z_INFO */
+	0x00000000, /* DB_STENCIL_INFO */
+
+	0xc0016900,
+	0x00000080,
+	0x00000000, /* PA_SC_WINDOW_OFFSET */
+
+	0xc00d6900,
+	0x00000083,
+	0x0000ffff, /* PA_SC_CLIPRECT_RULE */
+	0x00000000, /* PA_SC_CLIPRECT_0_TL */
+	0x20002000, /* PA_SC_CLIPRECT_0_BR */
+	0x00000000,
+	0x20002000,
+	0x00000000,
+	0x20002000,
+	0x00000000,
+	0x20002000,
+	0xaaaaaaaa, /* PA_SC_EDGERULE */
+	0x00000000, /* PA_SU_HARDWARE_SCREEN_OFFSET */
+	0x0000000f, /* CB_TARGET_MASK */
+	0x0000000f, /* CB_SHADER_MASK */
+
+	0xc0226900,
+	0x00000094,
+	0x80000000, /* PA_SC_VPORT_SCISSOR_0_TL */
+	0x20002000, /* PA_SC_VPORT_SCISSOR_0_BR */
+	0x80000000,
+	0x20002000,
+	0x80000000,
+	0x20002000,
+	0x80000000,
+	0x20002000,
+	0x80000000,
+	0x20002000,
+	0x80000000,
+	0x20002000,
+	0x80000000,
+	0x20002000,
+	0x80000000,
+	0x20002000,
+	0x80000000,
+	0x20002000,
+	0x80000000,
+	0x20002000,
+	0x80000000,
+	0x20002000,
+	0x80000000,
+	0x20002000,
+	0x80000000,
+	0x20002000,
+	0x80000000,
+	0x20002000,
+	0x80000000,
+	0x20002000,
+	0x80000000,
+	0x20002000,
+	0x00000000, /* PA_SC_VPORT_ZMIN_0 */
+	0x3f800000, /* PA_SC_VPORT_ZMAX_0 */
+
+	0xc0046900,
+	0x00000100,
+	0xffffffff, /* VGT_MAX_VTX_INDX */
+	0x00000000, /* VGT_MIN_VTX_INDX */
+	0x00000000, /* VGT_INDX_OFFSET */
+	0x00000000, /* VGT_MULTI_PRIM_IB_RESET_INDX */
+
+	0xc0046900,
+	0x00000105,
+	0x00000000, /* CB_BLEND_RED */
+	0x00000000, /* CB_BLEND_GREEN */
+	0x00000000, /* CB_BLEND_BLUE */
+	0x00000000, /* CB_BLEND_ALPHA */
+
+	0xc0016900,
+	0x000001e0,
+	0x00000000, /* CB_BLEND0_CONTROL */
+
+	0xc00c6900,
+	0x00000200,
+	0x00000000, /* DB_DEPTH_CONTROL */
+	0x00000000, /* DB_EQAA */
+	0x00cc0010, /* CB_COLOR_CONTROL */
+	0x00000210, /* DB_SHADER_CONTROL */
+	0x00010000, /* PA_CL_CLIP_CNTL */
+	0x00000004, /* PA_SU_SC_MODE_CNTL */
+	0x00000100, /* PA_CL_VTE_CNTL */
+	0x00000000, /* PA_CL_VS_OUT_CNTL */
+	0x00000000, /* PA_CL_NANINF_CNTL */
+	0x00000000, /* PA_SU_LINE_STIPPLE_CNTL */
+	0x00000000, /* PA_SU_LINE_STIPPLE_SCALE */
+	0x00000000, /* PA_SU_PRIM_FILTER_CNTL */
+
+	0xc0116900,
+	0x00000280,
+	0x00000000, /* PA_SU_POINT_SIZE */
+	0x00000000, /* PA_SU_POINT_MINMAX */
+	0x00000008, /* PA_SU_LINE_CNTL */
+	0x00000000, /* PA_SC_LINE_STIPPLE */
+	0x00000000, /* VGT_OUTPUT_PATH_CNTL */
+	0x00000000, /* VGT_HOS_CNTL */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000, /* VGT_GS_MODE */
+
+	0xc0026900,
+	0x00000292,
+	0x00000000, /* PA_SC_MODE_CNTL_0 */
+	0x00000000, /* PA_SC_MODE_CNTL_1 */
+
+	0xc0016900,
+	0x000002a1,
+	0x00000000, /* VGT_PRIMITIVEID_EN */
+
+	0xc0016900,
+	0x000002a5,
+	0x00000000, /* VGT_MULTI_PRIM_IB_RESET_EN */
+
+	0xc0026900,
+	0x000002a8,
+	0x00000000, /* VGT_INSTANCE_STEP_RATE_0 */
+	0x00000000,
+
+	0xc0026900,
+	0x000002ad,
+	0x00000000, /* VGT_REUSE_OFF */
+	0x00000000,
+
+	0xc0016900,
+	0x000002d5,
+	0x00000000, /* VGT_SHADER_STAGES_EN */
+
+	0xc0016900,
+	0x000002dc,
+	0x0000aa00, /* DB_ALPHA_TO_MASK */
+
+	0xc0066900,
+	0x000002de,
+	0x00000000, /* PA_SU_POLY_OFFSET_DB_FMT_CNTL */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+
+	0xc0026900,
+	0x000002e5,
+	0x00000000, /* VGT_STRMOUT_CONFIG */
+	0x00000000,
+
+	0xc01b6900,
+	0x000002f5,
+	0x76543210, /* PA_SC_CENTROID_PRIORITY_0 */
+	0xfedcba98, /* PA_SC_CENTROID_PRIORITY_1 */
+	0x00000000, /* PA_SC_LINE_CNTL */
+	0x00000000, /* PA_SC_AA_CONFIG */
+	0x00000005, /* PA_SU_VTX_CNTL */
+	0x3f800000, /* PA_CL_GB_VERT_CLIP_ADJ */
+	0x3f800000, /* PA_CL_GB_VERT_DISC_ADJ */
+	0x3f800000, /* PA_CL_GB_HORZ_CLIP_ADJ */
+	0x3f800000, /* PA_CL_GB_HORZ_DISC_ADJ */
+	0x00000000, /* PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_0 */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0xffffffff, /* PA_SC_AA_MASK_X0Y0_X1Y0 */
+	0xffffffff,
+
+	0xc0026900,
+	0x00000316,
+	0x0000000e, /* VGT_VERTEX_REUSE_BLOCK_CNTL */
+	0x00000010, /*  */
+};
+
+const u32 cik_default_size = ARRAY_SIZE(cik_default_state);
diff --git a/drivers/gpu/drm/radeon/cik_blit_shaders.h b/drivers/gpu/drm/radeon/cik_blit_shaders.h
new file mode 100644
index 0000000..dfe7314
--- /dev/null
+++ b/drivers/gpu/drm/radeon/cik_blit_shaders.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2012 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef CIK_BLIT_SHADERS_H
+#define CIK_BLIT_SHADERS_H
+
+extern const u32 cik_default_state[];
+
+extern const u32 cik_default_size;
+
+#endif
diff --git a/drivers/gpu/drm/radeon/cikd.h b/drivers/gpu/drm/radeon/cikd.h
index 2300ae0..0d1a298 100644
--- a/drivers/gpu/drm/radeon/cikd.h
+++ b/drivers/gpu/drm/radeon/cikd.h
@@ -263,11 +263,18 @@
 #define		MEC_ME2_HALT					(1 << 28)
 #define		MEC_ME1_HALT					(1 << 30)
 
+#define CP_MEC_CNTL					0x8234
+#define		MEC_ME2_HALT					(1 << 28)
+#define		MEC_ME1_HALT					(1 << 30)
+
 #define CP_ME_CNTL					0x86D8
 #define		CP_CE_HALT					(1 << 24)
 #define		CP_PFP_HALT					(1 << 26)
 #define		CP_ME_HALT					(1 << 28)
 
+#define	CP_RB0_RPTR					0x8700
+#define	CP_RB_WPTR_DELAY				0x8704
+
 #define CP_MEQ_THRESHOLDS				0x8764
 #define		MEQ1_START(x)				((x) << 0)
 #define		MEQ2_START(x)				((x) << 8)
@@ -445,12 +452,62 @@
 #define	TC_CFG_L1_VOLATILE				0xAC88
 #define	TC_CFG_L2_VOLATILE				0xAC8C
 
+#define	CP_RB0_BASE					0xC100
+#define	CP_RB0_CNTL					0xC104
+#define		RB_BUFSZ(x)					((x) << 0)
+#define		RB_BLKSZ(x)					((x) << 8)
+#define		BUF_SWAP_32BIT					(2 << 16)
+#define		RB_NO_UPDATE					(1 << 27)
+#define		RB_RPTR_WR_ENA					(1 << 31)
+
+#define	CP_RB0_RPTR_ADDR				0xC10C
+#define		RB_RPTR_SWAP_32BIT				(2 << 0)
+#define	CP_RB0_RPTR_ADDR_HI				0xC110
+#define	CP_RB0_WPTR					0xC114
+
+#define	CP_DEVICE_ID					0xC12C
+#define	CP_ENDIAN_SWAP					0xC140
+#define	CP_RB_VMID					0xC144
+
+#define	CP_PFP_UCODE_ADDR				0xC150
+#define	CP_PFP_UCODE_DATA				0xC154
+#define	CP_ME_RAM_RADDR					0xC158
+#define	CP_ME_RAM_WADDR					0xC15C
+#define	CP_ME_RAM_DATA					0xC160
+
+#define	CP_CE_UCODE_ADDR				0xC168
+#define	CP_CE_UCODE_DATA				0xC16C
+#define	CP_MEC_ME1_UCODE_ADDR				0xC170
+#define	CP_MEC_ME1_UCODE_DATA				0xC174
+#define	CP_MEC_ME2_UCODE_ADDR				0xC178
+#define	CP_MEC_ME2_UCODE_DATA				0xC17C
+
+#define	CP_MAX_CONTEXT					0xC2B8
+
+#define	CP_RB0_BASE_HI					0xC2C4
+
 #define PA_SC_RASTER_CONFIG                             0x28350
 #       define RASTER_CONFIG_RB_MAP_0                   0
 #       define RASTER_CONFIG_RB_MAP_1                   1
 #       define RASTER_CONFIG_RB_MAP_2                   2
 #       define RASTER_CONFIG_RB_MAP_3                   3
 
+#define	SCRATCH_REG0					0x30100
+#define	SCRATCH_REG1					0x30104
+#define	SCRATCH_REG2					0x30108
+#define	SCRATCH_REG3					0x3010C
+#define	SCRATCH_REG4					0x30110
+#define	SCRATCH_REG5					0x30114
+#define	SCRATCH_REG6					0x30118
+#define	SCRATCH_REG7					0x3011C
+
+#define	SCRATCH_UMSK					0x30140
+#define	SCRATCH_ADDR					0x30144
+
+#define	CP_SEM_WAIT_TIMER				0x301BC
+
+#define	CP_SEM_INCOMPLETE_TIMER_CNTL			0x301C8
+
 #define GRBM_GFX_INDEX          			0x30800
 #define		INSTANCE_INDEX(x)			((x) << 0)
 #define		SH_INDEX(x)     			((x) << 8)
@@ -482,4 +539,169 @@
 #define		TCC_DISABLE_MASK				0xFFFF0000
 #define		TCC_DISABLE_SHIFT				16
 
+/*
+ * PM4
+ */
+#define	PACKET_TYPE0	0
+#define	PACKET_TYPE1	1
+#define	PACKET_TYPE2	2
+#define	PACKET_TYPE3	3
+
+#define CP_PACKET_GET_TYPE(h) (((h) >> 30) & 3)
+#define CP_PACKET_GET_COUNT(h) (((h) >> 16) & 0x3FFF)
+#define CP_PACKET0_GET_REG(h) (((h) & 0xFFFF) << 2)
+#define CP_PACKET3_GET_OPCODE(h) (((h) >> 8) & 0xFF)
+#define PACKET0(reg, n)	((PACKET_TYPE0 << 30) |				\
+			 (((reg) >> 2) & 0xFFFF) |			\
+			 ((n) & 0x3FFF) << 16)
+#define CP_PACKET2			0x80000000
+#define		PACKET2_PAD_SHIFT		0
+#define		PACKET2_PAD_MASK		(0x3fffffff << 0)
+
+#define PACKET2(v)	(CP_PACKET2 | REG_SET(PACKET2_PAD, (v)))
+
+#define PACKET3(op, n)	((PACKET_TYPE3 << 30) |				\
+			 (((op) & 0xFF) << 8) |				\
+			 ((n) & 0x3FFF) << 16)
+
+#define PACKET3_COMPUTE(op, n) (PACKET3(op, n) | 1 << 1)
+
+/* Packet 3 types */
+#define	PACKET3_NOP					0x10
+#define	PACKET3_SET_BASE				0x11
+#define		PACKET3_BASE_INDEX(x)                  ((x) << 0)
+#define			CE_PARTITION_BASE		3
+#define	PACKET3_CLEAR_STATE				0x12
+#define	PACKET3_INDEX_BUFFER_SIZE			0x13
+#define	PACKET3_DISPATCH_DIRECT				0x15
+#define	PACKET3_DISPATCH_INDIRECT			0x16
+#define	PACKET3_ATOMIC_GDS				0x1D
+#define	PACKET3_ATOMIC_MEM				0x1E
+#define	PACKET3_OCCLUSION_QUERY				0x1F
+#define	PACKET3_SET_PREDICATION				0x20
+#define	PACKET3_REG_RMW					0x21
+#define	PACKET3_COND_EXEC				0x22
+#define	PACKET3_PRED_EXEC				0x23
+#define	PACKET3_DRAW_INDIRECT				0x24
+#define	PACKET3_DRAW_INDEX_INDIRECT			0x25
+#define	PACKET3_INDEX_BASE				0x26
+#define	PACKET3_DRAW_INDEX_2				0x27
+#define	PACKET3_CONTEXT_CONTROL				0x28
+#define	PACKET3_INDEX_TYPE				0x2A
+#define	PACKET3_DRAW_INDIRECT_MULTI			0x2C
+#define	PACKET3_DRAW_INDEX_AUTO				0x2D
+#define	PACKET3_NUM_INSTANCES				0x2F
+#define	PACKET3_DRAW_INDEX_MULTI_AUTO			0x30
+#define	PACKET3_INDIRECT_BUFFER_CONST			0x33
+#define	PACKET3_STRMOUT_BUFFER_UPDATE			0x34
+#define	PACKET3_DRAW_INDEX_OFFSET_2			0x35
+#define	PACKET3_DRAW_PREAMBLE				0x36
+#define	PACKET3_WRITE_DATA				0x37
+#define	PACKET3_DRAW_INDEX_INDIRECT_MULTI		0x38
+#define	PACKET3_MEM_SEMAPHORE				0x39
+#define	PACKET3_COPY_DW					0x3B
+#define	PACKET3_WAIT_REG_MEM				0x3C
+#define	PACKET3_INDIRECT_BUFFER				0x3F
+#define	PACKET3_COPY_DATA				0x40
+#define	PACKET3_PFP_SYNC_ME				0x42
+#define	PACKET3_SURFACE_SYNC				0x43
+#              define PACKET3_DEST_BASE_0_ENA      (1 << 0)
+#              define PACKET3_DEST_BASE_1_ENA      (1 << 1)
+#              define PACKET3_CB0_DEST_BASE_ENA    (1 << 6)
+#              define PACKET3_CB1_DEST_BASE_ENA    (1 << 7)
+#              define PACKET3_CB2_DEST_BASE_ENA    (1 << 8)
+#              define PACKET3_CB3_DEST_BASE_ENA    (1 << 9)
+#              define PACKET3_CB4_DEST_BASE_ENA    (1 << 10)
+#              define PACKET3_CB5_DEST_BASE_ENA    (1 << 11)
+#              define PACKET3_CB6_DEST_BASE_ENA    (1 << 12)
+#              define PACKET3_CB7_DEST_BASE_ENA    (1 << 13)
+#              define PACKET3_DB_DEST_BASE_ENA     (1 << 14)
+#              define PACKET3_TCL1_VOL_ACTION_ENA  (1 << 15)
+#              define PACKET3_TC_VOL_ACTION_ENA    (1 << 16) /* L2 */
+#              define PACKET3_TC_WB_ACTION_ENA     (1 << 18) /* L2 */
+#              define PACKET3_DEST_BASE_2_ENA      (1 << 19)
+#              define PACKET3_DEST_BASE_3_ENA      (1 << 21)
+#              define PACKET3_TCL1_ACTION_ENA      (1 << 22)
+#              define PACKET3_TC_ACTION_ENA        (1 << 23) /* L2 */
+#              define PACKET3_CB_ACTION_ENA        (1 << 25)
+#              define PACKET3_DB_ACTION_ENA        (1 << 26)
+#              define PACKET3_SH_KCACHE_ACTION_ENA (1 << 27)
+#              define PACKET3_SH_KCACHE_VOL_ACTION_ENA (1 << 28)
+#              define PACKET3_SH_ICACHE_ACTION_ENA (1 << 29)
+#define	PACKET3_COND_WRITE				0x45
+#define	PACKET3_EVENT_WRITE				0x46
+#define		EVENT_TYPE(x)                           ((x) << 0)
+#define		EVENT_INDEX(x)                          ((x) << 8)
+                /* 0 - any non-TS event
+		 * 1 - ZPASS_DONE, PIXEL_PIPE_STAT_*
+		 * 2 - SAMPLE_PIPELINESTAT
+		 * 3 - SAMPLE_STREAMOUTSTAT*
+		 * 4 - *S_PARTIAL_FLUSH
+		 * 5 - EOP events
+		 * 6 - EOS events
+		 */
+#define	PACKET3_EVENT_WRITE_EOP				0x47
+#define		EOP_TCL1_VOL_ACTION_EN                  (1 << 12)
+#define		EOP_TC_VOL_ACTION_EN                    (1 << 13) /* L2 */
+#define		EOP_TC_WB_ACTION_EN                     (1 << 15) /* L2 */
+#define		EOP_TCL1_ACTION_EN                      (1 << 16)
+#define		EOP_TC_ACTION_EN                        (1 << 17) /* L2 */
+#define		CACHE_POLICY(x)                         ((x) << 25)
+                /* 0 - LRU
+		 * 1 - Stream
+		 * 2 - Bypass
+		 */
+#define		TCL2_VOLATILE                           (1 << 27)
+#define		DATA_SEL(x)                             ((x) << 29)
+                /* 0 - discard
+		 * 1 - send low 32bit data
+		 * 2 - send 64bit data
+		 * 3 - send 64bit GPU counter value
+		 * 4 - send 64bit sys counter value
+		 */
+#define		INT_SEL(x)                              ((x) << 24)
+                /* 0 - none
+		 * 1 - interrupt only (DATA_SEL = 0)
+		 * 2 - interrupt when data write is confirmed
+		 */
+#define		DST_SEL(x)                              ((x) << 16)
+                /* 0 - MC
+		 * 1 - TC/L2
+		 */
+#define	PACKET3_EVENT_WRITE_EOS				0x48
+#define	PACKET3_RELEASE_MEM				0x49
+#define	PACKET3_PREAMBLE_CNTL				0x4A
+#              define PACKET3_PREAMBLE_BEGIN_CLEAR_STATE     (2 << 28)
+#              define PACKET3_PREAMBLE_END_CLEAR_STATE       (3 << 28)
+#define	PACKET3_DMA_DATA				0x50
+#define	PACKET3_AQUIRE_MEM				0x58
+#define	PACKET3_REWIND					0x59
+#define	PACKET3_LOAD_UCONFIG_REG			0x5E
+#define	PACKET3_LOAD_SH_REG				0x5F
+#define	PACKET3_LOAD_CONFIG_REG				0x60
+#define	PACKET3_LOAD_CONTEXT_REG			0x61
+#define	PACKET3_SET_CONFIG_REG				0x68
+#define		PACKET3_SET_CONFIG_REG_START			0x00008000
+#define		PACKET3_SET_CONFIG_REG_END			0x0000b000
+#define	PACKET3_SET_CONTEXT_REG				0x69
+#define		PACKET3_SET_CONTEXT_REG_START			0x00028000
+#define		PACKET3_SET_CONTEXT_REG_END			0x00029000
+#define	PACKET3_SET_CONTEXT_REG_INDIRECT		0x73
+#define	PACKET3_SET_SH_REG				0x76
+#define		PACKET3_SET_SH_REG_START			0x0000b000
+#define		PACKET3_SET_SH_REG_END				0x0000c000
+#define	PACKET3_SET_SH_REG_OFFSET			0x77
+#define	PACKET3_SET_QUEUE_REG				0x78
+#define	PACKET3_SET_UCONFIG_REG				0x79
+#define	PACKET3_SCRATCH_RAM_WRITE			0x7D
+#define	PACKET3_SCRATCH_RAM_READ			0x7E
+#define	PACKET3_LOAD_CONST_RAM				0x80
+#define	PACKET3_WRITE_CONST_RAM				0x81
+#define	PACKET3_DUMP_CONST_RAM				0x83
+#define	PACKET3_INCREMENT_CE_COUNTER			0x84
+#define	PACKET3_INCREMENT_DE_COUNTER			0x85
+#define	PACKET3_WAIT_ON_CE_COUNTER			0x86
+#define	PACKET3_WAIT_ON_DE_COUNTER_DIFF			0x88
+
+
 #endif
diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c
index 7e265a5..cf71734 100644
--- a/drivers/gpu/drm/radeon/radeon_cs.c
+++ b/drivers/gpu/drm/radeon/radeon_cs.c
@@ -121,7 +121,9 @@ static int radeon_cs_get_ring(struct radeon_cs_parser *p, u32 ring, s32 priority
 		p->ring = RADEON_RING_TYPE_GFX_INDEX;
 		break;
 	case RADEON_CS_RING_COMPUTE:
-		if (p->rdev->family >= CHIP_TAHITI) {
+		if (p->rdev->family >= CHIP_BONAIRE)
+			p->ring = RADEON_RING_TYPE_GFX_INDEX;
+		else if (p->rdev->family >= CHIP_TAHITI) {
 			if (p->priority > 0)
 				p->ring = CAYMAN_RING_TYPE_CP1_INDEX;
 			else
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 014/165] drm/radeon: add IB and fence dispatch functions for CIK gfx (v7)
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (13 preceding siblings ...)
  2013-06-26 13:21 ` [PATCH 013/165] drm/radeon: Add CP init for CIK (v7) alexdeucher
@ 2013-06-26 13:21 ` alexdeucher
  2013-06-26 13:21 ` [PATCH 015/165] drm/radeon: add ring and IB tests for CIK (v3) alexdeucher
                   ` (98 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:21 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

For gfx ring only.  Compute is still todo.

v2: add documentation
v3: update to latest reset changes, integrate emit update patch.
v4: fix count on wait_reg_mem for HDP flush
v5: use old hdp flush method for fence
v6: set valid bit for IB
v7: cleanup for release

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/cik.c  |  134 +++++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/radeon/cikd.h |  120 +++++++++++++++++++++++++++++++++++-
 2 files changed, 251 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
index 5712526..0b9c3c9 100644
--- a/drivers/gpu/drm/radeon/cik.c
+++ b/drivers/gpu/drm/radeon/cik.c
@@ -1493,6 +1493,140 @@ static void cik_gpu_init(struct radeon_device *rdev)
 }
 
 /*
+ * GPU scratch registers helpers function.
+ */
+/**
+ * cik_scratch_init - setup driver info for CP scratch regs
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Set up the number and offset of the CP scratch registers.
+ * NOTE: use of CP scratch registers is a legacy inferface and
+ * is not used by default on newer asics (r6xx+).  On newer asics,
+ * memory buffers are used for fences rather than scratch regs.
+ */
+static void cik_scratch_init(struct radeon_device *rdev)
+{
+	int i;
+
+	rdev->scratch.num_reg = 7;
+	rdev->scratch.reg_base = SCRATCH_REG0;
+	for (i = 0; i < rdev->scratch.num_reg; i++) {
+		rdev->scratch.free[i] = true;
+		rdev->scratch.reg[i] = rdev->scratch.reg_base + (i * 4);
+	}
+}
+
+/**
+ * cik_fence_ring_emit - emit a fence on the gfx ring
+ *
+ * @rdev: radeon_device pointer
+ * @fence: radeon fence object
+ *
+ * Emits a fence sequnce number on the gfx ring and flushes
+ * GPU caches.
+ */
+void cik_fence_ring_emit(struct radeon_device *rdev,
+			 struct radeon_fence *fence)
+{
+	struct radeon_ring *ring = &rdev->ring[fence->ring];
+	u64 addr = rdev->fence_drv[fence->ring].gpu_addr;
+
+	/* EVENT_WRITE_EOP - flush caches, send int */
+	radeon_ring_write(ring, PACKET3(PACKET3_EVENT_WRITE_EOP, 4));
+	radeon_ring_write(ring, (EOP_TCL1_ACTION_EN |
+				 EOP_TC_ACTION_EN |
+				 EVENT_TYPE(CACHE_FLUSH_AND_INV_TS_EVENT) |
+				 EVENT_INDEX(5)));
+	radeon_ring_write(ring, addr & 0xfffffffc);
+	radeon_ring_write(ring, (upper_32_bits(addr) & 0xffff) | DATA_SEL(1) | INT_SEL(2));
+	radeon_ring_write(ring, fence->seq);
+	radeon_ring_write(ring, 0);
+	/* HDP flush */
+	/* We should be using the new WAIT_REG_MEM special op packet here
+	 * but it causes the CP to hang
+	 */
+	radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
+	radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
+				 WRITE_DATA_DST_SEL(0)));
+	radeon_ring_write(ring, HDP_MEM_COHERENCY_FLUSH_CNTL >> 2);
+	radeon_ring_write(ring, 0);
+	radeon_ring_write(ring, 0);
+}
+
+void cik_semaphore_ring_emit(struct radeon_device *rdev,
+			     struct radeon_ring *ring,
+			     struct radeon_semaphore *semaphore,
+			     bool emit_wait)
+{
+	uint64_t addr = semaphore->gpu_addr;
+	unsigned sel = emit_wait ? PACKET3_SEM_SEL_WAIT : PACKET3_SEM_SEL_SIGNAL;
+
+	radeon_ring_write(ring, PACKET3(PACKET3_MEM_SEMAPHORE, 1));
+	radeon_ring_write(ring, addr & 0xffffffff);
+	radeon_ring_write(ring, (upper_32_bits(addr) & 0xffff) | sel);
+}
+
+/*
+ * IB stuff
+ */
+/**
+ * cik_ring_ib_execute - emit an IB (Indirect Buffer) on the gfx ring
+ *
+ * @rdev: radeon_device pointer
+ * @ib: radeon indirect buffer object
+ *
+ * Emits an DE (drawing engine) or CE (constant engine) IB
+ * on the gfx ring.  IBs are usually generated by userspace
+ * acceleration drivers and submitted to the kernel for
+ * sheduling on the ring.  This function schedules the IB
+ * on the gfx ring for execution by the GPU.
+ */
+void cik_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)
+{
+	struct radeon_ring *ring = &rdev->ring[ib->ring];
+	u32 header, control = INDIRECT_BUFFER_VALID;
+
+	if (ib->is_const_ib) {
+		/* set switch buffer packet before const IB */
+		radeon_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0));
+		radeon_ring_write(ring, 0);
+
+		header = PACKET3(PACKET3_INDIRECT_BUFFER_CONST, 2);
+	} else {
+		u32 next_rptr;
+		if (ring->rptr_save_reg) {
+			next_rptr = ring->wptr + 3 + 4;
+			radeon_ring_write(ring, PACKET3(PACKET3_SET_UCONFIG_REG, 1));
+			radeon_ring_write(ring, ((ring->rptr_save_reg -
+						  PACKET3_SET_UCONFIG_REG_START) >> 2));
+			radeon_ring_write(ring, next_rptr);
+		} else if (rdev->wb.enabled) {
+			next_rptr = ring->wptr + 5 + 4;
+			radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
+			radeon_ring_write(ring, WRITE_DATA_DST_SEL(1));
+			radeon_ring_write(ring, ring->next_rptr_gpu_addr & 0xfffffffc);
+			radeon_ring_write(ring, upper_32_bits(ring->next_rptr_gpu_addr) & 0xffffffff);
+			radeon_ring_write(ring, next_rptr);
+		}
+
+		header = PACKET3(PACKET3_INDIRECT_BUFFER, 2);
+	}
+
+	control |= ib->length_dw |
+		(ib->vm ? (ib->vm->id << 24) : 0);
+
+	radeon_ring_write(ring, header);
+	radeon_ring_write(ring,
+#ifdef __BIG_ENDIAN
+			  (2 << 0) |
+#endif
+			  (ib->gpu_addr & 0xFFFFFFFC));
+	radeon_ring_write(ring, upper_32_bits(ib->gpu_addr) & 0xFFFF);
+	radeon_ring_write(ring, control);
+}
+
+/*
  * CP.
  * On CIK, gfx and compute now have independant command processors.
  *
diff --git a/drivers/gpu/drm/radeon/cikd.h b/drivers/gpu/drm/radeon/cikd.h
index 0d1a298..783cf60 100644
--- a/drivers/gpu/drm/radeon/cikd.h
+++ b/drivers/gpu/drm/radeon/cikd.h
@@ -188,6 +188,21 @@
 
 #define HDP_REG_COHERENCY_FLUSH_CNTL			0x54A0
 
+#define GPU_HDP_FLUSH_REQ				0x54DC
+#define GPU_HDP_FLUSH_DONE				0x54E0
+#define		CP0					(1 << 0)
+#define		CP1					(1 << 1)
+#define		CP2					(1 << 2)
+#define		CP3					(1 << 3)
+#define		CP4					(1 << 4)
+#define		CP5					(1 << 5)
+#define		CP6					(1 << 6)
+#define		CP7					(1 << 7)
+#define		CP8					(1 << 8)
+#define		CP9					(1 << 9)
+#define		SDMA0					(1 << 10)
+#define		SDMA1					(1 << 11)
+
 #define	GRBM_CNTL					0x8000
 #define		GRBM_READ_TIMEOUT(x)				((x) << 0)
 
@@ -492,6 +507,49 @@
 #       define RASTER_CONFIG_RB_MAP_2                   2
 #       define RASTER_CONFIG_RB_MAP_3                   3
 
+#define VGT_EVENT_INITIATOR                             0x28a90
+#       define SAMPLE_STREAMOUTSTATS1                   (1 << 0)
+#       define SAMPLE_STREAMOUTSTATS2                   (2 << 0)
+#       define SAMPLE_STREAMOUTSTATS3                   (3 << 0)
+#       define CACHE_FLUSH_TS                           (4 << 0)
+#       define CACHE_FLUSH                              (6 << 0)
+#       define CS_PARTIAL_FLUSH                         (7 << 0)
+#       define VGT_STREAMOUT_RESET                      (10 << 0)
+#       define END_OF_PIPE_INCR_DE                      (11 << 0)
+#       define END_OF_PIPE_IB_END                       (12 << 0)
+#       define RST_PIX_CNT                              (13 << 0)
+#       define VS_PARTIAL_FLUSH                         (15 << 0)
+#       define PS_PARTIAL_FLUSH                         (16 << 0)
+#       define CACHE_FLUSH_AND_INV_TS_EVENT             (20 << 0)
+#       define ZPASS_DONE                               (21 << 0)
+#       define CACHE_FLUSH_AND_INV_EVENT                (22 << 0)
+#       define PERFCOUNTER_START                        (23 << 0)
+#       define PERFCOUNTER_STOP                         (24 << 0)
+#       define PIPELINESTAT_START                       (25 << 0)
+#       define PIPELINESTAT_STOP                        (26 << 0)
+#       define PERFCOUNTER_SAMPLE                       (27 << 0)
+#       define SAMPLE_PIPELINESTAT                      (30 << 0)
+#       define SO_VGT_STREAMOUT_FLUSH                   (31 << 0)
+#       define SAMPLE_STREAMOUTSTATS                    (32 << 0)
+#       define RESET_VTX_CNT                            (33 << 0)
+#       define VGT_FLUSH                                (36 << 0)
+#       define BOTTOM_OF_PIPE_TS                        (40 << 0)
+#       define DB_CACHE_FLUSH_AND_INV                   (42 << 0)
+#       define FLUSH_AND_INV_DB_DATA_TS                 (43 << 0)
+#       define FLUSH_AND_INV_DB_META                    (44 << 0)
+#       define FLUSH_AND_INV_CB_DATA_TS                 (45 << 0)
+#       define FLUSH_AND_INV_CB_META                    (46 << 0)
+#       define CS_DONE                                  (47 << 0)
+#       define PS_DONE                                  (48 << 0)
+#       define FLUSH_AND_INV_CB_PIXEL_DATA              (49 << 0)
+#       define THREAD_TRACE_START                       (51 << 0)
+#       define THREAD_TRACE_STOP                        (52 << 0)
+#       define THREAD_TRACE_FLUSH                       (54 << 0)
+#       define THREAD_TRACE_FINISH                      (55 << 0)
+#       define PIXEL_PIPE_STAT_CONTROL                  (56 << 0)
+#       define PIXEL_PIPE_STAT_DUMP                     (57 << 0)
+#       define PIXEL_PIPE_STAT_RESET                    (58 << 0)
+
 #define	SCRATCH_REG0					0x30100
 #define	SCRATCH_REG1					0x30104
 #define	SCRATCH_REG2					0x30108
@@ -508,6 +566,8 @@
 
 #define	CP_SEM_INCOMPLETE_TIMER_CNTL			0x301C8
 
+#define	CP_WAIT_REG_MEM_TIMEOUT				0x301D0
+
 #define GRBM_GFX_INDEX          			0x30800
 #define		INSTANCE_INDEX(x)			((x) << 0)
 #define		SH_INDEX(x)     			((x) << 8)
@@ -597,11 +657,63 @@
 #define	PACKET3_DRAW_INDEX_OFFSET_2			0x35
 #define	PACKET3_DRAW_PREAMBLE				0x36
 #define	PACKET3_WRITE_DATA				0x37
+#define		WRITE_DATA_DST_SEL(x)                   ((x) << 8)
+                /* 0 - register
+		 * 1 - memory (sync - via GRBM)
+		 * 2 - gl2
+		 * 3 - gds
+		 * 4 - reserved
+		 * 5 - memory (async - direct)
+		 */
+#define		WR_ONE_ADDR                             (1 << 16)
+#define		WR_CONFIRM                              (1 << 20)
+#define		WRITE_DATA_CACHE_POLICY(x)              ((x) << 25)
+                /* 0 - LRU
+		 * 1 - Stream
+		 */
+#define		WRITE_DATA_ENGINE_SEL(x)                ((x) << 30)
+                /* 0 - me
+		 * 1 - pfp
+		 * 2 - ce
+		 */
 #define	PACKET3_DRAW_INDEX_INDIRECT_MULTI		0x38
 #define	PACKET3_MEM_SEMAPHORE				0x39
+#              define PACKET3_SEM_USE_MAILBOX       (0x1 << 16)
+#              define PACKET3_SEM_SEL_SIGNAL_TYPE   (0x1 << 20) /* 0 = increment, 1 = write 1 */
+#              define PACKET3_SEM_CLIENT_CODE	    ((x) << 24) /* 0 = CP, 1 = CB, 2 = DB */
+#              define PACKET3_SEM_SEL_SIGNAL	    (0x6 << 29)
+#              define PACKET3_SEM_SEL_WAIT	    (0x7 << 29)
 #define	PACKET3_COPY_DW					0x3B
 #define	PACKET3_WAIT_REG_MEM				0x3C
+#define		WAIT_REG_MEM_FUNCTION(x)                ((x) << 0)
+                /* 0 - always
+		 * 1 - <
+		 * 2 - <=
+		 * 3 - ==
+		 * 4 - !=
+		 * 5 - >=
+		 * 6 - >
+		 */
+#define		WAIT_REG_MEM_MEM_SPACE(x)               ((x) << 4)
+                /* 0 - reg
+		 * 1 - mem
+		 */
+#define		WAIT_REG_MEM_OPERATION(x)               ((x) << 6)
+                /* 0 - wait_reg_mem
+		 * 1 - wr_wait_wr_reg
+		 */
+#define		WAIT_REG_MEM_ENGINE(x)                  ((x) << 8)
+                /* 0 - me
+		 * 1 - pfp
+		 */
 #define	PACKET3_INDIRECT_BUFFER				0x3F
+#define		INDIRECT_BUFFER_TCL2_VOLATILE           (1 << 22)
+#define		INDIRECT_BUFFER_VALID                   (1 << 23)
+#define		INDIRECT_BUFFER_CACHE_POLICY(x)         ((x) << 28)
+                /* 0 - LRU
+		 * 1 - Stream
+		 * 2 - Bypass
+		 */
 #define	PACKET3_COPY_DATA				0x40
 #define	PACKET3_PFP_SYNC_ME				0x42
 #define	PACKET3_SURFACE_SYNC				0x43
@@ -646,12 +758,12 @@
 #define		EOP_TC_WB_ACTION_EN                     (1 << 15) /* L2 */
 #define		EOP_TCL1_ACTION_EN                      (1 << 16)
 #define		EOP_TC_ACTION_EN                        (1 << 17) /* L2 */
-#define		CACHE_POLICY(x)                         ((x) << 25)
+#define		EOP_CACHE_POLICY(x)                     ((x) << 25)
                 /* 0 - LRU
 		 * 1 - Stream
 		 * 2 - Bypass
 		 */
-#define		TCL2_VOLATILE                           (1 << 27)
+#define		EOP_TCL2_VOLATILE                       (1 << 27)
 #define		DATA_SEL(x)                             ((x) << 29)
                 /* 0 - discard
 		 * 1 - send low 32bit data
@@ -693,6 +805,8 @@
 #define	PACKET3_SET_SH_REG_OFFSET			0x77
 #define	PACKET3_SET_QUEUE_REG				0x78
 #define	PACKET3_SET_UCONFIG_REG				0x79
+#define		PACKET3_SET_UCONFIG_REG_START			0x00030000
+#define		PACKET3_SET_UCONFIG_REG_END			0x00031000
 #define	PACKET3_SCRATCH_RAM_WRITE			0x7D
 #define	PACKET3_SCRATCH_RAM_READ			0x7E
 #define	PACKET3_LOAD_CONST_RAM				0x80
@@ -702,6 +816,6 @@
 #define	PACKET3_INCREMENT_DE_COUNTER			0x85
 #define	PACKET3_WAIT_ON_CE_COUNTER			0x86
 #define	PACKET3_WAIT_ON_DE_COUNTER_DIFF			0x88
-
+#define	PACKET3_SWITCH_BUFFER				0x8B
 
 #endif
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 015/165] drm/radeon: add ring and IB tests for CIK (v3)
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (14 preceding siblings ...)
  2013-06-26 13:21 ` [PATCH 014/165] drm/radeon: add IB and fence dispatch functions for CIK gfx (v7) alexdeucher
@ 2013-06-26 13:21 ` alexdeucher
  2013-06-26 13:21 ` [PATCH 016/165] drm/radeon: implement async vm_flush for the CP (v7) alexdeucher
                   ` (97 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:21 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

v2: add documenation
v3: update the latest ib changes

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/cik.c |  114 ++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 114 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
index 0b9c3c9..0cf04f3 100644
--- a/drivers/gpu/drm/radeon/cik.c
+++ b/drivers/gpu/drm/radeon/cik.c
@@ -1518,6 +1518,57 @@ static void cik_scratch_init(struct radeon_device *rdev)
 }
 
 /**
+ * cik_ring_test - basic gfx ring test
+ *
+ * @rdev: radeon_device pointer
+ * @ring: radeon_ring structure holding ring information
+ *
+ * Allocate a scratch register and write to it using the gfx ring (CIK).
+ * Provides a basic gfx ring test to verify that the ring is working.
+ * Used by cik_cp_gfx_resume();
+ * Returns 0 on success, error on failure.
+ */
+int cik_ring_test(struct radeon_device *rdev, struct radeon_ring *ring)
+{
+	uint32_t scratch;
+	uint32_t tmp = 0;
+	unsigned i;
+	int r;
+
+	r = radeon_scratch_get(rdev, &scratch);
+	if (r) {
+		DRM_ERROR("radeon: cp failed to get scratch reg (%d).\n", r);
+		return r;
+	}
+	WREG32(scratch, 0xCAFEDEAD);
+	r = radeon_ring_lock(rdev, ring, 3);
+	if (r) {
+		DRM_ERROR("radeon: cp failed to lock ring %d (%d).\n", ring->idx, r);
+		radeon_scratch_free(rdev, scratch);
+		return r;
+	}
+	radeon_ring_write(ring, PACKET3(PACKET3_SET_UCONFIG_REG, 1));
+	radeon_ring_write(ring, ((scratch - PACKET3_SET_UCONFIG_REG_START) >> 2));
+	radeon_ring_write(ring, 0xDEADBEEF);
+	radeon_ring_unlock_commit(rdev, ring);
+	for (i = 0; i < rdev->usec_timeout; i++) {
+		tmp = RREG32(scratch);
+		if (tmp == 0xDEADBEEF)
+			break;
+		DRM_UDELAY(1);
+	}
+	if (i < rdev->usec_timeout) {
+		DRM_INFO("ring test on %d succeeded in %d usecs\n", ring->idx, i);
+	} else {
+		DRM_ERROR("radeon: ring %d test failed (scratch(0x%04X)=0x%08X)\n",
+			  ring->idx, scratch, tmp);
+		r = -EINVAL;
+	}
+	radeon_scratch_free(rdev, scratch);
+	return r;
+}
+
+/**
  * cik_fence_ring_emit - emit a fence on the gfx ring
  *
  * @rdev: radeon_device pointer
@@ -1626,6 +1677,69 @@ void cik_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)
 	radeon_ring_write(ring, control);
 }
 
+/**
+ * cik_ib_test - basic gfx ring IB test
+ *
+ * @rdev: radeon_device pointer
+ * @ring: radeon_ring structure holding ring information
+ *
+ * Allocate an IB and execute it on the gfx ring (CIK).
+ * Provides a basic gfx ring test to verify that IBs are working.
+ * Returns 0 on success, error on failure.
+ */
+int cik_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)
+{
+	struct radeon_ib ib;
+	uint32_t scratch;
+	uint32_t tmp = 0;
+	unsigned i;
+	int r;
+
+	r = radeon_scratch_get(rdev, &scratch);
+	if (r) {
+		DRM_ERROR("radeon: failed to get scratch reg (%d).\n", r);
+		return r;
+	}
+	WREG32(scratch, 0xCAFEDEAD);
+	r = radeon_ib_get(rdev, ring->idx, &ib, NULL, 256);
+	if (r) {
+		DRM_ERROR("radeon: failed to get ib (%d).\n", r);
+		return r;
+	}
+	ib.ptr[0] = PACKET3(PACKET3_SET_UCONFIG_REG, 1);
+	ib.ptr[1] = ((scratch - PACKET3_SET_UCONFIG_REG_START) >> 2);
+	ib.ptr[2] = 0xDEADBEEF;
+	ib.length_dw = 3;
+	r = radeon_ib_schedule(rdev, &ib, NULL);
+	if (r) {
+		radeon_scratch_free(rdev, scratch);
+		radeon_ib_free(rdev, &ib);
+		DRM_ERROR("radeon: failed to schedule ib (%d).\n", r);
+		return r;
+	}
+	r = radeon_fence_wait(ib.fence, false);
+	if (r) {
+		DRM_ERROR("radeon: fence wait failed (%d).\n", r);
+		return r;
+	}
+	for (i = 0; i < rdev->usec_timeout; i++) {
+		tmp = RREG32(scratch);
+		if (tmp == 0xDEADBEEF)
+			break;
+		DRM_UDELAY(1);
+	}
+	if (i < rdev->usec_timeout) {
+		DRM_INFO("ib test on ring %d succeeded in %u usecs\n", ib.fence->ring, i);
+	} else {
+		DRM_ERROR("radeon: ib test failed (scratch(0x%04X)=0x%08X)\n",
+			  scratch, tmp);
+		r = -EINVAL;
+	}
+	radeon_scratch_free(rdev, scratch);
+	radeon_ib_free(rdev, &ib);
+	return r;
+}
+
 /*
  * CP.
  * On CIK, gfx and compute now have independant command processors.
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 016/165] drm/radeon: implement async vm_flush for the CP (v7)
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (15 preceding siblings ...)
  2013-06-26 13:21 ` [PATCH 015/165] drm/radeon: add ring and IB tests for CIK (v3) alexdeucher
@ 2013-06-26 13:21 ` alexdeucher
  2013-06-26 13:21 ` [PATCH 017/165] drm/radeon: Add support for RLC init on CIK (v4) alexdeucher
                   ` (96 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:21 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Update the page table base address and flush the
VM TLB using the CP.

v2: update for 2 level PTs
v3: use new packet for invalidate
v4: update SH_MEM* regs when flushing the VM
v5: add pfp sync, go back to old style vm TLB invalidate
v6: fix hdp flush packet count
v7: use old style HDP flush

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/cik.c |   79 ++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 79 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
index 0cf04f3..ba242eb 100644
--- a/drivers/gpu/drm/radeon/cik.c
+++ b/drivers/gpu/drm/radeon/cik.c
@@ -2698,3 +2698,82 @@ void cik_vm_fini(struct radeon_device *rdev)
 {
 }
 
+/**
+ * cik_vm_flush - cik vm flush using the CP
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Update the page table base and flush the VM TLB
+ * using the CP (CIK).
+ */
+void cik_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
+{
+	struct radeon_ring *ring = &rdev->ring[ridx];
+
+	if (vm == NULL)
+		return;
+
+	radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
+	radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
+				 WRITE_DATA_DST_SEL(0)));
+	if (vm->id < 8) {
+		radeon_ring_write(ring,
+				  (VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm->id << 2)) >> 2);
+	} else {
+		radeon_ring_write(ring,
+				  (VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((vm->id - 8) << 2)) >> 2);
+	}
+	radeon_ring_write(ring, 0);
+	radeon_ring_write(ring, vm->pd_gpu_addr >> 12);
+
+	/* update SH_MEM_* regs */
+	radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
+	radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
+				 WRITE_DATA_DST_SEL(0)));
+	radeon_ring_write(ring, SRBM_GFX_CNTL >> 2);
+	radeon_ring_write(ring, 0);
+	radeon_ring_write(ring, VMID(vm->id));
+
+	radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 6));
+	radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
+				 WRITE_DATA_DST_SEL(0)));
+	radeon_ring_write(ring, SH_MEM_BASES >> 2);
+	radeon_ring_write(ring, 0);
+
+	radeon_ring_write(ring, 0); /* SH_MEM_BASES */
+	radeon_ring_write(ring, 0); /* SH_MEM_CONFIG */
+	radeon_ring_write(ring, 1); /* SH_MEM_APE1_BASE */
+	radeon_ring_write(ring, 0); /* SH_MEM_APE1_LIMIT */
+
+	radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
+	radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
+				 WRITE_DATA_DST_SEL(0)));
+	radeon_ring_write(ring, SRBM_GFX_CNTL >> 2);
+	radeon_ring_write(ring, 0);
+	radeon_ring_write(ring, VMID(0));
+
+	/* HDP flush */
+	/* We should be using the WAIT_REG_MEM packet here like in
+	 * cik_fence_ring_emit(), but it causes the CP to hang in this
+	 * context...
+	 */
+	radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
+	radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
+				 WRITE_DATA_DST_SEL(0)));
+	radeon_ring_write(ring, HDP_MEM_COHERENCY_FLUSH_CNTL >> 2);
+	radeon_ring_write(ring, 0);
+	radeon_ring_write(ring, 0);
+
+	/* bits 0-15 are the VM contexts0-15 */
+	radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
+	radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
+				 WRITE_DATA_DST_SEL(0)));
+	radeon_ring_write(ring, VM_INVALIDATE_REQUEST >> 2);
+	radeon_ring_write(ring, 0);
+	radeon_ring_write(ring, 1 << vm->id);
+
+	/* sync PFP to ME, otherwise we might get invalid PFP reads */
+	radeon_ring_write(ring, PACKET3(PACKET3_PFP_SYNC_ME, 0));
+	radeon_ring_write(ring, 0x0);
+}
+
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 017/165] drm/radeon: Add support for RLC init on CIK (v4)
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (16 preceding siblings ...)
  2013-06-26 13:21 ` [PATCH 016/165] drm/radeon: implement async vm_flush for the CP (v7) alexdeucher
@ 2013-06-26 13:21 ` alexdeucher
  2013-06-26 13:21 ` [PATCH 018/165] drm/radeon: add support for interrupts on CIK (v5) alexdeucher
                   ` (95 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:21 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

RLC handles the interrupt controller and other tasks
on the GPU.

v2: add documentation
v3: update programming sequence
v4: additional setup

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/cik.c  |  142 +++++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/radeon/cikd.h |   47 ++++++++++++++
 2 files changed, 189 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
index ba242eb..a44ede6 100644
--- a/drivers/gpu/drm/radeon/cik.c
+++ b/drivers/gpu/drm/radeon/cik.c
@@ -2777,3 +2777,145 @@ void cik_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
 	radeon_ring_write(ring, 0x0);
 }
 
+/*
+ * RLC
+ * The RLC is a multi-purpose microengine that handles a
+ * variety of functions, the most important of which is
+ * the interrupt controller.
+ */
+/**
+ * cik_rlc_stop - stop the RLC ME
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Halt the RLC ME (MicroEngine) (CIK).
+ */
+static void cik_rlc_stop(struct radeon_device *rdev)
+{
+	int i, j, k;
+	u32 mask, tmp;
+
+	tmp = RREG32(CP_INT_CNTL_RING0);
+	tmp &= ~(CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE);
+	WREG32(CP_INT_CNTL_RING0, tmp);
+
+	RREG32(CB_CGTT_SCLK_CTRL);
+	RREG32(CB_CGTT_SCLK_CTRL);
+	RREG32(CB_CGTT_SCLK_CTRL);
+	RREG32(CB_CGTT_SCLK_CTRL);
+
+	tmp = RREG32(RLC_CGCG_CGLS_CTRL) & 0xfffffffc;
+	WREG32(RLC_CGCG_CGLS_CTRL, tmp);
+
+	WREG32(RLC_CNTL, 0);
+
+	for (i = 0; i < rdev->config.cik.max_shader_engines; i++) {
+		for (j = 0; j < rdev->config.cik.max_sh_per_se; j++) {
+			cik_select_se_sh(rdev, i, j);
+			for (k = 0; k < rdev->usec_timeout; k++) {
+				if (RREG32(RLC_SERDES_CU_MASTER_BUSY) == 0)
+					break;
+				udelay(1);
+			}
+		}
+	}
+	cik_select_se_sh(rdev, 0xffffffff, 0xffffffff);
+
+	mask = SE_MASTER_BUSY_MASK | GC_MASTER_BUSY | TC0_MASTER_BUSY | TC1_MASTER_BUSY;
+	for (k = 0; k < rdev->usec_timeout; k++) {
+		if ((RREG32(RLC_SERDES_NONCU_MASTER_BUSY) & mask) == 0)
+			break;
+		udelay(1);
+	}
+}
+
+/**
+ * cik_rlc_start - start the RLC ME
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Unhalt the RLC ME (MicroEngine) (CIK).
+ */
+static void cik_rlc_start(struct radeon_device *rdev)
+{
+	u32 tmp;
+
+	WREG32(RLC_CNTL, RLC_ENABLE);
+
+	tmp = RREG32(CP_INT_CNTL_RING0);
+	tmp |= (CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE);
+	WREG32(CP_INT_CNTL_RING0, tmp);
+
+	udelay(50);
+}
+
+/**
+ * cik_rlc_resume - setup the RLC hw
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Initialize the RLC registers, load the ucode,
+ * and start the RLC (CIK).
+ * Returns 0 for success, -EINVAL if the ucode is not available.
+ */
+static int cik_rlc_resume(struct radeon_device *rdev)
+{
+	u32 i, size;
+	u32 clear_state_info[3];
+	const __be32 *fw_data;
+
+	if (!rdev->rlc_fw)
+		return -EINVAL;
+
+	switch (rdev->family) {
+	case CHIP_BONAIRE:
+	default:
+		size = BONAIRE_RLC_UCODE_SIZE;
+		break;
+	case CHIP_KAVERI:
+		size = KV_RLC_UCODE_SIZE;
+		break;
+	case CHIP_KABINI:
+		size = KB_RLC_UCODE_SIZE;
+		break;
+	}
+
+	cik_rlc_stop(rdev);
+
+	WREG32(GRBM_SOFT_RESET, SOFT_RESET_RLC);
+	RREG32(GRBM_SOFT_RESET);
+	udelay(50);
+	WREG32(GRBM_SOFT_RESET, 0);
+	RREG32(GRBM_SOFT_RESET);
+	udelay(50);
+
+	WREG32(RLC_LB_CNTR_INIT, 0);
+	WREG32(RLC_LB_CNTR_MAX, 0x00008000);
+
+	cik_select_se_sh(rdev, 0xffffffff, 0xffffffff);
+	WREG32(RLC_LB_INIT_CU_MASK, 0xffffffff);
+	WREG32(RLC_LB_PARAMS, 0x00600408);
+	WREG32(RLC_LB_CNTL, 0x80000004);
+
+	WREG32(RLC_MC_CNTL, 0);
+	WREG32(RLC_UCODE_CNTL, 0);
+
+	fw_data = (const __be32 *)rdev->rlc_fw->data;
+		WREG32(RLC_GPM_UCODE_ADDR, 0);
+	for (i = 0; i < size; i++)
+		WREG32(RLC_GPM_UCODE_DATA, be32_to_cpup(fw_data++));
+	WREG32(RLC_GPM_UCODE_ADDR, 0);
+
+	/* XXX */
+	clear_state_info[0] = 0;//upper_32_bits(rdev->rlc.save_restore_gpu_addr);
+	clear_state_info[1] = 0;//rdev->rlc.save_restore_gpu_addr;
+	clear_state_info[2] = 0;//cik_default_size;
+	WREG32(RLC_GPM_SCRATCH_ADDR, 0x3d);
+	for (i = 0; i < 3; i++)
+		WREG32(RLC_GPM_SCRATCH_DATA, clear_state_info[i]);
+	WREG32(RLC_DRIVER_DMA_STATUS, 0);
+
+	cik_rlc_start(rdev);
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/radeon/cikd.h b/drivers/gpu/drm/radeon/cikd.h
index 783cf60..a116020 100644
--- a/drivers/gpu/drm/radeon/cikd.h
+++ b/drivers/gpu/drm/radeon/cikd.h
@@ -497,10 +497,55 @@
 #define	CP_MEC_ME2_UCODE_ADDR				0xC178
 #define	CP_MEC_ME2_UCODE_DATA				0xC17C
 
+#define CP_INT_CNTL_RING0                               0xC1A8
+#       define CNTX_BUSY_INT_ENABLE                     (1 << 19)
+#       define CNTX_EMPTY_INT_ENABLE                    (1 << 20)
+#       define PRIV_INSTR_INT_ENABLE                    (1 << 22)
+#       define PRIV_REG_INT_ENABLE                      (1 << 23)
+#       define TIME_STAMP_INT_ENABLE                    (1 << 26)
+#       define CP_RINGID2_INT_ENABLE                    (1 << 29)
+#       define CP_RINGID1_INT_ENABLE                    (1 << 30)
+#       define CP_RINGID0_INT_ENABLE                    (1 << 31)
+
 #define	CP_MAX_CONTEXT					0xC2B8
 
 #define	CP_RB0_BASE_HI					0xC2C4
 
+#define RLC_CNTL                                          0xC300
+#       define RLC_ENABLE                                 (1 << 0)
+
+#define RLC_MC_CNTL                                       0xC30C
+
+#define RLC_LB_CNTR_MAX                                   0xC348
+
+#define RLC_LB_CNTL                                       0xC364
+
+#define RLC_LB_CNTR_INIT                                  0xC36C
+
+#define RLC_SAVE_AND_RESTORE_BASE                         0xC374
+#define RLC_DRIVER_DMA_STATUS                             0xC378
+
+#define RLC_GPM_UCODE_ADDR                                0xC388
+#define RLC_GPM_UCODE_DATA                                0xC38C
+
+#define RLC_UCODE_CNTL                                    0xC39C
+
+#define RLC_CGCG_CGLS_CTRL                                0xC424
+
+#define RLC_LB_INIT_CU_MASK                               0xC43C
+
+#define RLC_LB_PARAMS                                     0xC444
+
+#define RLC_SERDES_CU_MASTER_BUSY                         0xC484
+#define RLC_SERDES_NONCU_MASTER_BUSY                      0xC488
+#       define SE_MASTER_BUSY_MASK                        0x0000ffff
+#       define GC_MASTER_BUSY                             (1 << 16)
+#       define TC0_MASTER_BUSY                            (1 << 17)
+#       define TC1_MASTER_BUSY                            (1 << 18)
+
+#define RLC_GPM_SCRATCH_ADDR                              0xC4B0
+#define RLC_GPM_SCRATCH_DATA                              0xC4B4
+
 #define PA_SC_RASTER_CONFIG                             0x28350
 #       define RASTER_CONFIG_RB_MAP_0                   0
 #       define RASTER_CONFIG_RB_MAP_1                   1
@@ -599,6 +644,8 @@
 #define		TCC_DISABLE_MASK				0xFFFF0000
 #define		TCC_DISABLE_SHIFT				16
 
+#define	CB_CGTT_SCLK_CTRL				0x3c2a0
+
 /*
  * PM4
  */
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 018/165] drm/radeon: add support for interrupts on CIK (v5)
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (17 preceding siblings ...)
  2013-06-26 13:21 ` [PATCH 017/165] drm/radeon: Add support for RLC init on CIK (v4) alexdeucher
@ 2013-06-26 13:21 ` alexdeucher
  2013-06-26 13:21 ` [PATCH 019/165] drm/radeon/cik: log and handle VM page fault interrupts alexdeucher
                   ` (94 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:21 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Todo:
- handle interrupts for compute queues

v2: add documentation
v3: update to latest reset code
v4: update to latest illegal CP handling
v5: fix missing break in interrupt handler switch statement

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/cik.c    |  840 +++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/radeon/cikd.h   |  170 ++++++++
 drivers/gpu/drm/radeon/radeon.h |   11 +
 3 files changed, 1021 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
index a44ede6..72c7e83 100644
--- a/drivers/gpu/drm/radeon/cik.c
+++ b/drivers/gpu/drm/radeon/cik.c
@@ -62,6 +62,8 @@ MODULE_FIRMWARE("radeon/KABINI_ce.bin");
 MODULE_FIRMWARE("radeon/KABINI_mec.bin");
 MODULE_FIRMWARE("radeon/KABINI_rlc.bin");
 
+extern int r600_ih_ring_alloc(struct radeon_device *rdev);
+extern void r600_ih_ring_fini(struct radeon_device *rdev);
 extern void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save);
 extern void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save);
 extern void si_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc);
@@ -2919,3 +2921,841 @@ static int cik_rlc_resume(struct radeon_device *rdev)
 
 	return 0;
 }
+
+/*
+ * Interrupts
+ * Starting with r6xx, interrupts are handled via a ring buffer.
+ * Ring buffers are areas of GPU accessible memory that the GPU
+ * writes interrupt vectors into and the host reads vectors out of.
+ * There is a rptr (read pointer) that determines where the
+ * host is currently reading, and a wptr (write pointer)
+ * which determines where the GPU has written.  When the
+ * pointers are equal, the ring is idle.  When the GPU
+ * writes vectors to the ring buffer, it increments the
+ * wptr.  When there is an interrupt, the host then starts
+ * fetching commands and processing them until the pointers are
+ * equal again at which point it updates the rptr.
+ */
+
+/**
+ * cik_enable_interrupts - Enable the interrupt ring buffer
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Enable the interrupt ring buffer (CIK).
+ */
+static void cik_enable_interrupts(struct radeon_device *rdev)
+{
+	u32 ih_cntl = RREG32(IH_CNTL);
+	u32 ih_rb_cntl = RREG32(IH_RB_CNTL);
+
+	ih_cntl |= ENABLE_INTR;
+	ih_rb_cntl |= IH_RB_ENABLE;
+	WREG32(IH_CNTL, ih_cntl);
+	WREG32(IH_RB_CNTL, ih_rb_cntl);
+	rdev->ih.enabled = true;
+}
+
+/**
+ * cik_disable_interrupts - Disable the interrupt ring buffer
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Disable the interrupt ring buffer (CIK).
+ */
+static void cik_disable_interrupts(struct radeon_device *rdev)
+{
+	u32 ih_rb_cntl = RREG32(IH_RB_CNTL);
+	u32 ih_cntl = RREG32(IH_CNTL);
+
+	ih_rb_cntl &= ~IH_RB_ENABLE;
+	ih_cntl &= ~ENABLE_INTR;
+	WREG32(IH_RB_CNTL, ih_rb_cntl);
+	WREG32(IH_CNTL, ih_cntl);
+	/* set rptr, wptr to 0 */
+	WREG32(IH_RB_RPTR, 0);
+	WREG32(IH_RB_WPTR, 0);
+	rdev->ih.enabled = false;
+	rdev->ih.rptr = 0;
+}
+
+/**
+ * cik_disable_interrupt_state - Disable all interrupt sources
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Clear all interrupt enable bits used by the driver (CIK).
+ */
+static void cik_disable_interrupt_state(struct radeon_device *rdev)
+{
+	u32 tmp;
+
+	/* gfx ring */
+	WREG32(CP_INT_CNTL_RING0, CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE);
+	/* compute queues */
+	WREG32(CP_ME1_PIPE0_INT_CNTL, 0);
+	WREG32(CP_ME1_PIPE1_INT_CNTL, 0);
+	WREG32(CP_ME1_PIPE2_INT_CNTL, 0);
+	WREG32(CP_ME1_PIPE3_INT_CNTL, 0);
+	WREG32(CP_ME2_PIPE0_INT_CNTL, 0);
+	WREG32(CP_ME2_PIPE1_INT_CNTL, 0);
+	WREG32(CP_ME2_PIPE2_INT_CNTL, 0);
+	WREG32(CP_ME2_PIPE3_INT_CNTL, 0);
+	/* grbm */
+	WREG32(GRBM_INT_CNTL, 0);
+	/* vline/vblank, etc. */
+	WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
+	WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
+	if (rdev->num_crtc >= 4) {
+		WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0);
+		WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0);
+	}
+	if (rdev->num_crtc >= 6) {
+		WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0);
+		WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0);
+	}
+
+	/* dac hotplug */
+	WREG32(DAC_AUTODETECT_INT_CONTROL, 0);
+
+	/* digital hotplug */
+	tmp = RREG32(DC_HPD1_INT_CONTROL) & DC_HPDx_INT_POLARITY;
+	WREG32(DC_HPD1_INT_CONTROL, tmp);
+	tmp = RREG32(DC_HPD2_INT_CONTROL) & DC_HPDx_INT_POLARITY;
+	WREG32(DC_HPD2_INT_CONTROL, tmp);
+	tmp = RREG32(DC_HPD3_INT_CONTROL) & DC_HPDx_INT_POLARITY;
+	WREG32(DC_HPD3_INT_CONTROL, tmp);
+	tmp = RREG32(DC_HPD4_INT_CONTROL) & DC_HPDx_INT_POLARITY;
+	WREG32(DC_HPD4_INT_CONTROL, tmp);
+	tmp = RREG32(DC_HPD5_INT_CONTROL) & DC_HPDx_INT_POLARITY;
+	WREG32(DC_HPD5_INT_CONTROL, tmp);
+	tmp = RREG32(DC_HPD6_INT_CONTROL) & DC_HPDx_INT_POLARITY;
+	WREG32(DC_HPD6_INT_CONTROL, tmp);
+
+}
+
+/**
+ * cik_irq_init - init and enable the interrupt ring
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Allocate a ring buffer for the interrupt controller,
+ * enable the RLC, disable interrupts, enable the IH
+ * ring buffer and enable it (CIK).
+ * Called at device load and reume.
+ * Returns 0 for success, errors for failure.
+ */
+static int cik_irq_init(struct radeon_device *rdev)
+{
+	int ret = 0;
+	int rb_bufsz;
+	u32 interrupt_cntl, ih_cntl, ih_rb_cntl;
+
+	/* allocate ring */
+	ret = r600_ih_ring_alloc(rdev);
+	if (ret)
+		return ret;
+
+	/* disable irqs */
+	cik_disable_interrupts(rdev);
+
+	/* init rlc */
+	ret = cik_rlc_resume(rdev);
+	if (ret) {
+		r600_ih_ring_fini(rdev);
+		return ret;
+	}
+
+	/* setup interrupt control */
+	/* XXX this should actually be a bus address, not an MC address. same on older asics */
+	WREG32(INTERRUPT_CNTL2, rdev->ih.gpu_addr >> 8);
+	interrupt_cntl = RREG32(INTERRUPT_CNTL);
+	/* IH_DUMMY_RD_OVERRIDE=0 - dummy read disabled with msi, enabled without msi
+	 * IH_DUMMY_RD_OVERRIDE=1 - dummy read controlled by IH_DUMMY_RD_EN
+	 */
+	interrupt_cntl &= ~IH_DUMMY_RD_OVERRIDE;
+	/* IH_REQ_NONSNOOP_EN=1 if ring is in non-cacheable memory, e.g., vram */
+	interrupt_cntl &= ~IH_REQ_NONSNOOP_EN;
+	WREG32(INTERRUPT_CNTL, interrupt_cntl);
+
+	WREG32(IH_RB_BASE, rdev->ih.gpu_addr >> 8);
+	rb_bufsz = drm_order(rdev->ih.ring_size / 4);
+
+	ih_rb_cntl = (IH_WPTR_OVERFLOW_ENABLE |
+		      IH_WPTR_OVERFLOW_CLEAR |
+		      (rb_bufsz << 1));
+
+	if (rdev->wb.enabled)
+		ih_rb_cntl |= IH_WPTR_WRITEBACK_ENABLE;
+
+	/* set the writeback address whether it's enabled or not */
+	WREG32(IH_RB_WPTR_ADDR_LO, (rdev->wb.gpu_addr + R600_WB_IH_WPTR_OFFSET) & 0xFFFFFFFC);
+	WREG32(IH_RB_WPTR_ADDR_HI, upper_32_bits(rdev->wb.gpu_addr + R600_WB_IH_WPTR_OFFSET) & 0xFF);
+
+	WREG32(IH_RB_CNTL, ih_rb_cntl);
+
+	/* set rptr, wptr to 0 */
+	WREG32(IH_RB_RPTR, 0);
+	WREG32(IH_RB_WPTR, 0);
+
+	/* Default settings for IH_CNTL (disabled at first) */
+	ih_cntl = MC_WRREQ_CREDIT(0x10) | MC_WR_CLEAN_CNT(0x10) | MC_VMID(0);
+	/* RPTR_REARM only works if msi's are enabled */
+	if (rdev->msi_enabled)
+		ih_cntl |= RPTR_REARM;
+	WREG32(IH_CNTL, ih_cntl);
+
+	/* force the active interrupt state to all disabled */
+	cik_disable_interrupt_state(rdev);
+
+	pci_set_master(rdev->pdev);
+
+	/* enable irqs */
+	cik_enable_interrupts(rdev);
+
+	return ret;
+}
+
+/**
+ * cik_irq_set - enable/disable interrupt sources
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Enable interrupt sources on the GPU (vblanks, hpd,
+ * etc.) (CIK).
+ * Returns 0 for success, errors for failure.
+ */
+int cik_irq_set(struct radeon_device *rdev)
+{
+	u32 cp_int_cntl = CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE |
+		PRIV_INSTR_INT_ENABLE | PRIV_REG_INT_ENABLE;
+	u32 crtc1 = 0, crtc2 = 0, crtc3 = 0, crtc4 = 0, crtc5 = 0, crtc6 = 0;
+	u32 hpd1, hpd2, hpd3, hpd4, hpd5, hpd6;
+	u32 grbm_int_cntl = 0;
+
+	if (!rdev->irq.installed) {
+		WARN(1, "Can't enable IRQ/MSI because no handler is installed\n");
+		return -EINVAL;
+	}
+	/* don't enable anything if the ih is disabled */
+	if (!rdev->ih.enabled) {
+		cik_disable_interrupts(rdev);
+		/* force the active interrupt state to all disabled */
+		cik_disable_interrupt_state(rdev);
+		return 0;
+	}
+
+	hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~DC_HPDx_INT_EN;
+	hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~DC_HPDx_INT_EN;
+	hpd3 = RREG32(DC_HPD3_INT_CONTROL) & ~DC_HPDx_INT_EN;
+	hpd4 = RREG32(DC_HPD4_INT_CONTROL) & ~DC_HPDx_INT_EN;
+	hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~DC_HPDx_INT_EN;
+	hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~DC_HPDx_INT_EN;
+
+	/* enable CP interrupts on all rings */
+	if (atomic_read(&rdev->irq.ring_int[RADEON_RING_TYPE_GFX_INDEX])) {
+		DRM_DEBUG("cik_irq_set: sw int gfx\n");
+		cp_int_cntl |= TIME_STAMP_INT_ENABLE;
+	}
+	/* TODO: compute queues! */
+	/* CP_ME[1-2]_PIPE[0-3]_INT_CNTL */
+
+	if (rdev->irq.crtc_vblank_int[0] ||
+	    atomic_read(&rdev->irq.pflip[0])) {
+		DRM_DEBUG("cik_irq_set: vblank 0\n");
+		crtc1 |= VBLANK_INTERRUPT_MASK;
+	}
+	if (rdev->irq.crtc_vblank_int[1] ||
+	    atomic_read(&rdev->irq.pflip[1])) {
+		DRM_DEBUG("cik_irq_set: vblank 1\n");
+		crtc2 |= VBLANK_INTERRUPT_MASK;
+	}
+	if (rdev->irq.crtc_vblank_int[2] ||
+	    atomic_read(&rdev->irq.pflip[2])) {
+		DRM_DEBUG("cik_irq_set: vblank 2\n");
+		crtc3 |= VBLANK_INTERRUPT_MASK;
+	}
+	if (rdev->irq.crtc_vblank_int[3] ||
+	    atomic_read(&rdev->irq.pflip[3])) {
+		DRM_DEBUG("cik_irq_set: vblank 3\n");
+		crtc4 |= VBLANK_INTERRUPT_MASK;
+	}
+	if (rdev->irq.crtc_vblank_int[4] ||
+	    atomic_read(&rdev->irq.pflip[4])) {
+		DRM_DEBUG("cik_irq_set: vblank 4\n");
+		crtc5 |= VBLANK_INTERRUPT_MASK;
+	}
+	if (rdev->irq.crtc_vblank_int[5] ||
+	    atomic_read(&rdev->irq.pflip[5])) {
+		DRM_DEBUG("cik_irq_set: vblank 5\n");
+		crtc6 |= VBLANK_INTERRUPT_MASK;
+	}
+	if (rdev->irq.hpd[0]) {
+		DRM_DEBUG("cik_irq_set: hpd 1\n");
+		hpd1 |= DC_HPDx_INT_EN;
+	}
+	if (rdev->irq.hpd[1]) {
+		DRM_DEBUG("cik_irq_set: hpd 2\n");
+		hpd2 |= DC_HPDx_INT_EN;
+	}
+	if (rdev->irq.hpd[2]) {
+		DRM_DEBUG("cik_irq_set: hpd 3\n");
+		hpd3 |= DC_HPDx_INT_EN;
+	}
+	if (rdev->irq.hpd[3]) {
+		DRM_DEBUG("cik_irq_set: hpd 4\n");
+		hpd4 |= DC_HPDx_INT_EN;
+	}
+	if (rdev->irq.hpd[4]) {
+		DRM_DEBUG("cik_irq_set: hpd 5\n");
+		hpd5 |= DC_HPDx_INT_EN;
+	}
+	if (rdev->irq.hpd[5]) {
+		DRM_DEBUG("cik_irq_set: hpd 6\n");
+		hpd6 |= DC_HPDx_INT_EN;
+	}
+
+	WREG32(CP_INT_CNTL_RING0, cp_int_cntl);
+
+	WREG32(GRBM_INT_CNTL, grbm_int_cntl);
+
+	WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, crtc1);
+	WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, crtc2);
+	if (rdev->num_crtc >= 4) {
+		WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC2_REGISTER_OFFSET, crtc3);
+		WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC3_REGISTER_OFFSET, crtc4);
+	}
+	if (rdev->num_crtc >= 6) {
+		WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC4_REGISTER_OFFSET, crtc5);
+		WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC5_REGISTER_OFFSET, crtc6);
+	}
+
+	WREG32(DC_HPD1_INT_CONTROL, hpd1);
+	WREG32(DC_HPD2_INT_CONTROL, hpd2);
+	WREG32(DC_HPD3_INT_CONTROL, hpd3);
+	WREG32(DC_HPD4_INT_CONTROL, hpd4);
+	WREG32(DC_HPD5_INT_CONTROL, hpd5);
+	WREG32(DC_HPD6_INT_CONTROL, hpd6);
+
+	return 0;
+}
+
+/**
+ * cik_irq_ack - ack interrupt sources
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Ack interrupt sources on the GPU (vblanks, hpd,
+ * etc.) (CIK).  Certain interrupts sources are sw
+ * generated and do not require an explicit ack.
+ */
+static inline void cik_irq_ack(struct radeon_device *rdev)
+{
+	u32 tmp;
+
+	rdev->irq.stat_regs.cik.disp_int = RREG32(DISP_INTERRUPT_STATUS);
+	rdev->irq.stat_regs.cik.disp_int_cont = RREG32(DISP_INTERRUPT_STATUS_CONTINUE);
+	rdev->irq.stat_regs.cik.disp_int_cont2 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE2);
+	rdev->irq.stat_regs.cik.disp_int_cont3 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE3);
+	rdev->irq.stat_regs.cik.disp_int_cont4 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE4);
+	rdev->irq.stat_regs.cik.disp_int_cont5 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE5);
+	rdev->irq.stat_regs.cik.disp_int_cont6 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE6);
+
+	if (rdev->irq.stat_regs.cik.disp_int & LB_D1_VBLANK_INTERRUPT)
+		WREG32(LB_VBLANK_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET, VBLANK_ACK);
+	if (rdev->irq.stat_regs.cik.disp_int & LB_D1_VLINE_INTERRUPT)
+		WREG32(LB_VLINE_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET, VLINE_ACK);
+	if (rdev->irq.stat_regs.cik.disp_int_cont & LB_D2_VBLANK_INTERRUPT)
+		WREG32(LB_VBLANK_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET, VBLANK_ACK);
+	if (rdev->irq.stat_regs.cik.disp_int_cont & LB_D2_VLINE_INTERRUPT)
+		WREG32(LB_VLINE_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET, VLINE_ACK);
+
+	if (rdev->num_crtc >= 4) {
+		if (rdev->irq.stat_regs.cik.disp_int_cont2 & LB_D3_VBLANK_INTERRUPT)
+			WREG32(LB_VBLANK_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET, VBLANK_ACK);
+		if (rdev->irq.stat_regs.cik.disp_int_cont2 & LB_D3_VLINE_INTERRUPT)
+			WREG32(LB_VLINE_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET, VLINE_ACK);
+		if (rdev->irq.stat_regs.cik.disp_int_cont3 & LB_D4_VBLANK_INTERRUPT)
+			WREG32(LB_VBLANK_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET, VBLANK_ACK);
+		if (rdev->irq.stat_regs.cik.disp_int_cont3 & LB_D4_VLINE_INTERRUPT)
+			WREG32(LB_VLINE_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET, VLINE_ACK);
+	}
+
+	if (rdev->num_crtc >= 6) {
+		if (rdev->irq.stat_regs.cik.disp_int_cont4 & LB_D5_VBLANK_INTERRUPT)
+			WREG32(LB_VBLANK_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET, VBLANK_ACK);
+		if (rdev->irq.stat_regs.cik.disp_int_cont4 & LB_D5_VLINE_INTERRUPT)
+			WREG32(LB_VLINE_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET, VLINE_ACK);
+		if (rdev->irq.stat_regs.cik.disp_int_cont5 & LB_D6_VBLANK_INTERRUPT)
+			WREG32(LB_VBLANK_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET, VBLANK_ACK);
+		if (rdev->irq.stat_regs.cik.disp_int_cont5 & LB_D6_VLINE_INTERRUPT)
+			WREG32(LB_VLINE_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET, VLINE_ACK);
+	}
+
+	if (rdev->irq.stat_regs.cik.disp_int & DC_HPD1_INTERRUPT) {
+		tmp = RREG32(DC_HPD1_INT_CONTROL);
+		tmp |= DC_HPDx_INT_ACK;
+		WREG32(DC_HPD1_INT_CONTROL, tmp);
+	}
+	if (rdev->irq.stat_regs.cik.disp_int_cont & DC_HPD2_INTERRUPT) {
+		tmp = RREG32(DC_HPD2_INT_CONTROL);
+		tmp |= DC_HPDx_INT_ACK;
+		WREG32(DC_HPD2_INT_CONTROL, tmp);
+	}
+	if (rdev->irq.stat_regs.cik.disp_int_cont2 & DC_HPD3_INTERRUPT) {
+		tmp = RREG32(DC_HPD3_INT_CONTROL);
+		tmp |= DC_HPDx_INT_ACK;
+		WREG32(DC_HPD3_INT_CONTROL, tmp);
+	}
+	if (rdev->irq.stat_regs.cik.disp_int_cont3 & DC_HPD4_INTERRUPT) {
+		tmp = RREG32(DC_HPD4_INT_CONTROL);
+		tmp |= DC_HPDx_INT_ACK;
+		WREG32(DC_HPD4_INT_CONTROL, tmp);
+	}
+	if (rdev->irq.stat_regs.cik.disp_int_cont4 & DC_HPD5_INTERRUPT) {
+		tmp = RREG32(DC_HPD5_INT_CONTROL);
+		tmp |= DC_HPDx_INT_ACK;
+		WREG32(DC_HPD5_INT_CONTROL, tmp);
+	}
+	if (rdev->irq.stat_regs.cik.disp_int_cont5 & DC_HPD6_INTERRUPT) {
+		tmp = RREG32(DC_HPD5_INT_CONTROL);
+		tmp |= DC_HPDx_INT_ACK;
+		WREG32(DC_HPD6_INT_CONTROL, tmp);
+	}
+}
+
+/**
+ * cik_irq_disable - disable interrupts
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Disable interrupts on the hw (CIK).
+ */
+static void cik_irq_disable(struct radeon_device *rdev)
+{
+	cik_disable_interrupts(rdev);
+	/* Wait and acknowledge irq */
+	mdelay(1);
+	cik_irq_ack(rdev);
+	cik_disable_interrupt_state(rdev);
+}
+
+/**
+ * cik_irq_disable - disable interrupts for suspend
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Disable interrupts and stop the RLC (CIK).
+ * Used for suspend.
+ */
+static void cik_irq_suspend(struct radeon_device *rdev)
+{
+	cik_irq_disable(rdev);
+	cik_rlc_stop(rdev);
+}
+
+/**
+ * cik_irq_fini - tear down interrupt support
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Disable interrupts on the hw and free the IH ring
+ * buffer (CIK).
+ * Used for driver unload.
+ */
+static void cik_irq_fini(struct radeon_device *rdev)
+{
+	cik_irq_suspend(rdev);
+	r600_ih_ring_fini(rdev);
+}
+
+/**
+ * cik_get_ih_wptr - get the IH ring buffer wptr
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Get the IH ring buffer wptr from either the register
+ * or the writeback memory buffer (CIK).  Also check for
+ * ring buffer overflow and deal with it.
+ * Used by cik_irq_process().
+ * Returns the value of the wptr.
+ */
+static inline u32 cik_get_ih_wptr(struct radeon_device *rdev)
+{
+	u32 wptr, tmp;
+
+	if (rdev->wb.enabled)
+		wptr = le32_to_cpu(rdev->wb.wb[R600_WB_IH_WPTR_OFFSET/4]);
+	else
+		wptr = RREG32(IH_RB_WPTR);
+
+	if (wptr & RB_OVERFLOW) {
+		/* When a ring buffer overflow happen start parsing interrupt
+		 * from the last not overwritten vector (wptr + 16). Hopefully
+		 * this should allow us to catchup.
+		 */
+		dev_warn(rdev->dev, "IH ring buffer overflow (0x%08X, %d, %d)\n",
+			wptr, rdev->ih.rptr, (wptr + 16) + rdev->ih.ptr_mask);
+		rdev->ih.rptr = (wptr + 16) & rdev->ih.ptr_mask;
+		tmp = RREG32(IH_RB_CNTL);
+		tmp |= IH_WPTR_OVERFLOW_CLEAR;
+		WREG32(IH_RB_CNTL, tmp);
+	}
+	return (wptr & rdev->ih.ptr_mask);
+}
+
+/*        CIK IV Ring
+ * Each IV ring entry is 128 bits:
+ * [7:0]    - interrupt source id
+ * [31:8]   - reserved
+ * [59:32]  - interrupt source data
+ * [63:60]  - reserved
+ * [71:64]  - RINGID: ME_ID [1:0], PIPE_ID[1:0], QUEUE_ID[2:0]
+ *            QUEUE_ID - for compute, which of the 8 queues owned by the dispatcher
+ *                     - for gfx, hw shader state (0=PS...5=LS, 6=CS)
+ *            ME_ID - 0 = gfx, 1 = first 4 CS pipes, 2 = second 4 CS pipes
+ *            PIPE_ID - ME0 0=3D
+ *                    - ME1&2 compute dispatcher (4 pipes each)
+ * [79:72]  - VMID
+ * [95:80]  - PASID
+ * [127:96] - reserved
+ */
+/**
+ * cik_irq_process - interrupt handler
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Interrupt hander (CIK).  Walk the IH ring,
+ * ack interrupts and schedule work to handle
+ * interrupt events.
+ * Returns irq process return code.
+ */
+int cik_irq_process(struct radeon_device *rdev)
+{
+	u32 wptr;
+	u32 rptr;
+	u32 src_id, src_data, ring_id;
+	u8 me_id, pipe_id, queue_id;
+	u32 ring_index;
+	bool queue_hotplug = false;
+	bool queue_reset = false;
+
+	if (!rdev->ih.enabled || rdev->shutdown)
+		return IRQ_NONE;
+
+	wptr = cik_get_ih_wptr(rdev);
+
+restart_ih:
+	/* is somebody else already processing irqs? */
+	if (atomic_xchg(&rdev->ih.lock, 1))
+		return IRQ_NONE;
+
+	rptr = rdev->ih.rptr;
+	DRM_DEBUG("cik_irq_process start: rptr %d, wptr %d\n", rptr, wptr);
+
+	/* Order reading of wptr vs. reading of IH ring data */
+	rmb();
+
+	/* display interrupts */
+	cik_irq_ack(rdev);
+
+	while (rptr != wptr) {
+		/* wptr/rptr are in bytes! */
+		ring_index = rptr / 4;
+		src_id =  le32_to_cpu(rdev->ih.ring[ring_index]) & 0xff;
+		src_data = le32_to_cpu(rdev->ih.ring[ring_index + 1]) & 0xfffffff;
+		ring_id = le32_to_cpu(rdev->ih.ring[ring_index + 2]) & 0xff;
+		/* XXX check the bitfield order! */
+		me_id = (ring_id & 0x60) >> 5;
+		pipe_id = (ring_id & 0x18) >> 3;
+		queue_id = (ring_id & 0x7) >> 0;
+
+		switch (src_id) {
+		case 1: /* D1 vblank/vline */
+			switch (src_data) {
+			case 0: /* D1 vblank */
+				if (rdev->irq.stat_regs.cik.disp_int & LB_D1_VBLANK_INTERRUPT) {
+					if (rdev->irq.crtc_vblank_int[0]) {
+						drm_handle_vblank(rdev->ddev, 0);
+						rdev->pm.vblank_sync = true;
+						wake_up(&rdev->irq.vblank_queue);
+					}
+					if (atomic_read(&rdev->irq.pflip[0]))
+						radeon_crtc_handle_flip(rdev, 0);
+					rdev->irq.stat_regs.cik.disp_int &= ~LB_D1_VBLANK_INTERRUPT;
+					DRM_DEBUG("IH: D1 vblank\n");
+				}
+				break;
+			case 1: /* D1 vline */
+				if (rdev->irq.stat_regs.cik.disp_int & LB_D1_VLINE_INTERRUPT) {
+					rdev->irq.stat_regs.cik.disp_int &= ~LB_D1_VLINE_INTERRUPT;
+					DRM_DEBUG("IH: D1 vline\n");
+				}
+				break;
+			default:
+				DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
+				break;
+			}
+			break;
+		case 2: /* D2 vblank/vline */
+			switch (src_data) {
+			case 0: /* D2 vblank */
+				if (rdev->irq.stat_regs.cik.disp_int_cont & LB_D2_VBLANK_INTERRUPT) {
+					if (rdev->irq.crtc_vblank_int[1]) {
+						drm_handle_vblank(rdev->ddev, 1);
+						rdev->pm.vblank_sync = true;
+						wake_up(&rdev->irq.vblank_queue);
+					}
+					if (atomic_read(&rdev->irq.pflip[1]))
+						radeon_crtc_handle_flip(rdev, 1);
+					rdev->irq.stat_regs.cik.disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT;
+					DRM_DEBUG("IH: D2 vblank\n");
+				}
+				break;
+			case 1: /* D2 vline */
+				if (rdev->irq.stat_regs.cik.disp_int_cont & LB_D2_VLINE_INTERRUPT) {
+					rdev->irq.stat_regs.cik.disp_int_cont &= ~LB_D2_VLINE_INTERRUPT;
+					DRM_DEBUG("IH: D2 vline\n");
+				}
+				break;
+			default:
+				DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
+				break;
+			}
+			break;
+		case 3: /* D3 vblank/vline */
+			switch (src_data) {
+			case 0: /* D3 vblank */
+				if (rdev->irq.stat_regs.cik.disp_int_cont2 & LB_D3_VBLANK_INTERRUPT) {
+					if (rdev->irq.crtc_vblank_int[2]) {
+						drm_handle_vblank(rdev->ddev, 2);
+						rdev->pm.vblank_sync = true;
+						wake_up(&rdev->irq.vblank_queue);
+					}
+					if (atomic_read(&rdev->irq.pflip[2]))
+						radeon_crtc_handle_flip(rdev, 2);
+					rdev->irq.stat_regs.cik.disp_int_cont2 &= ~LB_D3_VBLANK_INTERRUPT;
+					DRM_DEBUG("IH: D3 vblank\n");
+				}
+				break;
+			case 1: /* D3 vline */
+				if (rdev->irq.stat_regs.cik.disp_int_cont2 & LB_D3_VLINE_INTERRUPT) {
+					rdev->irq.stat_regs.cik.disp_int_cont2 &= ~LB_D3_VLINE_INTERRUPT;
+					DRM_DEBUG("IH: D3 vline\n");
+				}
+				break;
+			default:
+				DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
+				break;
+			}
+			break;
+		case 4: /* D4 vblank/vline */
+			switch (src_data) {
+			case 0: /* D4 vblank */
+				if (rdev->irq.stat_regs.cik.disp_int_cont3 & LB_D4_VBLANK_INTERRUPT) {
+					if (rdev->irq.crtc_vblank_int[3]) {
+						drm_handle_vblank(rdev->ddev, 3);
+						rdev->pm.vblank_sync = true;
+						wake_up(&rdev->irq.vblank_queue);
+					}
+					if (atomic_read(&rdev->irq.pflip[3]))
+						radeon_crtc_handle_flip(rdev, 3);
+					rdev->irq.stat_regs.cik.disp_int_cont3 &= ~LB_D4_VBLANK_INTERRUPT;
+					DRM_DEBUG("IH: D4 vblank\n");
+				}
+				break;
+			case 1: /* D4 vline */
+				if (rdev->irq.stat_regs.cik.disp_int_cont3 & LB_D4_VLINE_INTERRUPT) {
+					rdev->irq.stat_regs.cik.disp_int_cont3 &= ~LB_D4_VLINE_INTERRUPT;
+					DRM_DEBUG("IH: D4 vline\n");
+				}
+				break;
+			default:
+				DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
+				break;
+			}
+			break;
+		case 5: /* D5 vblank/vline */
+			switch (src_data) {
+			case 0: /* D5 vblank */
+				if (rdev->irq.stat_regs.cik.disp_int_cont4 & LB_D5_VBLANK_INTERRUPT) {
+					if (rdev->irq.crtc_vblank_int[4]) {
+						drm_handle_vblank(rdev->ddev, 4);
+						rdev->pm.vblank_sync = true;
+						wake_up(&rdev->irq.vblank_queue);
+					}
+					if (atomic_read(&rdev->irq.pflip[4]))
+						radeon_crtc_handle_flip(rdev, 4);
+					rdev->irq.stat_regs.cik.disp_int_cont4 &= ~LB_D5_VBLANK_INTERRUPT;
+					DRM_DEBUG("IH: D5 vblank\n");
+				}
+				break;
+			case 1: /* D5 vline */
+				if (rdev->irq.stat_regs.cik.disp_int_cont4 & LB_D5_VLINE_INTERRUPT) {
+					rdev->irq.stat_regs.cik.disp_int_cont4 &= ~LB_D5_VLINE_INTERRUPT;
+					DRM_DEBUG("IH: D5 vline\n");
+				}
+				break;
+			default:
+				DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
+				break;
+			}
+			break;
+		case 6: /* D6 vblank/vline */
+			switch (src_data) {
+			case 0: /* D6 vblank */
+				if (rdev->irq.stat_regs.cik.disp_int_cont5 & LB_D6_VBLANK_INTERRUPT) {
+					if (rdev->irq.crtc_vblank_int[5]) {
+						drm_handle_vblank(rdev->ddev, 5);
+						rdev->pm.vblank_sync = true;
+						wake_up(&rdev->irq.vblank_queue);
+					}
+					if (atomic_read(&rdev->irq.pflip[5]))
+						radeon_crtc_handle_flip(rdev, 5);
+					rdev->irq.stat_regs.cik.disp_int_cont5 &= ~LB_D6_VBLANK_INTERRUPT;
+					DRM_DEBUG("IH: D6 vblank\n");
+				}
+				break;
+			case 1: /* D6 vline */
+				if (rdev->irq.stat_regs.cik.disp_int_cont5 & LB_D6_VLINE_INTERRUPT) {
+					rdev->irq.stat_regs.cik.disp_int_cont5 &= ~LB_D6_VLINE_INTERRUPT;
+					DRM_DEBUG("IH: D6 vline\n");
+				}
+				break;
+			default:
+				DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
+				break;
+			}
+			break;
+		case 42: /* HPD hotplug */
+			switch (src_data) {
+			case 0:
+				if (rdev->irq.stat_regs.cik.disp_int & DC_HPD1_INTERRUPT) {
+					rdev->irq.stat_regs.cik.disp_int &= ~DC_HPD1_INTERRUPT;
+					queue_hotplug = true;
+					DRM_DEBUG("IH: HPD1\n");
+				}
+				break;
+			case 1:
+				if (rdev->irq.stat_regs.cik.disp_int_cont & DC_HPD2_INTERRUPT) {
+					rdev->irq.stat_regs.cik.disp_int_cont &= ~DC_HPD2_INTERRUPT;
+					queue_hotplug = true;
+					DRM_DEBUG("IH: HPD2\n");
+				}
+				break;
+			case 2:
+				if (rdev->irq.stat_regs.cik.disp_int_cont2 & DC_HPD3_INTERRUPT) {
+					rdev->irq.stat_regs.cik.disp_int_cont2 &= ~DC_HPD3_INTERRUPT;
+					queue_hotplug = true;
+					DRM_DEBUG("IH: HPD3\n");
+				}
+				break;
+			case 3:
+				if (rdev->irq.stat_regs.cik.disp_int_cont3 & DC_HPD4_INTERRUPT) {
+					rdev->irq.stat_regs.cik.disp_int_cont3 &= ~DC_HPD4_INTERRUPT;
+					queue_hotplug = true;
+					DRM_DEBUG("IH: HPD4\n");
+				}
+				break;
+			case 4:
+				if (rdev->irq.stat_regs.cik.disp_int_cont4 & DC_HPD5_INTERRUPT) {
+					rdev->irq.stat_regs.cik.disp_int_cont4 &= ~DC_HPD5_INTERRUPT;
+					queue_hotplug = true;
+					DRM_DEBUG("IH: HPD5\n");
+				}
+				break;
+			case 5:
+				if (rdev->irq.stat_regs.cik.disp_int_cont5 & DC_HPD6_INTERRUPT) {
+					rdev->irq.stat_regs.cik.disp_int_cont5 &= ~DC_HPD6_INTERRUPT;
+					queue_hotplug = true;
+					DRM_DEBUG("IH: HPD6\n");
+				}
+				break;
+			default:
+				DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
+				break;
+			}
+			break;
+		case 176: /* GFX RB CP_INT */
+		case 177: /* GFX IB CP_INT */
+			radeon_fence_process(rdev, RADEON_RING_TYPE_GFX_INDEX);
+			break;
+		case 181: /* CP EOP event */
+			DRM_DEBUG("IH: CP EOP\n");
+			switch (me_id) {
+			case 0:
+				radeon_fence_process(rdev, RADEON_RING_TYPE_GFX_INDEX);
+				break;
+			case 1:
+				/* XXX compute */
+				break;
+			case 2:
+				/* XXX compute */
+				break;
+			}
+			break;
+		case 184: /* CP Privileged reg access */
+			DRM_ERROR("Illegal register access in command stream\n");
+			/* XXX check the bitfield order! */
+			me_id = (ring_id & 0x60) >> 5;
+			pipe_id = (ring_id & 0x18) >> 3;
+			queue_id = (ring_id & 0x7) >> 0;
+			switch (me_id) {
+			case 0:
+				/* This results in a full GPU reset, but all we need to do is soft
+				 * reset the CP for gfx
+				 */
+				queue_reset = true;
+				break;
+			case 1:
+				/* XXX compute */
+				break;
+			case 2:
+				/* XXX compute */
+				break;
+			}
+			break;
+		case 185: /* CP Privileged inst */
+			DRM_ERROR("Illegal instruction in command stream\n");
+			switch (me_id) {
+			case 0:
+				/* This results in a full GPU reset, but all we need to do is soft
+				 * reset the CP for gfx
+				 */
+				queue_reset = true;
+				break;
+			case 1:
+				/* XXX compute */
+				break;
+			case 2:
+				/* XXX compute */
+				break;
+			}
+			break;
+		case 233: /* GUI IDLE */
+			DRM_DEBUG("IH: GUI idle\n");
+			break;
+		default:
+			DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
+			break;
+		}
+
+		/* wptr/rptr are in bytes! */
+		rptr += 16;
+		rptr &= rdev->ih.ptr_mask;
+	}
+	if (queue_hotplug)
+		schedule_work(&rdev->hotplug_work);
+	if (queue_reset)
+		schedule_work(&rdev->reset_work);
+	rdev->ih.rptr = rptr;
+	WREG32(IH_RB_RPTR, rdev->ih.rptr);
+	atomic_set(&rdev->ih.lock, 0);
+
+	/* make sure wptr hasn't changed while processing */
+	wptr = cik_get_ih_wptr(rdev);
+	if (wptr != rptr)
+		goto restart_ih;
+
+	return IRQ_HANDLED;
+}
diff --git a/drivers/gpu/drm/radeon/cikd.h b/drivers/gpu/drm/radeon/cikd.h
index a116020..a282168 100644
--- a/drivers/gpu/drm/radeon/cikd.h
+++ b/drivers/gpu/drm/radeon/cikd.h
@@ -178,8 +178,42 @@
 #define HDP_MISC_CNTL					0x2F4C
 #define 	HDP_FLUSH_INVALIDATE_CACHE			(1 << 0)
 
+#define IH_RB_CNTL                                        0x3e00
+#       define IH_RB_ENABLE                               (1 << 0)
+#       define IH_RB_SIZE(x)                              ((x) << 1) /* log2 */
+#       define IH_RB_FULL_DRAIN_ENABLE                    (1 << 6)
+#       define IH_WPTR_WRITEBACK_ENABLE                   (1 << 8)
+#       define IH_WPTR_WRITEBACK_TIMER(x)                 ((x) << 9) /* log2 */
+#       define IH_WPTR_OVERFLOW_ENABLE                    (1 << 16)
+#       define IH_WPTR_OVERFLOW_CLEAR                     (1 << 31)
+#define IH_RB_BASE                                        0x3e04
+#define IH_RB_RPTR                                        0x3e08
+#define IH_RB_WPTR                                        0x3e0c
+#       define RB_OVERFLOW                                (1 << 0)
+#       define WPTR_OFFSET_MASK                           0x3fffc
+#define IH_RB_WPTR_ADDR_HI                                0x3e10
+#define IH_RB_WPTR_ADDR_LO                                0x3e14
+#define IH_CNTL                                           0x3e18
+#       define ENABLE_INTR                                (1 << 0)
+#       define IH_MC_SWAP(x)                              ((x) << 1)
+#       define IH_MC_SWAP_NONE                            0
+#       define IH_MC_SWAP_16BIT                           1
+#       define IH_MC_SWAP_32BIT                           2
+#       define IH_MC_SWAP_64BIT                           3
+#       define RPTR_REARM                                 (1 << 4)
+#       define MC_WRREQ_CREDIT(x)                         ((x) << 15)
+#       define MC_WR_CLEAN_CNT(x)                         ((x) << 20)
+#       define MC_VMID(x)                                 ((x) << 25)
+
 #define	CONFIG_MEMSIZE					0x5428
 
+#define INTERRUPT_CNTL                                    0x5468
+#       define IH_DUMMY_RD_OVERRIDE                       (1 << 0)
+#       define IH_DUMMY_RD_EN                             (1 << 1)
+#       define IH_REQ_NONSNOOP_EN                         (1 << 3)
+#       define GEN_IH_INT_EN                              (1 << 8)
+#define INTERRUPT_CNTL2                                   0x546c
+
 #define HDP_MEM_COHERENCY_FLUSH_CNTL			0x5480
 
 #define	BIF_FB_EN						0x5490
@@ -203,6 +237,99 @@
 #define		SDMA0					(1 << 10)
 #define		SDMA1					(1 << 11)
 
+/* 0x6b24, 0x7724, 0x10324, 0x10f24, 0x11b24, 0x12724 */
+#define LB_VLINE_STATUS                                 0x6b24
+#       define VLINE_OCCURRED                           (1 << 0)
+#       define VLINE_ACK                                (1 << 4)
+#       define VLINE_STAT                               (1 << 12)
+#       define VLINE_INTERRUPT                          (1 << 16)
+#       define VLINE_INTERRUPT_TYPE                     (1 << 17)
+/* 0x6b2c, 0x772c, 0x1032c, 0x10f2c, 0x11b2c, 0x1272c */
+#define LB_VBLANK_STATUS                                0x6b2c
+#       define VBLANK_OCCURRED                          (1 << 0)
+#       define VBLANK_ACK                               (1 << 4)
+#       define VBLANK_STAT                              (1 << 12)
+#       define VBLANK_INTERRUPT                         (1 << 16)
+#       define VBLANK_INTERRUPT_TYPE                    (1 << 17)
+
+/* 0x6b20, 0x7720, 0x10320, 0x10f20, 0x11b20, 0x12720 */
+#define LB_INTERRUPT_MASK                               0x6b20
+#       define VBLANK_INTERRUPT_MASK                    (1 << 0)
+#       define VLINE_INTERRUPT_MASK                     (1 << 4)
+#       define VLINE2_INTERRUPT_MASK                    (1 << 8)
+
+#define DISP_INTERRUPT_STATUS                           0x60f4
+#       define LB_D1_VLINE_INTERRUPT                    (1 << 2)
+#       define LB_D1_VBLANK_INTERRUPT                   (1 << 3)
+#       define DC_HPD1_INTERRUPT                        (1 << 17)
+#       define DC_HPD1_RX_INTERRUPT                     (1 << 18)
+#       define DACA_AUTODETECT_INTERRUPT                (1 << 22)
+#       define DACB_AUTODETECT_INTERRUPT                (1 << 23)
+#       define DC_I2C_SW_DONE_INTERRUPT                 (1 << 24)
+#       define DC_I2C_HW_DONE_INTERRUPT                 (1 << 25)
+#define DISP_INTERRUPT_STATUS_CONTINUE                  0x60f8
+#       define LB_D2_VLINE_INTERRUPT                    (1 << 2)
+#       define LB_D2_VBLANK_INTERRUPT                   (1 << 3)
+#       define DC_HPD2_INTERRUPT                        (1 << 17)
+#       define DC_HPD2_RX_INTERRUPT                     (1 << 18)
+#       define DISP_TIMER_INTERRUPT                     (1 << 24)
+#define DISP_INTERRUPT_STATUS_CONTINUE2                 0x60fc
+#       define LB_D3_VLINE_INTERRUPT                    (1 << 2)
+#       define LB_D3_VBLANK_INTERRUPT                   (1 << 3)
+#       define DC_HPD3_INTERRUPT                        (1 << 17)
+#       define DC_HPD3_RX_INTERRUPT                     (1 << 18)
+#define DISP_INTERRUPT_STATUS_CONTINUE3                 0x6100
+#       define LB_D4_VLINE_INTERRUPT                    (1 << 2)
+#       define LB_D4_VBLANK_INTERRUPT                   (1 << 3)
+#       define DC_HPD4_INTERRUPT                        (1 << 17)
+#       define DC_HPD4_RX_INTERRUPT                     (1 << 18)
+#define DISP_INTERRUPT_STATUS_CONTINUE4                 0x614c
+#       define LB_D5_VLINE_INTERRUPT                    (1 << 2)
+#       define LB_D5_VBLANK_INTERRUPT                   (1 << 3)
+#       define DC_HPD5_INTERRUPT                        (1 << 17)
+#       define DC_HPD5_RX_INTERRUPT                     (1 << 18)
+#define DISP_INTERRUPT_STATUS_CONTINUE5                 0x6150
+#       define LB_D6_VLINE_INTERRUPT                    (1 << 2)
+#       define LB_D6_VBLANK_INTERRUPT                   (1 << 3)
+#       define DC_HPD6_INTERRUPT                        (1 << 17)
+#       define DC_HPD6_RX_INTERRUPT                     (1 << 18)
+#define DISP_INTERRUPT_STATUS_CONTINUE6                 0x6780
+
+#define	DAC_AUTODETECT_INT_CONTROL			0x67c8
+
+#define DC_HPD1_INT_STATUS                              0x601c
+#define DC_HPD2_INT_STATUS                              0x6028
+#define DC_HPD3_INT_STATUS                              0x6034
+#define DC_HPD4_INT_STATUS                              0x6040
+#define DC_HPD5_INT_STATUS                              0x604c
+#define DC_HPD6_INT_STATUS                              0x6058
+#       define DC_HPDx_INT_STATUS                       (1 << 0)
+#       define DC_HPDx_SENSE                            (1 << 1)
+#       define DC_HPDx_SENSE_DELAYED                    (1 << 4)
+#       define DC_HPDx_RX_INT_STATUS                    (1 << 8)
+
+#define DC_HPD1_INT_CONTROL                             0x6020
+#define DC_HPD2_INT_CONTROL                             0x602c
+#define DC_HPD3_INT_CONTROL                             0x6038
+#define DC_HPD4_INT_CONTROL                             0x6044
+#define DC_HPD5_INT_CONTROL                             0x6050
+#define DC_HPD6_INT_CONTROL                             0x605c
+#       define DC_HPDx_INT_ACK                          (1 << 0)
+#       define DC_HPDx_INT_POLARITY                     (1 << 8)
+#       define DC_HPDx_INT_EN                           (1 << 16)
+#       define DC_HPDx_RX_INT_ACK                       (1 << 20)
+#       define DC_HPDx_RX_INT_EN                        (1 << 24)
+
+#define DC_HPD1_CONTROL                                   0x6024
+#define DC_HPD2_CONTROL                                   0x6030
+#define DC_HPD3_CONTROL                                   0x603c
+#define DC_HPD4_CONTROL                                   0x6048
+#define DC_HPD5_CONTROL                                   0x6054
+#define DC_HPD6_CONTROL                                   0x6060
+#       define DC_HPDx_CONNECTION_TIMER(x)                ((x) << 0)
+#       define DC_HPDx_RX_INT_TIMER(x)                    ((x) << 16)
+#       define DC_HPDx_EN                                 (1 << 28)
+
 #define	GRBM_CNTL					0x8000
 #define		GRBM_READ_TIMEOUT(x)				((x) << 0)
 
@@ -274,6 +401,10 @@
 #define		SOFT_RESET_CPC					(1 << 18) /* CP Compute (MEC1/2) */
 #define		SOFT_RESET_CPG					(1 << 19) /* CP GFX (PFP, ME, CE) */
 
+#define GRBM_INT_CNTL                                   0x8060
+#       define RDERR_INT_ENABLE                         (1 << 0)
+#       define GUI_IDLE_INT_ENABLE                      (1 << 19)
+
 #define CP_MEC_CNTL					0x8234
 #define		MEC_ME2_HALT					(1 << 28)
 #define		MEC_ME1_HALT					(1 << 30)
@@ -507,6 +638,45 @@
 #       define CP_RINGID1_INT_ENABLE                    (1 << 30)
 #       define CP_RINGID0_INT_ENABLE                    (1 << 31)
 
+#define CP_INT_STATUS_RING0                             0xC1B4
+#       define PRIV_INSTR_INT_STAT                      (1 << 22)
+#       define PRIV_REG_INT_STAT                        (1 << 23)
+#       define TIME_STAMP_INT_STAT                      (1 << 26)
+#       define CP_RINGID2_INT_STAT                      (1 << 29)
+#       define CP_RINGID1_INT_STAT                      (1 << 30)
+#       define CP_RINGID0_INT_STAT                      (1 << 31)
+
+#define CP_ME1_PIPE0_INT_CNTL                           0xC214
+#define CP_ME1_PIPE1_INT_CNTL                           0xC218
+#define CP_ME1_PIPE2_INT_CNTL                           0xC21C
+#define CP_ME1_PIPE3_INT_CNTL                           0xC220
+#define CP_ME2_PIPE0_INT_CNTL                           0xC224
+#define CP_ME2_PIPE1_INT_CNTL                           0xC228
+#define CP_ME2_PIPE2_INT_CNTL                           0xC22C
+#define CP_ME2_PIPE3_INT_CNTL                           0xC230
+#       define DEQUEUE_REQUEST_INT_ENABLE               (1 << 13)
+#       define WRM_POLL_TIMEOUT_INT_ENABLE              (1 << 17)
+#       define PRIV_REG_INT_ENABLE                      (1 << 23)
+#       define TIME_STAMP_INT_ENABLE                    (1 << 26)
+#       define GENERIC2_INT_ENABLE                      (1 << 29)
+#       define GENERIC1_INT_ENABLE                      (1 << 30)
+#       define GENERIC0_INT_ENABLE                      (1 << 31)
+#define CP_ME1_PIPE0_INT_STATUS                         0xC214
+#define CP_ME1_PIPE1_INT_STATUS                         0xC218
+#define CP_ME1_PIPE2_INT_STATUS                         0xC21C
+#define CP_ME1_PIPE3_INT_STATUS                         0xC220
+#define CP_ME2_PIPE0_INT_STATUS                         0xC224
+#define CP_ME2_PIPE1_INT_STATUS                         0xC228
+#define CP_ME2_PIPE2_INT_STATUS                         0xC22C
+#define CP_ME2_PIPE3_INT_STATUS                         0xC230
+#       define DEQUEUE_REQUEST_INT_STATUS               (1 << 13)
+#       define WRM_POLL_TIMEOUT_INT_STATUS              (1 << 17)
+#       define PRIV_REG_INT_STATUS                      (1 << 23)
+#       define TIME_STAMP_INT_STATUS                    (1 << 26)
+#       define GENERIC2_INT_STATUS                      (1 << 29)
+#       define GENERIC1_INT_STATUS                      (1 << 30)
+#       define GENERIC0_INT_STATUS                      (1 << 31)
+
 #define	CP_MAX_CONTEXT					0xC2B8
 
 #define	CP_RB0_BASE_HI					0xC2C4
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 1c06c47..e09157b 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -600,10 +600,21 @@ struct evergreen_irq_stat_regs {
 	u32 afmt_status6;
 };
 
+struct cik_irq_stat_regs {
+	u32 disp_int;
+	u32 disp_int_cont;
+	u32 disp_int_cont2;
+	u32 disp_int_cont3;
+	u32 disp_int_cont4;
+	u32 disp_int_cont5;
+	u32 disp_int_cont6;
+};
+
 union radeon_irq_stat_regs {
 	struct r500_irq_stat_regs r500;
 	struct r600_irq_stat_regs r600;
 	struct evergreen_irq_stat_regs evergreen;
+	struct cik_irq_stat_regs cik;
 };
 
 #define RADEON_MAX_HPD_PINS 6
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 019/165] drm/radeon/cik: log and handle VM page fault interrupts
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (18 preceding siblings ...)
  2013-06-26 13:21 ` [PATCH 018/165] drm/radeon: add support for interrupts on CIK (v5) alexdeucher
@ 2013-06-26 13:21 ` alexdeucher
  2013-06-26 13:21 ` [PATCH 020/165] drm/radeon/cik: add support for sDMA dma engines (v8) alexdeucher
                   ` (93 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:21 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/cik.c  |   10 ++++++++++
 drivers/gpu/drm/radeon/cikd.h |    4 ++++
 2 files changed, 14 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
index 72c7e83..b70f017 100644
--- a/drivers/gpu/drm/radeon/cik.c
+++ b/drivers/gpu/drm/radeon/cik.c
@@ -3676,6 +3676,16 @@ restart_ih:
 				break;
 			}
 			break;
+		case 146:
+		case 147:
+			dev_err(rdev->dev, "GPU fault detected: %d 0x%08x\n", src_id, src_data);
+			dev_err(rdev->dev, "  VM_CONTEXT1_PROTECTION_FAULT_ADDR   0x%08X\n",
+				RREG32(VM_CONTEXT1_PROTECTION_FAULT_ADDR));
+			dev_err(rdev->dev, "  VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x%08X\n",
+				RREG32(VM_CONTEXT1_PROTECTION_FAULT_STATUS));
+			/* reset addr and status */
+			WREG32_P(VM_CONTEXT1_CNTL2, 1, ~1);
+			break;
 		case 176: /* GFX RB CP_INT */
 		case 177: /* GFX IB CP_INT */
 			radeon_fence_process(rdev, RADEON_RING_TYPE_GFX_INDEX);
diff --git a/drivers/gpu/drm/radeon/cikd.h b/drivers/gpu/drm/radeon/cikd.h
index a282168..cc4f28e 100644
--- a/drivers/gpu/drm/radeon/cikd.h
+++ b/drivers/gpu/drm/radeon/cikd.h
@@ -95,6 +95,10 @@
 #define VM_INVALIDATE_REQUEST				0x1478
 #define VM_INVALIDATE_RESPONSE				0x147c
 
+#define	VM_CONTEXT1_PROTECTION_FAULT_STATUS		0x14DC
+
+#define	VM_CONTEXT1_PROTECTION_FAULT_ADDR		0x14FC
+
 #define VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR	0x1518
 #define VM_CONTEXT1_PROTECTION_FAULT_DEFAULT_ADDR	0x151c
 
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 020/165] drm/radeon/cik: add support for sDMA dma engines (v8)
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (19 preceding siblings ...)
  2013-06-26 13:21 ` [PATCH 019/165] drm/radeon/cik: log and handle VM page fault interrupts alexdeucher
@ 2013-06-26 13:21 ` alexdeucher
  2013-06-26 13:21 ` [PATCH 021/165] drm/radeon: implement async vm_flush for the sDMA (v6) alexdeucher
                   ` (92 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:21 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

CIK has new asynchronous DMA engines called sDMA
(system DMA).  Each engine supports 1 ring buffer
for kernel and gfx and 2 userspace queues for compute.

TODO: fill in the compute setup.

v2: update to the latest reset code
v3: remove ib_parse
v4: fix copy_dma()
v5: drop WIP compute sDMA queues
v6: rebase
v7: endian fixes for IB
v8: cleanup for release

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/cik.c    |  745 ++++++++++++++++++++++++++++++++++++++-
 drivers/gpu/drm/radeon/cikd.h   |  130 +++++++
 drivers/gpu/drm/radeon/radeon.h |    1 +
 3 files changed, 870 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
index b70f017..931169e 100644
--- a/drivers/gpu/drm/radeon/cik.c
+++ b/drivers/gpu/drm/radeon/cik.c
@@ -44,6 +44,9 @@
 #define KV_RLC_UCODE_SIZE 2560
 /* gddr controller */
 #define CIK_MC_UCODE_SIZE 7866
+/* sdma */
+#define CIK_SDMA_UCODE_SIZE 1050
+#define CIK_SDMA_UCODE_VERSION 64
 
 MODULE_FIRMWARE("radeon/BONAIRE_pfp.bin");
 MODULE_FIRMWARE("radeon/BONAIRE_me.bin");
@@ -51,16 +54,19 @@ MODULE_FIRMWARE("radeon/BONAIRE_ce.bin");
 MODULE_FIRMWARE("radeon/BONAIRE_mec.bin");
 MODULE_FIRMWARE("radeon/BONAIRE_mc.bin");
 MODULE_FIRMWARE("radeon/BONAIRE_rlc.bin");
+MODULE_FIRMWARE("radeon/BONAIRE_sdma.bin");
 MODULE_FIRMWARE("radeon/KAVERI_pfp.bin");
 MODULE_FIRMWARE("radeon/KAVERI_me.bin");
 MODULE_FIRMWARE("radeon/KAVERI_ce.bin");
 MODULE_FIRMWARE("radeon/KAVERI_mec.bin");
 MODULE_FIRMWARE("radeon/KAVERI_rlc.bin");
+MODULE_FIRMWARE("radeon/KAVERI_sdma.bin");
 MODULE_FIRMWARE("radeon/KABINI_pfp.bin");
 MODULE_FIRMWARE("radeon/KABINI_me.bin");
 MODULE_FIRMWARE("radeon/KABINI_ce.bin");
 MODULE_FIRMWARE("radeon/KABINI_mec.bin");
 MODULE_FIRMWARE("radeon/KABINI_rlc.bin");
+MODULE_FIRMWARE("radeon/KABINI_sdma.bin");
 
 extern int r600_ih_ring_alloc(struct radeon_device *rdev);
 extern void r600_ih_ring_fini(struct radeon_device *rdev);
@@ -198,7 +204,8 @@ static int cik_init_microcode(struct radeon_device *rdev)
 	struct platform_device *pdev;
 	const char *chip_name;
 	size_t pfp_req_size, me_req_size, ce_req_size,
-		mec_req_size, rlc_req_size, mc_req_size;
+		mec_req_size, rlc_req_size, mc_req_size,
+		sdma_req_size;
 	char fw_name[30];
 	int err;
 
@@ -220,6 +227,7 @@ static int cik_init_microcode(struct radeon_device *rdev)
 		mec_req_size = CIK_MEC_UCODE_SIZE * 4;
 		rlc_req_size = BONAIRE_RLC_UCODE_SIZE * 4;
 		mc_req_size = CIK_MC_UCODE_SIZE * 4;
+		sdma_req_size = CIK_SDMA_UCODE_SIZE * 4;
 		break;
 	case CHIP_KAVERI:
 		chip_name = "KAVERI";
@@ -228,6 +236,7 @@ static int cik_init_microcode(struct radeon_device *rdev)
 		ce_req_size = CIK_CE_UCODE_SIZE * 4;
 		mec_req_size = CIK_MEC_UCODE_SIZE * 4;
 		rlc_req_size = KV_RLC_UCODE_SIZE * 4;
+		sdma_req_size = CIK_SDMA_UCODE_SIZE * 4;
 		break;
 	case CHIP_KABINI:
 		chip_name = "KABINI";
@@ -236,6 +245,7 @@ static int cik_init_microcode(struct radeon_device *rdev)
 		ce_req_size = CIK_CE_UCODE_SIZE * 4;
 		mec_req_size = CIK_MEC_UCODE_SIZE * 4;
 		rlc_req_size = KB_RLC_UCODE_SIZE * 4;
+		sdma_req_size = CIK_SDMA_UCODE_SIZE * 4;
 		break;
 	default: BUG();
 	}
@@ -298,6 +308,17 @@ static int cik_init_microcode(struct radeon_device *rdev)
 		err = -EINVAL;
 	}
 
+	snprintf(fw_name, sizeof(fw_name), "radeon/%s_sdma.bin", chip_name);
+	err = request_firmware(&rdev->sdma_fw, fw_name, &pdev->dev);
+	if (err)
+		goto out;
+	if (rdev->sdma_fw->size != sdma_req_size) {
+		printk(KERN_ERR
+		       "cik_sdma: Bogus length %zu in firmware \"%s\"\n",
+		       rdev->sdma_fw->size, fw_name);
+		err = -EINVAL;
+	}
+
 	/* No MC ucode on APUs */
 	if (!(rdev->flags & RADEON_IS_IGP)) {
 		snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name);
@@ -1425,6 +1446,8 @@ static void cik_gpu_init(struct radeon_device *rdev)
 	WREG32(GB_ADDR_CONFIG, gb_addr_config);
 	WREG32(HDP_ADDR_CONFIG, gb_addr_config);
 	WREG32(DMIF_ADDR_CALC, gb_addr_config);
+	WREG32(SDMA0_TILING_CONFIG + SDMA0_REGISTER_OFFSET, gb_addr_config & 0x70);
+	WREG32(SDMA0_TILING_CONFIG + SDMA1_REGISTER_OFFSET, gb_addr_config & 0x70);
 
 	cik_tiling_mode_table_init(rdev);
 
@@ -2136,6 +2159,578 @@ static int cik_cp_resume(struct radeon_device *rdev)
 	return 0;
 }
 
+/*
+ * sDMA - System DMA
+ * Starting with CIK, the GPU has new asynchronous
+ * DMA engines.  These engines are used for compute
+ * and gfx.  There are two DMA engines (SDMA0, SDMA1)
+ * and each one supports 1 ring buffer used for gfx
+ * and 2 queues used for compute.
+ *
+ * The programming model is very similar to the CP
+ * (ring buffer, IBs, etc.), but sDMA has it's own
+ * packet format that is different from the PM4 format
+ * used by the CP. sDMA supports copying data, writing
+ * embedded data, solid fills, and a number of other
+ * things.  It also has support for tiling/detiling of
+ * buffers.
+ */
+/**
+ * cik_sdma_ring_ib_execute - Schedule an IB on the DMA engine
+ *
+ * @rdev: radeon_device pointer
+ * @ib: IB object to schedule
+ *
+ * Schedule an IB in the DMA ring (CIK).
+ */
+void cik_sdma_ring_ib_execute(struct radeon_device *rdev,
+			      struct radeon_ib *ib)
+{
+	struct radeon_ring *ring = &rdev->ring[ib->ring];
+	u32 extra_bits = (ib->vm ? ib->vm->id : 0) & 0xf;
+
+	if (rdev->wb.enabled) {
+		u32 next_rptr = ring->wptr + 5;
+		while ((next_rptr & 7) != 4)
+			next_rptr++;
+		next_rptr += 4;
+		radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_WRITE, SDMA_WRITE_SUB_OPCODE_LINEAR, 0));
+		radeon_ring_write(ring, ring->next_rptr_gpu_addr & 0xfffffffc);
+		radeon_ring_write(ring, upper_32_bits(ring->next_rptr_gpu_addr) & 0xffffffff);
+		radeon_ring_write(ring, 1); /* number of DWs to follow */
+		radeon_ring_write(ring, next_rptr);
+	}
+
+	/* IB packet must end on a 8 DW boundary */
+	while ((ring->wptr & 7) != 4)
+		radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_NOP, 0, 0));
+	radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_INDIRECT_BUFFER, 0, extra_bits));
+	radeon_ring_write(ring, ib->gpu_addr & 0xffffffe0); /* base must be 32 byte aligned */
+	radeon_ring_write(ring, upper_32_bits(ib->gpu_addr) & 0xffffffff);
+	radeon_ring_write(ring, ib->length_dw);
+
+}
+
+/**
+ * cik_sdma_fence_ring_emit - emit a fence on the DMA ring
+ *
+ * @rdev: radeon_device pointer
+ * @fence: radeon fence object
+ *
+ * Add a DMA fence packet to the ring to write
+ * the fence seq number and DMA trap packet to generate
+ * an interrupt if needed (CIK).
+ */
+void cik_sdma_fence_ring_emit(struct radeon_device *rdev,
+			      struct radeon_fence *fence)
+{
+	struct radeon_ring *ring = &rdev->ring[fence->ring];
+	u64 addr = rdev->fence_drv[fence->ring].gpu_addr;
+	u32 extra_bits = (SDMA_POLL_REG_MEM_EXTRA_OP(1) |
+			  SDMA_POLL_REG_MEM_EXTRA_FUNC(3)); /* == */
+	u32 ref_and_mask;
+
+	if (fence->ring == R600_RING_TYPE_DMA_INDEX)
+		ref_and_mask = SDMA0;
+	else
+		ref_and_mask = SDMA1;
+
+	/* write the fence */
+	radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_FENCE, 0, 0));
+	radeon_ring_write(ring, addr & 0xffffffff);
+	radeon_ring_write(ring, upper_32_bits(addr) & 0xffffffff);
+	radeon_ring_write(ring, fence->seq);
+	/* generate an interrupt */
+	radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_TRAP, 0, 0));
+	/* flush HDP */
+	radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_POLL_REG_MEM, 0, extra_bits));
+	radeon_ring_write(ring, GPU_HDP_FLUSH_DONE);
+	radeon_ring_write(ring, GPU_HDP_FLUSH_REQ);
+	radeon_ring_write(ring, ref_and_mask); /* REFERENCE */
+	radeon_ring_write(ring, ref_and_mask); /* MASK */
+	radeon_ring_write(ring, (4 << 16) | 10); /* RETRY_COUNT, POLL_INTERVAL */
+}
+
+/**
+ * cik_sdma_semaphore_ring_emit - emit a semaphore on the dma ring
+ *
+ * @rdev: radeon_device pointer
+ * @ring: radeon_ring structure holding ring information
+ * @semaphore: radeon semaphore object
+ * @emit_wait: wait or signal semaphore
+ *
+ * Add a DMA semaphore packet to the ring wait on or signal
+ * other rings (CIK).
+ */
+void cik_sdma_semaphore_ring_emit(struct radeon_device *rdev,
+				  struct radeon_ring *ring,
+				  struct radeon_semaphore *semaphore,
+				  bool emit_wait)
+{
+	u64 addr = semaphore->gpu_addr;
+	u32 extra_bits = emit_wait ? 0 : SDMA_SEMAPHORE_EXTRA_S;
+
+	radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SEMAPHORE, 0, extra_bits));
+	radeon_ring_write(ring, addr & 0xfffffff8);
+	radeon_ring_write(ring, upper_32_bits(addr) & 0xffffffff);
+}
+
+/**
+ * cik_sdma_gfx_stop - stop the gfx async dma engines
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Stop the gfx async dma ring buffers (CIK).
+ */
+static void cik_sdma_gfx_stop(struct radeon_device *rdev)
+{
+	u32 rb_cntl, reg_offset;
+	int i;
+
+	radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size);
+
+	for (i = 0; i < 2; i++) {
+		if (i == 0)
+			reg_offset = SDMA0_REGISTER_OFFSET;
+		else
+			reg_offset = SDMA1_REGISTER_OFFSET;
+		rb_cntl = RREG32(SDMA0_GFX_RB_CNTL + reg_offset);
+		rb_cntl &= ~SDMA_RB_ENABLE;
+		WREG32(SDMA0_GFX_RB_CNTL + reg_offset, rb_cntl);
+		WREG32(SDMA0_GFX_IB_CNTL + reg_offset, 0);
+	}
+}
+
+/**
+ * cik_sdma_rlc_stop - stop the compute async dma engines
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Stop the compute async dma queues (CIK).
+ */
+static void cik_sdma_rlc_stop(struct radeon_device *rdev)
+{
+	/* XXX todo */
+}
+
+/**
+ * cik_sdma_enable - stop the async dma engines
+ *
+ * @rdev: radeon_device pointer
+ * @enable: enable/disable the DMA MEs.
+ *
+ * Halt or unhalt the async dma engines (CIK).
+ */
+static void cik_sdma_enable(struct radeon_device *rdev, bool enable)
+{
+	u32 me_cntl, reg_offset;
+	int i;
+
+	for (i = 0; i < 2; i++) {
+		if (i == 0)
+			reg_offset = SDMA0_REGISTER_OFFSET;
+		else
+			reg_offset = SDMA1_REGISTER_OFFSET;
+		me_cntl = RREG32(SDMA0_ME_CNTL + reg_offset);
+		if (enable)
+			me_cntl &= ~SDMA_HALT;
+		else
+			me_cntl |= SDMA_HALT;
+		WREG32(SDMA0_ME_CNTL + reg_offset, me_cntl);
+	}
+}
+
+/**
+ * cik_sdma_gfx_resume - setup and start the async dma engines
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Set up the gfx DMA ring buffers and enable them (CIK).
+ * Returns 0 for success, error for failure.
+ */
+static int cik_sdma_gfx_resume(struct radeon_device *rdev)
+{
+	struct radeon_ring *ring;
+	u32 rb_cntl, ib_cntl;
+	u32 rb_bufsz;
+	u32 reg_offset, wb_offset;
+	int i, r;
+
+	for (i = 0; i < 2; i++) {
+		if (i == 0) {
+			ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX];
+			reg_offset = SDMA0_REGISTER_OFFSET;
+			wb_offset = R600_WB_DMA_RPTR_OFFSET;
+		} else {
+			ring = &rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX];
+			reg_offset = SDMA1_REGISTER_OFFSET;
+			wb_offset = CAYMAN_WB_DMA1_RPTR_OFFSET;
+		}
+
+		WREG32(SDMA0_SEM_INCOMPLETE_TIMER_CNTL + reg_offset, 0);
+		WREG32(SDMA0_SEM_WAIT_FAIL_TIMER_CNTL + reg_offset, 0);
+
+		/* Set ring buffer size in dwords */
+		rb_bufsz = drm_order(ring->ring_size / 4);
+		rb_cntl = rb_bufsz << 1;
+#ifdef __BIG_ENDIAN
+		rb_cntl |= SDMA_RB_SWAP_ENABLE | SDMA_RPTR_WRITEBACK_SWAP_ENABLE;
+#endif
+		WREG32(SDMA0_GFX_RB_CNTL + reg_offset, rb_cntl);
+
+		/* Initialize the ring buffer's read and write pointers */
+		WREG32(SDMA0_GFX_RB_RPTR + reg_offset, 0);
+		WREG32(SDMA0_GFX_RB_WPTR + reg_offset, 0);
+
+		/* set the wb address whether it's enabled or not */
+		WREG32(SDMA0_GFX_RB_RPTR_ADDR_HI + reg_offset,
+		       upper_32_bits(rdev->wb.gpu_addr + wb_offset) & 0xFFFFFFFF);
+		WREG32(SDMA0_GFX_RB_RPTR_ADDR_LO + reg_offset,
+		       ((rdev->wb.gpu_addr + wb_offset) & 0xFFFFFFFC));
+
+		if (rdev->wb.enabled)
+			rb_cntl |= SDMA_RPTR_WRITEBACK_ENABLE;
+
+		WREG32(SDMA0_GFX_RB_BASE + reg_offset, ring->gpu_addr >> 8);
+		WREG32(SDMA0_GFX_RB_BASE_HI + reg_offset, ring->gpu_addr >> 40);
+
+		ring->wptr = 0;
+		WREG32(SDMA0_GFX_RB_WPTR + reg_offset, ring->wptr << 2);
+
+		ring->rptr = RREG32(SDMA0_GFX_RB_RPTR + reg_offset) >> 2;
+
+		/* enable DMA RB */
+		WREG32(SDMA0_GFX_RB_CNTL + reg_offset, rb_cntl | SDMA_RB_ENABLE);
+
+		ib_cntl = SDMA_IB_ENABLE;
+#ifdef __BIG_ENDIAN
+		ib_cntl |= SDMA_IB_SWAP_ENABLE;
+#endif
+		/* enable DMA IBs */
+		WREG32(SDMA0_GFX_IB_CNTL + reg_offset, ib_cntl);
+
+		ring->ready = true;
+
+		r = radeon_ring_test(rdev, ring->idx, ring);
+		if (r) {
+			ring->ready = false;
+			return r;
+		}
+	}
+
+	radeon_ttm_set_active_vram_size(rdev, rdev->mc.real_vram_size);
+
+	return 0;
+}
+
+/**
+ * cik_sdma_rlc_resume - setup and start the async dma engines
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Set up the compute DMA queues and enable them (CIK).
+ * Returns 0 for success, error for failure.
+ */
+static int cik_sdma_rlc_resume(struct radeon_device *rdev)
+{
+	/* XXX todo */
+	return 0;
+}
+
+/**
+ * cik_sdma_load_microcode - load the sDMA ME ucode
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Loads the sDMA0/1 ucode.
+ * Returns 0 for success, -EINVAL if the ucode is not available.
+ */
+static int cik_sdma_load_microcode(struct radeon_device *rdev)
+{
+	const __be32 *fw_data;
+	int i;
+
+	if (!rdev->sdma_fw)
+		return -EINVAL;
+
+	/* stop the gfx rings and rlc compute queues */
+	cik_sdma_gfx_stop(rdev);
+	cik_sdma_rlc_stop(rdev);
+
+	/* halt the MEs */
+	cik_sdma_enable(rdev, false);
+
+	/* sdma0 */
+	fw_data = (const __be32 *)rdev->sdma_fw->data;
+	WREG32(SDMA0_UCODE_ADDR + SDMA0_REGISTER_OFFSET, 0);
+	for (i = 0; i < CIK_SDMA_UCODE_SIZE; i++)
+		WREG32(SDMA0_UCODE_DATA + SDMA0_REGISTER_OFFSET, be32_to_cpup(fw_data++));
+	WREG32(SDMA0_UCODE_DATA + SDMA0_REGISTER_OFFSET, CIK_SDMA_UCODE_VERSION);
+
+	/* sdma1 */
+	fw_data = (const __be32 *)rdev->sdma_fw->data;
+	WREG32(SDMA0_UCODE_ADDR + SDMA1_REGISTER_OFFSET, 0);
+	for (i = 0; i < CIK_SDMA_UCODE_SIZE; i++)
+		WREG32(SDMA0_UCODE_DATA + SDMA1_REGISTER_OFFSET, be32_to_cpup(fw_data++));
+	WREG32(SDMA0_UCODE_DATA + SDMA1_REGISTER_OFFSET, CIK_SDMA_UCODE_VERSION);
+
+	WREG32(SDMA0_UCODE_ADDR + SDMA0_REGISTER_OFFSET, 0);
+	WREG32(SDMA0_UCODE_ADDR + SDMA1_REGISTER_OFFSET, 0);
+	return 0;
+}
+
+/**
+ * cik_sdma_resume - setup and start the async dma engines
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Set up the DMA engines and enable them (CIK).
+ * Returns 0 for success, error for failure.
+ */
+static int cik_sdma_resume(struct radeon_device *rdev)
+{
+	int r;
+
+	/* Reset dma */
+	WREG32(SRBM_SOFT_RESET, SOFT_RESET_SDMA | SOFT_RESET_SDMA1);
+	RREG32(SRBM_SOFT_RESET);
+	udelay(50);
+	WREG32(SRBM_SOFT_RESET, 0);
+	RREG32(SRBM_SOFT_RESET);
+
+	r = cik_sdma_load_microcode(rdev);
+	if (r)
+		return r;
+
+	/* unhalt the MEs */
+	cik_sdma_enable(rdev, true);
+
+	/* start the gfx rings and rlc compute queues */
+	r = cik_sdma_gfx_resume(rdev);
+	if (r)
+		return r;
+	r = cik_sdma_rlc_resume(rdev);
+	if (r)
+		return r;
+
+	return 0;
+}
+
+/**
+ * cik_sdma_fini - tear down the async dma engines
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Stop the async dma engines and free the rings (CIK).
+ */
+static void cik_sdma_fini(struct radeon_device *rdev)
+{
+	/* stop the gfx rings and rlc compute queues */
+	cik_sdma_gfx_stop(rdev);
+	cik_sdma_rlc_stop(rdev);
+	/* halt the MEs */
+	cik_sdma_enable(rdev, false);
+	radeon_ring_fini(rdev, &rdev->ring[R600_RING_TYPE_DMA_INDEX]);
+	radeon_ring_fini(rdev, &rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX]);
+	/* XXX - compute dma queue tear down */
+}
+
+/**
+ * cik_copy_dma - copy pages using the DMA engine
+ *
+ * @rdev: radeon_device pointer
+ * @src_offset: src GPU address
+ * @dst_offset: dst GPU address
+ * @num_gpu_pages: number of GPU pages to xfer
+ * @fence: radeon fence object
+ *
+ * Copy GPU paging using the DMA engine (CIK).
+ * Used by the radeon ttm implementation to move pages if
+ * registered as the asic copy callback.
+ */
+int cik_copy_dma(struct radeon_device *rdev,
+		 uint64_t src_offset, uint64_t dst_offset,
+		 unsigned num_gpu_pages,
+		 struct radeon_fence **fence)
+{
+	struct radeon_semaphore *sem = NULL;
+	int ring_index = rdev->asic->copy.dma_ring_index;
+	struct radeon_ring *ring = &rdev->ring[ring_index];
+	u32 size_in_bytes, cur_size_in_bytes;
+	int i, num_loops;
+	int r = 0;
+
+	r = radeon_semaphore_create(rdev, &sem);
+	if (r) {
+		DRM_ERROR("radeon: moving bo (%d).\n", r);
+		return r;
+	}
+
+	size_in_bytes = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT);
+	num_loops = DIV_ROUND_UP(size_in_bytes, 0x1fffff);
+	r = radeon_ring_lock(rdev, ring, num_loops * 7 + 14);
+	if (r) {
+		DRM_ERROR("radeon: moving bo (%d).\n", r);
+		radeon_semaphore_free(rdev, &sem, NULL);
+		return r;
+	}
+
+	if (radeon_fence_need_sync(*fence, ring->idx)) {
+		radeon_semaphore_sync_rings(rdev, sem, (*fence)->ring,
+					    ring->idx);
+		radeon_fence_note_sync(*fence, ring->idx);
+	} else {
+		radeon_semaphore_free(rdev, &sem, NULL);
+	}
+
+	for (i = 0; i < num_loops; i++) {
+		cur_size_in_bytes = size_in_bytes;
+		if (cur_size_in_bytes > 0x1fffff)
+			cur_size_in_bytes = 0x1fffff;
+		size_in_bytes -= cur_size_in_bytes;
+		radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_COPY, SDMA_COPY_SUB_OPCODE_LINEAR, 0));
+		radeon_ring_write(ring, cur_size_in_bytes);
+		radeon_ring_write(ring, 0); /* src/dst endian swap */
+		radeon_ring_write(ring, src_offset & 0xffffffff);
+		radeon_ring_write(ring, upper_32_bits(src_offset) & 0xffffffff);
+		radeon_ring_write(ring, dst_offset & 0xfffffffc);
+		radeon_ring_write(ring, upper_32_bits(dst_offset) & 0xffffffff);
+		src_offset += cur_size_in_bytes;
+		dst_offset += cur_size_in_bytes;
+	}
+
+	r = radeon_fence_emit(rdev, fence, ring->idx);
+	if (r) {
+		radeon_ring_unlock_undo(rdev, ring);
+		return r;
+	}
+
+	radeon_ring_unlock_commit(rdev, ring);
+	radeon_semaphore_free(rdev, &sem, *fence);
+
+	return r;
+}
+
+/**
+ * cik_sdma_ring_test - simple async dma engine test
+ *
+ * @rdev: radeon_device pointer
+ * @ring: radeon_ring structure holding ring information
+ *
+ * Test the DMA engine by writing using it to write an
+ * value to memory. (CIK).
+ * Returns 0 for success, error for failure.
+ */
+int cik_sdma_ring_test(struct radeon_device *rdev,
+		       struct radeon_ring *ring)
+{
+	unsigned i;
+	int r;
+	void __iomem *ptr = (void *)rdev->vram_scratch.ptr;
+	u32 tmp;
+
+	if (!ptr) {
+		DRM_ERROR("invalid vram scratch pointer\n");
+		return -EINVAL;
+	}
+
+	tmp = 0xCAFEDEAD;
+	writel(tmp, ptr);
+
+	r = radeon_ring_lock(rdev, ring, 4);
+	if (r) {
+		DRM_ERROR("radeon: dma failed to lock ring %d (%d).\n", ring->idx, r);
+		return r;
+	}
+	radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_WRITE, SDMA_WRITE_SUB_OPCODE_LINEAR, 0));
+	radeon_ring_write(ring, rdev->vram_scratch.gpu_addr & 0xfffffffc);
+	radeon_ring_write(ring, upper_32_bits(rdev->vram_scratch.gpu_addr) & 0xffffffff);
+	radeon_ring_write(ring, 1); /* number of DWs to follow */
+	radeon_ring_write(ring, 0xDEADBEEF);
+	radeon_ring_unlock_commit(rdev, ring);
+
+	for (i = 0; i < rdev->usec_timeout; i++) {
+		tmp = readl(ptr);
+		if (tmp == 0xDEADBEEF)
+			break;
+		DRM_UDELAY(1);
+	}
+
+	if (i < rdev->usec_timeout) {
+		DRM_INFO("ring test on %d succeeded in %d usecs\n", ring->idx, i);
+	} else {
+		DRM_ERROR("radeon: ring %d test failed (0x%08X)\n",
+			  ring->idx, tmp);
+		r = -EINVAL;
+	}
+	return r;
+}
+
+/**
+ * cik_sdma_ib_test - test an IB on the DMA engine
+ *
+ * @rdev: radeon_device pointer
+ * @ring: radeon_ring structure holding ring information
+ *
+ * Test a simple IB in the DMA ring (CIK).
+ * Returns 0 on success, error on failure.
+ */
+int cik_sdma_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)
+{
+	struct radeon_ib ib;
+	unsigned i;
+	int r;
+	void __iomem *ptr = (void *)rdev->vram_scratch.ptr;
+	u32 tmp = 0;
+
+	if (!ptr) {
+		DRM_ERROR("invalid vram scratch pointer\n");
+		return -EINVAL;
+	}
+
+	tmp = 0xCAFEDEAD;
+	writel(tmp, ptr);
+
+	r = radeon_ib_get(rdev, ring->idx, &ib, NULL, 256);
+	if (r) {
+		DRM_ERROR("radeon: failed to get ib (%d).\n", r);
+		return r;
+	}
+
+	ib.ptr[0] = SDMA_PACKET(SDMA_OPCODE_WRITE, SDMA_WRITE_SUB_OPCODE_LINEAR, 0);
+	ib.ptr[1] = rdev->vram_scratch.gpu_addr & 0xfffffffc;
+	ib.ptr[2] = upper_32_bits(rdev->vram_scratch.gpu_addr) & 0xffffffff;
+	ib.ptr[3] = 1;
+	ib.ptr[4] = 0xDEADBEEF;
+	ib.length_dw = 5;
+
+	r = radeon_ib_schedule(rdev, &ib, NULL);
+	if (r) {
+		radeon_ib_free(rdev, &ib);
+		DRM_ERROR("radeon: failed to schedule ib (%d).\n", r);
+		return r;
+	}
+	r = radeon_fence_wait(ib.fence, false);
+	if (r) {
+		DRM_ERROR("radeon: fence wait failed (%d).\n", r);
+		return r;
+	}
+	for (i = 0; i < rdev->usec_timeout; i++) {
+		tmp = readl(ptr);
+		if (tmp == 0xDEADBEEF)
+			break;
+		DRM_UDELAY(1);
+	}
+	if (i < rdev->usec_timeout) {
+		DRM_INFO("ib test on ring %d succeeded in %u usecs\n", ib.fence->ring, i);
+	} else {
+		DRM_ERROR("radeon: ib test failed (0x%08X)\n", tmp);
+		r = -EINVAL;
+	}
+	radeon_ib_free(rdev, &ib);
+	return r;
+}
+
 /**
  * cik_gpu_is_lockup - check if the 3D engine is locked up
  *
@@ -2330,6 +2925,32 @@ int cik_asic_reset(struct radeon_device *rdev)
 	return cik_gfx_gpu_soft_reset(rdev);
 }
 
+/**
+ * cik_sdma_is_lockup - Check if the DMA engine is locked up
+ *
+ * @rdev: radeon_device pointer
+ * @ring: radeon_ring structure holding ring information
+ *
+ * Check if the async DMA engine is locked up (CIK).
+ * Returns true if the engine appears to be locked up, false if not.
+ */
+bool cik_sdma_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)
+{
+	u32 dma_status_reg;
+
+	if (ring->idx == R600_RING_TYPE_DMA_INDEX)
+		dma_status_reg = RREG32(SDMA0_STATUS_REG + SDMA0_REGISTER_OFFSET);
+	else
+		dma_status_reg = RREG32(SDMA0_STATUS_REG + SDMA1_REGISTER_OFFSET);
+	if (dma_status_reg & SDMA_IDLE) {
+		radeon_ring_lockup_update(ring);
+		return false;
+	}
+	/* force ring activities */
+	radeon_ring_force_activity(rdev, ring);
+	return radeon_ring_test_lockup(rdev, ring);
+}
+
 /* MC */
 /**
  * cik_mc_program - program the GPU memory controller
@@ -2588,10 +3209,17 @@ static int cik_pcie_gart_enable(struct radeon_device *rdev)
 	/* where to put LDS, scratch, GPUVM in FSA64 space */
 	for (i = 0; i < 16; i++) {
 		WREG32(SRBM_GFX_CNTL, VMID(i));
+		/* CP and shaders */
 		WREG32(SH_MEM_CONFIG, 0);
 		WREG32(SH_MEM_APE1_BASE, 1);
 		WREG32(SH_MEM_APE1_LIMIT, 0);
 		WREG32(SH_MEM_BASES, 0);
+		/* SDMA GFX */
+		WREG32(SDMA0_GFX_VIRTUAL_ADDR + SDMA0_REGISTER_OFFSET, 0);
+		WREG32(SDMA0_GFX_APE1_CNTL + SDMA0_REGISTER_OFFSET, 0);
+		WREG32(SDMA0_GFX_VIRTUAL_ADDR + SDMA1_REGISTER_OFFSET, 0);
+		WREG32(SDMA0_GFX_APE1_CNTL + SDMA1_REGISTER_OFFSET, 0);
+		/* XXX SDMA RLC - todo */
 	}
 	WREG32(SRBM_GFX_CNTL, 0);
 
@@ -2992,6 +3620,11 @@ static void cik_disable_interrupt_state(struct radeon_device *rdev)
 
 	/* gfx ring */
 	WREG32(CP_INT_CNTL_RING0, CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE);
+	/* sdma */
+	tmp = RREG32(SDMA0_CNTL + SDMA0_REGISTER_OFFSET) & ~TRAP_ENABLE;
+	WREG32(SDMA0_CNTL + SDMA0_REGISTER_OFFSET, tmp);
+	tmp = RREG32(SDMA0_CNTL + SDMA1_REGISTER_OFFSET) & ~TRAP_ENABLE;
+	WREG32(SDMA0_CNTL + SDMA1_REGISTER_OFFSET, tmp);
 	/* compute queues */
 	WREG32(CP_ME1_PIPE0_INT_CNTL, 0);
 	WREG32(CP_ME1_PIPE1_INT_CNTL, 0);
@@ -3132,6 +3765,7 @@ int cik_irq_set(struct radeon_device *rdev)
 	u32 crtc1 = 0, crtc2 = 0, crtc3 = 0, crtc4 = 0, crtc5 = 0, crtc6 = 0;
 	u32 hpd1, hpd2, hpd3, hpd4, hpd5, hpd6;
 	u32 grbm_int_cntl = 0;
+	u32 dma_cntl, dma_cntl1;
 
 	if (!rdev->irq.installed) {
 		WARN(1, "Can't enable IRQ/MSI because no handler is installed\n");
@@ -3152,6 +3786,9 @@ int cik_irq_set(struct radeon_device *rdev)
 	hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~DC_HPDx_INT_EN;
 	hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~DC_HPDx_INT_EN;
 
+	dma_cntl = RREG32(SDMA0_CNTL + SDMA0_REGISTER_OFFSET) & ~TRAP_ENABLE;
+	dma_cntl1 = RREG32(SDMA0_CNTL + SDMA1_REGISTER_OFFSET) & ~TRAP_ENABLE;
+
 	/* enable CP interrupts on all rings */
 	if (atomic_read(&rdev->irq.ring_int[RADEON_RING_TYPE_GFX_INDEX])) {
 		DRM_DEBUG("cik_irq_set: sw int gfx\n");
@@ -3160,6 +3797,16 @@ int cik_irq_set(struct radeon_device *rdev)
 	/* TODO: compute queues! */
 	/* CP_ME[1-2]_PIPE[0-3]_INT_CNTL */
 
+	if (atomic_read(&rdev->irq.ring_int[R600_RING_TYPE_DMA_INDEX])) {
+		DRM_DEBUG("cik_irq_set: sw int dma\n");
+		dma_cntl |= TRAP_ENABLE;
+	}
+
+	if (atomic_read(&rdev->irq.ring_int[CAYMAN_RING_TYPE_DMA1_INDEX])) {
+		DRM_DEBUG("cik_irq_set: sw int dma1\n");
+		dma_cntl1 |= TRAP_ENABLE;
+	}
+
 	if (rdev->irq.crtc_vblank_int[0] ||
 	    atomic_read(&rdev->irq.pflip[0])) {
 		DRM_DEBUG("cik_irq_set: vblank 0\n");
@@ -3217,6 +3864,9 @@ int cik_irq_set(struct radeon_device *rdev)
 
 	WREG32(CP_INT_CNTL_RING0, cp_int_cntl);
 
+	WREG32(SDMA0_CNTL + SDMA0_REGISTER_OFFSET, dma_cntl);
+	WREG32(SDMA0_CNTL + SDMA1_REGISTER_OFFSET, dma_cntl1);
+
 	WREG32(GRBM_INT_CNTL, grbm_int_cntl);
 
 	WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, crtc1);
@@ -3410,12 +4060,18 @@ static inline u32 cik_get_ih_wptr(struct radeon_device *rdev)
  * [31:8]   - reserved
  * [59:32]  - interrupt source data
  * [63:60]  - reserved
- * [71:64]  - RINGID: ME_ID [1:0], PIPE_ID[1:0], QUEUE_ID[2:0]
+ * [71:64]  - RINGID
+ *            CP:
+ *            ME_ID [1:0], PIPE_ID[1:0], QUEUE_ID[2:0]
  *            QUEUE_ID - for compute, which of the 8 queues owned by the dispatcher
  *                     - for gfx, hw shader state (0=PS...5=LS, 6=CS)
  *            ME_ID - 0 = gfx, 1 = first 4 CS pipes, 2 = second 4 CS pipes
  *            PIPE_ID - ME0 0=3D
  *                    - ME1&2 compute dispatcher (4 pipes each)
+ *            SDMA:
+ *            INSTANCE_ID [1:0], QUEUE_ID[1:0]
+ *            INSTANCE_ID - 0 = sdma0, 1 = sdma1
+ *            QUEUE_ID - 0 = gfx, 1 = rlc0, 2 = rlc1
  * [79:72]  - VMID
  * [95:80]  - PASID
  * [127:96] - reserved
@@ -3465,10 +4121,6 @@ restart_ih:
 		src_id =  le32_to_cpu(rdev->ih.ring[ring_index]) & 0xff;
 		src_data = le32_to_cpu(rdev->ih.ring[ring_index + 1]) & 0xfffffff;
 		ring_id = le32_to_cpu(rdev->ih.ring[ring_index + 2]) & 0xff;
-		/* XXX check the bitfield order! */
-		me_id = (ring_id & 0x60) >> 5;
-		pipe_id = (ring_id & 0x18) >> 3;
-		queue_id = (ring_id & 0x7) >> 0;
 
 		switch (src_id) {
 		case 1: /* D1 vblank/vline */
@@ -3692,6 +4344,10 @@ restart_ih:
 			break;
 		case 181: /* CP EOP event */
 			DRM_DEBUG("IH: CP EOP\n");
+			/* XXX check the bitfield order! */
+			me_id = (ring_id & 0x60) >> 5;
+			pipe_id = (ring_id & 0x18) >> 3;
+			queue_id = (ring_id & 0x7) >> 0;
 			switch (me_id) {
 			case 0:
 				radeon_fence_process(rdev, RADEON_RING_TYPE_GFX_INDEX);
@@ -3727,6 +4383,10 @@ restart_ih:
 			break;
 		case 185: /* CP Privileged inst */
 			DRM_ERROR("Illegal instruction in command stream\n");
+			/* XXX check the bitfield order! */
+			me_id = (ring_id & 0x60) >> 5;
+			pipe_id = (ring_id & 0x18) >> 3;
+			queue_id = (ring_id & 0x7) >> 0;
 			switch (me_id) {
 			case 0:
 				/* This results in a full GPU reset, but all we need to do is soft
@@ -3742,6 +4402,79 @@ restart_ih:
 				break;
 			}
 			break;
+		case 224: /* SDMA trap event */
+			/* XXX check the bitfield order! */
+			me_id = (ring_id & 0x3) >> 0;
+			queue_id = (ring_id & 0xc) >> 2;
+			DRM_DEBUG("IH: SDMA trap\n");
+			switch (me_id) {
+			case 0:
+				switch (queue_id) {
+				case 0:
+					radeon_fence_process(rdev, R600_RING_TYPE_DMA_INDEX);
+					break;
+				case 1:
+					/* XXX compute */
+					break;
+				case 2:
+					/* XXX compute */
+					break;
+				}
+				break;
+			case 1:
+				switch (queue_id) {
+				case 0:
+					radeon_fence_process(rdev, CAYMAN_RING_TYPE_DMA1_INDEX);
+					break;
+				case 1:
+					/* XXX compute */
+					break;
+				case 2:
+					/* XXX compute */
+					break;
+				}
+				break;
+			}
+			break;
+		case 241: /* SDMA Privileged inst */
+		case 247: /* SDMA Privileged inst */
+			DRM_ERROR("Illegal instruction in SDMA command stream\n");
+			/* XXX check the bitfield order! */
+			me_id = (ring_id & 0x3) >> 0;
+			queue_id = (ring_id & 0xc) >> 2;
+			switch (me_id) {
+			case 0:
+				switch (queue_id) {
+				case 0:
+					queue_reset = true;
+					break;
+				case 1:
+					/* XXX compute */
+					queue_reset = true;
+					break;
+				case 2:
+					/* XXX compute */
+					queue_reset = true;
+					break;
+				}
+				break;
+			case 1:
+				switch (queue_id) {
+				case 0:
+					queue_reset = true;
+					break;
+				case 1:
+					/* XXX compute */
+					queue_reset = true;
+					break;
+				case 2:
+					/* XXX compute */
+					queue_reset = true;
+					break;
+				}
+				break;
+			}
+			break;
 		case 233: /* GUI IDLE */
 			DRM_DEBUG("IH: GUI idle\n");
 			break;
diff --git a/drivers/gpu/drm/radeon/cikd.h b/drivers/gpu/drm/radeon/cikd.h
index cc4f28e..39ed517 100644
--- a/drivers/gpu/drm/radeon/cikd.h
+++ b/drivers/gpu/drm/radeon/cikd.h
@@ -42,6 +42,24 @@
 #define	SRBM_STATUS2				        0xE4C
 #define	SRBM_STATUS				        0xE50
 
+#define	SRBM_SOFT_RESET				        0xE60
+#define		SOFT_RESET_BIF				(1 << 1)
+#define		SOFT_RESET_R0PLL			(1 << 4)
+#define		SOFT_RESET_DC				(1 << 5)
+#define		SOFT_RESET_SDMA1			(1 << 6)
+#define		SOFT_RESET_GRBM				(1 << 8)
+#define		SOFT_RESET_HDP				(1 << 9)
+#define		SOFT_RESET_IH				(1 << 10)
+#define		SOFT_RESET_MC				(1 << 11)
+#define		SOFT_RESET_ROM				(1 << 14)
+#define		SOFT_RESET_SEM				(1 << 15)
+#define		SOFT_RESET_VMC				(1 << 17)
+#define		SOFT_RESET_SDMA				(1 << 20)
+#define		SOFT_RESET_TST				(1 << 21)
+#define		SOFT_RESET_REGBB		       	(1 << 22)
+#define		SOFT_RESET_ORB				(1 << 23)
+#define		SOFT_RESET_VCE				(1 << 24)
+
 #define VM_L2_CNTL					0x1400
 #define		ENABLE_L2_CACHE					(1 << 0)
 #define		ENABLE_L2_FRAGMENT_PROCESSING			(1 << 1)
@@ -1039,4 +1057,116 @@
 #define	PACKET3_WAIT_ON_DE_COUNTER_DIFF			0x88
 #define	PACKET3_SWITCH_BUFFER				0x8B
 
+/* SDMA - first instance at 0xd000, second at 0xd800 */
+#define SDMA0_REGISTER_OFFSET                             0x0 /* not a register */
+#define SDMA1_REGISTER_OFFSET                             0x800 /* not a register */
+
+#define	SDMA0_UCODE_ADDR                                  0xD000
+#define	SDMA0_UCODE_DATA                                  0xD004
+
+#define SDMA0_CNTL                                        0xD010
+#       define TRAP_ENABLE                                (1 << 0)
+#       define SEM_INCOMPLETE_INT_ENABLE                  (1 << 1)
+#       define SEM_WAIT_INT_ENABLE                        (1 << 2)
+#       define DATA_SWAP_ENABLE                           (1 << 3)
+#       define FENCE_SWAP_ENABLE                          (1 << 4)
+#       define AUTO_CTXSW_ENABLE                          (1 << 18)
+#       define CTXEMPTY_INT_ENABLE                        (1 << 28)
+
+#define SDMA0_TILING_CONFIG  				  0xD018
+
+#define SDMA0_SEM_INCOMPLETE_TIMER_CNTL                   0xD020
+#define SDMA0_SEM_WAIT_FAIL_TIMER_CNTL                    0xD024
+
+#define SDMA0_STATUS_REG                                  0xd034
+#       define SDMA_IDLE                                  (1 << 0)
+
+#define SDMA0_ME_CNTL                                     0xD048
+#       define SDMA_HALT                                  (1 << 0)
+
+#define SDMA0_GFX_RB_CNTL                                 0xD200
+#       define SDMA_RB_ENABLE                             (1 << 0)
+#       define SDMA_RB_SIZE(x)                            ((x) << 1) /* log2 */
+#       define SDMA_RB_SWAP_ENABLE                        (1 << 9) /* 8IN32 */
+#       define SDMA_RPTR_WRITEBACK_ENABLE                 (1 << 12)
+#       define SDMA_RPTR_WRITEBACK_SWAP_ENABLE            (1 << 13)  /* 8IN32 */
+#       define SDMA_RPTR_WRITEBACK_TIMER(x)               ((x) << 16) /* log2 */
+#define SDMA0_GFX_RB_BASE                                 0xD204
+#define SDMA0_GFX_RB_BASE_HI                              0xD208
+#define SDMA0_GFX_RB_RPTR                                 0xD20C
+#define SDMA0_GFX_RB_WPTR                                 0xD210
+
+#define SDMA0_GFX_RB_RPTR_ADDR_HI                         0xD220
+#define SDMA0_GFX_RB_RPTR_ADDR_LO                         0xD224
+#define SDMA0_GFX_IB_CNTL                                 0xD228
+#       define SDMA_IB_ENABLE                             (1 << 0)
+#       define SDMA_IB_SWAP_ENABLE                        (1 << 4)
+#       define SDMA_SWITCH_INSIDE_IB                      (1 << 8)
+#       define SDMA_CMD_VMID(x)                           ((x) << 16)
+
+#define SDMA0_GFX_VIRTUAL_ADDR                            0xD29C
+#define SDMA0_GFX_APE1_CNTL                               0xD2A0
+
+#define SDMA_PACKET(op, sub_op, e)	((((e) & 0xFFFF) << 16) |	\
+					 (((sub_op) & 0xFF) << 8) |	\
+					 (((op) & 0xFF) << 0))
+/* sDMA opcodes */
+#define	SDMA_OPCODE_NOP					  0
+#define	SDMA_OPCODE_COPY				  1
+#       define SDMA_COPY_SUB_OPCODE_LINEAR                0
+#       define SDMA_COPY_SUB_OPCODE_TILED                 1
+#       define SDMA_COPY_SUB_OPCODE_SOA                   3
+#       define SDMA_COPY_SUB_OPCODE_LINEAR_SUB_WINDOW     4
+#       define SDMA_COPY_SUB_OPCODE_TILED_SUB_WINDOW      5
+#       define SDMA_COPY_SUB_OPCODE_T2T_SUB_WINDOW        6
+#define	SDMA_OPCODE_WRITE				  2
+#       define SDMA_WRITE_SUB_OPCODE_LINEAR               0
+#       define SDMA_WRTIE_SUB_OPCODE_TILED                1
+#define	SDMA_OPCODE_INDIRECT_BUFFER			  4
+#define	SDMA_OPCODE_FENCE				  5
+#define	SDMA_OPCODE_TRAP				  6
+#define	SDMA_OPCODE_SEMAPHORE				  7
+#       define SDMA_SEMAPHORE_EXTRA_O                     (1 << 13)
+                /* 0 - increment
+		 * 1 - write 1
+		 */
+#       define SDMA_SEMAPHORE_EXTRA_S                     (1 << 14)
+                /* 0 - wait
+		 * 1 - signal
+		 */
+#       define SDMA_SEMAPHORE_EXTRA_M                     (1 << 15)
+                /* mailbox */
+#define	SDMA_OPCODE_POLL_REG_MEM			  8
+#       define SDMA_POLL_REG_MEM_EXTRA_OP(x)              ((x) << 10)
+                /* 0 - wait_reg_mem
+		 * 1 - wr_wait_wr_reg
+		 */
+#       define SDMA_POLL_REG_MEM_EXTRA_FUNC(x)            ((x) << 12)
+                /* 0 - always
+		 * 1 - <
+		 * 2 - <=
+		 * 3 - ==
+		 * 4 - !=
+		 * 5 - >=
+		 * 6 - >
+		 */
+#       define SDMA_POLL_REG_MEM_EXTRA_M                  (1 << 15)
+                /* 0 = register
+		 * 1 = memory
+		 */
+#define	SDMA_OPCODE_COND_EXEC				  9
+#define	SDMA_OPCODE_CONSTANT_FILL			  11
+#       define SDMA_CONSTANT_FILL_EXTRA_SIZE(x)           ((x) << 14)
+                /* 0 = byte fill
+		 * 2 = DW fill
+		 */
+#define	SDMA_OPCODE_GENERATE_PTE_PDE			  12
+#define	SDMA_OPCODE_TIMESTAMP				  13
+#       define SDMA_TIMESTAMP_SUB_OPCODE_SET_LOCAL        0
+#       define SDMA_TIMESTAMP_SUB_OPCODE_GET_LOCAL        1
+#       define SDMA_TIMESTAMP_SUB_OPCODE_GET_GLOBAL       2
+#define	SDMA_OPCODE_SRBM_WRITE				  14
+#       define SDMA_SRBM_WRITE_EXTRA_BYTE_ENABLE(x)       ((x) << 12)
+                /* byte mask */
+
 #endif
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index e09157b..919c4d8 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -1726,6 +1726,7 @@ struct radeon_device {
 	const struct firmware *ce_fw;	/* SI CE firmware */
 	const struct firmware *uvd_fw;	/* UVD firmware */
 	const struct firmware *mec_fw;	/* CIK MEC firmware */
+	const struct firmware *sdma_fw;	/* CIK SDMA firmware */
 	struct r600_blit r600_blit;
 	struct r600_vram_scratch vram_scratch;
 	int msi_enabled; /* msi enabled */
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 021/165] drm/radeon: implement async vm_flush for the sDMA (v6)
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (20 preceding siblings ...)
  2013-06-26 13:21 ` [PATCH 020/165] drm/radeon/cik: add support for sDMA dma engines (v8) alexdeucher
@ 2013-06-26 13:21 ` alexdeucher
  2013-06-26 13:21 ` [PATCH 022/165] drm/radeon/cik: add support for doing async VM pt updates (v5) alexdeucher
                   ` (91 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:21 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Update the page table base address and flush the
VM TLB using the sDMA.

V2: update for 2 level PTs
V3: update vm flush
V4: update SH_MEM* regs
V5: switch back to old style VM TLB invalidate
V6: fix packet formatting

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/cik.c |   70 ++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 70 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
index 931169e..3c18a63 100644
--- a/drivers/gpu/drm/radeon/cik.c
+++ b/drivers/gpu/drm/radeon/cik.c
@@ -3407,6 +3407,76 @@ void cik_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
 	radeon_ring_write(ring, 0x0);
 }
 
+/**
+ * cik_dma_vm_flush - cik vm flush using sDMA
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Update the page table base and flush the VM TLB
+ * using sDMA (CIK).
+ */
+void cik_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
+{
+	struct radeon_ring *ring = &rdev->ring[ridx];
+	u32 extra_bits = (SDMA_POLL_REG_MEM_EXTRA_OP(1) |
+			  SDMA_POLL_REG_MEM_EXTRA_FUNC(3)); /* == */
+	u32 ref_and_mask;
+
+	if (vm == NULL)
+		return;
+
+	if (ridx == R600_RING_TYPE_DMA_INDEX)
+		ref_and_mask = SDMA0;
+	else
+		ref_and_mask = SDMA1;
+
+	radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000));
+	if (vm->id < 8) {
+		radeon_ring_write(ring, (VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm->id << 2)) >> 2);
+	} else {
+		radeon_ring_write(ring, (VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((vm->id - 8) << 2)) >> 2);
+	}
+	radeon_ring_write(ring, vm->pd_gpu_addr >> 12);
+
+	/* update SH_MEM_* regs */
+	radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000));
+	radeon_ring_write(ring, SRBM_GFX_CNTL >> 2);
+	radeon_ring_write(ring, VMID(vm->id));
+
+	radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000));
+	radeon_ring_write(ring, SH_MEM_BASES >> 2);
+	radeon_ring_write(ring, 0);
+
+	radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000));
+	radeon_ring_write(ring, SH_MEM_CONFIG >> 2);
+	radeon_ring_write(ring, 0);
+
+	radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000));
+	radeon_ring_write(ring, SH_MEM_APE1_BASE >> 2);
+	radeon_ring_write(ring, 1);
+
+	radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000));
+	radeon_ring_write(ring, SH_MEM_APE1_LIMIT >> 2);
+	radeon_ring_write(ring, 0);
+
+	radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000));
+	radeon_ring_write(ring, SRBM_GFX_CNTL >> 2);
+	radeon_ring_write(ring, VMID(0));
+
+	/* flush HDP */
+	radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_POLL_REG_MEM, 0, extra_bits));
+	radeon_ring_write(ring, GPU_HDP_FLUSH_DONE);
+	radeon_ring_write(ring, GPU_HDP_FLUSH_REQ);
+	radeon_ring_write(ring, ref_and_mask); /* REFERENCE */
+	radeon_ring_write(ring, ref_and_mask); /* MASK */
+	radeon_ring_write(ring, (4 << 16) | 10); /* RETRY_COUNT, POLL_INTERVAL */
+
+	/* flush TLB */
+	radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000));
+	radeon_ring_write(ring, VM_INVALIDATE_REQUEST >> 2);
+	radeon_ring_write(ring, 1 << vm->id);
+}
+
 /*
  * RLC
  * The RLC is a multi-purpose microengine that handles a
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 022/165] drm/radeon/cik: add support for doing async VM pt updates (v5)
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (21 preceding siblings ...)
  2013-06-26 13:21 ` [PATCH 021/165] drm/radeon: implement async vm_flush for the sDMA (v6) alexdeucher
@ 2013-06-26 13:21 ` alexdeucher
  2013-06-26 13:21 ` [PATCH 023/165] drm/radeon/cik: fill in startup/shutdown callbacks (v4) alexdeucher
                   ` (90 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:21 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Async page table updates using the sDMA engine.  sDMA has a
special packet for updating entries for contiguous pages
that reduces overhead.

v2: add support for and use the CP for now.
v3: update for 2 level PTs
v4: rebase, fix DMA packet
v5: switch to using an IB

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/cik.c |  109 ++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 109 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
index 3c18a63..cf1e0b1 100644
--- a/drivers/gpu/drm/radeon/cik.c
+++ b/drivers/gpu/drm/radeon/cik.c
@@ -3408,6 +3408,115 @@ void cik_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
 }
 
 /**
+ * cik_vm_set_page - update the page tables using sDMA
+ *
+ * @rdev: radeon_device pointer
+ * @ib: indirect buffer to fill with commands
+ * @pe: addr of the page entry
+ * @addr: dst addr to write into pe
+ * @count: number of page entries to update
+ * @incr: increase next addr by incr bytes
+ * @flags: access flags
+ *
+ * Update the page tables using CP or sDMA (CIK).
+ */
+void cik_vm_set_page(struct radeon_device *rdev,
+		     struct radeon_ib *ib,
+		     uint64_t pe,
+		     uint64_t addr, unsigned count,
+		     uint32_t incr, uint32_t flags)
+{
+	uint32_t r600_flags = cayman_vm_page_flags(rdev, flags);
+	uint64_t value;
+	unsigned ndw;
+
+	if (rdev->asic->vm.pt_ring_index == RADEON_RING_TYPE_GFX_INDEX) {
+		/* CP */
+		while (count) {
+			ndw = 2 + count * 2;
+			if (ndw > 0x3FFE)
+				ndw = 0x3FFE;
+
+			ib->ptr[ib->length_dw++] = PACKET3(PACKET3_WRITE_DATA, ndw);
+			ib->ptr[ib->length_dw++] = (WRITE_DATA_ENGINE_SEL(0) |
+						    WRITE_DATA_DST_SEL(1));
+			ib->ptr[ib->length_dw++] = pe;
+			ib->ptr[ib->length_dw++] = upper_32_bits(pe);
+			for (; ndw > 2; ndw -= 2, --count, pe += 8) {
+				if (flags & RADEON_VM_PAGE_SYSTEM) {
+					value = radeon_vm_map_gart(rdev, addr);
+					value &= 0xFFFFFFFFFFFFF000ULL;
+				} else if (flags & RADEON_VM_PAGE_VALID) {
+					value = addr;
+				} else {
+					value = 0;
+				}
+				addr += incr;
+				value |= r600_flags;
+				ib->ptr[ib->length_dw++] = value;
+				ib->ptr[ib->length_dw++] = upper_32_bits(value);
+			}
+		}
+	} else {
+		/* DMA */
+		if (flags & RADEON_VM_PAGE_SYSTEM) {
+			while (count) {
+				ndw = count * 2;
+				if (ndw > 0xFFFFE)
+					ndw = 0xFFFFE;
+
+				/* for non-physically contiguous pages (system) */
+				ib->ptr[ib->length_dw++] = SDMA_PACKET(SDMA_OPCODE_WRITE, SDMA_WRITE_SUB_OPCODE_LINEAR, 0);
+				ib->ptr[ib->length_dw++] = pe;
+				ib->ptr[ib->length_dw++] = upper_32_bits(pe);
+				ib->ptr[ib->length_dw++] = ndw;
+				for (; ndw > 0; ndw -= 2, --count, pe += 8) {
+					if (flags & RADEON_VM_PAGE_SYSTEM) {
+						value = radeon_vm_map_gart(rdev, addr);
+						value &= 0xFFFFFFFFFFFFF000ULL;
+					} else if (flags & RADEON_VM_PAGE_VALID) {
+						value = addr;
+					} else {
+						value = 0;
+					}
+					addr += incr;
+					value |= r600_flags;
+					ib->ptr[ib->length_dw++] = value;
+					ib->ptr[ib->length_dw++] = upper_32_bits(value);
+				}
+			}
+		} else {
+			while (count) {
+				ndw = count;
+				if (ndw > 0x7FFFF)
+					ndw = 0x7FFFF;
+
+				if (flags & RADEON_VM_PAGE_VALID)
+					value = addr;
+				else
+					value = 0;
+				/* for physically contiguous pages (vram) */
+				ib->ptr[ib->length_dw++] = SDMA_PACKET(SDMA_OPCODE_GENERATE_PTE_PDE, 0, 0);
+				ib->ptr[ib->length_dw++] = pe; /* dst addr */
+				ib->ptr[ib->length_dw++] = upper_32_bits(pe);
+				ib->ptr[ib->length_dw++] = r600_flags; /* mask */
+				ib->ptr[ib->length_dw++] = 0;
+				ib->ptr[ib->length_dw++] = value; /* value */
+				ib->ptr[ib->length_dw++] = upper_32_bits(value);
+				ib->ptr[ib->length_dw++] = incr; /* increment size */
+				ib->ptr[ib->length_dw++] = 0;
+				ib->ptr[ib->length_dw++] = ndw; /* number of entries */
+				pe += ndw * 8;
+				addr += ndw * incr;
+				count -= ndw;
+			}
+		}
+		while (ib->length_dw & 0x7)
+			ib->ptr[ib->length_dw++] = SDMA_PACKET(SDMA_OPCODE_NOP, 0, 0);
+	}
+}
+
+/**
  * cik_dma_vm_flush - cik vm flush using sDMA
  *
  * @rdev: radeon_device pointer
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 023/165] drm/radeon/cik: fill in startup/shutdown callbacks (v4)
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (22 preceding siblings ...)
  2013-06-26 13:21 ` [PATCH 022/165] drm/radeon/cik: add support for doing async VM pt updates (v5) alexdeucher
@ 2013-06-26 13:21 ` alexdeucher
  2013-06-26 15:03   ` Christian König
  2013-06-26 13:21 ` [PATCH 024/165] drm/radeon: upstream ObjectID.h updates (v2) alexdeucher
                   ` (89 subsequent siblings)
  113 siblings, 1 reply; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:21 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

v2: update to latest driver changes
v3: properly tear down vm on suspend
v4: fix up irq init ordering

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/cik.c |  340 ++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 340 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
index cf1e0b1..cbc64a2 100644
--- a/drivers/gpu/drm/radeon/cik.c
+++ b/drivers/gpu/drm/radeon/cik.c
@@ -73,6 +73,8 @@ extern void r600_ih_ring_fini(struct radeon_device *rdev);
 extern void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save);
 extern void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save);
 extern void si_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc);
+extern void si_rlc_fini(struct radeon_device *rdev);
+extern int si_rlc_init(struct radeon_device *rdev);
 
 #define BONAIRE_IO_MC_REGS_SIZE 36
 
@@ -4681,3 +4683,341 @@ restart_ih:
 
 	return IRQ_HANDLED;
 }
+
+/*
+ * startup/shutdown callbacks
+ */
+/**
+ * cik_startup - program the asic to a functional state
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Programs the asic to a functional state (CIK).
+ * Called by cik_init() and cik_resume().
+ * Returns 0 for success, error for failure.
+ */
+static int cik_startup(struct radeon_device *rdev)
+{
+	struct radeon_ring *ring;
+	int r;
+
+	if (rdev->flags & RADEON_IS_IGP) {
+		if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw ||
+		    !rdev->mec_fw || !rdev->sdma_fw || !rdev->rlc_fw) {
+			r = cik_init_microcode(rdev);
+			if (r) {
+				DRM_ERROR("Failed to load firmware!\n");
+				return r;
+			}
+		}
+	} else {
+		if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw ||
+		    !rdev->mec_fw || !rdev->sdma_fw || !rdev->rlc_fw ||
+		    !rdev->mc_fw) {
+			r = cik_init_microcode(rdev);
+			if (r) {
+				DRM_ERROR("Failed to load firmware!\n");
+				return r;
+			}
+		}
+
+		r = ci_mc_load_microcode(rdev);
+		if (r) {
+			DRM_ERROR("Failed to load MC firmware!\n");
+			return r;
+		}
+	}
+
+	r = r600_vram_scratch_init(rdev);
+	if (r)
+		return r;
+
+	cik_mc_program(rdev);
+	r = cik_pcie_gart_enable(rdev);
+	if (r)
+		return r;
+	cik_gpu_init(rdev);
+
+	/* allocate rlc buffers */
+	r = si_rlc_init(rdev);
+	if (r) {
+		DRM_ERROR("Failed to init rlc BOs!\n");
+		return r;
+	}
+
+	/* allocate wb buffer */
+	r = radeon_wb_init(rdev);
+	if (r)
+		return r;
+
+	r = radeon_fence_driver_start_ring(rdev, RADEON_RING_TYPE_GFX_INDEX);
+	if (r) {
+		dev_err(rdev->dev, "failed initializing CP fences (%d).\n", r);
+		return r;
+	}
+
+	r = radeon_fence_driver_start_ring(rdev, R600_RING_TYPE_DMA_INDEX);
+	if (r) {
+		dev_err(rdev->dev, "failed initializing DMA fences (%d).\n", r);
+		return r;
+	}
+
+	r = radeon_fence_driver_start_ring(rdev, CAYMAN_RING_TYPE_DMA1_INDEX);
+	if (r) {
+		dev_err(rdev->dev, "failed initializing DMA fences (%d).\n", r);
+		return r;
+	}
+
+	/* Enable IRQ */
+	if (!rdev->irq.installed) {
+		r = radeon_irq_kms_init(rdev);
+		if (r)
+			return r;
+	}
+
+	r = cik_irq_init(rdev);
+	if (r) {
+		DRM_ERROR("radeon: IH init failed (%d).\n", r);
+		radeon_irq_kms_fini(rdev);
+		return r;
+	}
+	cik_irq_set(rdev);
+
+	ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
+	r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP_RPTR_OFFSET,
+			     CP_RB0_RPTR, CP_RB0_WPTR,
+			     0, 0xfffff, RADEON_CP_PACKET2);
+	if (r)
+		return r;
+
+	ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX];
+	r = radeon_ring_init(rdev, ring, ring->ring_size, R600_WB_DMA_RPTR_OFFSET,
+			     SDMA0_GFX_RB_RPTR + SDMA0_REGISTER_OFFSET,
+			     SDMA0_GFX_RB_WPTR + SDMA0_REGISTER_OFFSET,
+			     2, 0xfffffffc, SDMA_PACKET(SDMA_OPCODE_NOP, 0, 0));
+	if (r)
+		return r;
+
+	ring = &rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX];
+	r = radeon_ring_init(rdev, ring, ring->ring_size, CAYMAN_WB_DMA1_RPTR_OFFSET,
+			     SDMA0_GFX_RB_RPTR + SDMA1_REGISTER_OFFSET,
+			     SDMA0_GFX_RB_WPTR + SDMA1_REGISTER_OFFSET,
+			     2, 0xfffffffc, SDMA_PACKET(SDMA_OPCODE_NOP, 0, 0));
+	if (r)
+		return r;
+
+	r = cik_cp_resume(rdev);
+	if (r)
+		return r;
+
+	r = cik_sdma_resume(rdev);
+	if (r)
+		return r;
+
+	r = radeon_ib_pool_init(rdev);
+	if (r) {
+		dev_err(rdev->dev, "IB initialization failed (%d).\n", r);
+		return r;
+	}
+
+	r = radeon_vm_manager_init(rdev);
+	if (r) {
+		dev_err(rdev->dev, "vm manager initialization failed (%d).\n", r);
+		return r;
+	}
+
+	return 0;
+}
+
+/**
+ * cik_resume - resume the asic to a functional state
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Programs the asic to a functional state (CIK).
+ * Called at resume.
+ * Returns 0 for success, error for failure.
+ */
+int cik_resume(struct radeon_device *rdev)
+{
+	int r;
+
+	/* Do not reset GPU before posting, on rv770 hw unlike on r500 hw,
+	 * posting will perform necessary task to bring back GPU into good
+	 * shape.
+	 */
+	/* post card */
+	atom_asic_init(rdev->mode_info.atom_context);
+
+	rdev->accel_working = true;
+	r = cik_startup(rdev);
+	if (r) {
+		DRM_ERROR("cik startup failed on resume\n");
+		rdev->accel_working = false;
+		return r;
+	}
+
+	return r;
+
+}
+
+/**
+ * cik_suspend - suspend the asic
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Bring the chip into a state suitable for suspend (CIK).
+ * Called at suspend.
+ * Returns 0 for success.
+ */
+int cik_suspend(struct radeon_device *rdev)
+{
+	radeon_vm_manager_fini(rdev);
+	cik_cp_enable(rdev, false);
+	cik_sdma_enable(rdev, false);
+	cik_irq_suspend(rdev);
+	radeon_wb_disable(rdev);
+	cik_pcie_gart_disable(rdev);
+	return 0;
+}
+
+/* Plan is to move initialization in that function and use
+ * helper function so that radeon_device_init pretty much
+ * do nothing more than calling asic specific function. This
+ * should also allow to remove a bunch of callback function
+ * like vram_info.
+ */
+/**
+ * cik_init - asic specific driver and hw init
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Setup asic specific driver variables and program the hw
+ * to a functional state (CIK).
+ * Called at driver startup.
+ * Returns 0 for success, errors for failure.
+ */
+int cik_init(struct radeon_device *rdev)
+{
+	struct radeon_ring *ring;
+	int r;
+
+	/* Read BIOS */
+	if (!radeon_get_bios(rdev)) {
+		if (ASIC_IS_AVIVO(rdev))
+			return -EINVAL;
+	}
+	/* Must be an ATOMBIOS */
+	if (!rdev->is_atom_bios) {
+		dev_err(rdev->dev, "Expecting atombios for cayman GPU\n");
+		return -EINVAL;
+	}
+	r = radeon_atombios_init(rdev);
+	if (r)
+		return r;
+
+	/* Post card if necessary */
+	if (!radeon_card_posted(rdev)) {
+		if (!rdev->bios) {
+			dev_err(rdev->dev, "Card not posted and no BIOS - ignoring\n");
+			return -EINVAL;
+		}
+		DRM_INFO("GPU not posted. posting now...\n");
+		atom_asic_init(rdev->mode_info.atom_context);
+	}
+	/* Initialize scratch registers */
+	cik_scratch_init(rdev);
+	/* Initialize surface registers */
+	radeon_surface_init(rdev);
+	/* Initialize clocks */
+	radeon_get_clock_info(rdev->ddev);
+
+	/* Fence driver */
+	r = radeon_fence_driver_init(rdev);
+	if (r)
+		return r;
+
+	/* initialize memory controller */
+	r = cik_mc_init(rdev);
+	if (r)
+		return r;
+	/* Memory manager */
+	r = radeon_bo_init(rdev);
+	if (r)
+		return r;
+
+	ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
+	ring->ring_obj = NULL;
+	r600_ring_init(rdev, ring, 1024 * 1024);
+
+	ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX];
+	ring->ring_obj = NULL;
+	r600_ring_init(rdev, ring, 256 * 1024);
+
+	ring = &rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX];
+	ring->ring_obj = NULL;
+	r600_ring_init(rdev, ring, 256 * 1024);
+
+	rdev->ih.ring_obj = NULL;
+	r600_ih_ring_init(rdev, 64 * 1024);
+
+	r = r600_pcie_gart_init(rdev);
+	if (r)
+		return r;
+
+	rdev->accel_working = true;
+	r = cik_startup(rdev);
+	if (r) {
+		dev_err(rdev->dev, "disabling GPU acceleration\n");
+		cik_cp_fini(rdev);
+		cik_sdma_fini(rdev);
+		cik_irq_fini(rdev);
+		si_rlc_fini(rdev);
+		radeon_wb_fini(rdev);
+		radeon_ib_pool_fini(rdev);
+		radeon_vm_manager_fini(rdev);
+		radeon_irq_kms_fini(rdev);
+		cik_pcie_gart_fini(rdev);
+		rdev->accel_working = false;
+	}
+
+	/* Don't start up if the MC ucode is missing.
+	 * The default clocks and voltages before the MC ucode
+	 * is loaded are not suffient for advanced operations.
+	 */
+	if (!rdev->mc_fw && !(rdev->flags & RADEON_IS_IGP)) {
+		DRM_ERROR("radeon: MC ucode required for NI+.\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * cik_fini - asic specific driver and hw fini
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Tear down the asic specific driver variables and program the hw
+ * to an idle state (CIK).
+ * Called at driver unload.
+ */
+void cik_fini(struct radeon_device *rdev)
+{
+	cik_cp_fini(rdev);
+	cik_sdma_fini(rdev);
+	cik_irq_fini(rdev);
+	si_rlc_fini(rdev);
+	radeon_wb_fini(rdev);
+	radeon_vm_manager_fini(rdev);
+	radeon_ib_pool_fini(rdev);
+	radeon_irq_kms_fini(rdev);
+	cik_pcie_gart_fini(rdev);
+	r600_vram_scratch_fini(rdev);
+	radeon_gem_fini(rdev);
+	radeon_fence_driver_fini(rdev);
+	radeon_bo_fini(rdev);
+	radeon_atombios_fini(rdev);
+	kfree(rdev->bios);
+	rdev->bios = NULL;
+}
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 024/165] drm/radeon: upstream ObjectID.h updates (v2)
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (23 preceding siblings ...)
  2013-06-26 13:21 ` [PATCH 023/165] drm/radeon/cik: fill in startup/shutdown callbacks (v4) alexdeucher
@ 2013-06-26 13:21 ` alexdeucher
  2013-06-26 13:21 ` [PATCH 025/165] drm/radeon: upstream atombios.h " alexdeucher
                   ` (88 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:21 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

v2: further updates

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/ObjectID.h |   40 +++++++++++++++++++++++++++++++++++++
 1 files changed, 40 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/radeon/ObjectID.h b/drivers/gpu/drm/radeon/ObjectID.h
index ca4b038..0619269 100644
--- a/drivers/gpu/drm/radeon/ObjectID.h
+++ b/drivers/gpu/drm/radeon/ObjectID.h
@@ -69,6 +69,8 @@
 #define ENCODER_OBJECT_ID_ALMOND                  0x22
 #define ENCODER_OBJECT_ID_TRAVIS                  0x23
 #define ENCODER_OBJECT_ID_NUTMEG                  0x22
+#define ENCODER_OBJECT_ID_HDMI_ANX9805            0x26
+
 /* Kaleidoscope (KLDSCP) Class Display Hardware (internal) */
 #define ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1   0x13
 #define ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1    0x14
@@ -86,6 +88,8 @@
 #define ENCODER_OBJECT_ID_INTERNAL_UNIPHY1        0x20
 #define ENCODER_OBJECT_ID_INTERNAL_UNIPHY2        0x21
 #define ENCODER_OBJECT_ID_INTERNAL_VCE            0x24
+#define ENCODER_OBJECT_ID_INTERNAL_UNIPHY3        0x25
+#define ENCODER_OBJECT_ID_INTERNAL_AMCLK          0x27
 
 #define ENCODER_OBJECT_ID_GENERAL_EXTERNAL_DVO    0xFF
 
@@ -364,6 +368,14 @@
                                                  GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
                                                  ENCODER_OBJECT_ID_INTERNAL_UNIPHY2 << OBJECT_ID_SHIFT)
 
+#define ENCODER_INTERNAL_UNIPHY3_ENUM_ID1         ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+                                                 GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+                                                 ENCODER_OBJECT_ID_INTERNAL_UNIPHY3 << OBJECT_ID_SHIFT)
+
+#define ENCODER_INTERNAL_UNIPHY3_ENUM_ID2         ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+                                                 GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+                                                 ENCODER_OBJECT_ID_INTERNAL_UNIPHY3 << OBJECT_ID_SHIFT)
+
 #define ENCODER_GENERAL_EXTERNAL_DVO_ENUM_ID1    ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
                                                   GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
                                                   ENCODER_OBJECT_ID_GENERAL_EXTERNAL_DVO << OBJECT_ID_SHIFT)
@@ -392,6 +404,10 @@
                                                   GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
                                                   ENCODER_OBJECT_ID_INTERNAL_VCE << OBJECT_ID_SHIFT)
 
+#define ENCODER_HDMI_ANX9805_ENUM_ID1            ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+                                                  GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+                                                  ENCODER_OBJECT_ID_HDMI_ANX9805 << OBJECT_ID_SHIFT)
+
 /****************************************************/
 /* Connector Object ID definition - Shared with BIOS */
 /****************************************************/
@@ -461,6 +477,14 @@
                                                  GRAPH_OBJECT_ENUM_ID4 << ENUM_ID_SHIFT |\
                                                  CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D << OBJECT_ID_SHIFT)
 
+#define CONNECTOR_SINGLE_LINK_DVI_D_ENUM_ID5   ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+                                                 GRAPH_OBJECT_ENUM_ID5 << ENUM_ID_SHIFT |\
+                                                 CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_SINGLE_LINK_DVI_D_ENUM_ID6   ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+                                                 GRAPH_OBJECT_ENUM_ID6 << ENUM_ID_SHIFT |\
+                                                 CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D << OBJECT_ID_SHIFT)
+
 #define CONNECTOR_DUAL_LINK_DVI_D_ENUM_ID1     ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
                                                  GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
                                                  CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D << OBJECT_ID_SHIFT)
@@ -473,6 +497,10 @@
                                                  GRAPH_OBJECT_ENUM_ID3 << ENUM_ID_SHIFT |\
                                                  CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D << OBJECT_ID_SHIFT)
 
+#define CONNECTOR_DUAL_LINK_DVI_D_ENUM_ID4     ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+                                                 GRAPH_OBJECT_ENUM_ID4 << ENUM_ID_SHIFT |\
+                                                 CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D << OBJECT_ID_SHIFT)
+
 #define CONNECTOR_VGA_ENUM_ID1                 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
                                                  GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
                                                  CONNECTOR_OBJECT_ID_VGA << OBJECT_ID_SHIFT)
@@ -541,6 +569,18 @@
                                                  GRAPH_OBJECT_ENUM_ID3 << ENUM_ID_SHIFT |\
                                                  CONNECTOR_OBJECT_ID_HDMI_TYPE_A << OBJECT_ID_SHIFT)
 
+#define CONNECTOR_HDMI_TYPE_A_ENUM_ID4         ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+                                                 GRAPH_OBJECT_ENUM_ID4 << ENUM_ID_SHIFT |\
+                                                 CONNECTOR_OBJECT_ID_HDMI_TYPE_A << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_HDMI_TYPE_A_ENUM_ID5         ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+                                                 GRAPH_OBJECT_ENUM_ID5 << ENUM_ID_SHIFT |\
+                                                 CONNECTOR_OBJECT_ID_HDMI_TYPE_A << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_HDMI_TYPE_A_ENUM_ID6         ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+                                                 GRAPH_OBJECT_ENUM_ID6 << ENUM_ID_SHIFT |\
+                                                 CONNECTOR_OBJECT_ID_HDMI_TYPE_A << OBJECT_ID_SHIFT)
+
 #define CONNECTOR_HDMI_TYPE_B_ENUM_ID1         ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
                                                  GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
                                                  CONNECTOR_OBJECT_ID_HDMI_TYPE_B << OBJECT_ID_SHIFT)
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 025/165] drm/radeon: upstream atombios.h updates (v2)
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (24 preceding siblings ...)
  2013-06-26 13:21 ` [PATCH 024/165] drm/radeon: upstream ObjectID.h updates (v2) alexdeucher
@ 2013-06-26 13:21 ` alexdeucher
  2013-06-26 13:21 ` [PATCH 026/165] drm/radeon: atombios power table " alexdeucher
                   ` (87 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:21 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

v2: further updates

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/atombios.h |  486 ++++++++++++++++++++++++++++++++++---
 1 files changed, 454 insertions(+), 32 deletions(-)

diff --git a/drivers/gpu/drm/radeon/atombios.h b/drivers/gpu/drm/radeon/atombios.h
index 0ee5737..f19d9a6 100644
--- a/drivers/gpu/drm/radeon/atombios.h
+++ b/drivers/gpu/drm/radeon/atombios.h
@@ -74,6 +74,8 @@
 #define ATOM_PPLL2            1
 #define ATOM_DCPLL            2
 #define ATOM_PPLL0            2
+#define ATOM_PPLL3            3
+
 #define ATOM_EXT_PLL1         8
 #define ATOM_EXT_PLL2         9
 #define ATOM_EXT_CLOCK        10
@@ -259,7 +261,7 @@ typedef struct _ATOM_MASTER_LIST_OF_COMMAND_TABLES{
   USHORT AdjustDisplayPll;											 //Atomic Table,  used by various SW componentes. 
   USHORT AdjustMemoryController;                 //Atomic Table,  indirectly used by various SW components,called from SetMemoryClock                
   USHORT EnableASIC_StaticPwrMgt;                //Atomic Table,  only used by Bios
-  USHORT ASIC_StaticPwrMgtStatusChange;          //Obsolete ,     only used by Bios   
+  USHORT SetUniphyInstance;                      //Atomic Table,  only used by Bios   
   USHORT DAC_LoadDetection;                      //Atomic Table,  directly used by various SW components,latest version 1.2  
   USHORT LVTMAEncoderControl;                    //Atomic Table,directly used by various SW components,latest version 1.3
   USHORT HW_Misc_Operation;                      //Atomic Table,  directly used by various SW components,latest version 1.1 
@@ -271,7 +273,7 @@ typedef struct _ATOM_MASTER_LIST_OF_COMMAND_TABLES{
   USHORT TVEncoderControl;                       //Function Table,directly used by various SW components,latest version 1.1
   USHORT PatchMCSetting;                         //only used by BIOS
   USHORT MC_SEQ_Control;                         //only used by BIOS
-  USHORT TV1OutputControl;                       //Atomic Table,  Obsolete from Ry6xx, use DAC2 Output instead
+  USHORT Gfx_Harvesting;                         //Atomic Table,  Obsolete from Ry6xx, Now only used by BIOS for GFX harvesting
   USHORT EnableScaler;                           //Atomic Table,  used only by Bios
   USHORT BlankCRTC;                              //Atomic Table,  directly used by various SW components,latest version 1.1 
   USHORT EnableCRTC;                             //Atomic Table,  directly used by various SW components,latest version 1.1 
@@ -328,7 +330,7 @@ typedef struct _ATOM_MASTER_LIST_OF_COMMAND_TABLES{
 #define UNIPHYTransmitterControl			     DIG1TransmitterControl
 #define LVTMATransmitterControl				     DIG2TransmitterControl
 #define SetCRTC_DPM_State                        GetConditionalGoldenSetting
-#define SetUniphyInstance                        ASIC_StaticPwrMgtStatusChange
+#define ASIC_StaticPwrMgtStatusChange            SetUniphyInstance 
 #define HPDInterruptService                      ReadHWAssistedI2CStatus
 #define EnableVGA_Access                         GetSCLKOverMCLKRatio
 #define EnableYUV                                GetDispObjectInfo                         
@@ -338,7 +340,7 @@ typedef struct _ATOM_MASTER_LIST_OF_COMMAND_TABLES{
 #define TMDSAEncoderControl                      PatchMCSetting
 #define LVDSEncoderControl                       MC_SEQ_Control
 #define LCD1OutputControl                        HW_Misc_Operation
-
+#define TV1OutputControl                         Gfx_Harvesting
 
 typedef struct _ATOM_MASTER_COMMAND_TABLE
 {
@@ -478,11 +480,11 @@ typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V3
 typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V4
 {
 #if ATOM_BIG_ENDIAN
-  ULONG  ucPostDiv;          //return parameter: post divider which is used to program to register directly
+  ULONG  ucPostDiv:8;        //return parameter: post divider which is used to program to register directly
   ULONG  ulClock:24;         //Input= target clock, output = actual clock 
 #else
   ULONG  ulClock:24;         //Input= target clock, output = actual clock 
-  ULONG  ucPostDiv;          //return parameter: post divider which is used to program to register directly
+  ULONG  ucPostDiv:8;        //return parameter: post divider which is used to program to register directly
 #endif
 }COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V4;
 
@@ -504,6 +506,32 @@ typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V5
   UCHAR   ucReserved;                       
 }COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V5;
 
+
+typedef struct _COMPUTE_GPU_CLOCK_INPUT_PARAMETERS_V1_6
+{
+  ATOM_COMPUTE_CLOCK_FREQ  ulClock;         //Input Parameter
+  ULONG   ulReserved[2];
+}COMPUTE_GPU_CLOCK_INPUT_PARAMETERS_V1_6;
+
+//ATOM_COMPUTE_CLOCK_FREQ.ulComputeClockFlag
+#define COMPUTE_GPUCLK_INPUT_FLAG_CLK_TYPE_MASK            0x0f
+#define COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK           0x00
+#define COMPUTE_GPUCLK_INPUT_FLAG_SCLK                     0x01
+
+typedef struct _COMPUTE_GPU_CLOCK_OUTPUT_PARAMETERS_V1_6
+{
+  COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V4  ulClock;         //Output Parameter: ucPostDiv=DFS divider
+  ATOM_S_MPLL_FB_DIVIDER   ulFbDiv;         //Output Parameter: PLL FB divider
+  UCHAR   ucPllRefDiv;                      //Output Parameter: PLL ref divider      
+  UCHAR   ucPllPostDiv;                     //Output Parameter: PLL post divider      
+  UCHAR   ucPllCntlFlag;                    //Output Flags: control flag
+  UCHAR   ucReserved;                       
+}COMPUTE_GPU_CLOCK_OUTPUT_PARAMETERS_V1_6;
+
+//ucPllCntlFlag
+#define SPLL_CNTL_FLAG_VCO_MODE_MASK            0x03 
+
+
 // ucInputFlag
 #define ATOM_PLL_INPUT_FLAG_PLL_STROBE_MODE_EN  1   // 1-StrobeMode, 0-PerformanceMode
 
@@ -1686,6 +1714,7 @@ typedef struct _PIXEL_CLOCK_PARAMETERS_V6
 #define PIXEL_CLOCK_V6_MISC_HDMI_30BPP              0x08
 #define PIXEL_CLOCK_V6_MISC_HDMI_48BPP              0x0c
 #define PIXEL_CLOCK_V6_MISC_REF_DIV_SRC             0x10
+#define PIXEL_CLOCK_V6_MISC_GEN_DPREFCLK            0x40
 
 typedef struct _GET_DISP_PLL_STATUS_INPUT_PARAMETERS_V2
 {
@@ -2102,6 +2131,17 @@ typedef struct _DVO_ENCODER_CONTROL_PARAMETERS_V3
 }DVO_ENCODER_CONTROL_PARAMETERS_V3;
 #define DVO_ENCODER_CONTROL_PS_ALLOCATION_V3	DVO_ENCODER_CONTROL_PARAMETERS_V3
 
+typedef struct _DVO_ENCODER_CONTROL_PARAMETERS_V1_4
+{
+  USHORT usPixelClock; 
+  UCHAR  ucDVOConfig;
+  UCHAR  ucAction;														//ATOM_ENABLE/ATOM_DISABLE/ATOM_HPD_INIT
+  UCHAR  ucBitPerColor;                       //please refer to definition of PANEL_xBIT_PER_COLOR
+  UCHAR  ucReseved[3];
+}DVO_ENCODER_CONTROL_PARAMETERS_V1_4;
+#define DVO_ENCODER_CONTROL_PS_ALLOCATION_V1_4	DVO_ENCODER_CONTROL_PARAMETERS_V1_4
+
+
 //ucTableFormatRevision=1
 //ucTableContentRevision=3 structure is not changed but usMisc add bit 1 as another input for 
 // bit1=0: non-coherent mode
@@ -2165,7 +2205,7 @@ typedef struct _DVO_ENCODER_CONTROL_PARAMETERS_V3
 #define SET_ASIC_VOLTAGE_MODE_SOURCE_B         0x4
 
 #define	SET_ASIC_VOLTAGE_MODE_SET_VOLTAGE      0x0
-#define	SET_ASIC_VOLTAGE_MODE_GET_GPIOVAL      0x1	
+#define	SET_ASIC_VOLTAGE_MODE_GET_GPIOVAL      0x1
 #define	SET_ASIC_VOLTAGE_MODE_GET_GPIOMASK     0x2
 
 typedef struct	_SET_VOLTAGE_PARAMETERS
@@ -2200,15 +2240,20 @@ typedef struct	_SET_VOLTAGE_PARAMETERS_V1_3
 //SET_VOLTAGE_PARAMETERS_V3.ucVoltageMode
 #define ATOM_SET_VOLTAGE                     0        //Set voltage Level
 #define ATOM_INIT_VOLTAGE_REGULATOR          3        //Init Regulator
-#define ATOM_SET_VOLTAGE_PHASE               4        //Set Vregulator Phase
-#define ATOM_GET_MAX_VOLTAGE                 6        //Get Max Voltage, not used in SetVoltageTable v1.3
-#define ATOM_GET_VOLTAGE_LEVEL               6        //Get Voltage level from vitual voltage ID
+#define ATOM_SET_VOLTAGE_PHASE               4        //Set Vregulator Phase, only for SVID/PVID regulator
+#define ATOM_GET_MAX_VOLTAGE                 6        //Get Max Voltage, not used from SetVoltageTable v1.3
+#define ATOM_GET_VOLTAGE_LEVEL               6        //Get Voltage level from vitual voltage ID, not used for SetVoltage v1.4
+#define ATOM_GET_LEAKAGE_ID                  8        //Get Leakage Voltage Id ( starting from SMU7x IP ), SetVoltage v1.4 
 
 // define vitual voltage id in usVoltageLevel
 #define ATOM_VIRTUAL_VOLTAGE_ID0             0xff01
 #define ATOM_VIRTUAL_VOLTAGE_ID1             0xff02
 #define ATOM_VIRTUAL_VOLTAGE_ID2             0xff03
 #define ATOM_VIRTUAL_VOLTAGE_ID3             0xff04
+#define ATOM_VIRTUAL_VOLTAGE_ID4             0xff05
+#define ATOM_VIRTUAL_VOLTAGE_ID5             0xff06
+#define ATOM_VIRTUAL_VOLTAGE_ID6             0xff07
+#define ATOM_VIRTUAL_VOLTAGE_ID7             0xff08
 
 typedef struct _SET_VOLTAGE_PS_ALLOCATION
 {
@@ -2628,7 +2673,8 @@ typedef struct _ATOM_FIRMWARE_INFO_V2_2
   ULONG                           ulFirmwareRevision;
   ULONG                           ulDefaultEngineClock;       //In 10Khz unit
   ULONG                           ulDefaultMemoryClock;       //In 10Khz unit
-  ULONG                           ulReserved[2];
+  ULONG                           ulSPLL_OutputFreq;          //In 10Khz unit  
+  ULONG                           ulGPUPLL_OutputFreq;        //In 10Khz unit
   ULONG                           ulReserved1;                //Was ulMaxEngineClockPLL_Output; //In 10Khz unit*
   ULONG                           ulReserved2;                //Was ulMaxMemoryClockPLL_Output; //In 10Khz unit*
   ULONG                           ulMaxPixelClockPLL_Output;  //In 10Khz unit
@@ -3813,6 +3859,12 @@ typedef struct _ATOM_GPIO_PIN_ASSIGNMENT
   UCHAR                    ucGPIO_ID;
 }ATOM_GPIO_PIN_ASSIGNMENT;
 
+//ucGPIO_ID pre-define id for multiple usage
+//from SMU7.x, if ucGPIO_ID=PP_AC_DC_SWITCH_GPIO_PINID in GPIO_LUTTable, AC/DC swithing feature is enable
+#define PP_AC_DC_SWITCH_GPIO_PINID          60
+//from SMU7.x, if ucGPIO_ID=VDDC_REGULATOR_VRHOT_GPIO_PINID in GPIO_LUTable, VRHot feature is enable
+#define VDDC_VRHOT_GPIO_PINID               61
+
 typedef struct _ATOM_GPIO_PIN_LUT
 {
   ATOM_COMMON_TABLE_HEADER  sHeader;
@@ -4074,17 +4126,19 @@ typedef struct _EXT_DISPLAY_PATH
 
 //usCaps
 #define  EXT_DISPLAY_PATH_CAPS__HBR2_DISABLE          0x01
+#define  EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN        0x02
 
 typedef  struct _ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO
 {
   ATOM_COMMON_TABLE_HEADER sHeader;
   UCHAR                    ucGuid [NUMBER_OF_UCHAR_FOR_GUID];     // a GUID is a 16 byte long string
   EXT_DISPLAY_PATH         sPath[MAX_NUMBER_OF_EXT_DISPLAY_PATH]; // total of fixed 7 entries.
-  UCHAR                    ucChecksum;                            // a  simple Checksum of the sum of whole structure equal to 0x0. 
+  UCHAR                    ucChecksum;                            // a simple Checksum of the sum of whole structure equal to 0x0. 
   UCHAR                    uc3DStereoPinId;                       // use for eDP panel
   UCHAR                    ucRemoteDisplayConfig;
   UCHAR                    uceDPToLVDSRxId;
-  UCHAR                    Reserved[4];                           // for potential expansion
+  UCHAR                    ucFixDPVoltageSwing;                   // usCaps[1]=1, this indicate DP_LANE_SET value
+  UCHAR                    Reserved[3];                           // for potential expansion
 }ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO;
 
 //Related definitions, all records are different but they have a commond header
@@ -4416,6 +4470,13 @@ typedef struct _ATOM_VOLTAGE_CONTROL
 #define	VOLTAGE_CONTROL_ID_CHL822x						0x08									
 #define	VOLTAGE_CONTROL_ID_VT1586M						0x09
 #define VOLTAGE_CONTROL_ID_UP1637 						0x0A
+#define	VOLTAGE_CONTROL_ID_CHL8214            0x0B
+#define	VOLTAGE_CONTROL_ID_UP1801             0x0C
+#define	VOLTAGE_CONTROL_ID_ST6788A            0x0D
+#define VOLTAGE_CONTROL_ID_CHLIR3564SVI2      0x0E
+#define VOLTAGE_CONTROL_ID_AD527x      	      0x0F
+#define VOLTAGE_CONTROL_ID_NCP81022    	      0x10
+#define VOLTAGE_CONTROL_ID_LTC2635			  0x11
 
 typedef struct  _ATOM_VOLTAGE_OBJECT
 {
@@ -4458,6 +4519,15 @@ typedef struct _ATOM_VOLTAGE_OBJECT_HEADER_V3{
 	 USHORT		usSize;													//Size of Object	
 }ATOM_VOLTAGE_OBJECT_HEADER_V3;
 
+// ATOM_VOLTAGE_OBJECT_HEADER_V3.ucVoltageMode
+#define VOLTAGE_OBJ_GPIO_LUT                 0        //VOLTAGE and GPIO Lookup table ->ATOM_GPIO_VOLTAGE_OBJECT_V3
+#define VOLTAGE_OBJ_VR_I2C_INIT_SEQ          3        //VOLTAGE REGULATOR INIT sequece through I2C -> ATOM_I2C_VOLTAGE_OBJECT_V3
+#define VOLTAGE_OBJ_PHASE_LUT                4        //Set Vregulator Phase lookup table ->ATOM_GPIO_VOLTAGE_OBJECT_V3
+#define VOLTAGE_OBJ_SVID2                    7        //Indicate voltage control by SVID2 ->ATOM_SVID2_VOLTAGE_OBJECT_V3
+#define	VOLTAGE_OBJ_PWRBOOST_LEAKAGE_LUT     0x10     //Powerboost Voltage and LeakageId lookup table->ATOM_LEAKAGE_VOLTAGE_OBJECT_V3
+#define	VOLTAGE_OBJ_HIGH_STATE_LEAKAGE_LUT   0x11     //High voltage state Voltage and LeakageId lookup table->ATOM_LEAKAGE_VOLTAGE_OBJECT_V3
+#define VOLTAGE_OBJ_HIGH1_STATE_LEAKAGE_LUT  0x12     //High1 voltage state Voltage and LeakageId lookup table->ATOM_LEAKAGE_VOLTAGE_OBJECT_V3
+
 typedef struct  _VOLTAGE_LUT_ENTRY_V2
 {
 	 ULONG		ulVoltageId;									  // The Voltage ID which is used to program GPIO register
@@ -4473,7 +4543,7 @@ typedef struct  _LEAKAGE_VOLTAGE_LUT_ENTRY_V2
 
 typedef struct  _ATOM_I2C_VOLTAGE_OBJECT_V3
 {
-   ATOM_VOLTAGE_OBJECT_HEADER_V3 sHeader;
+   ATOM_VOLTAGE_OBJECT_HEADER_V3 sHeader;    // voltage mode = VOLTAGE_OBJ_VR_I2C_INIT_SEQ
    UCHAR	ucVoltageRegulatorId;					  //Indicate Voltage Regulator Id
    UCHAR    ucVoltageControlI2cLine;
    UCHAR    ucVoltageControlAddress;
@@ -4484,7 +4554,7 @@ typedef struct  _ATOM_I2C_VOLTAGE_OBJECT_V3
 
 typedef struct  _ATOM_GPIO_VOLTAGE_OBJECT_V3
 {
-   ATOM_VOLTAGE_OBJECT_HEADER_V3 sHeader;   
+   ATOM_VOLTAGE_OBJECT_HEADER_V3 sHeader;   // voltage mode = VOLTAGE_OBJ_GPIO_LUT or VOLTAGE_OBJ_PHASE_LUT
    UCHAR    ucVoltageGpioCntlId;         // default is 0 which indicate control through CG VID mode 
    UCHAR    ucGpioEntryNum;              // indiate the entry numbers of Votlage/Gpio value Look up table
    UCHAR    ucPhaseDelay;                // phase delay in unit of micro second
@@ -4495,7 +4565,7 @@ typedef struct  _ATOM_GPIO_VOLTAGE_OBJECT_V3
 
 typedef struct  _ATOM_LEAKAGE_VOLTAGE_OBJECT_V3
 {
-   ATOM_VOLTAGE_OBJECT_HEADER_V3 sHeader;
+   ATOM_VOLTAGE_OBJECT_HEADER_V3 sHeader;    // voltage mode = 0x10/0x11/0x12
    UCHAR    ucLeakageCntlId;             // default is 0
    UCHAR    ucLeakageEntryNum;           // indicate the entry number of LeakageId/Voltage Lut table
    UCHAR    ucReserved[2];               
@@ -4503,10 +4573,26 @@ typedef struct  _ATOM_LEAKAGE_VOLTAGE_OBJECT_V3
    LEAKAGE_VOLTAGE_LUT_ENTRY_V2 asLeakageIdLut[1];   
 }ATOM_LEAKAGE_VOLTAGE_OBJECT_V3;
 
+
+typedef struct  _ATOM_SVID2_VOLTAGE_OBJECT_V3
+{
+   ATOM_VOLTAGE_OBJECT_HEADER_V3 sHeader;    // voltage mode = VOLTAGE_OBJ_SVID2
+// 14:7 – PSI0_VID
+// 6 – PSI0_EN
+// 5 – PSI1
+// 4:2 – load line slope trim. 
+// 1:0 – offset trim, 
+   USHORT   usLoadLine_PSI;    
+// GPU GPIO pin Id to SVID2 regulator VRHot pin. possible value 0~31. 0 means GPIO0, 31 means GPIO31
+   UCHAR    ucReserved[2];
+   ULONG    ulReserved;
+}ATOM_SVID2_VOLTAGE_OBJECT_V3;
+
 typedef union _ATOM_VOLTAGE_OBJECT_V3{
   ATOM_GPIO_VOLTAGE_OBJECT_V3 asGpioVoltageObj;
   ATOM_I2C_VOLTAGE_OBJECT_V3 asI2cVoltageObj;
   ATOM_LEAKAGE_VOLTAGE_OBJECT_V3 asLeakageObj;
+  ATOM_SVID2_VOLTAGE_OBJECT_V3 asSVID2Obj;
 }ATOM_VOLTAGE_OBJECT_V3;
 
 typedef struct  _ATOM_VOLTAGE_OBJECT_INFO_V3_1
@@ -4536,6 +4622,21 @@ typedef struct  _ATOM_ASIC_PROFILING_INFO
 	ATOM_ASIC_PROFILE_VOLTAGE			asVoltage;
 }ATOM_ASIC_PROFILING_INFO;
 
+typedef struct  _ATOM_ASIC_PROFILING_INFO_V2_1
+{
+  ATOM_COMMON_TABLE_HEADER			asHeader; 
+  UCHAR  ucLeakageBinNum;                // indicate the entry number of LeakageId/Voltage Lut table
+  USHORT usLeakageBinArrayOffset;        // offset of USHORT Leakage Bin list array ( from lower LeakageId to higher) 
+
+  UCHAR  ucElbVDDC_Num;               
+  USHORT usElbVDDC_IdArrayOffset;        // offset of USHORT virtual VDDC voltage id ( 0xff01~0xff08 )
+  USHORT usElbVDDC_LevelArrayOffset;     // offset of 2 dimension voltage level USHORT array
+
+  UCHAR  ucElbVDDCI_Num;
+  USHORT usElbVDDCI_IdArrayOffset;       // offset of USHORT virtual VDDCI voltage id ( 0xff01~0xff08 )
+  USHORT usElbVDDCI_LevelArrayOffset;    // offset of 2 dimension voltage level USHORT array
+}ATOM_ASIC_PROFILING_INFO_V2_1;
+
 typedef struct _ATOM_POWER_SOURCE_OBJECT
 {
 	UCHAR	ucPwrSrcId;													// Power source
@@ -4652,6 +4753,8 @@ typedef struct _ATOM_INTEGRATED_SYSTEM_INFO_V6
 #define SYS_INFO_LVDSMISC__888_BPC                                                   0x04
 #define SYS_INFO_LVDSMISC__OVERRIDE_EN                                               0x08
 #define SYS_INFO_LVDSMISC__BLON_ACTIVE_LOW                                           0x10
+// new since Trinity
+#define SYS_INFO_LVDSMISC__TRAVIS_LVDS_VOL_OVERRIDE_EN                               0x20
 
 // not used any more
 #define SYS_INFO_LVDSMISC__VSYNC_ACTIVE_LOW                                          0x04
@@ -4752,6 +4855,29 @@ typedef struct _ATOM_FUSION_SYSTEM_INFO_V1
   ATOM_INTEGRATED_SYSTEM_INFO_V6    sIntegratedSysInfo;   
   ULONG  ulPowerplayTable[128];  
 }ATOM_FUSION_SYSTEM_INFO_V1; 
+
+
+typedef struct _ATOM_TDP_CONFIG_BITS
+{
+#if ATOM_BIG_ENDIAN
+  ULONG   uReserved:2;
+  ULONG   uTDP_Value:14;  // Original TDP value in tens of milli watts
+  ULONG   uCTDP_Value:14; // Override value in tens of milli watts
+  ULONG   uCTDP_Enable:2; // = (uCTDP_Value > uTDP_Value? 2: (uCTDP_Value < uTDP_Value))
+#else
+  ULONG   uCTDP_Enable:2; // = (uCTDP_Value > uTDP_Value? 2: (uCTDP_Value < uTDP_Value))
+  ULONG   uCTDP_Value:14; // Override value in tens of milli watts
+  ULONG   uTDP_Value:14;  // Original TDP value in tens of milli watts
+  ULONG   uReserved:2;
+#endif
+}ATOM_TDP_CONFIG_BITS;
+
+typedef union _ATOM_TDP_CONFIG
+{
+  ATOM_TDP_CONFIG_BITS TDP_config;
+  ULONG            TDP_config_all;
+}ATOM_TDP_CONFIG;
+
 /**********************************************************************************************************************
   ATOM_FUSION_SYSTEM_INFO_V1 Description
 sIntegratedSysInfo:               refer to ATOM_INTEGRATED_SYSTEM_INFO_V6 definition.
@@ -4784,7 +4910,8 @@ typedef struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7
   UCHAR  ucMemoryType;  
   UCHAR  ucUMAChannelNumber;
   UCHAR  strVBIOSMsg[40];
-  ULONG  ulReserved[20];
+  ATOM_TDP_CONFIG  asTdpConfig;
+  ULONG  ulReserved[19];
   ATOM_AVAILABLE_SCLK_LIST   sAvail_SCLK[5];
   ULONG  ulGMCRestoreResetTime;
   ULONG  ulMinimumNClk;
@@ -4809,7 +4936,7 @@ typedef struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7
   USHORT GnbTdpLimit;
   USHORT usMaxLVDSPclkFreqInSingleLink;
   UCHAR  ucLvdsMisc;
-  UCHAR  ucLVDSReserved;
+  UCHAR  ucTravisLVDSVolAdjust;
   UCHAR  ucLVDSPwrOnSeqDIGONtoDE_in4Ms;
   UCHAR  ucLVDSPwrOnSeqDEtoVARY_BL_in4Ms;
   UCHAR  ucLVDSPwrOffSeqVARY_BLtoDE_in4Ms;
@@ -4817,7 +4944,7 @@ typedef struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7
   UCHAR  ucLVDSOffToOnDelay_in4Ms;
   UCHAR  ucLVDSPwrOnSeqVARY_BLtoBLON_in4Ms;
   UCHAR  ucLVDSPwrOffSeqBLONtoVARY_BL_in4Ms;
-  UCHAR  ucLVDSReserved1;
+  UCHAR  ucMinAllowedBL_Level;
   ULONG  ulLCDBitDepthControlVal;
   ULONG  ulNbpStateMemclkFreq[4];
   USHORT usNBP2Voltage;               
@@ -4846,6 +4973,7 @@ typedef struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7
 #define SYS_INFO_GPUCAPS__TMDSHDMI_COHERENT_SINGLEPLL_MODE                0x01
 #define SYS_INFO_GPUCAPS__DP_SINGLEPLL_MODE                               0x02
 #define SYS_INFO_GPUCAPS__DISABLE_AUX_MODE_DETECT                         0x08
+#define SYS_INFO_GPUCAPS__ENABEL_DFS_BYPASS                               0x10
 
 /**********************************************************************************************************************
   ATOM_INTEGRATED_SYSTEM_INFO_V1_7 Description
@@ -4945,6 +5073,9 @@ ucLVDSMisc:                       [bit0] LVDS 888bit panel mode =0: LVDS 888 pan
                                   [bit2] LVDS 888bit per color mode  =0: 666 bit per color =1:888 bit per color
                                   [bit3] LVDS parameter override enable  =0: ucLvdsMisc parameter are not used =1: ucLvdsMisc parameter should be used
                                   [bit4] Polarity of signal sent to digital BLON output pin. =0: not inverted(active high) =1: inverted ( active low )
+                                  [bit5] Travid LVDS output voltage override enable, when =1, use ucTravisLVDSVolAdjust value to overwrite Traivs register LVDS_CTRL_4
+ucTravisLVDSVolAdjust             When ucLVDSMisc[5]=1,it means platform SBIOS want to overwrite TravisLVDSVoltage. Then VBIOS will use ucTravisLVDSVolAdjust 
+                                  value to program Travis register LVDS_CTRL_4
 ucLVDSPwrOnSeqDIGONtoDE_in4Ms:    LVDS power up sequence time in unit of 4ms, time delay from DIGON signal active to data enable signal active( DE ).
                                   =0 mean use VBIOS default which is 8 ( 32ms ). The LVDS power up sequence is as following: DIGON->DE->VARY_BL->BLON. 
                                   This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable.
@@ -4964,18 +5095,241 @@ ucLVDSOffToOnDelay_in4Ms:         LVDS power down sequence time in unit of 4ms.
                                   =0 means to use VBIOS default delay which is 125 ( 500ms ).
                                   This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable.
 
-ucLVDSPwrOnVARY_BLtoBLON_in4Ms:   LVDS power up sequence time in unit of 4ms. Time delay from VARY_BL signal on to DLON signal active. 
+ucLVDSPwrOnSeqVARY_BLtoBLON_in4Ms:
+                                  LVDS power up sequence time in unit of 4ms. Time delay from VARY_BL signal on to DLON signal active. 
                                   =0 means to use VBIOS default delay which is 0 ( 0ms ).
                                   This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable.
 
-ucLVDSPwrOffBLONtoVARY_BL_in4Ms:  LVDS power down sequence time in unit of 4ms. Time delay from BLON signal off to VARY_BL signal off. 
+ucLVDSPwrOffSeqBLONtoVARY_BL_in4Ms:  
+                                  LVDS power down sequence time in unit of 4ms. Time delay from BLON signal off to VARY_BL signal off. 
                                   =0 means to use VBIOS default delay which is 0 ( 0ms ).
                                   This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable.
 
+ucMinAllowedBL_Level:             Lowest LCD backlight PWM level. This is customer platform specific parameters. By default it is 0. 
+
 ulNbpStateMemclkFreq[4]:          system memory clock frequncey in unit of 10Khz in different NB pstate. 
 
 **********************************************************************************************************************/
 
+// this IntegrateSystemInfoTable is used for Kaveri & Kabini APU
+typedef struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_8
+{
+  ATOM_COMMON_TABLE_HEADER   sHeader;
+  ULONG  ulBootUpEngineClock;
+  ULONG  ulDentistVCOFreq;
+  ULONG  ulBootUpUMAClock;
+  ATOM_CLK_VOLT_CAPABILITY   sDISPCLK_Voltage[4];
+  ULONG  ulBootUpReqDisplayVector;
+  ULONG  ulVBIOSMisc;
+  ULONG  ulGPUCapInfo;
+  ULONG  ulDISP_CLK2Freq;
+  USHORT usRequestedPWMFreqInHz;
+  UCHAR  ucHtcTmpLmt;
+  UCHAR  ucHtcHystLmt;
+  ULONG  ulReserved2;
+  ULONG  ulSystemConfig;            
+  ULONG  ulCPUCapInfo;
+  ULONG  ulReserved3;
+  USHORT usGPUReservedSysMemSize;
+  USHORT usExtDispConnInfoOffset;
+  USHORT usPanelRefreshRateRange;     
+  UCHAR  ucMemoryType;  
+  UCHAR  ucUMAChannelNumber;
+  UCHAR  strVBIOSMsg[40];
+  ATOM_TDP_CONFIG  asTdpConfig;
+  ULONG  ulReserved[19];
+  ATOM_AVAILABLE_SCLK_LIST   sAvail_SCLK[5];
+  ULONG  ulGMCRestoreResetTime;
+  ULONG  ulReserved4;
+  ULONG  ulIdleNClk;
+  ULONG  ulDDR_DLL_PowerUpTime;
+  ULONG  ulDDR_PLL_PowerUpTime;
+  USHORT usPCIEClkSSPercentage;
+  USHORT usPCIEClkSSType;
+  USHORT usLvdsSSPercentage;
+  USHORT usLvdsSSpreadRateIn10Hz;
+  USHORT usHDMISSPercentage;
+  USHORT usHDMISSpreadRateIn10Hz;
+  USHORT usDVISSPercentage;
+  USHORT usDVISSpreadRateIn10Hz;
+  ULONG  ulGPUReservedSysMemBaseAddrLo;
+  ULONG  ulGPUReservedSysMemBaseAddrHi;
+  ULONG  ulReserved5[3];
+  USHORT usMaxLVDSPclkFreqInSingleLink;
+  UCHAR  ucLvdsMisc;
+  UCHAR  ucTravisLVDSVolAdjust;
+  UCHAR  ucLVDSPwrOnSeqDIGONtoDE_in4Ms;
+  UCHAR  ucLVDSPwrOnSeqDEtoVARY_BL_in4Ms;
+  UCHAR  ucLVDSPwrOffSeqVARY_BLtoDE_in4Ms;
+  UCHAR  ucLVDSPwrOffSeqDEtoDIGON_in4Ms;
+  UCHAR  ucLVDSOffToOnDelay_in4Ms;
+  UCHAR  ucLVDSPwrOnSeqVARY_BLtoBLON_in4Ms;
+  UCHAR  ucLVDSPwrOffSeqBLONtoVARY_BL_in4Ms;
+  UCHAR  ucMinAllowedBL_Level;
+  ULONG  ulLCDBitDepthControlVal;
+  ULONG  ulNbpStateMemclkFreq[4];
+  ULONG  ulReserved6;               
+  ULONG  ulNbpStateNClkFreq[4];
+  USHORT usNBPStateVoltage[4];            
+  USHORT usBootUpNBVoltage;   
+  USHORT usReserved2; 
+  ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO sExtDispConnInfo;
+}ATOM_INTEGRATED_SYSTEM_INFO_V1_8;
+
+/**********************************************************************************************************************
+  ATOM_INTEGRATED_SYSTEM_INFO_V1_8 Description
+ulBootUpEngineClock:              VBIOS bootup Engine clock frequency, in 10kHz unit. if it is equal 0, then VBIOS use pre-defined bootup engine clock
+ulDentistVCOFreq:                 Dentist VCO clock in 10kHz unit. 
+ulBootUpUMAClock:                 System memory boot up clock frequency in 10Khz unit. 
+sDISPCLK_Voltage:                 Report Display clock frequency requirement on GNB voltage(up to 4 voltage levels).
+ 
+ulBootUpReqDisplayVector:         VBIOS boot up display IDs, following are supported devices in Trinity projects:
+                                  ATOM_DEVICE_CRT1_SUPPORT                  0x0001
+                                  ATOM_DEVICE_DFP1_SUPPORT                  0x0008
+                                  ATOM_DEVICE_DFP6_SUPPORT                  0x0040
+                                  ATOM_DEVICE_DFP2_SUPPORT                  0x0080
+                                  ATOM_DEVICE_DFP3_SUPPORT                  0x0200
+                                  ATOM_DEVICE_DFP4_SUPPORT                  0x0400
+                                  ATOM_DEVICE_DFP5_SUPPORT                  0x0800
+                                  ATOM_DEVICE_LCD1_SUPPORT                  0x0002
+
+ulVBIOSMisc:      	              Miscellenous flags for VBIOS requirement and interface 
+                                  bit[0]=0: INT15 callback function Get LCD EDID ( ax=4e08, bl=1b ) is not supported by SBIOS. 
+                                        =1: INT15 callback function Get LCD EDID ( ax=4e08, bl=1b ) is supported by SBIOS.
+                                  bit[1]=0: INT15 callback function Get boot display( ax=4e08, bl=01h) is not supported by SBIOS
+                                        =1: INT15 callback function Get boot display( ax=4e08, bl=01h) is supported by SBIOS
+                                  bit[2]=0: INT15 callback function Get panel Expansion ( ax=4e08, bl=02h) is not supported by SBIOS
+                                        =1: INT15 callback function Get panel Expansion ( ax=4e08, bl=02h) is supported by SBIOS
+                                  bit[3]=0: VBIOS fast boot is disable
+                                        =1: VBIOS fast boot is enable. ( VBIOS skip display device detection in every set mode if LCD panel is connect and LID is open)
+
+ulGPUCapInfo:                     bit[0~2]= Reserved
+                                  bit[3]=0: Enable AUX HW mode detection logic
+                                        =1: Disable AUX HW mode detection logic
+                                  bit[4]=0: Disable DFS bypass feature
+                                        =1: Enable DFS bypass feature
+
+usRequestedPWMFreqInHz:           When it's set to 0x0 by SBIOS: the LCD BackLight is not controlled by GPU(SW). 
+                                  Any attempt to change BL using VBIOS function or enable VariBri from PP table is not effective since ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU==0;
+                                  
+                                  When it's set to a non-zero frequency, the BackLight is controlled by GPU (SW) in one of two ways below:
+                                  1. SW uses the GPU BL PWM output to control the BL, in chis case, this non-zero frequency determines what freq GPU should use;
+                                  VBIOS will set up proper PWM frequency and ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU==1,as the result,
+                                  Changing BL using VBIOS function is functional in both driver and non-driver present environment; 
+                                  and enabling VariBri under the driver environment from PP table is optional.
+
+                                  2. SW uses other means to control BL (like DPCD),this non-zero frequency serves as a flag only indicating
+                                  that BL control from GPU is expected.
+                                  VBIOS will NOT set up PWM frequency but make ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU==1
+                                  Changing BL using VBIOS function could be functional in both driver and non-driver present environment,but
+                                  it's per platform 
+                                  and enabling VariBri under the driver environment from PP table is optional.
+
+ucHtcTmpLmt:                      Refer to D18F3x64 bit[22:16], HtcTmpLmt. Threshold on value to enter HTC_active state.
+ucHtcHystLmt:                     Refer to D18F3x64 bit[27:24], HtcHystLmt. 
+                                  To calculate threshold off value to exit HTC_active state, which is Threshold on vlaue minus ucHtcHystLmt.
+
+ulSystemConfig:                   Bit[0]=0: PCIE Power Gating Disabled 
+                                        =1: PCIE Power Gating Enabled
+                                  Bit[1]=0: DDR-DLL shut-down feature disabled.
+                                         1: DDR-DLL shut-down feature enabled.
+                                  Bit[2]=0: DDR-PLL Power down feature disabled.
+                                         1: DDR-PLL Power down feature enabled. 
+                                  Bit[3]=0: GNB DPM is disabled
+                                        =1: GNB DPM is enabled                                
+ulCPUCapInfo:                     TBD
+
+usExtDispConnInfoOffset:          Offset to sExtDispConnInfo inside the structure
+usPanelRefreshRateRange:          Bit vector for LCD supported refresh rate range. If DRR is requestd by the platform, at least two bits need to be set
+                                  to indicate a range.
+                                  SUPPORTED_LCD_REFRESHRATE_30Hz          0x0004
+                                  SUPPORTED_LCD_REFRESHRATE_40Hz          0x0008
+                                  SUPPORTED_LCD_REFRESHRATE_50Hz          0x0010
+                                  SUPPORTED_LCD_REFRESHRATE_60Hz          0x0020
+
+ucMemoryType:                     [3:0]=1:DDR1;=2:DDR2;=3:DDR3;=5:GDDR5; [7:4] is reserved.
+ucUMAChannelNumber:      	        System memory channel numbers. 
+
+strVBIOSMsg[40]:                  VBIOS boot up customized message string 
+
+sAvail_SCLK[5]:                   Arrays to provide availabe list of SLCK and corresponding voltage, order from low to high  
+
+ulGMCRestoreResetTime:            GMC power restore and GMC reset time to calculate data reconnection latency. Unit in ns. 
+ulIdleNClk:                       NCLK speed while memory runs in self-refresh state, used to calculate self-refresh latency. Unit in 10kHz.
+ulDDR_DLL_PowerUpTime:            DDR PHY DLL power up time. Unit in ns.
+ulDDR_PLL_PowerUpTime:            DDR PHY PLL power up time. Unit in ns.
+
+usPCIEClkSSPercentage:            PCIE Clock Spread Spectrum Percentage in unit 0.01%; 100 mean 1%.
+usPCIEClkSSType:                  PCIE Clock Spread Spectrum Type. 0 for Down spread(default); 1 for Center spread.
+usLvdsSSPercentage:               LVDS panel ( not include eDP ) Spread Spectrum Percentage in unit of 0.01%, =0, use VBIOS default setting. 
+usLvdsSSpreadRateIn10Hz:          LVDS panel ( not include eDP ) Spread Spectrum frequency in unit of 10Hz, =0, use VBIOS default setting. 
+usHDMISSPercentage:               HDMI Spread Spectrum Percentage in unit 0.01%; 100 mean 1%,  =0, use VBIOS default setting. 
+usHDMISSpreadRateIn10Hz:          HDMI Spread Spectrum frequency in unit of 10Hz,  =0, use VBIOS default setting. 
+usDVISSPercentage:                DVI Spread Spectrum Percentage in unit 0.01%; 100 mean 1%,  =0, use VBIOS default setting. 
+usDVISSpreadRateIn10Hz:           DVI Spread Spectrum frequency in unit of 10Hz,  =0, use VBIOS default setting. 
+
+usGPUReservedSysMemSize:          Reserved system memory size for ACP engine in APU GNB, units in MB. 0/2/4MB based on CMOS options, current default could be 0MB. KV only, not on KB.
+ulGPUReservedSysMemBaseAddrLo:    Low 32 bits base address to the reserved system memory. 
+ulGPUReservedSysMemBaseAddrHi:    High 32 bits base address to the reserved system memory. 
+
+usMaxLVDSPclkFreqInSingleLink:    Max pixel clock LVDS panel single link, if=0 means VBIOS use default threhold, right now it is 85Mhz
+ucLVDSMisc:                       [bit0] LVDS 888bit panel mode =0: LVDS 888 panel in LDI mode, =1: LVDS 888 panel in FPDI mode
+                                  [bit1] LVDS panel lower and upper link mapping =0: lower link and upper link not swap, =1: lower link and upper link are swapped
+                                  [bit2] LVDS 888bit per color mode  =0: 666 bit per color =1:888 bit per color
+                                  [bit3] LVDS parameter override enable  =0: ucLvdsMisc parameter are not used =1: ucLvdsMisc parameter should be used
+                                  [bit4] Polarity of signal sent to digital BLON output pin. =0: not inverted(active high) =1: inverted ( active low )
+                                  [bit5] Travid LVDS output voltage override enable, when =1, use ucTravisLVDSVolAdjust value to overwrite Traivs register LVDS_CTRL_4
+ucTravisLVDSVolAdjust             When ucLVDSMisc[5]=1,it means platform SBIOS want to overwrite TravisLVDSVoltage. Then VBIOS will use ucTravisLVDSVolAdjust 
+                                  value to program Travis register LVDS_CTRL_4
+ucLVDSPwrOnSeqDIGONtoDE_in4Ms:    
+                                  LVDS power up sequence time in unit of 4ms, time delay from DIGON signal active to data enable signal active( DE ).
+                                  =0 mean use VBIOS default which is 8 ( 32ms ). The LVDS power up sequence is as following: DIGON->DE->VARY_BL->BLON. 
+                                  This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable.
+ucLVDSPwrOnDEtoVARY_BL_in4Ms:     
+                                  LVDS power up sequence time in unit of 4ms., time delay from DE( data enable ) active to Vary Brightness enable signal active( VARY_BL ).  
+                                  =0 mean use VBIOS default which is 90 ( 360ms ). The LVDS power up sequence is as following: DIGON->DE->VARY_BL->BLON. 
+                                  This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable.
+ucLVDSPwrOffVARY_BLtoDE_in4Ms:    
+                                  LVDS power down sequence time in unit of 4ms, time delay from data enable ( DE ) signal off to LCDVCC (DIGON) off. 
+                                  =0 mean use VBIOS default delay which is 8 ( 32ms ). The LVDS power down sequence is as following: BLON->VARY_BL->DE->DIGON
+                                  This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable.
+ucLVDSPwrOffDEtoDIGON_in4Ms:      
+                                   LVDS power down sequence time in unit of 4ms, time delay from vary brightness enable signal( VARY_BL) off to data enable ( DE ) signal off. 
+                                  =0 mean use VBIOS default which is 90 ( 360ms ). The LVDS power down sequence is as following: BLON->VARY_BL->DE->DIGON
+                                  This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable.
+ucLVDSOffToOnDelay_in4Ms:         
+                                  LVDS power down sequence time in unit of 4ms. Time delay from DIGON signal off to DIGON signal active. 
+                                  =0 means to use VBIOS default delay which is 125 ( 500ms ).
+                                  This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable.
+ucLVDSPwrOnSeqVARY_BLtoBLON_in4Ms:
+                                  LVDS power up sequence time in unit of 4ms. Time delay from VARY_BL signal on to DLON signal active. 
+                                  =0 means to use VBIOS default delay which is 0 ( 0ms ).
+                                  This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable.
+
+ucLVDSPwrOffSeqBLONtoVARY_BL_in4Ms:  
+                                  LVDS power down sequence time in unit of 4ms. Time delay from BLON signal off to VARY_BL signal off. 
+                                  =0 means to use VBIOS default delay which is 0 ( 0ms ).
+                                  This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable.
+ucMinAllowedBL_Level:             Lowest LCD backlight PWM level. This is customer platform specific parameters. By default it is 0. 
+
+ulLCDBitDepthControlVal:          GPU display control encoder bit dither control setting, used to program register mmFMT_BIT_DEPTH_CONTROL
+
+ulNbpStateMemclkFreq[4]:          system memory clock frequncey in unit of 10Khz in different NB P-State(P0, P1, P2 & P3).
+ulNbpStateNClkFreq[4]:            NB P-State NClk frequency in different NB P-State
+usNBPStateVoltage[4]:             NB P-State (P0/P1 & P2/P3) voltage; NBP3 refers to lowes voltage
+usBootUpNBVoltage:                NB P-State voltage during boot up before driver loaded 
+sExtDispConnInfo:                 Display connector information table provided to VBIOS
+
+**********************************************************************************************************************/
+
+// this Table is used for Kaveri/Kabini APU
+typedef struct _ATOM_FUSION_SYSTEM_INFO_V2
+{
+  ATOM_INTEGRATED_SYSTEM_INFO_V1_8    sIntegratedSysInfo;       // refer to ATOM_INTEGRATED_SYSTEM_INFO_V1_8 definition
+  ULONG                               ulPowerplayTable[128];    // Update comments here to link new powerplay table definition structure
+}ATOM_FUSION_SYSTEM_INFO_V2; 
+
+
 /**************************************************************************/
 // This portion is only used when ext thermal chip or engine/memory clock SS chip is populated on a design
 //Memory SS Info Table
@@ -5026,22 +5380,24 @@ typedef struct _ATOM_ASIC_SS_ASSIGNMENT
 
 //Define ucClockIndication, SW uses the IDs below to search if the SS is required/enabled on a clock branch/signal type.
 //SS is not required or enabled if a match is not found.
-#define ASIC_INTERNAL_MEMORY_SS			1
-#define ASIC_INTERNAL_ENGINE_SS			2
-#define ASIC_INTERNAL_UVD_SS        3
-#define ASIC_INTERNAL_SS_ON_TMDS    4
-#define ASIC_INTERNAL_SS_ON_HDMI    5
-#define ASIC_INTERNAL_SS_ON_LVDS    6
-#define ASIC_INTERNAL_SS_ON_DP      7
-#define ASIC_INTERNAL_SS_ON_DCPLL   8
-#define ASIC_EXTERNAL_SS_ON_DP_CLOCK 9
-#define ASIC_INTERNAL_VCE_SS        10
+#define ASIC_INTERNAL_MEMORY_SS	         1
+#define ASIC_INTERNAL_ENGINE_SS	         2
+#define ASIC_INTERNAL_UVD_SS             3
+#define ASIC_INTERNAL_SS_ON_TMDS         4
+#define ASIC_INTERNAL_SS_ON_HDMI         5
+#define ASIC_INTERNAL_SS_ON_LVDS         6
+#define ASIC_INTERNAL_SS_ON_DP           7
+#define ASIC_INTERNAL_SS_ON_DCPLL        8
+#define ASIC_EXTERNAL_SS_ON_DP_CLOCK     9
+#define ASIC_INTERNAL_VCE_SS             10
+#define ASIC_INTERNAL_GPUPLL_SS          11
+
 
 typedef struct _ATOM_ASIC_SS_ASSIGNMENT_V2
 {
 	ULONG								ulTargetClockRange;						//For mem/engine/uvd, Clock Out frequence (VCO ), in unit of 10Khz
                                                     //For TMDS/HDMI/LVDS, it is pixel clock , for DP, it is link clock ( 27000 or 16200 )
-  USHORT              usSpreadSpectrumPercentage;		//in unit of 0.01%
+  USHORT              usSpreadSpectrumPercentage;		//in unit of 0.01% or 0.001%, decided by ucSpreadSpectrumMode bit4
 	USHORT							usSpreadRateIn10Hz;						//in unit of 10Hz, modulation freq
   UCHAR               ucClockIndication;					  //Indicate which clock source needs SS
 	UCHAR								ucSpreadSpectrumMode;					//Bit0=0 Down Spread,=1 Center Spread, bit1=0: internal SS bit1=1: external SS
@@ -5079,6 +5435,11 @@ typedef struct _ATOM_ASIC_SS_ASSIGNMENT_V3
 	UCHAR								ucReserved[2];
 }ATOM_ASIC_SS_ASSIGNMENT_V3;
 
+//ATOM_ASIC_SS_ASSIGNMENT_V3.ucSpreadSpectrumMode
+#define SS_MODE_V3_CENTRE_SPREAD_MASK             0x01
+#define SS_MODE_V3_EXTERNAL_SS_MASK               0x02
+#define SS_MODE_V3_PERCENTAGE_DIV_BY_1000_MASK    0x10
+
 typedef struct _ATOM_ASIC_INTERNAL_SS_INFO_V3
 {
   ATOM_COMMON_TABLE_HEADER	      sHeader; 
@@ -5719,6 +6080,7 @@ typedef struct _INDIRECT_IO_ACCESS
 #define INDIRECT_IO_PCIE           3
 #define INDIRECT_IO_PCIEP          4
 #define INDIRECT_IO_NBMISC         5
+#define INDIRECT_IO_SMU            5
 
 #define INDIRECT_IO_PLL_READ       INDIRECT_IO_PLL   | INDIRECT_READ
 #define INDIRECT_IO_PLL_WRITE      INDIRECT_IO_PLL   | INDIRECT_WRITE
@@ -5730,6 +6092,8 @@ typedef struct _INDIRECT_IO_ACCESS
 #define INDIRECT_IO_PCIEP_WRITE    INDIRECT_IO_PCIEP | INDIRECT_WRITE
 #define INDIRECT_IO_NBMISC_READ    INDIRECT_IO_NBMISC | INDIRECT_READ
 #define INDIRECT_IO_NBMISC_WRITE   INDIRECT_IO_NBMISC | INDIRECT_WRITE
+#define INDIRECT_IO_SMU_READ       INDIRECT_IO_SMU | INDIRECT_READ
+#define INDIRECT_IO_SMU_WRITE      INDIRECT_IO_SMU | INDIRECT_WRITE
 
 typedef struct _ATOM_OEM_INFO
 { 
@@ -5875,6 +6239,7 @@ typedef struct _ATOM_MC_INIT_PARAM_TABLE
 #define _64Mx32             0x43
 #define _128Mx8             0x51
 #define _128Mx16            0x52
+#define _128Mx32            0x53
 #define _256Mx8             0x61
 #define _256Mx16            0x62
 
@@ -5893,6 +6258,8 @@ typedef struct _ATOM_MC_INIT_PARAM_TABLE
 #define PROMOS              MOSEL
 #define KRETON              INFINEON
 #define ELIXIR              NANYA
+#define MEZZA               ELPIDA
+
 
 /////////////Support for GDDR5 MC uCode to reside in upper 64K of ROM/////////////
 
@@ -6625,6 +6992,10 @@ typedef struct _ATOM_DISP_OUT_INFO_V3
 	ASIC_TRANSMITTER_INFO_V2  asTransmitterInfo[1];     // for alligment only
 }ATOM_DISP_OUT_INFO_V3;
 
+//ucDispCaps
+#define DISPLAY_CAPS__DP_PCLK_FROM_PPLL        0x01
+#define DISPLAY_CAPS__FORCE_DISPDEV_CONNECTED  0x02
+
 typedef enum CORE_REF_CLK_SOURCE{
   CLOCK_SRC_XTALIN=0,
   CLOCK_SRC_XO_IN=1,
@@ -6829,6 +7200,17 @@ typedef struct _DIG_TRANSMITTER_INFO_HEADER_V3_1{
   USHORT usPhyPllSettingOffset;          // offset of CLOCK_CONDITION_SETTING_ENTRY* with Phy Pll Settings
 }DIG_TRANSMITTER_INFO_HEADER_V3_1;
 
+typedef struct _DIG_TRANSMITTER_INFO_HEADER_V3_2{  
+  ATOM_COMMON_TABLE_HEADER sHeader;  
+  USHORT usDPVsPreEmphSettingOffset;     // offset of PHY_ANALOG_SETTING_INFO * with DP Voltage Swing and Pre-Emphasis for each Link clock 
+  USHORT usPhyAnalogRegListOffset;       // offset of CLOCK_CONDITION_REGESTER_INFO* with None-DP mode Analog Setting's register Info 
+  USHORT usPhyAnalogSettingOffset;       // offset of CLOCK_CONDITION_SETTING_ENTRY* with None-DP mode Analog Setting for each link clock range
+  USHORT usPhyPllRegListOffset;          // offset of CLOCK_CONDITION_REGESTER_INFO* with Phy Pll register Info 
+  USHORT usPhyPllSettingOffset;          // offset of CLOCK_CONDITION_SETTING_ENTRY* with Phy Pll Settings
+  USHORT usDPSSRegListOffset;            // offset of CLOCK_CONDITION_REGESTER_INFO* with Phy SS Pll register Info 
+  USHORT usDPSSSettingOffset;            // offset of CLOCK_CONDITION_SETTING_ENTRY* with Phy SS Pll Settings
+}DIG_TRANSMITTER_INFO_HEADER_V3_2;
+
 typedef struct _CLOCK_CONDITION_REGESTER_INFO{
   USHORT usRegisterIndex;
   UCHAR  ucStartBit;
@@ -6852,12 +7234,24 @@ typedef struct _PHY_CONDITION_REG_VAL{
   ULONG  ulRegVal;
 }PHY_CONDITION_REG_VAL;
 
+typedef struct _PHY_CONDITION_REG_VAL_V2{
+  ULONG  ulCondition;
+  UCHAR  ucCondition2;
+  ULONG  ulRegVal;
+}PHY_CONDITION_REG_VAL_V2;
+
 typedef struct _PHY_CONDITION_REG_INFO{
   USHORT usRegIndex;
   USHORT usSize;
   PHY_CONDITION_REG_VAL asRegVal[1];
 }PHY_CONDITION_REG_INFO;
 
+typedef struct _PHY_CONDITION_REG_INFO_V2{
+  USHORT usRegIndex;
+  USHORT usSize;
+  PHY_CONDITION_REG_VAL_V2 asRegVal[1];
+}PHY_CONDITION_REG_INFO_V2;
+
 typedef struct _PHY_ANALOG_SETTING_INFO{
   UCHAR  ucEncodeMode;
   UCHAR  ucPhySel;
@@ -6865,6 +7259,25 @@ typedef struct _PHY_ANALOG_SETTING_INFO{
   PHY_CONDITION_REG_INFO  asAnalogSetting[1];
 }PHY_ANALOG_SETTING_INFO;
 
+typedef struct _PHY_ANALOG_SETTING_INFO_V2{
+  UCHAR  ucEncodeMode;
+  UCHAR  ucPhySel;
+  USHORT usSize;
+  PHY_CONDITION_REG_INFO_V2  asAnalogSetting[1];
+}PHY_ANALOG_SETTING_INFO_V2;
+
+typedef struct _GFX_HAVESTING_PARAMETERS {
+  UCHAR ucGfxBlkId;                        //GFX blk id to be harvested, like CU, RB or PRIM
+  UCHAR ucReserved;                        //reserved 
+  UCHAR ucActiveUnitNumPerSH;              //requested active CU/RB/PRIM number per shader array
+  UCHAR ucMaxUnitNumPerSH;                 //max CU/RB/PRIM number per shader array   
+} GFX_HAVESTING_PARAMETERS;
+
+//ucGfxBlkId
+#define GFX_HARVESTING_CU_ID               0
+#define GFX_HARVESTING_RB_ID               1
+#define GFX_HARVESTING_PRIM_ID             2
+
 /****************************************************************************/	
 //Portion VI: Definitinos for vbios MC scratch registers that driver used
 /****************************************************************************/
@@ -6875,8 +7288,17 @@ typedef struct _PHY_ANALOG_SETTING_INFO{
 #define MC_MISC0__MEMORY_TYPE__GDDR3  0x30000000
 #define MC_MISC0__MEMORY_TYPE__GDDR4  0x40000000
 #define MC_MISC0__MEMORY_TYPE__GDDR5  0x50000000
+#define MC_MISC0__MEMORY_TYPE__HBM    0x60000000
 #define MC_MISC0__MEMORY_TYPE__DDR3   0xB0000000
 
+#define ATOM_MEM_TYPE_DDR_STRING      "DDR"
+#define ATOM_MEM_TYPE_DDR2_STRING     "DDR2"
+#define ATOM_MEM_TYPE_GDDR3_STRING    "GDDR3"
+#define ATOM_MEM_TYPE_GDDR4_STRING    "GDDR4"
+#define ATOM_MEM_TYPE_GDDR5_STRING    "GDDR5"
+#define ATOM_MEM_TYPE_HBM_STRING      "HBM"
+#define ATOM_MEM_TYPE_DDR3_STRING     "DDR3"
+
 /****************************************************************************/	
 //Portion VI: Definitinos being oboselete
 /****************************************************************************/
-- 
1.7.7.5

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 026/165] drm/radeon: atombios power table updates (v2)
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (25 preceding siblings ...)
  2013-06-26 13:21 ` [PATCH 025/165] drm/radeon: upstream atombios.h " alexdeucher
@ 2013-06-26 13:21 ` alexdeucher
  2013-06-26 13:21 ` [PATCH 027/165] drm/radeon: handle the integrated thermal controller on CI alexdeucher
                   ` (86 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:21 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

v2: further updates

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/atombios.h |   58 ++++++++++++++++++++++++++++++++++--
 1 files changed, 54 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/radeon/atombios.h b/drivers/gpu/drm/radeon/atombios.h
index f19d9a6..7ba9588 100644
--- a/drivers/gpu/drm/radeon/atombios.h
+++ b/drivers/gpu/drm/radeon/atombios.h
@@ -7696,6 +7696,7 @@ typedef struct _ATOM_PPLIB_THERMALCONTROLLER
 #define ATOM_PP_THERMALCONTROLLER_NISLANDS  15
 #define ATOM_PP_THERMALCONTROLLER_SISLANDS  16
 #define ATOM_PP_THERMALCONTROLLER_LM96163   17
+#define ATOM_PP_THERMALCONTROLLER_CISLANDS  18
 
 // Thermal controller 'combo type' to use an external controller for Fan control and an internal controller for thermal.
 // We probably should reserve the bit 0x80 for this use.
@@ -7738,6 +7739,8 @@ typedef struct _ATOM_PPLIB_EXTENDEDHEADER
     // Add extra system parameters here, always adjust size to include all fields.
     USHORT  usVCETableOffset; //points to ATOM_PPLIB_VCE_Table
     USHORT  usUVDTableOffset;   //points to ATOM_PPLIB_UVD_Table
+    USHORT  usSAMUTableOffset;  //points to ATOM_PPLIB_SAMU_Table
+    USHORT  usPPMTableOffset;   //points to ATOM_PPLIB_PPM_Table
 } ATOM_PPLIB_EXTENDEDHEADER;
 
 //// ATOM_PPLIB_POWERPLAYTABLE::ulPlatformCaps
@@ -7759,7 +7762,7 @@ typedef struct _ATOM_PPLIB_EXTENDEDHEADER
 #define ATOM_PP_PLATFORM_CAP_VDDCI_CONTROL 0x8000                   // Does the driver control VDDCI independently from VDDC.
 #define ATOM_PP_PLATFORM_CAP_REGULATOR_HOT 0x00010000               // Enable the 'regulator hot' feature.
 #define ATOM_PP_PLATFORM_CAP_BACO          0x00020000               // Does the driver supports BACO state.
-
+#define ATOM_PP_PLATFORM_CAP_NEW_CAC_VOLTAGE   0x00040000           // Does the driver supports new CAC voltage table.
 
 typedef struct _ATOM_PPLIB_POWERPLAYTABLE
 {
@@ -7820,7 +7823,7 @@ typedef struct _ATOM_PPLIB_POWERPLAYTABLE4
     USHORT                     usVddcDependencyOnMCLKOffset;
     USHORT                     usMaxClockVoltageOnDCOffset;
     USHORT                     usVddcPhaseShedLimitsTableOffset;    // Points to ATOM_PPLIB_PhaseSheddingLimits_Table
-    USHORT                     usReserved;  
+    USHORT                     usMvddDependencyOnMCLKOffset;  
 } ATOM_PPLIB_POWERPLAYTABLE4, *LPATOM_PPLIB_POWERPLAYTABLE4;
 
 typedef struct _ATOM_PPLIB_POWERPLAYTABLE5
@@ -7985,6 +7988,17 @@ typedef struct _ATOM_PPLIB_SI_CLOCK_INFO
 
 } ATOM_PPLIB_SI_CLOCK_INFO;
 
+typedef struct _ATOM_PPLIB_CI_CLOCK_INFO
+{
+      USHORT usEngineClockLow;
+      UCHAR  ucEngineClockHigh;
+
+      USHORT usMemoryClockLow;
+      UCHAR  ucMemoryClockHigh;
+      
+      UCHAR  ucPCIEGen;
+      USHORT usPCIELane;
+} ATOM_PPLIB_CI_CLOCK_INFO;
 
 typedef struct _ATOM_PPLIB_RS780_CLOCK_INFO
 
@@ -8102,8 +8116,8 @@ typedef struct _ATOM_PPLIB_Clock_Voltage_Limit_Table
 
 typedef struct _ATOM_PPLIB_CAC_Leakage_Record
 {
-    USHORT usVddc;  // We use this field for the "fake" standardized VDDC for power calculations                                                  
-    ULONG  ulLeakageValue;
+    USHORT usVddc;  // We use this field for the "fake" standardized VDDC for power calculations; For CI and newer, we use this as the real VDDC value.
+    ULONG  ulLeakageValue;  // For CI and newer we use this as the "fake" standar VDDC value.
 }ATOM_PPLIB_CAC_Leakage_Record;
 
 typedef struct _ATOM_PPLIB_CAC_Leakage_Table
@@ -8218,6 +8232,42 @@ typedef struct _ATOM_PPLIB_UVD_Table
 //    ATOM_PPLIB_UVD_State_Table states;
 }ATOM_PPLIB_UVD_Table;
 
+
+typedef struct _ATOM_PPLIB_SAMClk_Voltage_Limit_Record
+{
+      USHORT usVoltage;
+      USHORT usSAMClockLow;
+      UCHAR  ucSAMClockHigh;
+}ATOM_PPLIB_SAMClk_Voltage_Limit_Record;
+
+typedef struct _ATOM_PPLIB_SAMClk_Voltage_Limit_Table{
+    UCHAR numEntries;
+    ATOM_PPLIB_SAMClk_Voltage_Limit_Record entries[1];
+}ATOM_PPLIB_SAMClk_Voltage_Limit_Table;
+
+typedef struct _ATOM_PPLIB_SAMU_Table
+{
+      UCHAR revid;
+      ATOM_PPLIB_SAMClk_Voltage_Limit_Table limits;
+}ATOM_PPLIB_SAMU_Table;
+
+#define ATOM_PPM_A_A    1
+#define ATOM_PPM_A_I    2
+typedef struct _ATOM_PPLIB_PPM_Table
+{
+      UCHAR  ucRevId;
+      UCHAR  ucPpmDesign;          //A+I or A+A
+      USHORT usCpuCoreNumber;
+      ULONG  ulPlatformTDP;
+      ULONG  ulSmallACPlatformTDP;
+      ULONG  ulPlatformTDC;
+      ULONG  ulSmallACPlatformTDC;
+      ULONG  ulApuTDP;
+      ULONG  ulDGpuTDP;  
+      ULONG  ulDGpuUlvPower;
+      ULONG  ulTjmax;
+} ATOM_PPLIB_PPM_Table;
+
 /**************************************************************************/
 
 
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 027/165] drm/radeon: handle the integrated thermal controller on CI
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (26 preceding siblings ...)
  2013-06-26 13:21 ` [PATCH 026/165] drm/radeon: atombios power table " alexdeucher
@ 2013-06-26 13:21 ` alexdeucher
  2013-06-26 13:21 ` [PATCH 028/165] drm/radeon: update power state parsing for CI alexdeucher
                   ` (85 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:21 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

No support for reading the temperature yet.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/radeon.h          |    1 +
 drivers/gpu/drm/radeon/radeon_atombios.c |    6 ++++++
 2 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 919c4d8..04e8dbd 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -1033,6 +1033,7 @@ enum radeon_int_thermal_type {
 	THERMAL_TYPE_SUMO,
 	THERMAL_TYPE_NI,
 	THERMAL_TYPE_SI,
+	THERMAL_TYPE_CI,
 };
 
 struct radeon_voltage {
diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c
index dea6f63c..cb3273b 100644
--- a/drivers/gpu/drm/radeon/radeon_atombios.c
+++ b/drivers/gpu/drm/radeon/radeon_atombios.c
@@ -1927,6 +1927,7 @@ static const char *pp_lib_thermal_controller_names[] = {
 	"Northern Islands",
 	"Southern Islands",
 	"lm96163",
+	"Sea Islands",
 };
 
 union power_info {
@@ -2209,6 +2210,11 @@ static void radeon_atombios_add_pplib_thermal_controller(struct radeon_device *r
 				 (controller->ucFanParameters &
 				  ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
 			rdev->pm.int_thermal_type = THERMAL_TYPE_SI;
+		} else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_CISLANDS) {
+			DRM_INFO("Internal thermal controller %s fan control\n",
+				 (controller->ucFanParameters &
+				  ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
+			rdev->pm.int_thermal_type = THERMAL_TYPE_CI;
 		} else if ((controller->ucType ==
 			    ATOM_PP_THERMALCONTROLLER_EXTERNAL_GPIO) ||
 			   (controller->ucType ==
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 028/165] drm/radeon: update power state parsing for CI
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (27 preceding siblings ...)
  2013-06-26 13:21 ` [PATCH 027/165] drm/radeon: handle the integrated thermal controller on CI alexdeucher
@ 2013-06-26 13:21 ` alexdeucher
  2013-06-26 13:21 ` [PATCH 029/165] drm/radeon/dce8: add support for display watermark setup alexdeucher
                   ` (84 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:21 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/radeon_atombios.c |   10 ++++++++++
 1 files changed, 10 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c
index cb3273b..88a55af 100644
--- a/drivers/gpu/drm/radeon/radeon_atombios.c
+++ b/drivers/gpu/drm/radeon/radeon_atombios.c
@@ -1945,6 +1945,7 @@ union pplib_clock_info {
 	struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen;
 	struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo;
 	struct _ATOM_PPLIB_SI_CLOCK_INFO si;
+	struct _ATOM_PPLIB_CI_CLOCK_INFO ci;
 };
 
 union pplib_power_state {
@@ -2353,6 +2354,15 @@ static bool radeon_atombios_parse_pplib_clock_info(struct radeon_device *rdev,
 			sclk |= clock_info->rs780.ucLowEngineClockHigh << 16;
 			rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk;
 		}
+	} else if (rdev->family >= CHIP_BONAIRE) {
+		sclk = le16_to_cpu(clock_info->ci.usEngineClockLow);
+		sclk |= clock_info->ci.ucEngineClockHigh << 16;
+		mclk = le16_to_cpu(clock_info->ci.usMemoryClockLow);
+		mclk |= clock_info->ci.ucMemoryClockHigh << 16;
+		rdev->pm.power_state[state_index].clock_info[mode_index].mclk = mclk;
+		rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk;
+		rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type =
+			VOLTAGE_NONE;
 	} else if (rdev->family >= CHIP_TAHITI) {
 		sclk = le16_to_cpu(clock_info->si.usEngineClockLow);
 		sclk |= clock_info->si.ucEngineClockHigh << 16;
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 029/165] drm/radeon/dce8: add support for display watermark setup
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (28 preceding siblings ...)
  2013-06-26 13:21 ` [PATCH 028/165] drm/radeon: update power state parsing for CI alexdeucher
@ 2013-06-26 13:21 ` alexdeucher
  2013-06-26 13:21 ` [PATCH 030/165] drm/radeon/cik: add hw cursor support (v2) alexdeucher
                   ` (83 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:21 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/cik.c  |  537 +++++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/radeon/cikd.h |   11 +
 2 files changed, 548 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
index cbc64a2..228d399 100644
--- a/drivers/gpu/drm/radeon/cik.c
+++ b/drivers/gpu/drm/radeon/cik.c
@@ -5021,3 +5021,540 @@ void cik_fini(struct radeon_device *rdev)
 	kfree(rdev->bios);
 	rdev->bios = NULL;
 }
+
+/* display watermark setup */
+/**
+ * dce8_line_buffer_adjust - Set up the line buffer
+ *
+ * @rdev: radeon_device pointer
+ * @radeon_crtc: the selected display controller
+ * @mode: the current display mode on the selected display
+ * controller
+ *
+ * Setup up the line buffer allocation for
+ * the selected display controller (CIK).
+ * Returns the line buffer size in pixels.
+ */
+static u32 dce8_line_buffer_adjust(struct radeon_device *rdev,
+				   struct radeon_crtc *radeon_crtc,
+				   struct drm_display_mode *mode)
+{
+	u32 tmp;
+
+	/*
+	 * Line Buffer Setup
+	 * There are 6 line buffers, one for each display controllers.
+	 * There are 3 partitions per LB. Select the number of partitions
+	 * to enable based on the display width.  For display widths larger
+	 * than 4096, you need use to use 2 display controllers and combine
+	 * them using the stereo blender.
+	 */
+	if (radeon_crtc->base.enabled && mode) {
+		if (mode->crtc_hdisplay < 1920)
+			tmp = 1;
+		else if (mode->crtc_hdisplay < 2560)
+			tmp = 2;
+		else if (mode->crtc_hdisplay < 4096)
+			tmp = 0;
+		else {
+			DRM_DEBUG_KMS("Mode too big for LB!\n");
+			tmp = 0;
+		}
+	} else
+		tmp = 1;
+
+	WREG32(LB_MEMORY_CTRL + radeon_crtc->crtc_offset,
+	       LB_MEMORY_CONFIG(tmp) | LB_MEMORY_SIZE(0x6B0));
+
+	if (radeon_crtc->base.enabled && mode) {
+		switch (tmp) {
+		case 0:
+		default:
+			return 4096 * 2;
+		case 1:
+			return 1920 * 2;
+		case 2:
+			return 2560 * 2;
+		}
+	}
+
+	/* controller not enabled, so no lb used */
+	return 0;
+}
+
+/**
+ * cik_get_number_of_dram_channels - get the number of dram channels
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Look up the number of video ram channels (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns the number of dram channels
+ */
+static u32 cik_get_number_of_dram_channels(struct radeon_device *rdev)
+{
+	u32 tmp = RREG32(MC_SHARED_CHMAP);
+
+	switch ((tmp & NOOFCHAN_MASK) >> NOOFCHAN_SHIFT) {
+	case 0:
+	default:
+		return 1;
+	case 1:
+		return 2;
+	case 2:
+		return 4;
+	case 3:
+		return 8;
+	case 4:
+		return 3;
+	case 5:
+		return 6;
+	case 6:
+		return 10;
+	case 7:
+		return 12;
+	case 8:
+		return 16;
+	}
+}
+
+struct dce8_wm_params {
+	u32 dram_channels; /* number of dram channels */
+	u32 yclk;          /* bandwidth per dram data pin in kHz */
+	u32 sclk;          /* engine clock in kHz */
+	u32 disp_clk;      /* display clock in kHz */
+	u32 src_width;     /* viewport width */
+	u32 active_time;   /* active display time in ns */
+	u32 blank_time;    /* blank time in ns */
+	bool interlaced;    /* mode is interlaced */
+	fixed20_12 vsc;    /* vertical scale ratio */
+	u32 num_heads;     /* number of active crtcs */
+	u32 bytes_per_pixel; /* bytes per pixel display + overlay */
+	u32 lb_size;       /* line buffer allocated to pipe */
+	u32 vtaps;         /* vertical scaler taps */
+};
+
+/**
+ * dce8_dram_bandwidth - get the dram bandwidth
+ *
+ * @wm: watermark calculation data
+ *
+ * Calculate the raw dram bandwidth (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns the dram bandwidth in MBytes/s
+ */
+static u32 dce8_dram_bandwidth(struct dce8_wm_params *wm)
+{
+	/* Calculate raw DRAM Bandwidth */
+	fixed20_12 dram_efficiency; /* 0.7 */
+	fixed20_12 yclk, dram_channels, bandwidth;
+	fixed20_12 a;
+
+	a.full = dfixed_const(1000);
+	yclk.full = dfixed_const(wm->yclk);
+	yclk.full = dfixed_div(yclk, a);
+	dram_channels.full = dfixed_const(wm->dram_channels * 4);
+	a.full = dfixed_const(10);
+	dram_efficiency.full = dfixed_const(7);
+	dram_efficiency.full = dfixed_div(dram_efficiency, a);
+	bandwidth.full = dfixed_mul(dram_channels, yclk);
+	bandwidth.full = dfixed_mul(bandwidth, dram_efficiency);
+
+	return dfixed_trunc(bandwidth);
+}
+
+/**
+ * dce8_dram_bandwidth_for_display - get the dram bandwidth for display
+ *
+ * @wm: watermark calculation data
+ *
+ * Calculate the dram bandwidth used for display (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns the dram bandwidth for display in MBytes/s
+ */
+static u32 dce8_dram_bandwidth_for_display(struct dce8_wm_params *wm)
+{
+	/* Calculate DRAM Bandwidth and the part allocated to display. */
+	fixed20_12 disp_dram_allocation; /* 0.3 to 0.7 */
+	fixed20_12 yclk, dram_channels, bandwidth;
+	fixed20_12 a;
+
+	a.full = dfixed_const(1000);
+	yclk.full = dfixed_const(wm->yclk);
+	yclk.full = dfixed_div(yclk, a);
+	dram_channels.full = dfixed_const(wm->dram_channels * 4);
+	a.full = dfixed_const(10);
+	disp_dram_allocation.full = dfixed_const(3); /* XXX worse case value 0.3 */
+	disp_dram_allocation.full = dfixed_div(disp_dram_allocation, a);
+	bandwidth.full = dfixed_mul(dram_channels, yclk);
+	bandwidth.full = dfixed_mul(bandwidth, disp_dram_allocation);
+
+	return dfixed_trunc(bandwidth);
+}
+
+/**
+ * dce8_data_return_bandwidth - get the data return bandwidth
+ *
+ * @wm: watermark calculation data
+ *
+ * Calculate the data return bandwidth used for display (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns the data return bandwidth in MBytes/s
+ */
+static u32 dce8_data_return_bandwidth(struct dce8_wm_params *wm)
+{
+	/* Calculate the display Data return Bandwidth */
+	fixed20_12 return_efficiency; /* 0.8 */
+	fixed20_12 sclk, bandwidth;
+	fixed20_12 a;
+
+	a.full = dfixed_const(1000);
+	sclk.full = dfixed_const(wm->sclk);
+	sclk.full = dfixed_div(sclk, a);
+	a.full = dfixed_const(10);
+	return_efficiency.full = dfixed_const(8);
+	return_efficiency.full = dfixed_div(return_efficiency, a);
+	a.full = dfixed_const(32);
+	bandwidth.full = dfixed_mul(a, sclk);
+	bandwidth.full = dfixed_mul(bandwidth, return_efficiency);
+
+	return dfixed_trunc(bandwidth);
+}
+
+/**
+ * dce8_dmif_request_bandwidth - get the dmif bandwidth
+ *
+ * @wm: watermark calculation data
+ *
+ * Calculate the dmif bandwidth used for display (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns the dmif bandwidth in MBytes/s
+ */
+static u32 dce8_dmif_request_bandwidth(struct dce8_wm_params *wm)
+{
+	/* Calculate the DMIF Request Bandwidth */
+	fixed20_12 disp_clk_request_efficiency; /* 0.8 */
+	fixed20_12 disp_clk, bandwidth;
+	fixed20_12 a, b;
+
+	a.full = dfixed_const(1000);
+	disp_clk.full = dfixed_const(wm->disp_clk);
+	disp_clk.full = dfixed_div(disp_clk, a);
+	a.full = dfixed_const(32);
+	b.full = dfixed_mul(a, disp_clk);
+
+	a.full = dfixed_const(10);
+	disp_clk_request_efficiency.full = dfixed_const(8);
+	disp_clk_request_efficiency.full = dfixed_div(disp_clk_request_efficiency, a);
+
+	bandwidth.full = dfixed_mul(b, disp_clk_request_efficiency);
+
+	return dfixed_trunc(bandwidth);
+}
+
+/**
+ * dce8_available_bandwidth - get the min available bandwidth
+ *
+ * @wm: watermark calculation data
+ *
+ * Calculate the min available bandwidth used for display (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns the min available bandwidth in MBytes/s
+ */
+static u32 dce8_available_bandwidth(struct dce8_wm_params *wm)
+{
+	/* Calculate the Available bandwidth. Display can use this temporarily but not in average. */
+	u32 dram_bandwidth = dce8_dram_bandwidth(wm);
+	u32 data_return_bandwidth = dce8_data_return_bandwidth(wm);
+	u32 dmif_req_bandwidth = dce8_dmif_request_bandwidth(wm);
+
+	return min(dram_bandwidth, min(data_return_bandwidth, dmif_req_bandwidth));
+}
+
+/**
+ * dce8_average_bandwidth - get the average available bandwidth
+ *
+ * @wm: watermark calculation data
+ *
+ * Calculate the average available bandwidth used for display (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns the average available bandwidth in MBytes/s
+ */
+static u32 dce8_average_bandwidth(struct dce8_wm_params *wm)
+{
+	/* Calculate the display mode Average Bandwidth
+	 * DisplayMode should contain the source and destination dimensions,
+	 * timing, etc.
+	 */
+	fixed20_12 bpp;
+	fixed20_12 line_time;
+	fixed20_12 src_width;
+	fixed20_12 bandwidth;
+	fixed20_12 a;
+
+	a.full = dfixed_const(1000);
+	line_time.full = dfixed_const(wm->active_time + wm->blank_time);
+	line_time.full = dfixed_div(line_time, a);
+	bpp.full = dfixed_const(wm->bytes_per_pixel);
+	src_width.full = dfixed_const(wm->src_width);
+	bandwidth.full = dfixed_mul(src_width, bpp);
+	bandwidth.full = dfixed_mul(bandwidth, wm->vsc);
+	bandwidth.full = dfixed_div(bandwidth, line_time);
+
+	return dfixed_trunc(bandwidth);
+}
+
+/**
+ * dce8_latency_watermark - get the latency watermark
+ *
+ * @wm: watermark calculation data
+ *
+ * Calculate the latency watermark (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns the latency watermark in ns
+ */
+static u32 dce8_latency_watermark(struct dce8_wm_params *wm)
+{
+	/* First calculate the latency in ns */
+	u32 mc_latency = 2000; /* 2000 ns. */
+	u32 available_bandwidth = dce8_available_bandwidth(wm);
+	u32 worst_chunk_return_time = (512 * 8 * 1000) / available_bandwidth;
+	u32 cursor_line_pair_return_time = (128 * 4 * 1000) / available_bandwidth;
+	u32 dc_latency = 40000000 / wm->disp_clk; /* dc pipe latency */
+	u32 other_heads_data_return_time = ((wm->num_heads + 1) * worst_chunk_return_time) +
+		(wm->num_heads * cursor_line_pair_return_time);
+	u32 latency = mc_latency + other_heads_data_return_time + dc_latency;
+	u32 max_src_lines_per_dst_line, lb_fill_bw, line_fill_time;
+	u32 tmp, dmif_size = 12288;
+	fixed20_12 a, b, c;
+
+	if (wm->num_heads == 0)
+		return 0;
+
+	a.full = dfixed_const(2);
+	b.full = dfixed_const(1);
+	if ((wm->vsc.full > a.full) ||
+	    ((wm->vsc.full > b.full) && (wm->vtaps >= 3)) ||
+	    (wm->vtaps >= 5) ||
+	    ((wm->vsc.full >= a.full) && wm->interlaced))
+		max_src_lines_per_dst_line = 4;
+	else
+		max_src_lines_per_dst_line = 2;
+
+	a.full = dfixed_const(available_bandwidth);
+	b.full = dfixed_const(wm->num_heads);
+	a.full = dfixed_div(a, b);
+
+	b.full = dfixed_const(mc_latency + 512);
+	c.full = dfixed_const(wm->disp_clk);
+	b.full = dfixed_div(b, c);
+
+	c.full = dfixed_const(dmif_size);
+	b.full = dfixed_div(c, b);
+
+	tmp = min(dfixed_trunc(a), dfixed_trunc(b));
+
+	b.full = dfixed_const(1000);
+	c.full = dfixed_const(wm->disp_clk);
+	b.full = dfixed_div(c, b);
+	c.full = dfixed_const(wm->bytes_per_pixel);
+	b.full = dfixed_mul(b, c);
+
+	lb_fill_bw = min(tmp, dfixed_trunc(b));
+
+	a.full = dfixed_const(max_src_lines_per_dst_line * wm->src_width * wm->bytes_per_pixel);
+	b.full = dfixed_const(1000);
+	c.full = dfixed_const(lb_fill_bw);
+	b.full = dfixed_div(c, b);
+	a.full = dfixed_div(a, b);
+	line_fill_time = dfixed_trunc(a);
+
+	if (line_fill_time < wm->active_time)
+		return latency;
+	else
+		return latency + (line_fill_time - wm->active_time);
+
+}
+
+/**
+ * dce8_average_bandwidth_vs_dram_bandwidth_for_display - check
+ * average and available dram bandwidth
+ *
+ * @wm: watermark calculation data
+ *
+ * Check if the display average bandwidth fits in the display
+ * dram bandwidth (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns true if the display fits, false if not.
+ */
+static bool dce8_average_bandwidth_vs_dram_bandwidth_for_display(struct dce8_wm_params *wm)
+{
+	if (dce8_average_bandwidth(wm) <=
+	    (dce8_dram_bandwidth_for_display(wm) / wm->num_heads))
+		return true;
+	else
+		return false;
+}
+
+/**
+ * dce8_average_bandwidth_vs_available_bandwidth - check
+ * average and available bandwidth
+ *
+ * @wm: watermark calculation data
+ *
+ * Check if the display average bandwidth fits in the display
+ * available bandwidth (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns true if the display fits, false if not.
+ */
+static bool dce8_average_bandwidth_vs_available_bandwidth(struct dce8_wm_params *wm)
+{
+	if (dce8_average_bandwidth(wm) <=
+	    (dce8_available_bandwidth(wm) / wm->num_heads))
+		return true;
+	else
+		return false;
+}
+
+/**
+ * dce8_check_latency_hiding - check latency hiding
+ *
+ * @wm: watermark calculation data
+ *
+ * Check latency hiding (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns true if the display fits, false if not.
+ */
+static bool dce8_check_latency_hiding(struct dce8_wm_params *wm)
+{
+	u32 lb_partitions = wm->lb_size / wm->src_width;
+	u32 line_time = wm->active_time + wm->blank_time;
+	u32 latency_tolerant_lines;
+	u32 latency_hiding;
+	fixed20_12 a;
+
+	a.full = dfixed_const(1);
+	if (wm->vsc.full > a.full)
+		latency_tolerant_lines = 1;
+	else {
+		if (lb_partitions <= (wm->vtaps + 1))
+			latency_tolerant_lines = 1;
+		else
+			latency_tolerant_lines = 2;
+	}
+
+	latency_hiding = (latency_tolerant_lines * line_time + wm->blank_time);
+
+	if (dce8_latency_watermark(wm) <= latency_hiding)
+		return true;
+	else
+		return false;
+}
+
+/**
+ * dce8_program_watermarks - program display watermarks
+ *
+ * @rdev: radeon_device pointer
+ * @radeon_crtc: the selected display controller
+ * @lb_size: line buffer size
+ * @num_heads: number of display controllers in use
+ *
+ * Calculate and program the display watermarks for the
+ * selected display controller (CIK).
+ */
+static void dce8_program_watermarks(struct radeon_device *rdev,
+				    struct radeon_crtc *radeon_crtc,
+				    u32 lb_size, u32 num_heads)
+{
+	struct drm_display_mode *mode = &radeon_crtc->base.mode;
+	struct dce8_wm_params wm;
+	u32 pixel_period;
+	u32 line_time = 0;
+	u32 latency_watermark_a = 0, latency_watermark_b = 0;
+	u32 tmp, wm_mask;
+
+	if (radeon_crtc->base.enabled && num_heads && mode) {
+		pixel_period = 1000000 / (u32)mode->clock;
+		line_time = min((u32)mode->crtc_htotal * pixel_period, (u32)65535);
+
+		wm.yclk = rdev->pm.current_mclk * 10;
+		wm.sclk = rdev->pm.current_sclk * 10;
+		wm.disp_clk = mode->clock;
+		wm.src_width = mode->crtc_hdisplay;
+		wm.active_time = mode->crtc_hdisplay * pixel_period;
+		wm.blank_time = line_time - wm.active_time;
+		wm.interlaced = false;
+		if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+			wm.interlaced = true;
+		wm.vsc = radeon_crtc->vsc;
+		wm.vtaps = 1;
+		if (radeon_crtc->rmx_type != RMX_OFF)
+			wm.vtaps = 2;
+		wm.bytes_per_pixel = 4; /* XXX: get this from fb config */
+		wm.lb_size = lb_size;
+		wm.dram_channels = cik_get_number_of_dram_channels(rdev);
+		wm.num_heads = num_heads;
+
+		/* set for high clocks */
+		latency_watermark_a = min(dce8_latency_watermark(&wm), (u32)65535);
+		/* set for low clocks */
+		/* wm.yclk = low clk; wm.sclk = low clk */
+		latency_watermark_b = min(dce8_latency_watermark(&wm), (u32)65535);
+
+		/* possibly force display priority to high */
+		/* should really do this at mode validation time... */
+		if (!dce8_average_bandwidth_vs_dram_bandwidth_for_display(&wm) ||
+		    !dce8_average_bandwidth_vs_available_bandwidth(&wm) ||
+		    !dce8_check_latency_hiding(&wm) ||
+		    (rdev->disp_priority == 2)) {
+			DRM_DEBUG_KMS("force priority to high\n");
+		}
+	}
+
+	/* select wm A */
+	wm_mask = RREG32(DPG_WATERMARK_MASK_CONTROL + radeon_crtc->crtc_offset);
+	tmp = wm_mask;
+	tmp &= ~LATENCY_WATERMARK_MASK(3);
+	tmp |= LATENCY_WATERMARK_MASK(1);
+	WREG32(DPG_WATERMARK_MASK_CONTROL + radeon_crtc->crtc_offset, tmp);
+	WREG32(DPG_PIPE_LATENCY_CONTROL + radeon_crtc->crtc_offset,
+	       (LATENCY_LOW_WATERMARK(latency_watermark_a) |
+		LATENCY_HIGH_WATERMARK(line_time)));
+	/* select wm B */
+	tmp = RREG32(DPG_WATERMARK_MASK_CONTROL + radeon_crtc->crtc_offset);
+	tmp &= ~LATENCY_WATERMARK_MASK(3);
+	tmp |= LATENCY_WATERMARK_MASK(2);
+	WREG32(DPG_WATERMARK_MASK_CONTROL + radeon_crtc->crtc_offset, tmp);
+	WREG32(DPG_PIPE_LATENCY_CONTROL + radeon_crtc->crtc_offset,
+	       (LATENCY_LOW_WATERMARK(latency_watermark_b) |
+		LATENCY_HIGH_WATERMARK(line_time)));
+	/* restore original selection */
+	WREG32(DPG_WATERMARK_MASK_CONTROL + radeon_crtc->crtc_offset, wm_mask);
+}
+
+/**
+ * dce8_bandwidth_update - program display watermarks
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Calculate and program the display watermarks and line
+ * buffer allocation (CIK).
+ */
+void dce8_bandwidth_update(struct radeon_device *rdev)
+{
+	struct drm_display_mode *mode = NULL;
+	u32 num_heads = 0, lb_size;
+	int i;
+
+	radeon_update_display_priority(rdev);
+
+	for (i = 0; i < rdev->num_crtc; i++) {
+		if (rdev->mode_info.crtcs[i]->base.enabled)
+			num_heads++;
+	}
+	for (i = 0; i < rdev->num_crtc; i++) {
+		mode = &rdev->mode_info.crtcs[i]->base.mode;
+		lb_size = dce8_line_buffer_adjust(rdev, rdev->mode_info.crtcs[i], mode);
+		dce8_program_watermarks(rdev, rdev->mode_info.crtcs[i], lb_size, num_heads);
+	}
+}
diff --git a/drivers/gpu/drm/radeon/cikd.h b/drivers/gpu/drm/radeon/cikd.h
index 39ed517..3349e37 100644
--- a/drivers/gpu/drm/radeon/cikd.h
+++ b/drivers/gpu/drm/radeon/cikd.h
@@ -259,6 +259,17 @@
 #define		SDMA0					(1 << 10)
 #define		SDMA1					(1 << 11)
 
+/* 0x6b04, 0x7704, 0x10304, 0x10f04, 0x11b04, 0x12704 */
+#define	LB_MEMORY_CTRL					0x6b04
+#define		LB_MEMORY_SIZE(x)			((x) << 0)
+#define		LB_MEMORY_CONFIG(x)			((x) << 20)
+
+#define	DPG_WATERMARK_MASK_CONTROL			0x6cc8
+#       define LATENCY_WATERMARK_MASK(x)		((x) << 8)
+#define	DPG_PIPE_LATENCY_CONTROL			0x6ccc
+#       define LATENCY_LOW_WATERMARK(x)			((x) << 0)
+#       define LATENCY_HIGH_WATERMARK(x)		((x) << 16)
+
 /* 0x6b24, 0x7724, 0x10324, 0x10f24, 0x11b24, 0x12724 */
 #define LB_VLINE_STATUS                                 0x6b24
 #       define VLINE_OCCURRED                           (1 << 0)
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 030/165] drm/radeon/cik: add hw cursor support (v2)
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (29 preceding siblings ...)
  2013-06-26 13:21 ` [PATCH 029/165] drm/radeon/dce8: add support for display watermark setup alexdeucher
@ 2013-06-26 13:21 ` alexdeucher
  2013-06-26 13:21 ` [PATCH 031/165] drm/radeon/dce8: properly handle interlaced timing alexdeucher
                   ` (82 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:21 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

CIK (DCE8) hw cursors are programmed the same as evergreen
(DCE4) with the following caveats:
- cursors are now 128x128 pixels
- new alpha blend enable bit

v2: rebase

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/cik_reg.h        |   65 +++++++++++++++++++++++++++++++
 drivers/gpu/drm/radeon/radeon.h         |    7 +++
 drivers/gpu/drm/radeon/radeon_cursor.c  |   10 ++---
 drivers/gpu/drm/radeon/radeon_display.c |   16 +++++++-
 drivers/gpu/drm/radeon/radeon_mode.h    |    2 +
 drivers/gpu/drm/radeon/radeon_reg.h     |    1 +
 6 files changed, 94 insertions(+), 7 deletions(-)
 create mode 100644 drivers/gpu/drm/radeon/cik_reg.h

diff --git a/drivers/gpu/drm/radeon/cik_reg.h b/drivers/gpu/drm/radeon/cik_reg.h
new file mode 100644
index 0000000..b96dac0
--- /dev/null
+++ b/drivers/gpu/drm/radeon/cik_reg.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2012 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Alex Deucher
+ */
+#ifndef __CIK_REG_H__
+#define __CIK_REG_H__
+
+#define CIK_DC_GPIO_HPD_MASK                      0x65b0
+#define CIK_DC_GPIO_HPD_A                         0x65b4
+#define CIK_DC_GPIO_HPD_EN                        0x65b8
+#define CIK_DC_GPIO_HPD_Y                         0x65bc
+
+/* CUR blocks at 0x6998, 0x7598, 0x10198, 0x10d98, 0x11998, 0x12598 */
+#define CIK_CUR_CONTROL                           0x6998
+#       define CIK_CURSOR_EN                      (1 << 0)
+#       define CIK_CURSOR_MODE(x)                 (((x) & 0x3) << 8)
+#       define CIK_CURSOR_MONO                    0
+#       define CIK_CURSOR_24_1                    1
+#       define CIK_CURSOR_24_8_PRE_MULT           2
+#       define CIK_CURSOR_24_8_UNPRE_MULT         3
+#       define CIK_CURSOR_2X_MAGNIFY              (1 << 16)
+#       define CIK_CURSOR_FORCE_MC_ON             (1 << 20)
+#       define CIK_CURSOR_URGENT_CONTROL(x)       (((x) & 0x7) << 24)
+#       define CIK_CURSOR_URGENT_ALWAYS           0
+#       define CIK_CURSOR_URGENT_1_8              1
+#       define CIK_CURSOR_URGENT_1_4              2
+#       define CIK_CURSOR_URGENT_3_8              3
+#       define CIK_CURSOR_URGENT_1_2              4
+#define CIK_CUR_SURFACE_ADDRESS                   0x699c
+#       define CIK_CUR_SURFACE_ADDRESS_MASK       0xfffff000
+#define CIK_CUR_SIZE                              0x69a0
+#define CIK_CUR_SURFACE_ADDRESS_HIGH              0x69a4
+#define CIK_CUR_POSITION                          0x69a8
+#define CIK_CUR_HOT_SPOT                          0x69ac
+#define CIK_CUR_COLOR1                            0x69b0
+#define CIK_CUR_COLOR2                            0x69b4
+#define CIK_CUR_UPDATE                            0x69b8
+#       define CIK_CURSOR_UPDATE_PENDING          (1 << 0)
+#       define CIK_CURSOR_UPDATE_TAKEN            (1 << 1)
+#       define CIK_CURSOR_UPDATE_LOCK             (1 << 16)
+#       define CIK_CURSOR_DISABLE_MULTIPLE_UPDATE (1 << 24)
+
+#define CIK_ALPHA_CONTROL                         0x6af0
+#       define CIK_CURSOR_ALPHA_BLND_ENA          (1 << 1)
+
+#endif
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 04e8dbd..b329e99 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -150,6 +150,13 @@ extern int radeon_fastfb;
 #define RADEON_RESET_MC				(1 << 10)
 #define RADEON_RESET_DISPLAY			(1 << 11)
 
+/* max cursor sizes (in pixels) */
+#define CURSOR_WIDTH 64
+#define CURSOR_HEIGHT 64
+
+#define CIK_CURSOR_WIDTH 128
+#define CIK_CURSOR_HEIGHT 128
+
 /*
  * Errata workarounds.
  */
diff --git a/drivers/gpu/drm/radeon/radeon_cursor.c b/drivers/gpu/drm/radeon/radeon_cursor.c
index b097d5b..9630e8d 100644
--- a/drivers/gpu/drm/radeon/radeon_cursor.c
+++ b/drivers/gpu/drm/radeon/radeon_cursor.c
@@ -27,9 +27,6 @@
 #include <drm/radeon_drm.h>
 #include "radeon.h"
 
-#define CURSOR_WIDTH 64
-#define CURSOR_HEIGHT 64
-
 static void radeon_lock_cursor(struct drm_crtc *crtc, bool lock)
 {
 	struct radeon_device *rdev = crtc->dev->dev_private;
@@ -167,7 +164,8 @@ int radeon_crtc_cursor_set(struct drm_crtc *crtc,
 		goto unpin;
 	}
 
-	if ((width > CURSOR_WIDTH) || (height > CURSOR_HEIGHT)) {
+	if ((width > radeon_crtc->max_cursor_width) ||
+	    (height > radeon_crtc->max_cursor_height)) {
 		DRM_ERROR("bad cursor width or height %d x %d\n", width, height);
 		return -EINVAL;
 	}
@@ -233,11 +231,11 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc,
 	DRM_DEBUG("x %d y %d c->x %d c->y %d\n", x, y, crtc->x, crtc->y);
 
 	if (x < 0) {
-		xorigin = min(-x, CURSOR_WIDTH - 1);
+		xorigin = min(-x, radeon_crtc->max_cursor_width - 1);
 		x = 0;
 	}
 	if (y < 0) {
-		yorigin = min(-y, CURSOR_HEIGHT - 1);
+		yorigin = min(-y, radeon_crtc->max_cursor_height - 1);
 		y = 0;
 	}
 
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index eb18bb7..1f850eb 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -153,7 +153,13 @@ static void dce5_crtc_load_lut(struct drm_crtc *crtc)
 		NI_OUTPUT_CSC_OVL_MODE(NI_OUTPUT_CSC_BYPASS)));
 	/* XXX match this to the depth of the crtc fmt block, move to modeset? */
 	WREG32(0x6940 + radeon_crtc->crtc_offset, 0);
-
+	if (ASIC_IS_DCE8(rdev)) {
+		/* XXX this only needs to be programmed once per crtc at startup,
+		 * not sure where the best place for it is
+		 */
+		WREG32(CIK_ALPHA_CONTROL + radeon_crtc->crtc_offset,
+		       CIK_CURSOR_ALPHA_BLND_ENA);
+	}
 }
 
 static void legacy_crtc_load_lut(struct drm_crtc *crtc)
@@ -512,6 +518,14 @@ static void radeon_crtc_init(struct drm_device *dev, int index)
 	radeon_crtc->crtc_id = index;
 	rdev->mode_info.crtcs[index] = radeon_crtc;
 
+	if (rdev->family >= CHIP_BONAIRE) {
+		radeon_crtc->max_cursor_width = CIK_CURSOR_WIDTH;
+		radeon_crtc->max_cursor_height = CIK_CURSOR_HEIGHT;
+	} else {
+		radeon_crtc->max_cursor_width = CURSOR_WIDTH;
+		radeon_crtc->max_cursor_height = CURSOR_HEIGHT;
+	}
+
 #if 0
 	radeon_crtc->mode_set.crtc = &radeon_crtc->base;
 	radeon_crtc->mode_set.connectors = (struct drm_connector **)(radeon_crtc + 1);
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
index 69ad4fe..4ed0a4c 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -307,6 +307,8 @@ struct radeon_crtc {
 	uint64_t cursor_addr;
 	int cursor_width;
 	int cursor_height;
+	int max_cursor_width;
+	int max_cursor_height;
 	uint32_t legacy_display_base_addr;
 	uint32_t legacy_cursor_offset;
 	enum radeon_rmx_type rmx_type;
diff --git a/drivers/gpu/drm/radeon/radeon_reg.h b/drivers/gpu/drm/radeon/radeon_reg.h
index 7e2c2b7..62d5497 100644
--- a/drivers/gpu/drm/radeon/radeon_reg.h
+++ b/drivers/gpu/drm/radeon/radeon_reg.h
@@ -57,6 +57,7 @@
 #include "evergreen_reg.h"
 #include "ni_reg.h"
 #include "si_reg.h"
+#include "cik_reg.h"
 
 #define RADEON_MC_AGP_LOCATION		0x014c
 #define		RADEON_MC_AGP_START_MASK	0x0000FFFF
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 031/165] drm/radeon/dce8: properly handle interlaced timing
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (30 preceding siblings ...)
  2013-06-26 13:21 ` [PATCH 030/165] drm/radeon/cik: add hw cursor support (v2) alexdeucher
@ 2013-06-26 13:21 ` alexdeucher
  2013-06-26 13:21 ` [PATCH 032/165] drm/radeon/dce8: crtc_set_base updates alexdeucher
                   ` (81 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:21 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

The register bits changed on DCE8 compared to previous
families.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/atombios_encoders.c |    8 +++++++-
 drivers/gpu/drm/radeon/cik_reg.h           |    3 +++
 2 files changed, 10 insertions(+), 1 deletions(-)

diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c
index 4120d35..4439419 100644
--- a/drivers/gpu/drm/radeon/atombios_encoders.c
+++ b/drivers/gpu/drm/radeon/atombios_encoders.c
@@ -1962,7 +1962,13 @@ atombios_apply_encoder_quirks(struct drm_encoder *encoder,
 	/* set scaler clears this on some chips */
 	if (ASIC_IS_AVIVO(rdev) &&
 	    (!(radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)))) {
-		if (ASIC_IS_DCE4(rdev)) {
+		if (ASIC_IS_DCE8(rdev)) {
+			if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+				WREG32(CIK_LB_DATA_FORMAT + radeon_crtc->crtc_offset,
+				       CIK_INTERLEAVE_EN);
+			else
+				WREG32(CIK_LB_DATA_FORMAT + radeon_crtc->crtc_offset, 0);
+		} else if (ASIC_IS_DCE4(rdev)) {
 			if (mode->flags & DRM_MODE_FLAG_INTERLACE)
 				WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset,
 				       EVERGREEN_INTERLEAVE_EN);
diff --git a/drivers/gpu/drm/radeon/cik_reg.h b/drivers/gpu/drm/radeon/cik_reg.h
index b96dac0..58b29b5 100644
--- a/drivers/gpu/drm/radeon/cik_reg.h
+++ b/drivers/gpu/drm/radeon/cik_reg.h
@@ -62,4 +62,7 @@
 #define CIK_ALPHA_CONTROL                         0x6af0
 #       define CIK_CURSOR_ALPHA_BLND_ENA          (1 << 1)
 
+#define CIK_LB_DATA_FORMAT                        0x6b00
+#       define CIK_INTERLEAVE_EN                  (1 << 3)
+
 #endif
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 032/165] drm/radeon/dce8: crtc_set_base updates
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (31 preceding siblings ...)
  2013-06-26 13:21 ` [PATCH 031/165] drm/radeon/dce8: properly handle interlaced timing alexdeucher
@ 2013-06-26 13:21 ` alexdeucher
  2013-06-26 13:21 ` [PATCH 033/165] drm/radeon/atom: add DCE8 encoder support alexdeucher
                   ` (80 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:21 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Some new fields and DESKTOP_HEIGHT register moved.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/atombios_crtc.c |   34 ++++++++++++--
 drivers/gpu/drm/radeon/cik_reg.h       |   79 ++++++++++++++++++++++++++++++++
 2 files changed, 108 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c
index d5df8fd..4ba5184 100644
--- a/drivers/gpu/drm/radeon/atombios_crtc.c
+++ b/drivers/gpu/drm/radeon/atombios_crtc.c
@@ -1143,7 +1143,9 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
 	}
 
 	if (tiling_flags & RADEON_TILING_MACRO) {
-		if (rdev->family >= CHIP_TAHITI)
+		if (rdev->family >= CHIP_BONAIRE)
+			tmp = rdev->config.cik.tile_config;
+		else if (rdev->family >= CHIP_TAHITI)
 			tmp = rdev->config.si.tile_config;
 		else if (rdev->family >= CHIP_CAYMAN)
 			tmp = rdev->config.cayman.tile_config;
@@ -1170,11 +1172,29 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
 		fb_format |= EVERGREEN_GRPH_BANK_WIDTH(bankw);
 		fb_format |= EVERGREEN_GRPH_BANK_HEIGHT(bankh);
 		fb_format |= EVERGREEN_GRPH_MACRO_TILE_ASPECT(mtaspect);
+		if (rdev->family >= CHIP_BONAIRE) {
+			/* XXX need to know more about the surface tiling mode */
+			fb_format |= CIK_GRPH_MICRO_TILE_MODE(CIK_DISPLAY_MICRO_TILING);
+		}
 	} else if (tiling_flags & RADEON_TILING_MICRO)
 		fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_1D_TILED_THIN1);
 
-	if ((rdev->family == CHIP_TAHITI) ||
-	    (rdev->family == CHIP_PITCAIRN))
+	if (rdev->family >= CHIP_BONAIRE) {
+		u32 num_pipe_configs = rdev->config.cik.max_tile_pipes;
+		u32 num_rb = rdev->config.cik.max_backends_per_se;
+		if (num_pipe_configs > 8)
+			num_pipe_configs = 8;
+		if (num_pipe_configs == 8)
+			fb_format |= CIK_GRPH_PIPE_CONFIG(CIK_ADDR_SURF_P8_32x32_16x16);
+		else if (num_pipe_configs == 4) {
+			if (num_rb == 4)
+				fb_format |= CIK_GRPH_PIPE_CONFIG(CIK_ADDR_SURF_P4_16x16);
+			else if (num_rb < 4)
+				fb_format |= CIK_GRPH_PIPE_CONFIG(CIK_ADDR_SURF_P4_8x16);
+		} else if (num_pipe_configs == 2)
+			fb_format |= CIK_GRPH_PIPE_CONFIG(CIK_ADDR_SURF_P2);
+	} else if ((rdev->family == CHIP_TAHITI) ||
+		   (rdev->family == CHIP_PITCAIRN))
 		fb_format |= SI_GRPH_PIPE_CONFIG(SI_ADDR_SURF_P8_32x32_8x16);
 	else if (rdev->family == CHIP_VERDE)
 		fb_format |= SI_GRPH_PIPE_CONFIG(SI_ADDR_SURF_P4_8x16);
@@ -1224,8 +1244,12 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
 	WREG32(EVERGREEN_GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels);
 	WREG32(EVERGREEN_GRPH_ENABLE + radeon_crtc->crtc_offset, 1);
 
-	WREG32(EVERGREEN_DESKTOP_HEIGHT + radeon_crtc->crtc_offset,
-	       target_fb->height);
+	if (rdev->family >= CHIP_BONAIRE)
+		WREG32(CIK_LB_DESKTOP_HEIGHT + radeon_crtc->crtc_offset,
+		       target_fb->height);
+	else
+		WREG32(EVERGREEN_DESKTOP_HEIGHT + radeon_crtc->crtc_offset,
+		       target_fb->height);
 	x &= ~3;
 	y &= ~1;
 	WREG32(EVERGREEN_VIEWPORT_START + radeon_crtc->crtc_offset,
diff --git a/drivers/gpu/drm/radeon/cik_reg.h b/drivers/gpu/drm/radeon/cik_reg.h
index 58b29b5..d71e46d 100644
--- a/drivers/gpu/drm/radeon/cik_reg.h
+++ b/drivers/gpu/drm/radeon/cik_reg.h
@@ -29,6 +29,83 @@
 #define CIK_DC_GPIO_HPD_EN                        0x65b8
 #define CIK_DC_GPIO_HPD_Y                         0x65bc
 
+#define CIK_GRPH_CONTROL                          0x6804
+#       define CIK_GRPH_DEPTH(x)                  (((x) & 0x3) << 0)
+#       define CIK_GRPH_DEPTH_8BPP                0
+#       define CIK_GRPH_DEPTH_16BPP               1
+#       define CIK_GRPH_DEPTH_32BPP               2
+#       define CIK_GRPH_NUM_BANKS(x)              (((x) & 0x3) << 2)
+#       define CIK_ADDR_SURF_2_BANK               0
+#       define CIK_ADDR_SURF_4_BANK               1
+#       define CIK_ADDR_SURF_8_BANK               2
+#       define CIK_ADDR_SURF_16_BANK              3
+#       define CIK_GRPH_Z(x)                      (((x) & 0x3) << 4)
+#       define CIK_GRPH_BANK_WIDTH(x)             (((x) & 0x3) << 6)
+#       define CIK_ADDR_SURF_BANK_WIDTH_1         0
+#       define CIK_ADDR_SURF_BANK_WIDTH_2         1
+#       define CIK_ADDR_SURF_BANK_WIDTH_4         2
+#       define CIK_ADDR_SURF_BANK_WIDTH_8         3
+#       define CIK_GRPH_FORMAT(x)                 (((x) & 0x7) << 8)
+/* 8 BPP */
+#       define CIK_GRPH_FORMAT_INDEXED            0
+/* 16 BPP */
+#       define CIK_GRPH_FORMAT_ARGB1555           0
+#       define CIK_GRPH_FORMAT_ARGB565            1
+#       define CIK_GRPH_FORMAT_ARGB4444           2
+#       define CIK_GRPH_FORMAT_AI88               3
+#       define CIK_GRPH_FORMAT_MONO16             4
+#       define CIK_GRPH_FORMAT_BGRA5551           5
+/* 32 BPP */
+#       define CIK_GRPH_FORMAT_ARGB8888           0
+#       define CIK_GRPH_FORMAT_ARGB2101010        1
+#       define CIK_GRPH_FORMAT_32BPP_DIG          2
+#       define CIK_GRPH_FORMAT_8B_ARGB2101010     3
+#       define CIK_GRPH_FORMAT_BGRA1010102        4
+#       define CIK_GRPH_FORMAT_8B_BGRA1010102     5
+#       define CIK_GRPH_FORMAT_RGB111110          6
+#       define CIK_GRPH_FORMAT_BGR101111          7
+#       define CIK_GRPH_BANK_HEIGHT(x)            (((x) & 0x3) << 11)
+#       define CIK_ADDR_SURF_BANK_HEIGHT_1        0
+#       define CIK_ADDR_SURF_BANK_HEIGHT_2        1
+#       define CIK_ADDR_SURF_BANK_HEIGHT_4        2
+#       define CIK_ADDR_SURF_BANK_HEIGHT_8        3
+#       define CIK_GRPH_TILE_SPLIT(x)             (((x) & 0x7) << 13)
+#       define CIK_ADDR_SURF_TILE_SPLIT_64B       0
+#       define CIK_ADDR_SURF_TILE_SPLIT_128B      1
+#       define CIK_ADDR_SURF_TILE_SPLIT_256B      2
+#       define CIK_ADDR_SURF_TILE_SPLIT_512B      3
+#       define CIK_ADDR_SURF_TILE_SPLIT_1KB       4
+#       define CIK_ADDR_SURF_TILE_SPLIT_2KB       5
+#       define CIK_ADDR_SURF_TILE_SPLIT_4KB       6
+#       define CIK_GRPH_MACRO_TILE_ASPECT(x)      (((x) & 0x3) << 18)
+#       define CIK_ADDR_SURF_MACRO_TILE_ASPECT_1  0
+#       define CIK_ADDR_SURF_MACRO_TILE_ASPECT_2  1
+#       define CIK_ADDR_SURF_MACRO_TILE_ASPECT_4  2
+#       define CIK_ADDR_SURF_MACRO_TILE_ASPECT_8  3
+#       define CIK_GRPH_ARRAY_MODE(x)             (((x) & 0x7) << 20)
+#       define CIK_GRPH_ARRAY_LINEAR_GENERAL      0
+#       define CIK_GRPH_ARRAY_LINEAR_ALIGNED      1
+#       define CIK_GRPH_ARRAY_1D_TILED_THIN1      2
+#       define CIK_GRPH_ARRAY_2D_TILED_THIN1      4
+#       define CIK_GRPH_PIPE_CONFIG(x)		 (((x) & 0x1f) << 24)
+#       define CIK_ADDR_SURF_P2			 0
+#       define CIK_ADDR_SURF_P4_8x16		 4
+#       define CIK_ADDR_SURF_P4_16x16		 5
+#       define CIK_ADDR_SURF_P4_16x32		 6
+#       define CIK_ADDR_SURF_P4_32x32		 7
+#       define CIK_ADDR_SURF_P8_16x16_8x16	 8
+#       define CIK_ADDR_SURF_P8_16x32_8x16	 9
+#       define CIK_ADDR_SURF_P8_32x32_8x16	 10
+#       define CIK_ADDR_SURF_P8_16x32_16x16	 11
+#       define CIK_ADDR_SURF_P8_32x32_16x16	 12
+#       define CIK_ADDR_SURF_P8_32x32_16x32	 13
+#       define CIK_ADDR_SURF_P8_32x64_32x32	 14
+#       define CIK_GRPH_MICRO_TILE_MODE(x)       (((x) & 0x7) << 29)
+#       define CIK_DISPLAY_MICRO_TILING          0
+#       define CIK_THIN_MICRO_TILING             1
+#       define CIK_DEPTH_MICRO_TILING            2
+#       define CIK_ROTATED_MICRO_TILING          4
+
 /* CUR blocks at 0x6998, 0x7598, 0x10198, 0x10d98, 0x11998, 0x12598 */
 #define CIK_CUR_CONTROL                           0x6998
 #       define CIK_CURSOR_EN                      (1 << 0)
@@ -65,4 +142,6 @@
 #define CIK_LB_DATA_FORMAT                        0x6b00
 #       define CIK_INTERLEAVE_EN                  (1 << 3)
 
+#define CIK_LB_DESKTOP_HEIGHT                     0x6b0c
+
 #endif
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 033/165] drm/radeon/atom: add DCE8 encoder support
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (32 preceding siblings ...)
  2013-06-26 13:21 ` [PATCH 032/165] drm/radeon/dce8: crtc_set_base updates alexdeucher
@ 2013-06-26 13:21 ` alexdeucher
  2013-06-26 13:21 ` [PATCH 034/165] drm/radeon/atom: add support for new DVO tables alexdeucher
                   ` (79 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:21 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/atombios_encoders.c |   27 ++++++++++++++++++++++++---
 drivers/gpu/drm/radeon/radeon_display.c    |    5 +++--
 2 files changed, 27 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c
index 4439419..1bf13b3 100644
--- a/drivers/gpu/drm/radeon/atombios_encoders.c
+++ b/drivers/gpu/drm/radeon/atombios_encoders.c
@@ -303,6 +303,7 @@ static inline bool radeon_encoder_is_digital(struct drm_encoder *encoder)
 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
 		return true;
 	default:
 		return false;
@@ -922,10 +923,14 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mo
 				args.v4.ucLaneNum = 4;
 
 			if (ENCODER_MODE_IS_DP(args.v4.ucEncoderMode)) {
-				if (dp_clock == 270000)
-					args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_2_70GHZ;
-				else if (dp_clock == 540000)
+				if (dp_clock == 540000)
 					args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_5_40GHZ;
+				else if (dp_clock == 324000)
+					args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_3_24GHZ;
+				else if (dp_clock == 270000)
+					args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_2_70GHZ;
+				else
+					args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_1_62GHZ;
 			}
 			args.v4.acConfig.ucDigSel = dig->dig_encoder;
 			args.v4.ucBitPerColor = radeon_atom_get_bpc(encoder);
@@ -1019,6 +1024,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
 		index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl);
 		break;
 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
@@ -1278,6 +1284,9 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
 				else
 					args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYE;
 				break;
+			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
+				args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYG;
+				break;
 			}
 			if (is_dp)
 				args.v5.ucLaneNum = dp_lane_count;
@@ -1742,6 +1751,7 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode)
 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
 		radeon_atom_encoder_dpms_dig(encoder, mode);
 		break;
@@ -1879,6 +1889,7 @@ atombios_set_encoder_crtc_source(struct drm_encoder *encoder)
 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
 			case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
 				dig = radeon_encoder->enc_priv;
 				switch (dig->dig_encoder) {
@@ -1900,6 +1911,9 @@ atombios_set_encoder_crtc_source(struct drm_encoder *encoder)
 				case 5:
 					args.v2.ucEncoderID = ASIC_INT_DIG6_ENCODER_ID;
 					break;
+				case 6:
+					args.v2.ucEncoderID = ASIC_INT_DIG7_ENCODER_ID;
+					break;
 				}
 				break;
 			case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
@@ -2015,6 +2029,9 @@ static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder)
 			else
 				return 4;
 			break;
+		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
+			return 6;
+			break;
 		}
 	} else if (ASIC_IS_DCE4(rdev)) {
 		/* DCE4/5 */
@@ -2099,6 +2116,7 @@ radeon_atom_encoder_init(struct radeon_device *rdev)
 		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
 		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
 		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
 		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
 			atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_INIT, 0, 0);
 			break;
@@ -2143,6 +2161,7 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
 		/* handled in dpms */
 		break;
@@ -2408,6 +2427,7 @@ static void radeon_atom_encoder_disable(struct drm_encoder *encoder)
 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
 		/* handled in dpms */
 		break;
@@ -2639,6 +2659,7 @@ radeon_add_atom_encoder(struct drm_device *dev,
 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
 		if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
 			radeon_encoder->rmx_type = RMX_FULL;
 			drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_LVDS);
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index 1f850eb..c2b67b4 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -544,7 +544,7 @@ static void radeon_crtc_init(struct drm_device *dev, int index)
 		radeon_legacy_init_crtc(dev, radeon_crtc);
 }
 
-static const char *encoder_names[37] = {
+static const char *encoder_names[38] = {
 	"NONE",
 	"INTERNAL_LVDS",
 	"INTERNAL_TMDS1",
@@ -581,7 +581,8 @@ static const char *encoder_names[37] = {
 	"INTERNAL_UNIPHY2",
 	"NUTMEG",
 	"TRAVIS",
-	"INTERNAL_VCE"
+	"INTERNAL_VCE",
+	"INTERNAL_UNIPHY3",
 };
 
 static const char *hpd_names[6] = {
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 034/165] drm/radeon/atom: add support for new DVO tables
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (33 preceding siblings ...)
  2013-06-26 13:21 ` [PATCH 033/165] drm/radeon/atom: add DCE8 encoder support alexdeucher
@ 2013-06-26 13:21 ` alexdeucher
  2013-06-26 13:21 ` [PATCH 035/165] drm/radeon: update DISPCLK programming for DCE8 alexdeucher
                   ` (78 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:21 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/atombios_encoders.c |    9 ++++++++-
 1 files changed, 8 insertions(+), 1 deletions(-)

diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c
index 1bf13b3..092275d 100644
--- a/drivers/gpu/drm/radeon/atombios_encoders.c
+++ b/drivers/gpu/drm/radeon/atombios_encoders.c
@@ -487,11 +487,11 @@ static u8 radeon_atom_get_bpc(struct drm_encoder *encoder)
 	}
 }
 
-
 union dvo_encoder_control {
 	ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION ext_tmds;
 	DVO_ENCODER_CONTROL_PS_ALLOCATION dvo;
 	DVO_ENCODER_CONTROL_PS_ALLOCATION_V3 dvo_v3;
+	DVO_ENCODER_CONTROL_PS_ALLOCATION_V1_4 dvo_v4;
 };
 
 void
@@ -541,6 +541,13 @@ atombios_dvo_setup(struct drm_encoder *encoder, int action)
 			args.dvo_v3.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
 			args.dvo_v3.ucDVOConfig = 0; /* XXX */
 			break;
+		case 4:
+			/* DCE8 */
+			args.dvo_v4.ucAction = action;
+			args.dvo_v4.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
+			args.dvo_v4.ucDVOConfig = 0; /* XXX */
+			args.dvo_v4.ucBitPerColor = radeon_atom_get_bpc(encoder);
+			break;
 		default:
 			DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
 			break;
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 035/165] drm/radeon: update DISPCLK programming for DCE8
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (34 preceding siblings ...)
  2013-06-26 13:21 ` [PATCH 034/165] drm/radeon/atom: add support for new DVO tables alexdeucher
@ 2013-06-26 13:21 ` alexdeucher
  2013-06-26 13:21 ` [PATCH 036/165] drm/radeon: add support pll selection for DCE8 (v4) alexdeucher
                   ` (77 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:21 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/atombios_crtc.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c
index 4ba5184..586c452 100644
--- a/drivers/gpu/drm/radeon/atombios_crtc.c
+++ b/drivers/gpu/drm/radeon/atombios_crtc.c
@@ -743,7 +743,7 @@ static void atombios_crtc_set_disp_eng_pll(struct radeon_device *rdev,
 			 * SetPixelClock provides the dividers
 			 */
 			args.v6.ulDispEngClkFreq = cpu_to_le32(dispclk);
-			if (ASIC_IS_DCE61(rdev))
+			if (ASIC_IS_DCE61(rdev) || ASIC_IS_DCE8(rdev))
 				args.v6.ucPpll = ATOM_EXT_PLL1;
 			else if (ASIC_IS_DCE6(rdev))
 				args.v6.ucPpll = ATOM_PPLL0;
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 036/165] drm/radeon: add support pll selection for DCE8 (v4)
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (35 preceding siblings ...)
  2013-06-26 13:21 ` [PATCH 035/165] drm/radeon: update DISPCLK programming for DCE8 alexdeucher
@ 2013-06-26 13:21 ` alexdeucher
  2013-06-26 13:21 ` [PATCH 037/165] drm/radeon: Handle PPLL0 powerdown on DCE8 alexdeucher
                   ` (76 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:21 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

v2: make PPLL0 is available for non-DP on CI
v3: rebase changes, update documentation
v4: fix kabini

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/atombios_crtc.c |   48 +++++++++++++++++++++++++++++++-
 1 files changed, 47 insertions(+), 1 deletions(-)

diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c
index 586c452..590e4eb 100644
--- a/drivers/gpu/drm/radeon/atombios_crtc.c
+++ b/drivers/gpu/drm/radeon/atombios_crtc.c
@@ -1621,6 +1621,12 @@ static int radeon_get_shared_nondp_ppll(struct drm_crtc *crtc)
  *
  * Asic specific PLL information
  *
+ * DCE 8.x
+ * KB/KV
+ * - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP)
+ * CI
+ * - PPLL0, PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC
+ *
  * DCE 6.1
  * - PPLL2 is only available to UNIPHYA (both DP and non-DP)
  * - PPLL0, PPLL1 are available for UNIPHYB/C/D/E/F (both DP and non-DP)
@@ -1647,7 +1653,47 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc)
 	u32 pll_in_use;
 	int pll;
 
-	if (ASIC_IS_DCE61(rdev)) {
+	if (ASIC_IS_DCE8(rdev)) {
+		if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) {
+			if (rdev->clock.dp_extclk)
+				/* skip PPLL programming if using ext clock */
+				return ATOM_PPLL_INVALID;
+			else {
+				/* use the same PPLL for all DP monitors */
+				pll = radeon_get_shared_dp_ppll(crtc);
+				if (pll != ATOM_PPLL_INVALID)
+					return pll;
+			}
+		} else {
+			/* use the same PPLL for all monitors with the same clock */
+			pll = radeon_get_shared_nondp_ppll(crtc);
+			if (pll != ATOM_PPLL_INVALID)
+				return pll;
+		}
+		/* otherwise, pick one of the plls */
+		if ((rdev->family == CHIP_KAVERI) ||
+		    (rdev->family == CHIP_KABINI)) {
+			/* KB/KV has PPLL1 and PPLL2 */
+			pll_in_use = radeon_get_pll_use_mask(crtc);
+			if (!(pll_in_use & (1 << ATOM_PPLL2)))
+				return ATOM_PPLL2;
+			if (!(pll_in_use & (1 << ATOM_PPLL1)))
+				return ATOM_PPLL1;
+			DRM_ERROR("unable to allocate a PPLL\n");
+			return ATOM_PPLL_INVALID;
+		} else {
+			/* CI has PPLL0, PPLL1, and PPLL2 */
+			pll_in_use = radeon_get_pll_use_mask(crtc);
+			if (!(pll_in_use & (1 << ATOM_PPLL2)))
+				return ATOM_PPLL2;
+			if (!(pll_in_use & (1 << ATOM_PPLL1)))
+				return ATOM_PPLL1;
+			if (!(pll_in_use & (1 << ATOM_PPLL0)))
+				return ATOM_PPLL0;
+			DRM_ERROR("unable to allocate a PPLL\n");
+			return ATOM_PPLL_INVALID;
+		}
+	} else if (ASIC_IS_DCE61(rdev)) {
 		struct radeon_encoder_atom_dig *dig =
 			radeon_encoder->enc_priv;
 
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 037/165] drm/radeon: Handle PPLL0 powerdown on DCE8
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (36 preceding siblings ...)
  2013-06-26 13:21 ` [PATCH 036/165] drm/radeon: add support pll selection for DCE8 (v4) alexdeucher
@ 2013-06-26 13:21 ` alexdeucher
  2013-06-26 13:21 ` [PATCH 038/165] drm/radeon: use frac fb div " alexdeucher
                   ` (75 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:21 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Only Bonaire has PPLL0.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/atombios_crtc.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c
index 590e4eb..24eee7c 100644
--- a/drivers/gpu/drm/radeon/atombios_crtc.c
+++ b/drivers/gpu/drm/radeon/atombios_crtc.c
@@ -1931,7 +1931,7 @@ static void atombios_crtc_disable(struct drm_crtc *crtc)
 		break;
 	case ATOM_PPLL0:
 		/* disable the ppll */
-		if (ASIC_IS_DCE61(rdev))
+		if ((rdev->family == CHIP_ARUBA) || (rdev->family == CHIP_BONAIRE))
 			atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id,
 						  0, 0, ATOM_DISABLE, 0, 0, 0, 0, 0, false, &ss);
 		break;
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 038/165] drm/radeon: use frac fb div on DCE8
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (37 preceding siblings ...)
  2013-06-26 13:21 ` [PATCH 037/165] drm/radeon: Handle PPLL0 powerdown on DCE8 alexdeucher
@ 2013-06-26 13:21 ` alexdeucher
  2013-06-26 13:21 ` [PATCH 039/165] drm/radeon: add SS override support for KB/KV alexdeucher
                   ` (74 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:21 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/atombios_crtc.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c
index 24eee7c..c7ad4b9 100644
--- a/drivers/gpu/drm/radeon/atombios_crtc.c
+++ b/drivers/gpu/drm/radeon/atombios_crtc.c
@@ -555,7 +555,7 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
 		if (rdev->family < CHIP_RV770)
 			radeon_crtc->pll_flags |= RADEON_PLL_PREFER_MINM_OVER_MAXP;
 		/* use frac fb div on APUs */
-		if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE61(rdev))
+		if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE61(rdev) || ASIC_IS_DCE8(rdev))
 			radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV;
 		/* use frac fb div on RS780/RS880 */
 		if ((rdev->family == CHIP_RS780) || (rdev->family == CHIP_RS880))
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 039/165] drm/radeon: add SS override support for KB/KV
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (38 preceding siblings ...)
  2013-06-26 13:21 ` [PATCH 038/165] drm/radeon: use frac fb div " alexdeucher
@ 2013-06-26 13:21 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 040/165] drm/radeon: Update radeon_info_ioctl for CIK (v2) alexdeucher
                   ` (73 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:21 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/radeon_atombios.c |   17 +++++++++++++++++
 1 files changed, 17 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c
index 88a55af..3236755 100644
--- a/drivers/gpu/drm/radeon/radeon_atombios.c
+++ b/drivers/gpu/drm/radeon/radeon_atombios.c
@@ -1269,6 +1269,7 @@ union igp_info {
 	struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2;
 	struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 info_6;
 	struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7 info_7;
+	struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_8 info_8;
 };
 
 bool radeon_atombios_sideport_present(struct radeon_device *rdev)
@@ -1438,6 +1439,22 @@ static void radeon_atombios_get_igp_ss_overrides(struct radeon_device *rdev,
 				break;
 			}
 			break;
+		case 8:
+			switch (id) {
+			case ASIC_INTERNAL_SS_ON_TMDS:
+				percentage = le16_to_cpu(igp_info->info_8.usDVISSPercentage);
+				rate = le16_to_cpu(igp_info->info_8.usDVISSpreadRateIn10Hz);
+				break;
+			case ASIC_INTERNAL_SS_ON_HDMI:
+				percentage = le16_to_cpu(igp_info->info_8.usHDMISSPercentage);
+				rate = le16_to_cpu(igp_info->info_8.usHDMISSpreadRateIn10Hz);
+				break;
+			case ASIC_INTERNAL_SS_ON_LVDS:
+				percentage = le16_to_cpu(igp_info->info_8.usLvdsSSPercentage);
+				rate = le16_to_cpu(igp_info->info_8.usLvdsSSpreadRateIn10Hz);
+				break;
+			}
+			break;
 		default:
 			DRM_ERROR("Unsupported IGP table: %d %d\n", frev, crev);
 			break;
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 040/165] drm/radeon: Update radeon_info_ioctl for CIK (v2)
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (39 preceding siblings ...)
  2013-06-26 13:21 ` [PATCH 039/165] drm/radeon: add SS override support for KB/KV alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 041/165] drm/radeon: add get_gpu_clock_counter() callback for cik alexdeucher
                   ` (72 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

v2: rebase changes, fix a couple missed cases

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/radeon_kms.c |   33 ++++++++++++++++++++++++++-------
 1 files changed, 26 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c
index 4f2d4f4..c650228 100644
--- a/drivers/gpu/drm/radeon/radeon_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_kms.c
@@ -229,7 +229,9 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
 		*value = rdev->accel_working;
 		break;
 	case RADEON_INFO_TILING_CONFIG:
-		if (rdev->family >= CHIP_TAHITI)
+		if (rdev->family >= CHIP_BONAIRE)
+			*value = rdev->config.cik.tile_config;
+		else if (rdev->family >= CHIP_TAHITI)
 			*value = rdev->config.si.tile_config;
 		else if (rdev->family >= CHIP_CAYMAN)
 			*value = rdev->config.cayman.tile_config;
@@ -281,7 +283,10 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
 			*value = rdev->clock.spll.reference_freq * 10;
 		break;
 	case RADEON_INFO_NUM_BACKENDS:
-		if (rdev->family >= CHIP_TAHITI)
+		if (rdev->family >= CHIP_BONAIRE)
+			*value = rdev->config.cik.max_backends_per_se *
+				rdev->config.cik.max_shader_engines;
+		else if (rdev->family >= CHIP_TAHITI)
 			*value = rdev->config.si.max_backends_per_se *
 				rdev->config.si.max_shader_engines;
 		else if (rdev->family >= CHIP_CAYMAN)
@@ -298,7 +303,9 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
 		}
 		break;
 	case RADEON_INFO_NUM_TILE_PIPES:
-		if (rdev->family >= CHIP_TAHITI)
+		if (rdev->family >= CHIP_BONAIRE)
+			*value = rdev->config.cik.max_tile_pipes;
+		else if (rdev->family >= CHIP_TAHITI)
 			*value = rdev->config.si.max_tile_pipes;
 		else if (rdev->family >= CHIP_CAYMAN)
 			*value = rdev->config.cayman.max_tile_pipes;
@@ -316,7 +323,9 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
 		*value = 1;
 		break;
 	case RADEON_INFO_BACKEND_MAP:
-		if (rdev->family >= CHIP_TAHITI)
+		if (rdev->family >= CHIP_BONAIRE)
+			return -EINVAL;
+		else if (rdev->family >= CHIP_TAHITI)
 			*value = rdev->config.si.backend_map;
 		else if (rdev->family >= CHIP_CAYMAN)
 			*value = rdev->config.cayman.backend_map;
@@ -343,7 +352,9 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
 		*value = RADEON_IB_VM_MAX_SIZE;
 		break;
 	case RADEON_INFO_MAX_PIPES:
-		if (rdev->family >= CHIP_TAHITI)
+		if (rdev->family >= CHIP_BONAIRE)
+			*value = rdev->config.cik.max_cu_per_sh;
+		else if (rdev->family >= CHIP_TAHITI)
 			*value = rdev->config.si.max_cu_per_sh;
 		else if (rdev->family >= CHIP_CAYMAN)
 			*value = rdev->config.cayman.max_pipes_per_simd;
@@ -367,7 +378,9 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
 		value64 = radeon_get_gpu_clock_counter(rdev);
 		break;
 	case RADEON_INFO_MAX_SE:
-		if (rdev->family >= CHIP_TAHITI)
+		if (rdev->family >= CHIP_BONAIRE)
+			*value = rdev->config.cik.max_shader_engines;
+		else if (rdev->family >= CHIP_TAHITI)
 			*value = rdev->config.si.max_shader_engines;
 		else if (rdev->family >= CHIP_CAYMAN)
 			*value = rdev->config.cayman.max_shader_engines;
@@ -377,7 +390,9 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
 			*value = 1;
 		break;
 	case RADEON_INFO_MAX_SH_PER_SE:
-		if (rdev->family >= CHIP_TAHITI)
+		if (rdev->family >= CHIP_BONAIRE)
+			*value = rdev->config.cik.max_sh_per_se;
+		else if (rdev->family >= CHIP_TAHITI)
 			*value = rdev->config.si.max_sh_per_se;
 		else
 			return -EINVAL;
@@ -407,6 +422,10 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
 		}
 		break;
 	case RADEON_INFO_SI_TILE_MODE_ARRAY:
+		if (rdev->family >= CHIP_BONAIRE) {
+			DRM_DEBUG_KMS("tile mode array is not implemented yet\n");
+			return -EINVAL;
+		}
 		if (rdev->family < CHIP_TAHITI) {
 			DRM_DEBUG_KMS("tile mode array is si only!\n");
 			return -EINVAL;
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 041/165] drm/radeon: add get_gpu_clock_counter() callback for cik
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (40 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 040/165] drm/radeon: Update radeon_info_ioctl for CIK (v2) alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 042/165] drm/radeon: update CIK soft reset alexdeucher
                   ` (71 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Used for GPU clock counter snapshots.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/cik.c         |   21 +++++++++++++++++++++
 drivers/gpu/drm/radeon/cikd.h        |    4 +++-
 drivers/gpu/drm/radeon/radeon_asic.h |    5 +++++
 3 files changed, 29 insertions(+), 1 deletions(-)

diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
index 228d399..d241cfd 100644
--- a/drivers/gpu/drm/radeon/cik.c
+++ b/drivers/gpu/drm/radeon/cik.c
@@ -5558,3 +5558,24 @@ void dce8_bandwidth_update(struct radeon_device *rdev)
 		dce8_program_watermarks(rdev, rdev->mode_info.crtcs[i], lb_size, num_heads);
 	}
 }
+
+/**
+ * cik_get_gpu_clock_counter - return GPU clock counter snapshot
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Fetches a GPU clock counter snapshot (SI).
+ * Returns the 64 bit clock counter snapshot.
+ */
+uint64_t cik_get_gpu_clock_counter(struct radeon_device *rdev)
+{
+	uint64_t clock;
+
+	mutex_lock(&rdev->gpu_clock_mutex);
+	WREG32(RLC_CAPTURE_GPU_CLOCK_COUNT, 1);
+	clock = (uint64_t)RREG32(RLC_GPU_CLOCK_COUNT_LSB) |
+	        ((uint64_t)RREG32(RLC_GPU_CLOCK_COUNT_MSB) << 32ULL);
+	mutex_unlock(&rdev->gpu_clock_mutex);
+	return clock;
+}
+
diff --git a/drivers/gpu/drm/radeon/cikd.h b/drivers/gpu/drm/radeon/cikd.h
index 3349e37..daa51ac 100644
--- a/drivers/gpu/drm/radeon/cikd.h
+++ b/drivers/gpu/drm/radeon/cikd.h
@@ -730,7 +730,9 @@
 
 #define RLC_GPM_UCODE_ADDR                                0xC388
 #define RLC_GPM_UCODE_DATA                                0xC38C
-
+#define RLC_GPU_CLOCK_COUNT_LSB                           0xC390
+#define RLC_GPU_CLOCK_COUNT_MSB                           0xC394
+#define RLC_CAPTURE_GPU_CLOCK_COUNT                       0xC398
 #define RLC_UCODE_CNTL                                    0xC39C
 
 #define RLC_CGCG_CGLS_CTRL                                0xC424
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index a72759e..248da72 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -553,4 +553,9 @@ 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);
 
+/*
+ * cik
+ */
+uint64_t cik_get_gpu_clock_counter(struct radeon_device *rdev);
+
 #endif
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 042/165] drm/radeon: update CIK soft reset
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (41 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 041/165] drm/radeon: add get_gpu_clock_counter() callback for cik alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 043/165] drm/radeon: add indirect register accessors for SMC registers alexdeucher
                   ` (70 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Update to the newer programming model.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/cik.c  |  387 +++++++++++++++++++++++++----------------
 drivers/gpu/drm/radeon/cikd.h |   12 ++
 2 files changed, 253 insertions(+), 146 deletions(-)

diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
index d241cfd..aaf7bba 100644
--- a/drivers/gpu/drm/radeon/cik.c
+++ b/drivers/gpu/drm/radeon/cik.c
@@ -72,9 +72,11 @@ extern int r600_ih_ring_alloc(struct radeon_device *rdev);
 extern void r600_ih_ring_fini(struct radeon_device *rdev);
 extern void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save);
 extern void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save);
+extern bool evergreen_is_display_hung(struct radeon_device *rdev);
 extern void si_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc);
 extern void si_rlc_fini(struct radeon_device *rdev);
 extern int si_rlc_init(struct radeon_device *rdev);
+static void cik_rlc_stop(struct radeon_device *rdev);
 
 #define BONAIRE_IO_MC_REGS_SIZE 36
 
@@ -2733,56 +2735,9 @@ int cik_sdma_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)
 	return r;
 }
 
-/**
- * cik_gpu_is_lockup - check if the 3D engine is locked up
- *
- * @rdev: radeon_device pointer
- * @ring: radeon_ring structure holding ring information
- *
- * Check if the 3D engine is locked up (CIK).
- * Returns true if the engine is locked, false if not.
- */
-bool cik_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)
-{
-	u32 srbm_status, srbm_status2;
-	u32 grbm_status, grbm_status2;
-	u32 grbm_status_se0, grbm_status_se1, grbm_status_se2, grbm_status_se3;
-
-	srbm_status = RREG32(SRBM_STATUS);
-	srbm_status2 = RREG32(SRBM_STATUS2);
-	grbm_status = RREG32(GRBM_STATUS);
-	grbm_status2 = RREG32(GRBM_STATUS2);
-	grbm_status_se0 = RREG32(GRBM_STATUS_SE0);
-	grbm_status_se1 = RREG32(GRBM_STATUS_SE1);
-	grbm_status_se2 = RREG32(GRBM_STATUS_SE2);
-	grbm_status_se3 = RREG32(GRBM_STATUS_SE3);
-	if (!(grbm_status & GUI_ACTIVE)) {
-		radeon_ring_lockup_update(ring);
-		return false;
-	}
-	/* force CP activities */
-	radeon_ring_force_activity(rdev, ring);
-	return radeon_ring_test_lockup(rdev, ring);
-}
 
-/**
- * cik_gfx_gpu_soft_reset - soft reset the 3D engine and CPG
- *
- * @rdev: radeon_device pointer
- *
- * Soft reset the GFX engine and CPG blocks (CIK).
- * XXX: deal with reseting RLC and CPF
- * Returns 0 for success.
- */
-static int cik_gfx_gpu_soft_reset(struct radeon_device *rdev)
+static void cik_print_gpu_status_regs(struct radeon_device *rdev)
 {
-	struct evergreen_mc_save save;
-	u32 grbm_reset = 0;
-
-	if (!(RREG32(GRBM_STATUS) & GUI_ACTIVE))
-		return 0;
-
-	dev_info(rdev->dev, "GPU GFX softreset \n");
 	dev_info(rdev->dev, "  GRBM_STATUS=0x%08X\n",
 		RREG32(GRBM_STATUS));
 	dev_info(rdev->dev, "  GRBM_STATUS2=0x%08X\n",
@@ -2799,132 +2754,270 @@ static int cik_gfx_gpu_soft_reset(struct radeon_device *rdev)
 		RREG32(SRBM_STATUS));
 	dev_info(rdev->dev, "  SRBM_STATUS2=0x%08X\n",
 		RREG32(SRBM_STATUS2));
-	evergreen_mc_stop(rdev, &save);
-	if (radeon_mc_wait_for_idle(rdev)) {
-		dev_warn(rdev->dev, "Wait for MC idle timedout !\n");
-	}
-	/* Disable CP parsing/prefetching */
-	WREG32(CP_ME_CNTL, CP_ME_HALT | CP_PFP_HALT | CP_CE_HALT);
+	dev_info(rdev->dev, "  SDMA0_STATUS_REG   = 0x%08X\n",
+		RREG32(SDMA0_STATUS_REG + SDMA0_REGISTER_OFFSET));
+	dev_info(rdev->dev, "  SDMA1_STATUS_REG   = 0x%08X\n",
+		 RREG32(SDMA0_STATUS_REG + SDMA1_REGISTER_OFFSET));
+}
 
-	/* reset all the gfx block and all CPG blocks */
-	grbm_reset = SOFT_RESET_CPG | SOFT_RESET_GFX;
+/**
+ * cik_gpu_check_soft_reset - check which blocks are busy
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Check which blocks are busy and return the relevant reset
+ * mask to be used by cik_gpu_soft_reset().
+ * Returns a mask of the blocks to be reset.
+ */
+static u32 cik_gpu_check_soft_reset(struct radeon_device *rdev)
+{
+	u32 reset_mask = 0;
+	u32 tmp;
 
-	dev_info(rdev->dev, "  GRBM_SOFT_RESET=0x%08X\n", grbm_reset);
-	WREG32(GRBM_SOFT_RESET, grbm_reset);
-	(void)RREG32(GRBM_SOFT_RESET);
-	udelay(50);
-	WREG32(GRBM_SOFT_RESET, 0);
-	(void)RREG32(GRBM_SOFT_RESET);
-	/* Wait a little for things to settle down */
-	udelay(50);
-	dev_info(rdev->dev, "  GRBM_STATUS=0x%08X\n",
-		RREG32(GRBM_STATUS));
-	dev_info(rdev->dev, "  GRBM_STATUS2=0x%08X\n",
-		RREG32(GRBM_STATUS2));
-	dev_info(rdev->dev, "  GRBM_STATUS_SE0=0x%08X\n",
-		RREG32(GRBM_STATUS_SE0));
-	dev_info(rdev->dev, "  GRBM_STATUS_SE1=0x%08X\n",
-		RREG32(GRBM_STATUS_SE1));
-	dev_info(rdev->dev, "  GRBM_STATUS_SE2=0x%08X\n",
-		RREG32(GRBM_STATUS_SE2));
-	dev_info(rdev->dev, "  GRBM_STATUS_SE3=0x%08X\n",
-		RREG32(GRBM_STATUS_SE3));
-	dev_info(rdev->dev, "  SRBM_STATUS=0x%08X\n",
-		RREG32(SRBM_STATUS));
-	dev_info(rdev->dev, "  SRBM_STATUS2=0x%08X\n",
-		RREG32(SRBM_STATUS2));
-	evergreen_mc_resume(rdev, &save);
-	return 0;
+	/* GRBM_STATUS */
+	tmp = RREG32(GRBM_STATUS);
+	if (tmp & (PA_BUSY | SC_BUSY |
+		   BCI_BUSY | SX_BUSY |
+		   TA_BUSY | VGT_BUSY |
+		   DB_BUSY | CB_BUSY |
+		   GDS_BUSY | SPI_BUSY |
+		   IA_BUSY | IA_BUSY_NO_DMA))
+		reset_mask |= RADEON_RESET_GFX;
+
+	if (tmp & (CP_BUSY | CP_COHERENCY_BUSY))
+		reset_mask |= RADEON_RESET_CP;
+
+	/* GRBM_STATUS2 */
+	tmp = RREG32(GRBM_STATUS2);
+	if (tmp & RLC_BUSY)
+		reset_mask |= RADEON_RESET_RLC;
+
+	/* SDMA0_STATUS_REG */
+	tmp = RREG32(SDMA0_STATUS_REG + SDMA0_REGISTER_OFFSET);
+	if (!(tmp & SDMA_IDLE))
+		reset_mask |= RADEON_RESET_DMA;
+
+	/* SDMA1_STATUS_REG */
+	tmp = RREG32(SDMA0_STATUS_REG + SDMA1_REGISTER_OFFSET);
+	if (!(tmp & SDMA_IDLE))
+		reset_mask |= RADEON_RESET_DMA1;
+
+	/* SRBM_STATUS2 */
+	tmp = RREG32(SRBM_STATUS2);
+	if (tmp & SDMA_BUSY)
+		reset_mask |= RADEON_RESET_DMA;
+
+	if (tmp & SDMA1_BUSY)
+		reset_mask |= RADEON_RESET_DMA1;
+
+	/* SRBM_STATUS */
+	tmp = RREG32(SRBM_STATUS);
+
+	if (tmp & IH_BUSY)
+		reset_mask |= RADEON_RESET_IH;
+
+	if (tmp & SEM_BUSY)
+		reset_mask |= RADEON_RESET_SEM;
+
+	if (tmp & GRBM_RQ_PENDING)
+		reset_mask |= RADEON_RESET_GRBM;
+
+	if (tmp & VMC_BUSY)
+		reset_mask |= RADEON_RESET_VMC;
+
+	if (tmp & (MCB_BUSY | MCB_NON_DISPLAY_BUSY |
+		   MCC_BUSY | MCD_BUSY))
+		reset_mask |= RADEON_RESET_MC;
+
+	if (evergreen_is_display_hung(rdev))
+		reset_mask |= RADEON_RESET_DISPLAY;
+
+	/* Skip MC reset as it's mostly likely not hung, just busy */
+	if (reset_mask & RADEON_RESET_MC) {
+		DRM_DEBUG("MC busy: 0x%08X, clearing.\n", reset_mask);
+		reset_mask &= ~RADEON_RESET_MC;
+	}
+
+	return reset_mask;
 }
 
 /**
- * cik_compute_gpu_soft_reset - soft reset CPC
+ * cik_gpu_soft_reset - soft reset GPU
  *
  * @rdev: radeon_device pointer
+ * @reset_mask: mask of which blocks to reset
  *
- * Soft reset the CPC blocks (CIK).
- * XXX: deal with reseting RLC and CPF
- * Returns 0 for success.
+ * Soft reset the blocks specified in @reset_mask.
  */
-static int cik_compute_gpu_soft_reset(struct radeon_device *rdev)
+static void cik_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask)
 {
 	struct evergreen_mc_save save;
-	u32 grbm_reset = 0;
+	u32 grbm_soft_reset = 0, srbm_soft_reset = 0;
+	u32 tmp;
+
+	if (reset_mask == 0)
+		return;
+
+	dev_info(rdev->dev, "GPU softreset: 0x%08X\n", reset_mask);
+
+	cik_print_gpu_status_regs(rdev);
+	dev_info(rdev->dev, "  VM_CONTEXT1_PROTECTION_FAULT_ADDR   0x%08X\n",
+		 RREG32(VM_CONTEXT1_PROTECTION_FAULT_ADDR));
+	dev_info(rdev->dev, "  VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x%08X\n",
+		 RREG32(VM_CONTEXT1_PROTECTION_FAULT_STATUS));
+
+	/* stop the rlc */
+	cik_rlc_stop(rdev);
+
+	/* Disable GFX parsing/prefetching */
+	WREG32(CP_ME_CNTL, CP_ME_HALT | CP_PFP_HALT | CP_CE_HALT);
+
+	/* Disable MEC parsing/prefetching */
+	WREG32(CP_MEC_CNTL, MEC_ME1_HALT | MEC_ME2_HALT);
+
+	if (reset_mask & RADEON_RESET_DMA) {
+		/* sdma0 */
+		tmp = RREG32(SDMA0_ME_CNTL + SDMA0_REGISTER_OFFSET);
+		tmp |= SDMA_HALT;
+		WREG32(SDMA0_ME_CNTL + SDMA0_REGISTER_OFFSET, tmp);
+	}
+	if (reset_mask & RADEON_RESET_DMA1) {
+		/* sdma1 */
+		tmp = RREG32(SDMA0_ME_CNTL + SDMA1_REGISTER_OFFSET);
+		tmp |= SDMA_HALT;
+		WREG32(SDMA0_ME_CNTL + SDMA1_REGISTER_OFFSET, tmp);
+	}
 
-	dev_info(rdev->dev, "GPU compute softreset \n");
-	dev_info(rdev->dev, "  GRBM_STATUS=0x%08X\n",
-		RREG32(GRBM_STATUS));
-	dev_info(rdev->dev, "  GRBM_STATUS2=0x%08X\n",
-		RREG32(GRBM_STATUS2));
-	dev_info(rdev->dev, "  GRBM_STATUS_SE0=0x%08X\n",
-		RREG32(GRBM_STATUS_SE0));
-	dev_info(rdev->dev, "  GRBM_STATUS_SE1=0x%08X\n",
-		RREG32(GRBM_STATUS_SE1));
-	dev_info(rdev->dev, "  GRBM_STATUS_SE2=0x%08X\n",
-		RREG32(GRBM_STATUS_SE2));
-	dev_info(rdev->dev, "  GRBM_STATUS_SE3=0x%08X\n",
-		RREG32(GRBM_STATUS_SE3));
-	dev_info(rdev->dev, "  SRBM_STATUS=0x%08X\n",
-		RREG32(SRBM_STATUS));
-	dev_info(rdev->dev, "  SRBM_STATUS2=0x%08X\n",
-		RREG32(SRBM_STATUS2));
 	evergreen_mc_stop(rdev, &save);
-	if (radeon_mc_wait_for_idle(rdev)) {
+	if (evergreen_mc_wait_for_idle(rdev)) {
 		dev_warn(rdev->dev, "Wait for MC idle timedout !\n");
 	}
-	/* Disable CP parsing/prefetching */
-	WREG32(CP_MEC_CNTL, MEC_ME1_HALT | MEC_ME2_HALT);
 
-	/* reset all the CPC blocks */
-	grbm_reset = SOFT_RESET_CPG;
+	if (reset_mask & (RADEON_RESET_GFX | RADEON_RESET_COMPUTE | RADEON_RESET_CP))
+		grbm_soft_reset = SOFT_RESET_CP | SOFT_RESET_GFX;
+
+	if (reset_mask & RADEON_RESET_CP) {
+		grbm_soft_reset |= SOFT_RESET_CP;
+
+		srbm_soft_reset |= SOFT_RESET_GRBM;
+	}
+
+	if (reset_mask & RADEON_RESET_DMA)
+		srbm_soft_reset |= SOFT_RESET_SDMA;
+
+	if (reset_mask & RADEON_RESET_DMA1)
+		srbm_soft_reset |= SOFT_RESET_SDMA1;
+
+	if (reset_mask & RADEON_RESET_DISPLAY)
+		srbm_soft_reset |= SOFT_RESET_DC;
+
+	if (reset_mask & RADEON_RESET_RLC)
+		grbm_soft_reset |= SOFT_RESET_RLC;
+
+	if (reset_mask & RADEON_RESET_SEM)
+		srbm_soft_reset |= SOFT_RESET_SEM;
+
+	if (reset_mask & RADEON_RESET_IH)
+		srbm_soft_reset |= SOFT_RESET_IH;
+
+	if (reset_mask & RADEON_RESET_GRBM)
+		srbm_soft_reset |= SOFT_RESET_GRBM;
+
+	if (reset_mask & RADEON_RESET_VMC)
+		srbm_soft_reset |= SOFT_RESET_VMC;
+
+	if (!(rdev->flags & RADEON_IS_IGP)) {
+		if (reset_mask & RADEON_RESET_MC)
+			srbm_soft_reset |= SOFT_RESET_MC;
+	}
+
+	if (grbm_soft_reset) {
+		tmp = RREG32(GRBM_SOFT_RESET);
+		tmp |= grbm_soft_reset;
+		dev_info(rdev->dev, "GRBM_SOFT_RESET=0x%08X\n", tmp);
+		WREG32(GRBM_SOFT_RESET, tmp);
+		tmp = RREG32(GRBM_SOFT_RESET);
+
+		udelay(50);
+
+		tmp &= ~grbm_soft_reset;
+		WREG32(GRBM_SOFT_RESET, tmp);
+		tmp = RREG32(GRBM_SOFT_RESET);
+	}
+
+	if (srbm_soft_reset) {
+		tmp = RREG32(SRBM_SOFT_RESET);
+		tmp |= srbm_soft_reset;
+		dev_info(rdev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp);
+		WREG32(SRBM_SOFT_RESET, tmp);
+		tmp = RREG32(SRBM_SOFT_RESET);
+
+		udelay(50);
+
+		tmp &= ~srbm_soft_reset;
+		WREG32(SRBM_SOFT_RESET, tmp);
+		tmp = RREG32(SRBM_SOFT_RESET);
+	}
 
-	dev_info(rdev->dev, "  GRBM_SOFT_RESET=0x%08X\n", grbm_reset);
-	WREG32(GRBM_SOFT_RESET, grbm_reset);
-	(void)RREG32(GRBM_SOFT_RESET);
-	udelay(50);
-	WREG32(GRBM_SOFT_RESET, 0);
-	(void)RREG32(GRBM_SOFT_RESET);
 	/* Wait a little for things to settle down */
 	udelay(50);
-	dev_info(rdev->dev, "  GRBM_STATUS=0x%08X\n",
-		RREG32(GRBM_STATUS));
-	dev_info(rdev->dev, "  GRBM_STATUS2=0x%08X\n",
-		RREG32(GRBM_STATUS2));
-	dev_info(rdev->dev, "  GRBM_STATUS_SE0=0x%08X\n",
-		RREG32(GRBM_STATUS_SE0));
-	dev_info(rdev->dev, "  GRBM_STATUS_SE1=0x%08X\n",
-		RREG32(GRBM_STATUS_SE1));
-	dev_info(rdev->dev, "  GRBM_STATUS_SE2=0x%08X\n",
-		RREG32(GRBM_STATUS_SE2));
-	dev_info(rdev->dev, "  GRBM_STATUS_SE3=0x%08X\n",
-		RREG32(GRBM_STATUS_SE3));
-	dev_info(rdev->dev, "  SRBM_STATUS=0x%08X\n",
-		RREG32(SRBM_STATUS));
-	dev_info(rdev->dev, "  SRBM_STATUS2=0x%08X\n",
-		RREG32(SRBM_STATUS2));
+
 	evergreen_mc_resume(rdev, &save);
-	return 0;
+	udelay(50);
+
+	cik_print_gpu_status_regs(rdev);
 }
 
 /**
- * cik_asic_reset - soft reset compute and gfx
+ * cik_asic_reset - soft reset GPU
  *
  * @rdev: radeon_device pointer
  *
- * Soft reset the CPC blocks (CIK).
- * XXX: make this more fine grained and only reset
- * what is necessary.
+ * Look up which blocks are hung and attempt
+ * to reset them.
  * Returns 0 for success.
  */
 int cik_asic_reset(struct radeon_device *rdev)
 {
-	int r;
+	u32 reset_mask;
 
-	r = cik_compute_gpu_soft_reset(rdev);
-	if (r)
-		dev_info(rdev->dev, "Compute reset failed!\n");
+	reset_mask = cik_gpu_check_soft_reset(rdev);
+
+	if (reset_mask)
+		r600_set_bios_scratch_engine_hung(rdev, true);
+
+	cik_gpu_soft_reset(rdev, reset_mask);
 
-	return cik_gfx_gpu_soft_reset(rdev);
+	reset_mask = cik_gpu_check_soft_reset(rdev);
+
+	if (!reset_mask)
+		r600_set_bios_scratch_engine_hung(rdev, false);
+
+	return 0;
+}
+
+/**
+ * cik_gfx_is_lockup - check if the 3D engine is locked up
+ *
+ * @rdev: radeon_device pointer
+ * @ring: radeon_ring structure holding ring information
+ *
+ * Check if the 3D engine is locked up (CIK).
+ * Returns true if the engine is locked, false if not.
+ */
+bool cik_gfx_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)
+{
+	u32 reset_mask = cik_gpu_check_soft_reset(rdev);
+
+	if (!(reset_mask & (RADEON_RESET_GFX |
+			    RADEON_RESET_COMPUTE |
+			    RADEON_RESET_CP))) {
+		radeon_ring_lockup_update(ring);
+		return false;
+	}
+	/* force CP activities */
+	radeon_ring_force_activity(rdev, ring);
+	return radeon_ring_test_lockup(rdev, ring);
 }
 
 /**
@@ -2938,13 +3031,15 @@ int cik_asic_reset(struct radeon_device *rdev)
  */
 bool cik_sdma_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)
 {
-	u32 dma_status_reg;
+	u32 reset_mask = cik_gpu_check_soft_reset(rdev);
+	u32 mask;
 
 	if (ring->idx == R600_RING_TYPE_DMA_INDEX)
-		dma_status_reg = RREG32(SDMA0_STATUS_REG + SDMA0_REGISTER_OFFSET);
+		mask = RADEON_RESET_DMA;
 	else
-		dma_status_reg = RREG32(SDMA0_STATUS_REG + SDMA1_REGISTER_OFFSET);
-	if (dma_status_reg & SDMA_IDLE) {
+		mask = RADEON_RESET_DMA1;
+
+	if (!(reset_mask & mask)) {
 		radeon_ring_lockup_update(ring);
 		return false;
 	}
diff --git a/drivers/gpu/drm/radeon/cikd.h b/drivers/gpu/drm/radeon/cikd.h
index daa51ac..8afb334 100644
--- a/drivers/gpu/drm/radeon/cikd.h
+++ b/drivers/gpu/drm/radeon/cikd.h
@@ -40,7 +40,19 @@
 #define		QUEUEID(x)					((x) << 8)
 
 #define	SRBM_STATUS2				        0xE4C
+#define		SDMA_BUSY 				(1 << 5)
+#define		SDMA1_BUSY 				(1 << 6)
 #define	SRBM_STATUS				        0xE50
+#define		UVD_RQ_PENDING 				(1 << 1)
+#define		GRBM_RQ_PENDING 			(1 << 5)
+#define		VMC_BUSY 				(1 << 8)
+#define		MCB_BUSY 				(1 << 9)
+#define		MCB_NON_DISPLAY_BUSY 			(1 << 10)
+#define		MCC_BUSY 				(1 << 11)
+#define		MCD_BUSY 				(1 << 12)
+#define		SEM_BUSY 				(1 << 14)
+#define		IH_BUSY 				(1 << 17)
+#define		UVD_BUSY 				(1 << 19)
 
 #define	SRBM_SOFT_RESET				        0xE60
 #define		SOFT_RESET_BIF				(1 << 1)
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 043/165] drm/radeon: add indirect register accessors for SMC registers
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (42 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 042/165] drm/radeon: update CIK soft reset alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 044/165] drm/radeon: add get_xclk() callback for CIK alexdeucher
                   ` (69 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/evergreen_reg.h |    4 ++++
 drivers/gpu/drm/radeon/radeon.h        |   17 +++++++++++++++++
 2 files changed, 21 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/radeon/evergreen_reg.h b/drivers/gpu/drm/radeon/evergreen_reg.h
index 881aba2..50948ac 100644
--- a/drivers/gpu/drm/radeon/evergreen_reg.h
+++ b/drivers/gpu/drm/radeon/evergreen_reg.h
@@ -24,6 +24,10 @@
 #ifndef __EVERGREEN_REG_H__
 #define __EVERGREEN_REG_H__
 
+/* trinity */
+#define TN_SMC_IND_INDEX_0                              0x200
+#define TN_SMC_IND_DATA_0                               0x204
+
 /* evergreen */
 #define EVERGREEN_VGA_MEMORY_BASE_ADDRESS               0x310
 #define EVERGREEN_VGA_MEMORY_BASE_ADDRESS_HIGH          0x324
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index b329e99..9af0fa6 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -1806,6 +1806,8 @@ void r100_io_wreg(struct radeon_device *rdev, u32 reg, u32 v);
 #define WREG32_PCIE(reg, v) rv370_pcie_wreg(rdev, (reg), (v))
 #define RREG32_PCIE_PORT(reg) rdev->pciep_rreg(rdev, (reg))
 #define WREG32_PCIE_PORT(reg, v) rdev->pciep_wreg(rdev, (reg), (v))
+#define RREG32_SMC(reg) tn_smc_rreg(rdev, (reg))
+#define WREG32_SMC(reg, v) tn_smc_wreg(rdev, (reg), (v))
 #define WREG32_P(reg, val, mask)				\
 	do {							\
 		uint32_t tmp_ = RREG32(reg);			\
@@ -1844,6 +1846,21 @@ static inline void rv370_pcie_wreg(struct radeon_device *rdev, uint32_t reg, uin
 	WREG32(RADEON_PCIE_DATA, (v));
 }
 
+static inline u32 tn_smc_rreg(struct radeon_device *rdev, u32 reg)
+{
+	u32 r;
+
+	WREG32(TN_SMC_IND_INDEX_0, (reg));
+	r = RREG32(TN_SMC_IND_DATA_0);
+	return r;
+}
+
+static inline void tn_smc_wreg(struct radeon_device *rdev, u32 reg, u32 v)
+{
+	WREG32(TN_SMC_IND_INDEX_0, (reg));
+	WREG32(TN_SMC_IND_DATA_0, (v));
+}
+
 void r100_pll_errata_after_index(struct radeon_device *rdev);
 
 
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 044/165] drm/radeon: add get_xclk() callback for CIK
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (43 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 043/165] drm/radeon: add indirect register accessors for SMC registers alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 045/165] drm/radeon/cik: add pcie_port indirect register accessors alexdeucher
                   ` (68 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/cik.c         |   22 ++++++++++++++++++++++
 drivers/gpu/drm/radeon/cikd.h        |    7 +++++++
 drivers/gpu/drm/radeon/radeon_asic.h |    1 +
 3 files changed, 30 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
index aaf7bba..0db0ebc 100644
--- a/drivers/gpu/drm/radeon/cik.c
+++ b/drivers/gpu/drm/radeon/cik.c
@@ -78,6 +78,28 @@ extern void si_rlc_fini(struct radeon_device *rdev);
 extern int si_rlc_init(struct radeon_device *rdev);
 static void cik_rlc_stop(struct radeon_device *rdev);
 
+/**
+ * cik_get_xclk - get the xclk
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Returns the reference clock used by the gfx engine
+ * (CIK).
+ */
+u32 cik_get_xclk(struct radeon_device *rdev)
+{
+        u32 reference_clock = rdev->clock.spll.reference_freq;
+
+	if (rdev->flags & RADEON_IS_IGP) {
+		if (RREG32_SMC(GENERAL_PWRMGT) & GPU_COUNTER_CLK)
+			return reference_clock / 2;
+	} else {
+		if (RREG32_SMC(CG_CLKPIN_CNTL) & XTALIN_DIVIDE)
+			return reference_clock / 4;
+	}
+	return reference_clock;
+}
+
 #define BONAIRE_IO_MC_REGS_SIZE 36
 
 static const u32 bonaire_io_mc_regs[BONAIRE_IO_MC_REGS_SIZE][2] =
diff --git a/drivers/gpu/drm/radeon/cikd.h b/drivers/gpu/drm/radeon/cikd.h
index 8afb334..f00e273 100644
--- a/drivers/gpu/drm/radeon/cikd.h
+++ b/drivers/gpu/drm/radeon/cikd.h
@@ -28,6 +28,13 @@
 
 #define CIK_RB_BITMAP_WIDTH_PER_SH  2
 
+/* SMC IND registers */
+#define GENERAL_PWRMGT                                    0xC0200000
+#       define GPU_COUNTER_CLK                            (1 << 15)
+
+#define CG_CLKPIN_CNTL                                    0xC05001A0
+#       define XTALIN_DIVIDE                              (1 << 1)
+
 #define VGA_HDP_CONTROL  				0x328
 #define		VGA_MEMORY_DISABLE				(1 << 4)
 
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index 248da72..05f75f7 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -557,5 +557,6 @@ int si_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk);
  * cik
  */
 uint64_t cik_get_gpu_clock_counter(struct radeon_device *rdev);
+u32 cik_get_xclk(struct radeon_device *rdev);
 
 #endif
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 045/165] drm/radeon/cik: add pcie_port indirect register accessors
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (44 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 044/165] drm/radeon: add get_xclk() callback for CIK alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 046/165] drm/radeon: update radeon_atom_get_clock_dividers() for SI alexdeucher
                   ` (67 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/cik.c         |   21 +++++++++++++++++++++
 drivers/gpu/drm/radeon/cikd.h        |    3 +++
 drivers/gpu/drm/radeon/radeon_asic.c |    6 +++++-
 drivers/gpu/drm/radeon/radeon_asic.h |    2 ++
 4 files changed, 31 insertions(+), 1 deletions(-)

diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
index 0db0ebc..e8ea845 100644
--- a/drivers/gpu/drm/radeon/cik.c
+++ b/drivers/gpu/drm/radeon/cik.c
@@ -78,6 +78,27 @@ extern void si_rlc_fini(struct radeon_device *rdev);
 extern int si_rlc_init(struct radeon_device *rdev);
 static void cik_rlc_stop(struct radeon_device *rdev);
 
+/*
+ * Indirect registers accessor
+ */
+u32 cik_pciep_rreg(struct radeon_device *rdev, u32 reg)
+{
+	u32 r;
+
+	WREG32(PCIE_INDEX, reg);
+	(void)RREG32(PCIE_INDEX);
+	r = RREG32(PCIE_DATA);
+	return r;
+}
+
+void cik_pciep_wreg(struct radeon_device *rdev, u32 reg, u32 v)
+{
+	WREG32(PCIE_INDEX, reg);
+	(void)RREG32(PCIE_INDEX);
+	WREG32(PCIE_DATA, v);
+	(void)RREG32(PCIE_DATA);
+}
+
 /**
  * cik_get_xclk - get the xclk
  *
diff --git a/drivers/gpu/drm/radeon/cikd.h b/drivers/gpu/drm/radeon/cikd.h
index f00e273..d23809a 100644
--- a/drivers/gpu/drm/radeon/cikd.h
+++ b/drivers/gpu/drm/radeon/cikd.h
@@ -35,6 +35,9 @@
 #define CG_CLKPIN_CNTL                                    0xC05001A0
 #       define XTALIN_DIVIDE                              (1 << 1)
 
+#define PCIE_INDEX  					0x38
+#define PCIE_DATA  					0x3C
+
 #define VGA_HDP_CONTROL  				0x328
 #define		VGA_MEMORY_DISABLE				(1 << 4)
 
diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c
index a2802b47..717b537 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.c
+++ b/drivers/gpu/drm/radeon/radeon_asic.c
@@ -126,7 +126,11 @@ static void radeon_register_accessor_init(struct radeon_device *rdev)
 		rdev->mc_rreg = &rs780_mc_rreg;
 		rdev->mc_wreg = &rs780_mc_wreg;
 	}
-	if (rdev->family >= CHIP_R600) {
+
+	if (rdev->family >= CHIP_BONAIRE) {
+		rdev->pciep_rreg = &cik_pciep_rreg;
+		rdev->pciep_wreg = &cik_pciep_wreg;
+	} else if (rdev->family >= CHIP_R600) {
 		rdev->pciep_rreg = &r600_pciep_rreg;
 		rdev->pciep_wreg = &r600_pciep_wreg;
 	}
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index 05f75f7..8c19e36 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -558,5 +558,7 @@ int si_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk);
  */
 uint64_t cik_get_gpu_clock_counter(struct radeon_device *rdev);
 u32 cik_get_xclk(struct radeon_device *rdev);
+uint32_t cik_pciep_rreg(struct radeon_device *rdev, uint32_t reg);
+void cik_pciep_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
 
 #endif
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 046/165] drm/radeon: update radeon_atom_get_clock_dividers() for SI
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (45 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 045/165] drm/radeon/cik: add pcie_port indirect register accessors alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 047/165] drm/radeon: update radeon_atom_get_clock_dividers for CIK alexdeucher
                   ` (66 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

SI uses v5 of the command table and uses a different table
for memory PLLs.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/radeon_atombios.c |    6 +++++-
 1 files changed, 5 insertions(+), 1 deletions(-)

diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c
index 3236755..774e354 100644
--- a/drivers/gpu/drm/radeon/radeon_atombios.c
+++ b/drivers/gpu/drm/radeon/radeon_atombios.c
@@ -2732,7 +2732,8 @@ int radeon_atom_get_clock_dividers(struct radeon_device *rdev,
 		break;
 	case 2:
 	case 3:
-		/* r6xx, r7xx, evergreen, ni */
+	case 5:
+		/* r6xx, r7xx, evergreen, ni, si */
 		if (rdev->family <= CHIP_RV770) {
 			args.v2.ucAction = clock_type;
 			args.v2.ulClock = cpu_to_le32(clock);	/* 10 khz */
@@ -2765,6 +2766,9 @@ int radeon_atom_get_clock_dividers(struct radeon_device *rdev,
 				dividers->vco_mode = (args.v3.ucCntlFlag &
 						      ATOM_PLL_CNTL_FLAG_MPLL_VCO_MODE) ? 1 : 0;
 			} else {
+				/* for SI we use ComputeMemoryClockParam for memory plls */
+				if (rdev->family >= CHIP_TAHITI)
+					return -EINVAL;
 				args.v5.ulClockParams = cpu_to_le32((clock_type << 24) | clock);
 				if (strobe_mode)
 					args.v5.ucInputFlag = ATOM_PLL_INPUT_FLAG_PLL_STROBE_MODE_EN;
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 047/165] drm/radeon: update radeon_atom_get_clock_dividers for CIK
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (46 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 046/165] drm/radeon: update radeon_atom_get_clock_dividers() for SI alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 048/165] drm/radeon: add UVD support for CIK (v3) alexdeucher
                   ` (65 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

CIK uses a slightly different variant of the table structs
and params.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/radeon_atombios.c |   20 +++++++++++++++++++-
 drivers/gpu/drm/radeon/radeon_mode.h     |    3 +++
 2 files changed, 22 insertions(+), 1 deletions(-)

diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c
index 774e354..bf3b924 100644
--- a/drivers/gpu/drm/radeon/radeon_atombios.c
+++ b/drivers/gpu/drm/radeon/radeon_atombios.c
@@ -2700,6 +2700,8 @@ union get_clock_dividers {
 	struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V3 v3;
 	struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V4 v4;
 	struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V5 v5;
+	struct _COMPUTE_GPU_CLOCK_INPUT_PARAMETERS_V1_6 v6_in;
+	struct _COMPUTE_GPU_CLOCK_OUTPUT_PARAMETERS_V1_6 v6_out;
 };
 
 int radeon_atom_get_clock_dividers(struct radeon_device *rdev,
@@ -2794,9 +2796,25 @@ int radeon_atom_get_clock_dividers(struct radeon_device *rdev,
 
 		atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
 
-		dividers->post_div = args.v4.ucPostDiv;
+		dividers->post_divider = dividers->post_div = args.v4.ucPostDiv;
 		dividers->real_clock = le32_to_cpu(args.v4.ulClock);
 		break;
+	case 6:
+		/* CI */
+		/* COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK, COMPUTE_GPUCLK_INPUT_FLAG_SCLK */
+		args.v6_in.ulClock.ulComputeClockFlag = clock_type;
+		args.v6_in.ulClock.ulClockFreq = cpu_to_le32(clock);	/* 10 khz */
+
+		atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+
+		dividers->whole_fb_div = le16_to_cpu(args.v6_out.ulFbDiv.usFbDiv);
+		dividers->frac_fb_div = le16_to_cpu(args.v6_out.ulFbDiv.usFbDivFrac);
+		dividers->ref_div = args.v6_out.ucPllRefDiv;
+		dividers->post_div = args.v6_out.ucPllPostDiv;
+		dividers->flags = args.v6_out.ucPllCntlFlag;
+		dividers->real_clock = le32_to_cpu(args.v6_out.ulClock.ulClock);
+		dividers->post_divider = args.v6_out.ulClock.ucPostDiv;
+		break;
 	default:
 		return -EINVAL;
 	}
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
index 4ed0a4c..576511f 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -514,6 +514,9 @@ struct atom_clock_dividers {
 	bool enable_dithen;
 	u32 vco_mode;
 	u32 real_clock;
+	/* added for CI */
+	u32 post_divider;
+	u32 flags;
 };
 
 extern enum radeon_tv_std
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 048/165] drm/radeon: add UVD support for CIK (v3)
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (47 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 047/165] drm/radeon: update radeon_atom_get_clock_dividers for CIK alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 049/165] drm/radeon/cik: add srbm_select function alexdeucher
                   ` (64 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher, Christian König

From: Christian König <christian.koenig@amd.com>

v2: agd5f: fix clock dividers setup for bonaire
v3: agd5f: rebase

Signed-off-by: Christian König <christian.koenig@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/cik.c         |  111 ++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/radeon/cikd.h        |   28 +++++++++
 drivers/gpu/drm/radeon/radeon_asic.h |    2 +
 drivers/gpu/drm/radeon/radeon_uvd.c  |    8 +++
 4 files changed, 149 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
index e8ea845..29e0cdd 100644
--- a/drivers/gpu/drm/radeon/cik.c
+++ b/drivers/gpu/drm/radeon/cik.c
@@ -1495,6 +1495,9 @@ static void cik_gpu_init(struct radeon_device *rdev)
 	WREG32(DMIF_ADDR_CALC, gb_addr_config);
 	WREG32(SDMA0_TILING_CONFIG + SDMA0_REGISTER_OFFSET, gb_addr_config & 0x70);
 	WREG32(SDMA0_TILING_CONFIG + SDMA1_REGISTER_OFFSET, gb_addr_config & 0x70);
+	WREG32(UVD_UDEC_ADDR_CONFIG, gb_addr_config);
+	WREG32(UVD_UDEC_DB_ADDR_CONFIG, gb_addr_config);
+	WREG32(UVD_UDEC_DBW_ADDR_CONFIG, gb_addr_config);
 
 	cik_tiling_mode_table_init(rdev);
 
@@ -4906,6 +4909,16 @@ static int cik_startup(struct radeon_device *rdev)
 		return r;
 	}
 
+	r = cik_uvd_resume(rdev);
+	if (!r) {
+		r = radeon_fence_driver_start_ring(rdev,
+						   R600_RING_TYPE_UVD_INDEX);
+		if (r)
+			dev_err(rdev->dev, "UVD fences init error (%d).\n", r);
+	}
+	if (r)
+		rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0;
+
 	/* Enable IRQ */
 	if (!rdev->irq.installed) {
 		r = radeon_irq_kms_init(rdev);
@@ -4952,6 +4965,18 @@ static int cik_startup(struct radeon_device *rdev)
 	if (r)
 		return r;
 
+	ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];
+	if (ring->ring_size) {
+		r = radeon_ring_init(rdev, ring, ring->ring_size,
+				     R600_WB_UVD_RPTR_OFFSET,
+				     UVD_RBC_RB_RPTR, UVD_RBC_RB_WPTR,
+				     0, 0xfffff, RADEON_CP_PACKET2);
+		if (!r)
+			r = r600_uvd_init(rdev);
+		if (r)
+			DRM_ERROR("radeon: failed initializing UVD (%d).\n", r);
+	}
+
 	r = radeon_ib_pool_init(rdev);
 	if (r) {
 		dev_err(rdev->dev, "IB initialization failed (%d).\n", r);
@@ -5013,6 +5038,8 @@ int cik_suspend(struct radeon_device *rdev)
 	radeon_vm_manager_fini(rdev);
 	cik_cp_enable(rdev, false);
 	cik_sdma_enable(rdev, false);
+	r600_uvd_rbc_stop(rdev);
+	radeon_uvd_suspend(rdev);
 	cik_irq_suspend(rdev);
 	radeon_wb_disable(rdev);
 	cik_pcie_gart_disable(rdev);
@@ -5096,6 +5123,13 @@ int cik_init(struct radeon_device *rdev)
 	ring->ring_obj = NULL;
 	r600_ring_init(rdev, ring, 256 * 1024);
 
+	r = radeon_uvd_init(rdev);
+	if (!r) {
+		ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];
+		ring->ring_obj = NULL;
+		r600_ring_init(rdev, ring, 4096);
+	}
+
 	rdev->ih.ring_obj = NULL;
 	r600_ih_ring_init(rdev, 64 * 1024);
 
@@ -5150,6 +5184,7 @@ void cik_fini(struct radeon_device *rdev)
 	radeon_vm_manager_fini(rdev);
 	radeon_ib_pool_fini(rdev);
 	radeon_irq_kms_fini(rdev);
+	radeon_uvd_fini(rdev);
 	cik_pcie_gart_fini(rdev);
 	r600_vram_scratch_fini(rdev);
 	radeon_gem_fini(rdev);
@@ -5717,3 +5752,79 @@ uint64_t cik_get_gpu_clock_counter(struct radeon_device *rdev)
 	return clock;
 }
 
+static int cik_set_uvd_clock(struct radeon_device *rdev, u32 clock,
+                              u32 cntl_reg, u32 status_reg)
+{
+	int r, i;
+	struct atom_clock_dividers dividers;
+	uint32_t tmp;
+
+	r = radeon_atom_get_clock_dividers(rdev, COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK,
+					   clock, false, &dividers);
+	if (r)
+		return r;
+
+	tmp = RREG32_SMC(cntl_reg);
+	tmp &= ~(DCLK_DIR_CNTL_EN|DCLK_DIVIDER_MASK);
+	tmp |= dividers.post_divider;
+	WREG32_SMC(cntl_reg, tmp);
+
+	for (i = 0; i < 100; i++) {
+		if (RREG32_SMC(status_reg) & DCLK_STATUS)
+			break;
+		mdelay(10);
+	}
+	if (i == 100)
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
+int cik_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk)
+{
+	int r = 0;
+
+	r = cik_set_uvd_clock(rdev, vclk, CG_VCLK_CNTL, CG_VCLK_STATUS);
+	if (r)
+		return r;
+
+	r = cik_set_uvd_clock(rdev, dclk, CG_DCLK_CNTL, CG_DCLK_STATUS);
+	return r;
+}
+
+int cik_uvd_resume(struct radeon_device *rdev)
+{
+	uint64_t addr;
+	uint32_t size;
+	int r;
+
+	r = radeon_uvd_resume(rdev);
+	if (r)
+		return r;
+
+	/* programm the VCPU memory controller bits 0-27 */
+	addr = rdev->uvd.gpu_addr >> 3;
+	size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size + 4) >> 3;
+	WREG32(UVD_VCPU_CACHE_OFFSET0, addr);
+	WREG32(UVD_VCPU_CACHE_SIZE0, size);
+
+	addr += size;
+	size = RADEON_UVD_STACK_SIZE >> 3;
+	WREG32(UVD_VCPU_CACHE_OFFSET1, addr);
+	WREG32(UVD_VCPU_CACHE_SIZE1, size);
+
+	addr += size;
+	size = RADEON_UVD_HEAP_SIZE >> 3;
+	WREG32(UVD_VCPU_CACHE_OFFSET2, addr);
+	WREG32(UVD_VCPU_CACHE_SIZE2, size);
+
+	/* bits 28-31 */
+	addr = (rdev->uvd.gpu_addr >> 28) & 0xF;
+	WREG32(UVD_LMI_ADDR_EXT, (addr << 12) | (addr << 0));
+
+	/* bits 32-39 */
+	addr = (rdev->uvd.gpu_addr >> 32) & 0xFF;
+	WREG32(UVD_LMI_EXT40_ADDR, addr | (0x9 << 16) | (0x1 << 31));
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/radeon/cikd.h b/drivers/gpu/drm/radeon/cikd.h
index d23809a..79be39e 100644
--- a/drivers/gpu/drm/radeon/cikd.h
+++ b/drivers/gpu/drm/radeon/cikd.h
@@ -1204,4 +1204,32 @@
 #       define SDMA_SRBM_WRITE_EXTRA_BYTE_ENABLE(x)       ((x) << 12)
                 /* byte mask */
 
+/* UVD */
+
+#define UVD_UDEC_ADDR_CONFIG		0xef4c
+#define UVD_UDEC_DB_ADDR_CONFIG		0xef50
+#define UVD_UDEC_DBW_ADDR_CONFIG	0xef54
+
+#define UVD_LMI_EXT40_ADDR		0xf498
+#define UVD_LMI_ADDR_EXT		0xf594
+#define UVD_VCPU_CACHE_OFFSET0		0xf608
+#define UVD_VCPU_CACHE_SIZE0		0xf60c
+#define UVD_VCPU_CACHE_OFFSET1		0xf610
+#define UVD_VCPU_CACHE_SIZE1		0xf614
+#define UVD_VCPU_CACHE_OFFSET2		0xf618
+#define UVD_VCPU_CACHE_SIZE2		0xf61c
+
+#define UVD_RBC_RB_RPTR			0xf690
+#define UVD_RBC_RB_WPTR			0xf694
+
+/* UVD clocks */
+
+#define CG_DCLK_CNTL			0xC050009C
+#	define DCLK_DIVIDER_MASK	0x7f
+#	define DCLK_DIR_CNTL_EN		(1 << 8)
+#define CG_DCLK_STATUS			0xC05000A0
+#	define DCLK_STATUS		(1 << 0)
+#define CG_VCLK_CNTL			0xC05000A4
+#define CG_VCLK_STATUS			0xC05000A8
+
 #endif
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index 8c19e36..3405742 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -560,5 +560,7 @@ uint64_t cik_get_gpu_clock_counter(struct radeon_device *rdev);
 u32 cik_get_xclk(struct radeon_device *rdev);
 uint32_t cik_pciep_rreg(struct radeon_device *rdev, uint32_t reg);
 void cik_pciep_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
+int cik_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk);
+int cik_uvd_resume(struct radeon_device *rdev);
 
 #endif
diff --git a/drivers/gpu/drm/radeon/radeon_uvd.c b/drivers/gpu/drm/radeon/radeon_uvd.c
index cad735d..fdc77d1 100644
--- a/drivers/gpu/drm/radeon/radeon_uvd.c
+++ b/drivers/gpu/drm/radeon/radeon_uvd.c
@@ -44,11 +44,13 @@
 #define FIRMWARE_CYPRESS	"radeon/CYPRESS_uvd.bin"
 #define FIRMWARE_SUMO		"radeon/SUMO_uvd.bin"
 #define FIRMWARE_TAHITI		"radeon/TAHITI_uvd.bin"
+#define FIRMWARE_BONAIRE	"radeon/BONAIRE_uvd.bin"
 
 MODULE_FIRMWARE(FIRMWARE_RV710);
 MODULE_FIRMWARE(FIRMWARE_CYPRESS);
 MODULE_FIRMWARE(FIRMWARE_SUMO);
 MODULE_FIRMWARE(FIRMWARE_TAHITI);
+MODULE_FIRMWARE(FIRMWARE_BONAIRE);
 
 static void radeon_uvd_idle_work_handler(struct work_struct *work);
 
@@ -100,6 +102,12 @@ int radeon_uvd_init(struct radeon_device *rdev)
 		fw_name = FIRMWARE_TAHITI;
 		break;
 
+	case CHIP_BONAIRE:
+	case CHIP_KABINI:
+	case CHIP_KAVERI:
+		fw_name = FIRMWARE_BONAIRE;
+		break;
+
 	default:
 		return -EINVAL;
 	}
-- 
1.7.7.5

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 049/165] drm/radeon/cik: add srbm_select function
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (48 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 048/165] drm/radeon: add UVD support for CIK (v3) alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 050/165] drm/radeon: use callbacks for ring pointer handling alexdeucher
                   ` (63 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Allows us to select instanced registers based on:
- ME (micro engine
- Pipe
- Queue
- VMID

Switch MC setup to use this new function.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/cik.c |   27 +++++++++++++++++++++++++--
 1 files changed, 25 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
index 29e0cdd..bb7dbc4 100644
--- a/drivers/gpu/drm/radeon/cik.c
+++ b/drivers/gpu/drm/radeon/cik.c
@@ -163,6 +163,29 @@ static const u32 bonaire_io_mc_regs[BONAIRE_IO_MC_REGS_SIZE][2] =
 	{0x0000009f, 0x00b48000}
 };
 
+/**
+ * cik_srbm_select - select specific register instances
+ *
+ * @rdev: radeon_device pointer
+ * @me: selected ME (micro engine)
+ * @pipe: pipe
+ * @queue: queue
+ * @vmid: VMID
+ *
+ * Switches the currently active registers instances.  Some
+ * registers are instanced per VMID, others are instanced per
+ * me/pipe/queue combination.
+ */
+static void cik_srbm_select(struct radeon_device *rdev,
+			    u32 me, u32 pipe, u32 queue, u32 vmid)
+{
+	u32 srbm_gfx_cntl = (PIPEID(pipe & 0x3) |
+			     MEID(me & 0x3) |
+			     VMID(vmid & 0xf) |
+			     QUEUEID(queue & 0x7));
+	WREG32(SRBM_GFX_CNTL, srbm_gfx_cntl);
+}
+
 /* ucode loading */
 /**
  * ci_mc_load_microcode - load MC ucode into the hw
@@ -3351,7 +3374,7 @@ static int cik_pcie_gart_enable(struct radeon_device *rdev)
 	/* XXX SH_MEM regs */
 	/* where to put LDS, scratch, GPUVM in FSA64 space */
 	for (i = 0; i < 16; i++) {
-		WREG32(SRBM_GFX_CNTL, VMID(i));
+		cik_srbm_select(rdev, 0, 0, 0, i);
 		/* CP and shaders */
 		WREG32(SH_MEM_CONFIG, 0);
 		WREG32(SH_MEM_APE1_BASE, 1);
@@ -3364,7 +3387,7 @@ static int cik_pcie_gart_enable(struct radeon_device *rdev)
 		WREG32(SDMA0_GFX_APE1_CNTL + SDMA1_REGISTER_OFFSET, 0);
 		/* XXX SDMA RLC - todo */
 	}
-	WREG32(SRBM_GFX_CNTL, 0);
+	cik_srbm_select(rdev, 0, 0, 0, 0);
 
 	cik_pcie_gart_tlb_flush(rdev);
 	DRM_INFO("PCIE GART of %uM enabled (table at 0x%016llX).\n",
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 050/165] drm/radeon: use callbacks for ring pointer handling
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (49 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 049/165] drm/radeon/cik: add srbm_select function alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 15:31   ` Christian König
  2013-06-26 13:22 ` [PATCH 051/165] drm/radeon: implement simple doorbell page allocator alexdeucher
                   ` (62 subsequent siblings)
  113 siblings, 1 reply; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Add callbacks to the radeon_ring struct to handle
rptr/wptr fetchs and wptr updates.
We currently use one version for all rings, but this
allows us to override with a ring specific versions.

Needed for compute rings on CIK.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/radeon.h      |    5 +++
 drivers/gpu/drm/radeon/radeon_ring.c |   55 +++++++++++++++++++++++++--------
 2 files changed, 46 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 9af0fa6..ad4e68a 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -695,6 +695,11 @@ struct radeon_ring {
 	u32			idx;
 	u64			last_semaphore_signal_addr;
 	u64			last_semaphore_wait_addr;
+	struct {
+		u32			(*get_rptr)(struct radeon_device *rdev, struct radeon_ring *ring);
+		u32			(*get_wptr)(struct radeon_device *rdev, struct radeon_ring *ring);
+		void			(*set_wptr)(struct radeon_device *rdev, struct radeon_ring *ring);
+	} funcs;
 };
 
 /*
diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c
index e17faa7..53018e9 100644
--- a/drivers/gpu/drm/radeon/radeon_ring.c
+++ b/drivers/gpu/drm/radeon/radeon_ring.c
@@ -357,6 +357,38 @@ bool radeon_ring_supports_scratch_reg(struct radeon_device *rdev,
 	}
 }
 
+static u32 radeon_ring_get_rptr(struct radeon_device *rdev,
+				struct radeon_ring *ring)
+{
+	u32 rptr;
+
+	if (rdev->wb.enabled && ring != &rdev->ring[R600_RING_TYPE_UVD_INDEX])
+		rptr = le32_to_cpu(rdev->wb.wb[ring->rptr_offs/4]);
+	else
+		rptr = RREG32(ring->rptr_reg);
+	rptr = (rptr & ring->ptr_reg_mask) >> ring->ptr_reg_shift;
+
+	return rptr;
+}
+
+static u32 radeon_ring_get_wptr(struct radeon_device *rdev,
+				struct radeon_ring *ring)
+{
+	u32 wptr;
+
+	wptr = RREG32(ring->wptr_reg);
+	wptr = (wptr & ring->ptr_reg_mask) >> ring->ptr_reg_shift;
+
+	return wptr;
+}
+
+static void radeon_ring_set_wptr(struct radeon_device *rdev,
+				 struct radeon_ring *ring)
+{
+	WREG32(ring->wptr_reg, (ring->wptr << ring->ptr_reg_shift) & ring->ptr_reg_mask);
+	(void)RREG32(ring->wptr_reg);
+}
+
 /**
  * radeon_ring_free_size - update the free size
  *
@@ -367,13 +399,7 @@ bool radeon_ring_supports_scratch_reg(struct radeon_device *rdev,
  */
 void radeon_ring_free_size(struct radeon_device *rdev, struct radeon_ring *ring)
 {
-	u32 rptr;
-
-	if (rdev->wb.enabled && ring != &rdev->ring[R600_RING_TYPE_UVD_INDEX])
-		rptr = le32_to_cpu(rdev->wb.wb[ring->rptr_offs/4]);
-	else
-		rptr = RREG32(ring->rptr_reg);
-	ring->rptr = (rptr & ring->ptr_reg_mask) >> ring->ptr_reg_shift;
+	ring->rptr = ring->funcs.get_rptr(rdev, ring);
 	/* This works because ring_size is a power of 2 */
 	ring->ring_free_dw = (ring->rptr + (ring->ring_size / 4));
 	ring->ring_free_dw -= ring->wptr;
@@ -458,8 +484,7 @@ void radeon_ring_commit(struct radeon_device *rdev, struct radeon_ring *ring)
 		radeon_ring_write(ring, ring->nop);
 	}
 	DRM_MEMORYBARRIER();
-	WREG32(ring->wptr_reg, (ring->wptr << ring->ptr_reg_shift) & ring->ptr_reg_mask);
-	(void)RREG32(ring->wptr_reg);
+	ring->funcs.set_wptr(rdev, ring);
 }
 
 /**
@@ -561,7 +586,6 @@ void radeon_ring_lockup_update(struct radeon_ring *ring)
 bool radeon_ring_test_lockup(struct radeon_device *rdev, struct radeon_ring *ring)
 {
 	unsigned long cjiffies, elapsed;
-	uint32_t rptr;
 
 	cjiffies = jiffies;
 	if (!time_after(cjiffies, ring->last_activity)) {
@@ -569,8 +593,7 @@ bool radeon_ring_test_lockup(struct radeon_device *rdev, struct radeon_ring *rin
 		radeon_ring_lockup_update(ring);
 		return false;
 	}
-	rptr = RREG32(ring->rptr_reg);
-	ring->rptr = (rptr & ring->ptr_reg_mask) >> ring->ptr_reg_shift;
+	ring->rptr = ring->funcs.get_rptr(rdev, ring);
 	if (ring->rptr != ring->last_rptr) {
 		/* CP is still working no lockup */
 		radeon_ring_lockup_update(ring);
@@ -708,6 +731,10 @@ int radeon_ring_init(struct radeon_device *rdev, struct radeon_ring *ring, unsig
 	ring->ptr_reg_shift = ptr_reg_shift;
 	ring->ptr_reg_mask = ptr_reg_mask;
 	ring->nop = nop;
+	/* set the ptr callbacks */
+	ring->funcs.get_rptr = &radeon_ring_get_rptr;
+	ring->funcs.get_wptr = &radeon_ring_get_wptr;
+	ring->funcs.set_wptr = &radeon_ring_set_wptr;
 	/* Allocate ring buffer */
 	if (ring->ring_obj == NULL) {
 		r = radeon_bo_create(rdev, ring->ring_size, PAGE_SIZE, true,
@@ -797,9 +824,9 @@ static int radeon_debugfs_ring_info(struct seq_file *m, void *data)
 
 	radeon_ring_free_size(rdev, ring);
 	count = (ring->ring_size / 4) - ring->ring_free_dw;
-	tmp = RREG32(ring->wptr_reg) >> ring->ptr_reg_shift;
+	tmp = ring->funcs.get_wptr(rdev, ring);
 	seq_printf(m, "wptr(0x%04x): 0x%08x [%5d]\n", ring->wptr_reg, tmp, tmp);
-	tmp = RREG32(ring->rptr_reg) >> ring->ptr_reg_shift;
+	tmp = ring->funcs.get_rptr(rdev, ring);
 	seq_printf(m, "rptr(0x%04x): 0x%08x [%5d]\n", ring->rptr_reg, tmp, tmp);
 	if (ring->rptr_save_reg) {
 		seq_printf(m, "rptr next(0x%04x): 0x%08x\n", ring->rptr_save_reg,
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 051/165] drm/radeon: implement simple doorbell page allocator
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (50 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 050/165] drm/radeon: use callbacks for ring pointer handling alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 12:57   ` Jerome Glisse
  2013-06-26 13:22 ` [PATCH 052/165] drm/radeon/cik: Add support for compute queues (v2) alexdeucher
                   ` (61 subsequent siblings)
  113 siblings, 1 reply; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

The doorbell aperture is a PCI BAR whose pages can be
mapped to compute resources for things like wptrs
for userspace queues.

This patch maps the BAR and sets up a simple allocator
to allocate pages from the BAR.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/cik.c           |   38 +++++++++++++
 drivers/gpu/drm/radeon/radeon.h        |   21 +++++++
 drivers/gpu/drm/radeon/radeon_device.c |   94 ++++++++++++++++++++++++++++++++
 3 files changed, 153 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
index bb7dbc4..5c28fa5 100644
--- a/drivers/gpu/drm/radeon/cik.c
+++ b/drivers/gpu/drm/radeon/cik.c
@@ -121,6 +121,44 @@ u32 cik_get_xclk(struct radeon_device *rdev)
 	return reference_clock;
 }
 
+/**
+ * cik_mm_rdoorbell - read a doorbell dword
+ *
+ * @rdev: radeon_device pointer
+ * @offset: byte offset into the aperture
+ *
+ * Returns the value in the doorbell aperture at the
+ * requested offset (CIK).
+ */
+u32 cik_mm_rdoorbell(struct radeon_device *rdev, u32 offset)
+{
+	if (offset < rdev->doorbell.size) {
+		return readl(((void __iomem *)rdev->doorbell.ptr) + offset);
+	} else {
+		DRM_ERROR("reading beyond doorbell aperture: 0x%08x!\n", offset);
+		return 0;
+	}
+}
+
+/**
+ * cik_mm_wdoorbell - write a doorbell dword
+ *
+ * @rdev: radeon_device pointer
+ * @offset: byte offset into the aperture
+ * @v: value to write
+ *
+ * Writes @v to the doorbell aperture at the
+ * requested offset (CIK).
+ */
+void cik_mm_wdoorbell(struct radeon_device *rdev, u32 offset, u32 v)
+{
+	if (offset < rdev->doorbell.size) {
+		writel(v, ((void __iomem *)rdev->doorbell.ptr) + offset);
+	} else {
+		DRM_ERROR("writing beyond doorbell aperture: 0x%08x!\n", offset);
+	}
+}
+
 #define BONAIRE_IO_MC_REGS_SIZE 36
 
 static const u32 bonaire_io_mc_regs[BONAIRE_IO_MC_REGS_SIZE][2] =
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index ad4e68a..a2a3430 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -556,6 +556,20 @@ struct radeon_scratch {
 int radeon_scratch_get(struct radeon_device *rdev, uint32_t *reg);
 void radeon_scratch_free(struct radeon_device *rdev, uint32_t reg);
 
+/*
+ * GPU doorbell structures, functions & helpers
+ */
+struct radeon_doorbell {
+	u32			num_pages;
+	bool			free[1024];
+	/* doorbell mmio */
+	resource_size_t			base;
+	resource_size_t			size;
+	void __iomem			*ptr;
+};
+
+int radeon_doorbell_get(struct radeon_device *rdev, u32 *page);
+void radeon_doorbell_free(struct radeon_device *rdev, u32 doorbell);
 
 /*
  * IRQS.
@@ -1711,6 +1725,7 @@ struct radeon_device {
 	struct radeon_gart		gart;
 	struct radeon_mode_info		mode_info;
 	struct radeon_scratch		scratch;
+	struct radeon_doorbell		doorbell;
 	struct radeon_mman		mman;
 	struct radeon_fence_driver	fence_drv[RADEON_NUM_RINGS];
 	wait_queue_head_t		fence_queue;
@@ -1784,6 +1799,9 @@ void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v,
 u32 r100_io_rreg(struct radeon_device *rdev, u32 reg);
 void r100_io_wreg(struct radeon_device *rdev, u32 reg, u32 v);
 
+u32 cik_mm_rdoorbell(struct radeon_device *rdev, u32 offset);
+void cik_mm_wdoorbell(struct radeon_device *rdev, u32 offset, u32 v);
+
 /*
  * Cast helper
  */
@@ -1833,6 +1851,9 @@ void r100_io_wreg(struct radeon_device *rdev, u32 reg, u32 v);
 #define RREG32_IO(reg) r100_io_rreg(rdev, (reg))
 #define WREG32_IO(reg, v) r100_io_wreg(rdev, (reg), (v))
 
+#define RDOORBELL32(offset) cik_mm_rdoorbell(rdev, (offset))
+#define WDOORBELL32(offset, v) cik_mm_wdoorbell(rdev, (offset), (v))
+
 /*
  * Indirect registers accessor
  */
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
index 4e97ff7..82335e3 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -232,6 +232,94 @@ void radeon_scratch_free(struct radeon_device *rdev, uint32_t reg)
 }
 
 /*
+ * GPU doorbell aperture helpers function.
+ */
+/**
+ * radeon_doorbell_init - Init doorbell driver information.
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Init doorbell driver information (CIK)
+ * Returns 0 on success, error on failure.
+ */
+int radeon_doorbell_init(struct radeon_device *rdev)
+{
+	int i;
+
+	/* doorbell bar mapping */
+	rdev->doorbell.base = pci_resource_start(rdev->pdev, 2);
+	rdev->doorbell.size = pci_resource_len(rdev->pdev, 2);
+
+	/* limit to 4 MB for now */
+	if (rdev->doorbell.size > (4 * 1024 * 1024))
+		rdev->doorbell.size = 4 * 1024 * 1024;
+
+	rdev->doorbell.ptr = ioremap(rdev->doorbell.base, rdev->doorbell.size);
+	if (rdev->doorbell.ptr == NULL) {
+		return -ENOMEM;
+	}
+	DRM_INFO("doorbell mmio base: 0x%08X\n", (uint32_t)rdev->doorbell.base);
+	DRM_INFO("doorbell mmio size: %u\n", (unsigned)rdev->doorbell.size);
+
+	rdev->doorbell.num_pages = rdev->doorbell.size / PAGE_SIZE;
+
+	for (i = 0; i < rdev->doorbell.num_pages; i++) {
+		rdev->doorbell.free[i] = true;
+	}
+	return 0;
+}
+
+/**
+ * radeon_doorbell_fini - Tear down doorbell driver information.
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Tear down doorbell driver information (CIK)
+ */
+void radeon_doorbell_fini(struct radeon_device *rdev)
+{
+	iounmap(rdev->doorbell.ptr);
+	rdev->doorbell.ptr = NULL;
+}
+
+/**
+ * radeon_doorbell_get - Allocate a doorbell page
+ *
+ * @rdev: radeon_device pointer
+ * @doorbell: doorbell page number
+ *
+ * Allocate a doorbell page for use by the driver (all asics).
+ * Returns 0 on success or -EINVAL on failure.
+ */
+int radeon_doorbell_get(struct radeon_device *rdev, u32 *doorbell)
+{
+	int i;
+
+	for (i = 0; i < rdev->doorbell.num_pages; i++) {
+		if (rdev->doorbell.free[i]) {
+			rdev->doorbell.free[i] = false;
+			*doorbell = i;
+			return 0;
+		}
+	}
+	return -EINVAL;
+}
+
+/**
+ * radeon_doorbell_free - Free a doorbell page
+ *
+ * @rdev: radeon_device pointer
+ * @doorbell: doorbell page number
+ *
+ * Free a doorbell page allocated for use by the driver (all asics)
+ */
+void radeon_doorbell_free(struct radeon_device *rdev, u32 doorbell)
+{
+	if (doorbell < rdev->doorbell.num_pages)
+		rdev->doorbell.free[doorbell] = true;
+}
+
+/*
  * radeon_wb_*()
  * Writeback is the the method by which the the GPU updates special pages
  * in memory with the status of certain GPU events (fences, ring pointers,
@@ -1162,6 +1250,10 @@ int radeon_device_init(struct radeon_device *rdev,
 	DRM_INFO("register mmio base: 0x%08X\n", (uint32_t)rdev->rmmio_base);
 	DRM_INFO("register mmio size: %u\n", (unsigned)rdev->rmmio_size);
 
+	/* doorbell bar mapping */
+	if (rdev->family >= CHIP_BONAIRE)
+		radeon_doorbell_init(rdev);
+
 	/* io port mapping */
 	for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
 		if (pci_resource_flags(rdev->pdev, i) & IORESOURCE_IO) {
@@ -1239,6 +1331,8 @@ void radeon_device_fini(struct radeon_device *rdev)
 	rdev->rio_mem = NULL;
 	iounmap(rdev->rmmio);
 	rdev->rmmio = NULL;
+	if (rdev->family >= CHIP_BONAIRE)
+		radeon_doorbell_fini(rdev);
 	radeon_debugfs_remove_files(rdev);
 }
 
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 052/165] drm/radeon/cik: Add support for compute queues (v2)
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (51 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 051/165] drm/radeon: implement simple doorbell page allocator alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 10:08   ` Jerome Glisse
  2013-06-26 13:22 ` [PATCH 053/165] drm/radeon/cik: switch to type3 nop packet for compute rings alexdeucher
                   ` (60 subsequent siblings)
  113 siblings, 1 reply; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

On CIK, the compute rings work slightly differently than
on previous asics, however the basic concepts are the same.

The main differences:
- New MEC engines for compute queues
- Multiple queues per MEC:
  - CI/KB: 1 MEC, 4 pipes per MEC, 8 queues per pipe = 32 queues
  -    KV: 2 MEC, 4 pipes per MEC, 8 queues per pipe = 64 queues
- Queues can be allocated and scheduled by another queue
- New doorbell aperture allows you to assign space in the aperture
  for the wptr which allows for userspace access to queues

v2: add wptr shadow, fix eop setup

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/cik.c       |  528 +++++++++++++++++++++++++++++++++++-
 drivers/gpu/drm/radeon/cikd.h      |   62 +++++
 drivers/gpu/drm/radeon/radeon.h    |   19 ++
 drivers/gpu/drm/radeon/radeon_cs.c |    4 +-
 4 files changed, 601 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
index 5c28fa5..9d2d6bb 100644
--- a/drivers/gpu/drm/radeon/cik.c
+++ b/drivers/gpu/drm/radeon/cik.c
@@ -1687,6 +1687,7 @@ int cik_ring_test(struct radeon_device *rdev, struct radeon_ring *ring)
 	radeon_ring_write(ring, ((scratch - PACKET3_SET_UCONFIG_REG_START) >> 2));
 	radeon_ring_write(ring, 0xDEADBEEF);
 	radeon_ring_unlock_commit(rdev, ring);
+
 	for (i = 0; i < rdev->usec_timeout; i++) {
 		tmp = RREG32(scratch);
 		if (tmp == 0xDEADBEEF)
@@ -2112,6 +2113,51 @@ static int cik_cp_gfx_resume(struct radeon_device *rdev)
 	return 0;
 }
 
+static u32 cik_compute_ring_get_rptr(struct radeon_device *rdev,
+				     struct radeon_ring *ring)
+{
+	u32 rptr;
+
+
+
+	if (rdev->wb.enabled) {
+		rptr = le32_to_cpu(rdev->wb.wb[ring->rptr_offs/4]);
+	} else {
+		cik_srbm_select(rdev, ring->me, ring->pipe, ring->queue, 0);
+		rptr = RREG32(CP_HQD_PQ_RPTR);
+		cik_srbm_select(rdev, 0, 0, 0, 0);
+	}
+	rptr = (rptr & ring->ptr_reg_mask) >> ring->ptr_reg_shift;
+
+	return rptr;
+}
+
+static u32 cik_compute_ring_get_wptr(struct radeon_device *rdev,
+				     struct radeon_ring *ring)
+{
+	u32 wptr;
+
+	if (rdev->wb.enabled) {
+		wptr = le32_to_cpu(rdev->wb.wb[ring->wptr_offs/4]);
+	} else {
+		cik_srbm_select(rdev, ring->me, ring->pipe, ring->queue, 0);
+		wptr = RREG32(CP_HQD_PQ_WPTR);
+		cik_srbm_select(rdev, 0, 0, 0, 0);
+	}
+	wptr = (wptr & ring->ptr_reg_mask) >> ring->ptr_reg_shift;
+
+	return wptr;
+}
+
+static void cik_compute_ring_set_wptr(struct radeon_device *rdev,
+				      struct radeon_ring *ring)
+{
+	u32 wptr = (ring->wptr << ring->ptr_reg_shift) & ring->ptr_reg_mask;
+
+	rdev->wb.wb[ring->wptr_offs/4] = cpu_to_le32(wptr);
+	WDOORBELL32(ring->doorbell_offset, wptr);
+}
+
 /**
  * cik_cp_compute_enable - enable/disable the compute CP MEs
  *
@@ -2176,7 +2222,8 @@ static int cik_cp_compute_load_microcode(struct radeon_device *rdev)
  */
 static int cik_cp_compute_start(struct radeon_device *rdev)
 {
-	//todo
+	cik_cp_compute_enable(rdev, true);
+
 	return 0;
 }
 
@@ -2190,10 +2237,171 @@ static int cik_cp_compute_start(struct radeon_device *rdev)
  */
 static void cik_cp_compute_fini(struct radeon_device *rdev)
 {
+	int i, idx, r;
+
 	cik_cp_compute_enable(rdev, false);
-	//todo
+
+	for (i = 0; i < 2; i++) {
+		if (i == 0)
+			idx = CAYMAN_RING_TYPE_CP1_INDEX;
+		else
+			idx = CAYMAN_RING_TYPE_CP2_INDEX;
+
+		if (rdev->ring[idx].mqd_obj) {
+			r = radeon_bo_reserve(rdev->ring[idx].mqd_obj, false);
+			if (unlikely(r != 0))
+				dev_warn(rdev->dev, "(%d) reserve MQD bo failed\n", r);
+
+			radeon_bo_unpin(rdev->ring[idx].mqd_obj);
+			radeon_bo_unreserve(rdev->ring[idx].mqd_obj);
+
+			radeon_bo_unref(&rdev->ring[idx].mqd_obj);
+			rdev->ring[idx].mqd_obj = NULL;
+		}
+	}
+}
+
+static void cik_mec_fini(struct radeon_device *rdev)
+{
+	int r;
+
+	if (rdev->mec.hpd_eop_obj) {
+		r = radeon_bo_reserve(rdev->mec.hpd_eop_obj, false);
+		if (unlikely(r != 0))
+			dev_warn(rdev->dev, "(%d) reserve HPD EOP bo failed\n", r);
+		radeon_bo_unpin(rdev->mec.hpd_eop_obj);
+		radeon_bo_unreserve(rdev->mec.hpd_eop_obj);
+
+		radeon_bo_unref(&rdev->mec.hpd_eop_obj);
+		rdev->mec.hpd_eop_obj = NULL;
+	}
+}
+
+#define MEC_HPD_SIZE 2048
+
+static int cik_mec_init(struct radeon_device *rdev)
+{
+	int r;
+	u32 *hpd;
+
+	/*
+	 * KV:    2 MEC, 4 Pipes/MEC, 8 Queues/Pipe - 64 Queues total
+	 * CI/KB: 1 MEC, 4 Pipes/MEC, 8 Queues/Pipe - 32 Queues total
+	 */
+	if (rdev->family == CHIP_KAVERI)
+		rdev->mec.num_mec = 2;
+	else
+		rdev->mec.num_mec = 1;
+	rdev->mec.num_pipe = 4;
+	rdev->mec.num_queue = rdev->mec.num_mec * rdev->mec.num_pipe * 8;
+
+	if (rdev->mec.hpd_eop_obj == NULL) {
+		r = radeon_bo_create(rdev,
+				     rdev->mec.num_mec *rdev->mec.num_pipe * MEC_HPD_SIZE * 2,
+				     PAGE_SIZE, true,
+				     RADEON_GEM_DOMAIN_GTT, NULL,
+				     &rdev->mec.hpd_eop_obj);
+		if (r) {
+			dev_warn(rdev->dev, "(%d) create HDP EOP bo failed\n", r);
+			return r;
+		}
+	}
+
+	r = radeon_bo_reserve(rdev->mec.hpd_eop_obj, false);
+	if (unlikely(r != 0)) {
+		cik_mec_fini(rdev);
+		return r;
+	}
+	r = radeon_bo_pin(rdev->mec.hpd_eop_obj, RADEON_GEM_DOMAIN_GTT,
+			  &rdev->mec.hpd_eop_gpu_addr);
+	if (r) {
+		dev_warn(rdev->dev, "(%d) pin HDP EOP bo failed\n", r);
+		cik_mec_fini(rdev);
+		return r;
+	}
+	r = radeon_bo_kmap(rdev->mec.hpd_eop_obj, (void **)&hpd);
+	if (r) {
+		dev_warn(rdev->dev, "(%d) map HDP EOP bo failed\n", r);
+		cik_mec_fini(rdev);
+		return r;
+	}
+
+	/* clear memory.  Not sure if this is required or not */
+	memset(hpd, 0, rdev->mec.num_mec *rdev->mec.num_pipe * MEC_HPD_SIZE * 2);
+
+	radeon_bo_kunmap(rdev->mec.hpd_eop_obj);
+	radeon_bo_unreserve(rdev->mec.hpd_eop_obj);
+
+	return 0;
 }
 
+struct hqd_registers
+{
+	u32 cp_mqd_base_addr;
+	u32 cp_mqd_base_addr_hi;
+	u32 cp_hqd_active;
+	u32 cp_hqd_vmid;
+	u32 cp_hqd_persistent_state;
+	u32 cp_hqd_pipe_priority;
+	u32 cp_hqd_queue_priority;
+	u32 cp_hqd_quantum;
+	u32 cp_hqd_pq_base;
+	u32 cp_hqd_pq_base_hi;
+	u32 cp_hqd_pq_rptr;
+	u32 cp_hqd_pq_rptr_report_addr;
+	u32 cp_hqd_pq_rptr_report_addr_hi;
+	u32 cp_hqd_pq_wptr_poll_addr;
+	u32 cp_hqd_pq_wptr_poll_addr_hi;
+	u32 cp_hqd_pq_doorbell_control;
+	u32 cp_hqd_pq_wptr;
+	u32 cp_hqd_pq_control;
+	u32 cp_hqd_ib_base_addr;
+	u32 cp_hqd_ib_base_addr_hi;
+	u32 cp_hqd_ib_rptr;
+	u32 cp_hqd_ib_control;
+	u32 cp_hqd_iq_timer;
+	u32 cp_hqd_iq_rptr;
+	u32 cp_hqd_dequeue_request;
+	u32 cp_hqd_dma_offload;
+	u32 cp_hqd_sema_cmd;
+	u32 cp_hqd_msg_type;
+	u32 cp_hqd_atomic0_preop_lo;
+	u32 cp_hqd_atomic0_preop_hi;
+	u32 cp_hqd_atomic1_preop_lo;
+	u32 cp_hqd_atomic1_preop_hi;
+	u32 cp_hqd_hq_scheduler0;
+	u32 cp_hqd_hq_scheduler1;
+	u32 cp_mqd_control;
+};
+
+struct bonaire_mqd
+{
+	u32 header;
+	u32 dispatch_initiator;
+	u32 dimensions[3];
+	u32 start_idx[3];
+	u32 num_threads[3];
+	u32 pipeline_stat_enable;
+	u32 perf_counter_enable;
+	u32 pgm[2];
+	u32 tba[2];
+	u32 tma[2];
+	u32 pgm_rsrc[2];
+	u32 vmid;
+	u32 resource_limits;
+	u32 static_thread_mgmt01[2];
+	u32 tmp_ring_size;
+	u32 static_thread_mgmt23[2];
+	u32 restart[3];
+	u32 thread_trace_enable;
+	u32 reserved1;
+	u32 user_data[16];
+	u32 vgtcs_invoke_count[2];
+	struct hqd_registers queue_state;
+	u32 dequeue_cntr;
+	u32 interrupt_queue[64];
+};
+
 /**
  * cik_cp_compute_resume - setup the compute queue registers
  *
@@ -2205,24 +2413,247 @@ static void cik_cp_compute_fini(struct radeon_device *rdev)
  */
 static int cik_cp_compute_resume(struct radeon_device *rdev)
 {
-	int r;
+	int r, i, idx;
+	u32 tmp;
+	bool use_doorbell = true;
+	u64 hqd_gpu_addr;
+	u64 mqd_gpu_addr;
+	u64 eop_gpu_addr;
+	u64 wb_gpu_addr;
+	u32 *buf;
+	struct bonaire_mqd *mqd;
 
-	//todo
 	r = cik_cp_compute_start(rdev);
 	if (r)
 		return r;
+
+	/* fix up chicken bits */
+	tmp = RREG32(CP_CPF_DEBUG);
+	tmp |= (1 << 23);
+	WREG32(CP_CPF_DEBUG, tmp);
+
+	/* init the pipes */
+	for (i = 0; i < (rdev->mec.num_pipe * rdev->mec.num_mec); i++) {
+		int me = (i < 4) ? 1 : 2;
+		int pipe = (i < 4) ? i : (i - 4);
+
+		eop_gpu_addr = rdev->mec.hpd_eop_gpu_addr + (i * MEC_HPD_SIZE * 2);
+
+		cik_srbm_select(rdev, me, pipe, 0, 0);
+
+		/* write the EOP addr */
+		WREG32(CP_HPD_EOP_BASE_ADDR, eop_gpu_addr >> 8);
+		WREG32(CP_HPD_EOP_BASE_ADDR_HI, upper_32_bits(eop_gpu_addr) >> 8);
+
+		/* set the VMID assigned */
+		WREG32(CP_HPD_EOP_VMID, 0);
+
+		/* set the EOP size, register value is 2^(EOP_SIZE+1) dwords */
+		tmp = RREG32(CP_HPD_EOP_CONTROL);
+		tmp &= ~EOP_SIZE_MASK;
+		tmp |= drm_order(MEC_HPD_SIZE / 8);
+		WREG32(CP_HPD_EOP_CONTROL, tmp);
+	}
+	cik_srbm_select(rdev, 0, 0, 0, 0);
+
+	/* init the queues.  Just two for now. */
+	for (i = 0; i < 2; i++) {
+		if (i == 0)
+			idx = CAYMAN_RING_TYPE_CP1_INDEX;
+		else
+			idx = CAYMAN_RING_TYPE_CP2_INDEX;
+
+		if (rdev->ring[idx].mqd_obj == NULL) {
+			r = radeon_bo_create(rdev,
+					     sizeof(struct bonaire_mqd),
+					     PAGE_SIZE, true,
+					     RADEON_GEM_DOMAIN_GTT, NULL,
+					     &rdev->ring[idx].mqd_obj);
+			if (r) {
+				dev_warn(rdev->dev, "(%d) create MQD bo failed\n", r);
+				return r;
+			}
+		}
+
+		r = radeon_bo_reserve(rdev->ring[idx].mqd_obj, false);
+		if (unlikely(r != 0)) {
+			cik_cp_compute_fini(rdev);
+			return r;
+		}
+		r = radeon_bo_pin(rdev->ring[idx].mqd_obj, RADEON_GEM_DOMAIN_GTT,
+				  &mqd_gpu_addr);
+		if (r) {
+			dev_warn(rdev->dev, "(%d) pin MQD bo failed\n", r);
+			cik_cp_compute_fini(rdev);
+			return r;
+		}
+		r = radeon_bo_kmap(rdev->ring[idx].mqd_obj, (void **)&buf);
+		if (r) {
+			dev_warn(rdev->dev, "(%d) map MQD bo failed\n", r);
+			cik_cp_compute_fini(rdev);
+			return r;
+		}
+
+		/* doorbell offset */
+		rdev->ring[idx].doorbell_offset =
+			(rdev->ring[idx].doorbell_page_num * PAGE_SIZE) + 0;
+
+		/* init the mqd struct */
+		memset(buf, 0, sizeof(struct bonaire_mqd));
+
+		mqd = (struct bonaire_mqd *)buf;
+		mqd->header = 0xC0310800;
+		mqd->static_thread_mgmt01[0] = 0xffffffff;
+		mqd->static_thread_mgmt01[1] = 0xffffffff;
+		mqd->static_thread_mgmt23[0] = 0xffffffff;
+		mqd->static_thread_mgmt23[1] = 0xffffffff;
+
+		cik_srbm_select(rdev, rdev->ring[idx].me,
+				rdev->ring[idx].pipe,
+				rdev->ring[idx].queue, 0);
+
+		/* disable wptr polling */
+		tmp = RREG32(CP_PQ_WPTR_POLL_CNTL);
+		tmp &= ~WPTR_POLL_EN;
+		WREG32(CP_PQ_WPTR_POLL_CNTL, tmp);
+
+		/* enable doorbell? */
+		mqd->queue_state.cp_hqd_pq_doorbell_control =
+			RREG32(CP_HQD_PQ_DOORBELL_CONTROL);
+		if (use_doorbell)
+			mqd->queue_state.cp_hqd_pq_doorbell_control |= DOORBELL_EN;
+		else
+			mqd->queue_state.cp_hqd_pq_doorbell_control &= ~DOORBELL_EN;
+		WREG32(CP_HQD_PQ_DOORBELL_CONTROL,
+		       mqd->queue_state.cp_hqd_pq_doorbell_control);
+
+		/* disable the queue if it's active */
+		mqd->queue_state.cp_hqd_dequeue_request = 0;
+		mqd->queue_state.cp_hqd_pq_rptr = 0;
+		mqd->queue_state.cp_hqd_pq_wptr= 0;
+		if (RREG32(CP_HQD_ACTIVE) & 1) {
+			WREG32(CP_HQD_DEQUEUE_REQUEST, 1);
+			for (i = 0; i < rdev->usec_timeout; i++) {
+				if (!(RREG32(CP_HQD_ACTIVE) & 1))
+					break;
+				udelay(1);
+			}
+			WREG32(CP_HQD_DEQUEUE_REQUEST, mqd->queue_state.cp_hqd_dequeue_request);
+			WREG32(CP_HQD_PQ_RPTR, mqd->queue_state.cp_hqd_pq_rptr);
+			WREG32(CP_HQD_PQ_WPTR, mqd->queue_state.cp_hqd_pq_wptr);
+		}
+
+		/* set the pointer to the MQD */
+		mqd->queue_state.cp_mqd_base_addr = mqd_gpu_addr & 0xfffffffc;
+		mqd->queue_state.cp_mqd_base_addr_hi = upper_32_bits(mqd_gpu_addr);
+		WREG32(CP_MQD_BASE_ADDR, mqd->queue_state.cp_mqd_base_addr);
+		WREG32(CP_MQD_BASE_ADDR_HI, mqd->queue_state.cp_mqd_base_addr_hi);
+		/* set MQD vmid to 0 */
+		mqd->queue_state.cp_mqd_control = RREG32(CP_MQD_CONTROL);
+		mqd->queue_state.cp_mqd_control &= ~MQD_VMID_MASK;
+		WREG32(CP_MQD_CONTROL, mqd->queue_state.cp_mqd_control);
+
+		/* set the pointer to the HQD, this is similar CP_RB0_BASE/_HI */
+		hqd_gpu_addr = rdev->ring[idx].gpu_addr >> 8;
+		mqd->queue_state.cp_hqd_pq_base = hqd_gpu_addr;
+		mqd->queue_state.cp_hqd_pq_base_hi = upper_32_bits(hqd_gpu_addr);
+		WREG32(CP_HQD_PQ_BASE, mqd->queue_state.cp_hqd_pq_base);
+		WREG32(CP_HQD_PQ_BASE_HI, mqd->queue_state.cp_hqd_pq_base_hi);
+
+		/* set up the HQD, this is similar to CP_RB0_CNTL */
+		mqd->queue_state.cp_hqd_pq_control = RREG32(CP_HQD_PQ_CONTROL);
+		mqd->queue_state.cp_hqd_pq_control &=
+			~(QUEUE_SIZE_MASK | RPTR_BLOCK_SIZE_MASK);
+
+		mqd->queue_state.cp_hqd_pq_control |=
+			drm_order(rdev->ring[idx].ring_size / 8);
+		mqd->queue_state.cp_hqd_pq_control |=
+			(drm_order(RADEON_GPU_PAGE_SIZE/8) << 8);
+#ifdef __BIG_ENDIAN
+		mqd->queue_state.cp_hqd_pq_control |= BUF_SWAP_32BIT;
+#endif
+		mqd->queue_state.cp_hqd_pq_control &=
+			~(UNORD_DISPATCH | ROQ_PQ_IB_FLIP | PQ_VOLATILE);
+		mqd->queue_state.cp_hqd_pq_control |=
+			PRIV_STATE | KMD_QUEUE; /* assuming kernel queue control */
+		WREG32(CP_HQD_PQ_CONTROL, mqd->queue_state.cp_hqd_pq_control);
+
+		/* only used if CP_PQ_WPTR_POLL_CNTL.WPTR_POLL_EN=1 */
+		if (i == 0)
+			wb_gpu_addr = rdev->wb.gpu_addr + CIK_WB_CP1_WPTR_OFFSET;
+		else
+			wb_gpu_addr = rdev->wb.gpu_addr + CIK_WB_CP2_WPTR_OFFSET;
+		mqd->queue_state.cp_hqd_pq_wptr_poll_addr = wb_gpu_addr & 0xfffffffc;
+		mqd->queue_state.cp_hqd_pq_wptr_poll_addr_hi = upper_32_bits(wb_gpu_addr) & 0xffff;
+		WREG32(CP_HQD_PQ_WPTR_POLL_ADDR, mqd->queue_state.cp_hqd_pq_wptr_poll_addr);
+		WREG32(CP_HQD_PQ_WPTR_POLL_ADDR_HI,
+		       mqd->queue_state.cp_hqd_pq_wptr_poll_addr_hi);
+
+		/* set the wb address wether it's enabled or not */
+		if (i == 0)
+			wb_gpu_addr = rdev->wb.gpu_addr + RADEON_WB_CP1_RPTR_OFFSET;
+		else
+			wb_gpu_addr = rdev->wb.gpu_addr + RADEON_WB_CP2_RPTR_OFFSET;
+		mqd->queue_state.cp_hqd_pq_rptr_report_addr = wb_gpu_addr & 0xfffffffc;
+		mqd->queue_state.cp_hqd_pq_rptr_report_addr_hi =
+			upper_32_bits(wb_gpu_addr) & 0xffff;
+		WREG32(CP_HQD_PQ_RPTR_REPORT_ADDR,
+		       mqd->queue_state.cp_hqd_pq_rptr_report_addr);
+		WREG32(CP_HQD_PQ_RPTR_REPORT_ADDR_HI,
+		       mqd->queue_state.cp_hqd_pq_rptr_report_addr_hi);
+
+		/* enable the doorbell if requested */
+		if (use_doorbell) {
+			mqd->queue_state.cp_hqd_pq_doorbell_control =
+				RREG32(CP_HQD_PQ_DOORBELL_CONTROL);
+			mqd->queue_state.cp_hqd_pq_doorbell_control &= ~DOORBELL_OFFSET_MASK;
+			mqd->queue_state.cp_hqd_pq_doorbell_control |=
+				DOORBELL_OFFSET(rdev->ring[idx].doorbell_offset / 4);
+			mqd->queue_state.cp_hqd_pq_doorbell_control |= DOORBELL_EN;
+			mqd->queue_state.cp_hqd_pq_doorbell_control &=
+				~(DOORBELL_SOURCE | DOORBELL_HIT);
+
+		} else {
+			mqd->queue_state.cp_hqd_pq_doorbell_control = 0;
+		}
+		WREG32(CP_HQD_PQ_DOORBELL_CONTROL,
+		       mqd->queue_state.cp_hqd_pq_doorbell_control);
+
+		/* read and write pointers, similar to CP_RB0_WPTR/_RPTR */
+		rdev->ring[idx].wptr = 0;
+		mqd->queue_state.cp_hqd_pq_wptr = rdev->ring[idx].wptr;
+		WREG32(CP_HQD_PQ_WPTR, mqd->queue_state.cp_hqd_pq_wptr);
+		rdev->ring[idx].rptr = RREG32(CP_HQD_PQ_RPTR);
+		mqd->queue_state.cp_hqd_pq_rptr = rdev->ring[idx].rptr;
+
+		/* set the vmid for the queue */
+		mqd->queue_state.cp_hqd_vmid = 0;
+		WREG32(CP_HQD_VMID, mqd->queue_state.cp_hqd_vmid);
+
+		/* activate the queue */
+		mqd->queue_state.cp_hqd_active = 1;
+		WREG32(CP_HQD_ACTIVE, mqd->queue_state.cp_hqd_active);
+
+		cik_srbm_select(rdev, 0, 0, 0, 0);
+
+		radeon_bo_kunmap(rdev->ring[idx].mqd_obj);
+		radeon_bo_unreserve(rdev->ring[idx].mqd_obj);
+
+		rdev->ring[idx].ready = true;
+		r = radeon_ring_test(rdev, idx, &rdev->ring[idx]);
+		if (r)
+			rdev->ring[idx].ready = false;
+	}
+
 	return 0;
 }
 
-/* XXX temporary wrappers to handle both compute and gfx */
-/* XXX */
 static void cik_cp_enable(struct radeon_device *rdev, bool enable)
 {
 	cik_cp_gfx_enable(rdev, enable);
 	cik_cp_compute_enable(rdev, enable);
 }
 
-/* XXX */
 static int cik_cp_load_microcode(struct radeon_device *rdev)
 {
 	int r;
@@ -2237,14 +2668,12 @@ static int cik_cp_load_microcode(struct radeon_device *rdev)
 	return 0;
 }
 
-/* XXX */
 static void cik_cp_fini(struct radeon_device *rdev)
 {
 	cik_cp_gfx_fini(rdev);
 	cik_cp_compute_fini(rdev);
 }
 
-/* XXX */
 static int cik_cp_resume(struct radeon_device *rdev)
 {
 	int r;
@@ -2865,6 +3294,22 @@ static void cik_print_gpu_status_regs(struct radeon_device *rdev)
 		RREG32(SDMA0_STATUS_REG + SDMA0_REGISTER_OFFSET));
 	dev_info(rdev->dev, "  SDMA1_STATUS_REG   = 0x%08X\n",
 		 RREG32(SDMA0_STATUS_REG + SDMA1_REGISTER_OFFSET));
+	dev_info(rdev->dev, "  CP_STAT = 0x%08x\n", RREG32(CP_STAT));
+	dev_info(rdev->dev, "  CP_STALLED_STAT1 = 0x%08x\n",
+		 RREG32(CP_STALLED_STAT1));
+	dev_info(rdev->dev, "  CP_STALLED_STAT2 = 0x%08x\n",
+		 RREG32(CP_STALLED_STAT2));
+	dev_info(rdev->dev, "  CP_STALLED_STAT3 = 0x%08x\n",
+		 RREG32(CP_STALLED_STAT3));
+	dev_info(rdev->dev, "  CP_CPF_BUSY_STAT = 0x%08x\n",
+		 RREG32(CP_CPF_BUSY_STAT));
+	dev_info(rdev->dev, "  CP_CPF_STALLED_STAT1 = 0x%08x\n",
+		 RREG32(CP_CPF_STALLED_STAT1));
+	dev_info(rdev->dev, "  CP_CPF_STATUS = 0x%08x\n", RREG32(CP_CPF_STATUS));
+	dev_info(rdev->dev, "  CP_CPC_BUSY_STAT = 0x%08x\n", RREG32(CP_CPC_BUSY_STAT));
+	dev_info(rdev->dev, "  CP_CPC_STALLED_STAT1 = 0x%08x\n",
+		 RREG32(CP_CPC_STALLED_STAT1));
+	dev_info(rdev->dev, "  CP_CPC_STATUS = 0x%08x\n", RREG32(CP_CPC_STATUS));
 }
 
 /**
@@ -4952,12 +5397,31 @@ static int cik_startup(struct radeon_device *rdev)
 	if (r)
 		return r;
 
+	/* allocate rlc buffers */
+	r = cik_mec_init(rdev);
+	if (r) {
+		DRM_ERROR("Failed to init MEC BOs!\n");
+		return r;
+	}
+
 	r = radeon_fence_driver_start_ring(rdev, RADEON_RING_TYPE_GFX_INDEX);
 	if (r) {
 		dev_err(rdev->dev, "failed initializing CP fences (%d).\n", r);
 		return r;
 	}
 
+	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);
+		return r;
+	}
+
+	r = radeon_fence_driver_start_ring(rdev, CAYMAN_RING_TYPE_CP2_INDEX);
+	if (r) {
+		dev_err(rdev->dev, "failed initializing CP fences (%d).\n", r);
+		return r;
+	}
+
 	r = radeon_fence_driver_start_ring(rdev, R600_RING_TYPE_DMA_INDEX);
 	if (r) {
 		dev_err(rdev->dev, "failed initializing DMA fences (%d).\n", r);
@@ -5002,6 +5466,36 @@ static int cik_startup(struct radeon_device *rdev)
 	if (r)
 		return r;
 
+	/* set up the compute queues */
+	ring = &rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX];
+	r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP1_RPTR_OFFSET,
+			     CP_HQD_PQ_RPTR, CP_HQD_PQ_WPTR,
+			     0, 0xfffff, RADEON_CP_PACKET2);
+	if (r)
+		return r;
+	ring->me = 1; /* first MEC */
+	ring->pipe = 0; /* first pipe */
+	ring->queue = 0; /* first queue */
+	ring->wptr_offs = CIK_WB_CP1_WPTR_OFFSET;
+	ring->funcs.get_rptr = &cik_compute_ring_get_rptr;
+	ring->funcs.get_wptr = &cik_compute_ring_get_wptr;
+	ring->funcs.set_wptr = &cik_compute_ring_set_wptr;
+
+	ring = &rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX];
+	r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP2_RPTR_OFFSET,
+			     CP_HQD_PQ_RPTR, CP_HQD_PQ_WPTR,
+			     0, 0xffffffff, RADEON_CP_PACKET2);
+	if (r)
+		return r;
+	/* dGPU only have 1 MEC */
+	ring->me = 1; /* first MEC */
+	ring->pipe = 0; /* first pipe */
+	ring->queue = 1; /* second queue */
+	ring->wptr_offs = CIK_WB_CP2_WPTR_OFFSET;
+	ring->funcs.get_rptr = &cik_compute_ring_get_rptr;
+	ring->funcs.get_wptr = &cik_compute_ring_get_wptr;
+	ring->funcs.set_wptr = &cik_compute_ring_set_wptr;
+
 	ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX];
 	r = radeon_ring_init(rdev, ring, ring->ring_size, R600_WB_DMA_RPTR_OFFSET,
 			     SDMA0_GFX_RB_RPTR + SDMA0_REGISTER_OFFSET,
@@ -5176,6 +5670,20 @@ int cik_init(struct radeon_device *rdev)
 	ring->ring_obj = NULL;
 	r600_ring_init(rdev, ring, 1024 * 1024);
 
+	ring = &rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX];
+	ring->ring_obj = NULL;
+	r600_ring_init(rdev, ring, 1024 * 1024);
+	r = radeon_doorbell_get(rdev, &ring->doorbell_page_num);
+	if (r)
+		return r;
+
+	ring = &rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX];
+	ring->ring_obj = NULL;
+	r600_ring_init(rdev, ring, 1024 * 1024);
+	r = radeon_doorbell_get(rdev, &ring->doorbell_page_num);
+	if (r)
+		return r;
+
 	ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX];
 	ring->ring_obj = NULL;
 	r600_ring_init(rdev, ring, 256 * 1024);
@@ -5206,6 +5714,7 @@ int cik_init(struct radeon_device *rdev)
 		cik_sdma_fini(rdev);
 		cik_irq_fini(rdev);
 		si_rlc_fini(rdev);
+		cik_mec_fini(rdev);
 		radeon_wb_fini(rdev);
 		radeon_ib_pool_fini(rdev);
 		radeon_vm_manager_fini(rdev);
@@ -5241,6 +5750,7 @@ void cik_fini(struct radeon_device *rdev)
 	cik_sdma_fini(rdev);
 	cik_irq_fini(rdev);
 	si_rlc_fini(rdev);
+	cik_mec_fini(rdev);
 	radeon_wb_fini(rdev);
 	radeon_vm_manager_fini(rdev);
 	radeon_ib_pool_fini(rdev);
diff --git a/drivers/gpu/drm/radeon/cikd.h b/drivers/gpu/drm/radeon/cikd.h
index 79be39e..63514b9 100644
--- a/drivers/gpu/drm/radeon/cikd.h
+++ b/drivers/gpu/drm/radeon/cikd.h
@@ -460,6 +460,13 @@
 #       define RDERR_INT_ENABLE                         (1 << 0)
 #       define GUI_IDLE_INT_ENABLE                      (1 << 19)
 
+#define CP_CPC_STATUS					0x8210
+#define CP_CPC_BUSY_STAT				0x8214
+#define CP_CPC_STALLED_STAT1				0x8218
+#define CP_CPF_STATUS					0x821c
+#define CP_CPF_BUSY_STAT				0x8220
+#define CP_CPF_STALLED_STAT1				0x8224
+
 #define CP_MEC_CNTL					0x8234
 #define		MEC_ME2_HALT					(1 << 28)
 #define		MEC_ME1_HALT					(1 << 30)
@@ -468,6 +475,12 @@
 #define		MEC_ME2_HALT					(1 << 28)
 #define		MEC_ME1_HALT					(1 << 30)
 
+#define CP_STALLED_STAT3				0x8670
+#define CP_STALLED_STAT1				0x8674
+#define CP_STALLED_STAT2				0x8678
+
+#define CP_STAT						0x8680
+
 #define CP_ME_CNTL					0x86D8
 #define		CP_CE_HALT					(1 << 24)
 #define		CP_PFP_HALT					(1 << 26)
@@ -701,6 +714,11 @@
 #       define CP_RINGID1_INT_STAT                      (1 << 30)
 #       define CP_RINGID0_INT_STAT                      (1 << 31)
 
+#define CP_CPF_DEBUG                                    0xC200
+
+#define CP_PQ_WPTR_POLL_CNTL                            0xC20C
+#define		WPTR_POLL_EN      			(1 << 31)
+
 #define CP_ME1_PIPE0_INT_CNTL                           0xC214
 #define CP_ME1_PIPE1_INT_CNTL                           0xC218
 #define CP_ME1_PIPE2_INT_CNTL                           0xC21C
@@ -773,6 +791,50 @@
 #define RLC_GPM_SCRATCH_ADDR                              0xC4B0
 #define RLC_GPM_SCRATCH_DATA                              0xC4B4
 
+#define CP_HPD_EOP_BASE_ADDR                              0xC904
+#define CP_HPD_EOP_BASE_ADDR_HI                           0xC908
+#define CP_HPD_EOP_VMID                                   0xC90C
+#define CP_HPD_EOP_CONTROL                                0xC910
+#define		EOP_SIZE(x)				((x) << 0)
+#define		EOP_SIZE_MASK      			(0x3f << 0)
+#define CP_MQD_BASE_ADDR                                  0xC914
+#define CP_MQD_BASE_ADDR_HI                               0xC918
+#define CP_HQD_ACTIVE                                     0xC91C
+#define CP_HQD_VMID                                       0xC920
+
+#define CP_HQD_PQ_BASE                                    0xC934
+#define CP_HQD_PQ_BASE_HI                                 0xC938
+#define CP_HQD_PQ_RPTR                                    0xC93C
+#define CP_HQD_PQ_RPTR_REPORT_ADDR                        0xC940
+#define CP_HQD_PQ_RPTR_REPORT_ADDR_HI                     0xC944
+#define CP_HQD_PQ_WPTR_POLL_ADDR                          0xC948
+#define CP_HQD_PQ_WPTR_POLL_ADDR_HI                       0xC94C
+#define CP_HQD_PQ_DOORBELL_CONTROL                        0xC950
+#define		DOORBELL_OFFSET(x)			((x) << 2)
+#define		DOORBELL_OFFSET_MASK			(0x1fffff << 2)
+#define		DOORBELL_SOURCE      			(1 << 28)
+#define		DOORBELL_SCHD_HIT      			(1 << 29)
+#define		DOORBELL_EN      			(1 << 30)
+#define		DOORBELL_HIT      			(1 << 31)
+#define CP_HQD_PQ_WPTR                                    0xC954
+#define CP_HQD_PQ_CONTROL                                 0xC958
+#define		QUEUE_SIZE(x)				((x) << 0)
+#define		QUEUE_SIZE_MASK      			(0x3f << 0)
+#define		RPTR_BLOCK_SIZE(x)			((x) << 8)
+#define		RPTR_BLOCK_SIZE_MASK			(0x3f << 8)
+#define		PQ_VOLATILE      			(1 << 26)
+#define		NO_UPDATE_RPTR      			(1 << 27)
+#define		UNORD_DISPATCH      			(1 << 28)
+#define		ROQ_PQ_IB_FLIP      			(1 << 29)
+#define		PRIV_STATE      			(1 << 30)
+#define		KMD_QUEUE      				(1 << 31)
+
+#define CP_HQD_DEQUEUE_REQUEST                          0xC974
+
+#define CP_MQD_CONTROL                                  0xC99C
+#define		MQD_VMID(x)				((x) << 0)
+#define		MQD_VMID_MASK      			(0xf << 0)
+
 #define PA_SC_RASTER_CONFIG                             0x28350
 #       define RASTER_CONFIG_RB_MAP_0                   0
 #       define RASTER_CONFIG_RB_MAP_1                   1
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index a2a3430..d40d506 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -714,6 +714,22 @@ struct radeon_ring {
 		u32			(*get_wptr)(struct radeon_device *rdev, struct radeon_ring *ring);
 		void			(*set_wptr)(struct radeon_device *rdev, struct radeon_ring *ring);
 	} funcs;
+	/* for CIK queues */
+	u32 me;
+	u32 pipe;
+	u32 queue;
+	struct radeon_bo	*mqd_obj;
+	u32 doorbell_page_num;
+	u32 doorbell_offset;
+	unsigned		wptr_offs;
+};
+
+struct radeon_mec {
+	struct radeon_bo	*hpd_eop_obj;
+	u64			hpd_eop_gpu_addr;
+	u32 num_pipe;
+	u32 num_mec;
+	u32 num_queue;
 };
 
 /*
@@ -971,6 +987,8 @@ struct radeon_wb {
 #define CAYMAN_WB_DMA1_RPTR_OFFSET   2304
 #define R600_WB_UVD_RPTR_OFFSET  2560
 #define R600_WB_EVENT_OFFSET     3072
+#define CIK_WB_CP1_WPTR_OFFSET     3328
+#define CIK_WB_CP2_WPTR_OFFSET     3584
 
 /**
  * struct radeon_pm - power management datas
@@ -1760,6 +1778,7 @@ struct radeon_device {
 	int msi_enabled; /* msi enabled */
 	struct r600_ih ih; /* r6/700 interrupt ring */
 	struct si_rlc rlc;
+	struct radeon_mec mec;
 	struct work_struct hotplug_work;
 	struct work_struct audio_work;
 	struct work_struct reset_work;
diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c
index cf71734..7e265a5 100644
--- a/drivers/gpu/drm/radeon/radeon_cs.c
+++ b/drivers/gpu/drm/radeon/radeon_cs.c
@@ -121,9 +121,7 @@ static int radeon_cs_get_ring(struct radeon_cs_parser *p, u32 ring, s32 priority
 		p->ring = RADEON_RING_TYPE_GFX_INDEX;
 		break;
 	case RADEON_CS_RING_COMPUTE:
-		if (p->rdev->family >= CHIP_BONAIRE)
-			p->ring = RADEON_RING_TYPE_GFX_INDEX;
-		else if (p->rdev->family >= CHIP_TAHITI) {
+		if (p->rdev->family >= CHIP_TAHITI) {
 			if (p->priority > 0)
 				p->ring = CAYMAN_RING_TYPE_CP1_INDEX;
 			else
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 053/165] drm/radeon/cik: switch to type3 nop packet for compute rings
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (52 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 052/165] drm/radeon/cik: Add support for compute queues (v2) alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 10:10   ` Jerome Glisse
  2013-06-26 13:22 ` [PATCH 054/165] drm/radeon: fix up ring functions " alexdeucher
                   ` (59 subsequent siblings)
  113 siblings, 1 reply; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Type 2 packets are deprecated on CIK MEC and we should use
type 3 nop packets.  Setting the count field to the max value
(0x3fff) indicates that only one dword should be skipped
like a type 2 packet.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/cik.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
index 9d2d6bb..08dc4c2 100644
--- a/drivers/gpu/drm/radeon/cik.c
+++ b/drivers/gpu/drm/radeon/cik.c
@@ -5470,7 +5470,7 @@ static int cik_startup(struct radeon_device *rdev)
 	ring = &rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX];
 	r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP1_RPTR_OFFSET,
 			     CP_HQD_PQ_RPTR, CP_HQD_PQ_WPTR,
-			     0, 0xfffff, RADEON_CP_PACKET2);
+			     0, 0xfffff, PACKET3(PACKET3_NOP, 0x3FFF));
 	if (r)
 		return r;
 	ring->me = 1; /* first MEC */
@@ -5484,7 +5484,7 @@ static int cik_startup(struct radeon_device *rdev)
 	ring = &rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX];
 	r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP2_RPTR_OFFSET,
 			     CP_HQD_PQ_RPTR, CP_HQD_PQ_WPTR,
-			     0, 0xffffffff, RADEON_CP_PACKET2);
+			     0, 0xffffffff, PACKET3(PACKET3_NOP, 0x3FFF));
 	if (r)
 		return r;
 	/* dGPU only have 1 MEC */
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 054/165] drm/radeon: fix up ring functions for compute rings
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (53 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 053/165] drm/radeon/cik: switch to type3 nop packet for compute rings alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 055/165] drm/radeon/cik: add support for compute interrupts alexdeucher
                   ` (58 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

The compute rings use RELEASE_MEM rather then EOP
packets for writing fences and there is no SYNC_PFP_ME
packet on the compute rings.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/cik.c |   53 +++++++++++++++++++++++++++++++++++++----
 1 files changed, 47 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
index 08dc4c2..596bfed 100644
--- a/drivers/gpu/drm/radeon/cik.c
+++ b/drivers/gpu/drm/radeon/cik.c
@@ -1706,7 +1706,7 @@ int cik_ring_test(struct radeon_device *rdev, struct radeon_ring *ring)
 }
 
 /**
- * cik_fence_ring_emit - emit a fence on the gfx ring
+ * cik_fence_gfx_ring_emit - emit a fence on the gfx ring
  *
  * @rdev: radeon_device pointer
  * @fence: radeon fence object
@@ -1714,8 +1714,8 @@ int cik_ring_test(struct radeon_device *rdev, struct radeon_ring *ring)
  * Emits a fence sequnce number on the gfx ring and flushes
  * GPU caches.
  */
-void cik_fence_ring_emit(struct radeon_device *rdev,
-			 struct radeon_fence *fence)
+void cik_fence_gfx_ring_emit(struct radeon_device *rdev,
+			     struct radeon_fence *fence)
 {
 	struct radeon_ring *ring = &rdev->ring[fence->ring];
 	u64 addr = rdev->fence_drv[fence->ring].gpu_addr;
@@ -1742,6 +1742,44 @@ void cik_fence_ring_emit(struct radeon_device *rdev,
 	radeon_ring_write(ring, 0);
 }
 
+/**
+ * cik_fence_compute_ring_emit - emit a fence on the compute ring
+ *
+ * @rdev: radeon_device pointer
+ * @fence: radeon fence object
+ *
+ * Emits a fence sequnce number on the compute ring and flushes
+ * GPU caches.
+ */
+void cik_fence_compute_ring_emit(struct radeon_device *rdev,
+				 struct radeon_fence *fence)
+{
+	struct radeon_ring *ring = &rdev->ring[fence->ring];
+	u64 addr = rdev->fence_drv[fence->ring].gpu_addr;
+
+	/* RELEASE_MEM - flush caches, send int */
+	radeon_ring_write(ring, PACKET3(PACKET3_RELEASE_MEM, 5));
+	radeon_ring_write(ring, (EOP_TCL1_ACTION_EN |
+				 EOP_TC_ACTION_EN |
+				 EVENT_TYPE(CACHE_FLUSH_AND_INV_TS_EVENT) |
+				 EVENT_INDEX(5)));
+	radeon_ring_write(ring, DATA_SEL(1) | INT_SEL(2));
+	radeon_ring_write(ring, addr & 0xfffffffc);
+	radeon_ring_write(ring, upper_32_bits(addr));
+	radeon_ring_write(ring, fence->seq);
+	radeon_ring_write(ring, 0);
+	/* HDP flush */
+	/* We should be using the new WAIT_REG_MEM special op packet here
+	 * but it causes the CP to hang
+	 */
+	radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
+	radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
+				 WRITE_DATA_DST_SEL(0)));
+	radeon_ring_write(ring, HDP_MEM_COHERENCY_FLUSH_CNTL >> 2);
+	radeon_ring_write(ring, 0);
+	radeon_ring_write(ring, 0);
+}
+
 void cik_semaphore_ring_emit(struct radeon_device *rdev,
 			     struct radeon_ring *ring,
 			     struct radeon_semaphore *semaphore,
@@ -4051,9 +4089,12 @@ void cik_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
 	radeon_ring_write(ring, 0);
 	radeon_ring_write(ring, 1 << vm->id);
 
-	/* sync PFP to ME, otherwise we might get invalid PFP reads */
-	radeon_ring_write(ring, PACKET3(PACKET3_PFP_SYNC_ME, 0));
-	radeon_ring_write(ring, 0x0);
+	/* compute doesn't have PFP */
+	if (ridx == RADEON_RING_TYPE_GFX_INDEX) {
+		/* sync PFP to ME, otherwise we might get invalid PFP reads */
+		radeon_ring_write(ring, PACKET3(PACKET3_PFP_SYNC_ME, 0));
+		radeon_ring_write(ring, 0x0);
+	}
 }
 
 /**
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 055/165] drm/radeon/cik: add support for compute interrupts
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (54 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 054/165] drm/radeon: fix up ring functions " alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 056/165] drm/radeon/cik: add support for golden register init alexdeucher
                   ` (57 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/cik.c |  121 ++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 116 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
index 596bfed..5923ef7 100644
--- a/drivers/gpu/drm/radeon/cik.c
+++ b/drivers/gpu/drm/radeon/cik.c
@@ -4631,6 +4631,8 @@ int cik_irq_set(struct radeon_device *rdev)
 {
 	u32 cp_int_cntl = CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE |
 		PRIV_INSTR_INT_ENABLE | PRIV_REG_INT_ENABLE;
+	u32 cp_m1p0, cp_m1p1, cp_m1p2, cp_m1p3;
+	u32 cp_m2p0, cp_m2p1, cp_m2p2, cp_m2p3;
 	u32 crtc1 = 0, crtc2 = 0, crtc3 = 0, crtc4 = 0, crtc5 = 0, crtc6 = 0;
 	u32 hpd1, hpd2, hpd3, hpd4, hpd5, hpd6;
 	u32 grbm_int_cntl = 0;
@@ -4658,13 +4660,106 @@ int cik_irq_set(struct radeon_device *rdev)
 	dma_cntl = RREG32(SDMA0_CNTL + SDMA0_REGISTER_OFFSET) & ~TRAP_ENABLE;
 	dma_cntl1 = RREG32(SDMA0_CNTL + SDMA1_REGISTER_OFFSET) & ~TRAP_ENABLE;
 
+	cp_m1p0 = RREG32(CP_ME1_PIPE0_INT_CNTL) & ~TIME_STAMP_INT_ENABLE;
+	cp_m1p1 = RREG32(CP_ME1_PIPE1_INT_CNTL) & ~TIME_STAMP_INT_ENABLE;
+	cp_m1p2 = RREG32(CP_ME1_PIPE2_INT_CNTL) & ~TIME_STAMP_INT_ENABLE;
+	cp_m1p3 = RREG32(CP_ME1_PIPE3_INT_CNTL) & ~TIME_STAMP_INT_ENABLE;
+	cp_m2p0 = RREG32(CP_ME2_PIPE0_INT_CNTL) & ~TIME_STAMP_INT_ENABLE;
+	cp_m2p1 = RREG32(CP_ME2_PIPE1_INT_CNTL) & ~TIME_STAMP_INT_ENABLE;
+	cp_m2p2 = RREG32(CP_ME2_PIPE2_INT_CNTL) & ~TIME_STAMP_INT_ENABLE;
+	cp_m2p3 = RREG32(CP_ME2_PIPE3_INT_CNTL) & ~TIME_STAMP_INT_ENABLE;
+
 	/* enable CP interrupts on all rings */
 	if (atomic_read(&rdev->irq.ring_int[RADEON_RING_TYPE_GFX_INDEX])) {
 		DRM_DEBUG("cik_irq_set: sw int gfx\n");
 		cp_int_cntl |= TIME_STAMP_INT_ENABLE;
 	}
-	/* TODO: compute queues! */
-	/* CP_ME[1-2]_PIPE[0-3]_INT_CNTL */
+	if (atomic_read(&rdev->irq.ring_int[CAYMAN_RING_TYPE_CP1_INDEX])) {
+		struct radeon_ring *ring = &rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX];
+		DRM_DEBUG("si_irq_set: sw int cp1\n");
+		if (ring->me == 1) {
+			switch (ring->pipe) {
+			case 0:
+				cp_m1p0 |= TIME_STAMP_INT_ENABLE;
+				break;
+			case 1:
+				cp_m1p1 |= TIME_STAMP_INT_ENABLE;
+				break;
+			case 2:
+				cp_m1p2 |= TIME_STAMP_INT_ENABLE;
+				break;
+			case 3:
+				cp_m1p2 |= TIME_STAMP_INT_ENABLE;
+				break;
+			default:
+				DRM_DEBUG("si_irq_set: sw int cp1 invalid pipe %d\n", ring->pipe);
+				break;
+			}
+		} else if (ring->me == 2) {
+			switch (ring->pipe) {
+			case 0:
+				cp_m2p0 |= TIME_STAMP_INT_ENABLE;
+				break;
+			case 1:
+				cp_m2p1 |= TIME_STAMP_INT_ENABLE;
+				break;
+			case 2:
+				cp_m2p2 |= TIME_STAMP_INT_ENABLE;
+				break;
+			case 3:
+				cp_m2p2 |= TIME_STAMP_INT_ENABLE;
+				break;
+			default:
+				DRM_DEBUG("si_irq_set: sw int cp1 invalid pipe %d\n", ring->pipe);
+				break;
+			}
+		} else {
+			DRM_DEBUG("si_irq_set: sw int cp1 invalid me %d\n", ring->me);
+		}
+	}
+	if (atomic_read(&rdev->irq.ring_int[CAYMAN_RING_TYPE_CP2_INDEX])) {
+		struct radeon_ring *ring = &rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX];
+		DRM_DEBUG("si_irq_set: sw int cp2\n");
+		if (ring->me == 1) {
+			switch (ring->pipe) {
+			case 0:
+				cp_m1p0 |= TIME_STAMP_INT_ENABLE;
+				break;
+			case 1:
+				cp_m1p1 |= TIME_STAMP_INT_ENABLE;
+				break;
+			case 2:
+				cp_m1p2 |= TIME_STAMP_INT_ENABLE;
+				break;
+			case 3:
+				cp_m1p2 |= TIME_STAMP_INT_ENABLE;
+				break;
+			default:
+				DRM_DEBUG("si_irq_set: sw int cp2 invalid pipe %d\n", ring->pipe);
+				break;
+			}
+		} else if (ring->me == 2) {
+			switch (ring->pipe) {
+			case 0:
+				cp_m2p0 |= TIME_STAMP_INT_ENABLE;
+				break;
+			case 1:
+				cp_m2p1 |= TIME_STAMP_INT_ENABLE;
+				break;
+			case 2:
+				cp_m2p2 |= TIME_STAMP_INT_ENABLE;
+				break;
+			case 3:
+				cp_m2p2 |= TIME_STAMP_INT_ENABLE;
+				break;
+			default:
+				DRM_DEBUG("si_irq_set: sw int cp2 invalid pipe %d\n", ring->pipe);
+				break;
+			}
+		} else {
+			DRM_DEBUG("si_irq_set: sw int cp2 invalid me %d\n", ring->me);
+		}
+	}
 
 	if (atomic_read(&rdev->irq.ring_int[R600_RING_TYPE_DMA_INDEX])) {
 		DRM_DEBUG("cik_irq_set: sw int dma\n");
@@ -4736,6 +4831,15 @@ int cik_irq_set(struct radeon_device *rdev)
 	WREG32(SDMA0_CNTL + SDMA0_REGISTER_OFFSET, dma_cntl);
 	WREG32(SDMA0_CNTL + SDMA1_REGISTER_OFFSET, dma_cntl1);
 
+	WREG32(CP_ME1_PIPE0_INT_CNTL, cp_m1p0);
+	WREG32(CP_ME1_PIPE1_INT_CNTL, cp_m1p1);
+	WREG32(CP_ME1_PIPE2_INT_CNTL, cp_m1p2);
+	WREG32(CP_ME1_PIPE3_INT_CNTL, cp_m1p3);
+	WREG32(CP_ME2_PIPE0_INT_CNTL, cp_m2p0);
+	WREG32(CP_ME2_PIPE1_INT_CNTL, cp_m2p1);
+	WREG32(CP_ME2_PIPE2_INT_CNTL, cp_m2p2);
+	WREG32(CP_ME2_PIPE3_INT_CNTL, cp_m2p3);
+
 	WREG32(GRBM_INT_CNTL, grbm_int_cntl);
 
 	WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, crtc1);
@@ -4957,6 +5061,8 @@ static inline u32 cik_get_ih_wptr(struct radeon_device *rdev)
  */
 int cik_irq_process(struct radeon_device *rdev)
 {
+	struct radeon_ring *cp1_ring = &rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX];
+	struct radeon_ring *cp2_ring = &rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX];
 	u32 wptr;
 	u32 rptr;
 	u32 src_id, src_data, ring_id;
@@ -5222,10 +5328,11 @@ restart_ih:
 				radeon_fence_process(rdev, RADEON_RING_TYPE_GFX_INDEX);
 				break;
 			case 1:
-				/* XXX compute */
-				break;
 			case 2:
-				/* XXX compute */
+				if ((cp1_ring->me == me_id) & (cp1_ring->pipe == pipe_id))
+					radeon_fence_process(rdev, CAYMAN_RING_TYPE_CP1_INDEX);
+				if ((cp2_ring->me == me_id) & (cp2_ring->pipe == pipe_id))
+					radeon_fence_process(rdev, CAYMAN_RING_TYPE_CP2_INDEX);
 				break;
 			}
 			break;
@@ -5244,9 +5351,11 @@ restart_ih:
 				break;
 			case 1:
 				/* XXX compute */
+				queue_reset = true;
 				break;
 			case 2:
 				/* XXX compute */
+				queue_reset = true;
 				break;
 			}
 			break;
@@ -5265,9 +5374,11 @@ restart_ih:
 				break;
 			case 1:
 				/* XXX compute */
+				queue_reset = true;
 				break;
 			case 2:
 				/* XXX compute */
+				queue_reset = true;
 				break;
 			}
 			break;
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 056/165] drm/radeon/cik: add support for golden register init
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (55 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 055/165] drm/radeon/cik: add support for compute interrupts alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 057/165] drm/radeon: add radeon_asic struct for CIK (v11) alexdeucher
                   ` (56 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/cik.c |  438 ++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 438 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
index 5923ef7..e899c44 100644
--- a/drivers/gpu/drm/radeon/cik.c
+++ b/drivers/gpu/drm/radeon/cik.c
@@ -99,6 +99,439 @@ void cik_pciep_wreg(struct radeon_device *rdev, u32 reg, u32 v)
 	(void)RREG32(PCIE_DATA);
 }
 
+static const u32 bonaire_golden_spm_registers[] =
+{
+	0x30800, 0xe0ffffff, 0xe0000000
+};
+
+static const u32 bonaire_golden_common_registers[] =
+{
+	0xc770, 0xffffffff, 0x00000800,
+	0xc774, 0xffffffff, 0x00000800,
+	0xc798, 0xffffffff, 0x00007fbf,
+	0xc79c, 0xffffffff, 0x00007faf
+};
+
+static const u32 bonaire_golden_registers[] =
+{
+	0x3354, 0x00000333, 0x00000333,
+	0x3350, 0x000c0fc0, 0x00040200,
+	0x9a10, 0x00010000, 0x00058208,
+	0x3c000, 0xffff1fff, 0x00140000,
+	0x3c200, 0xfdfc0fff, 0x00000100,
+	0x3c234, 0x40000000, 0x40000200,
+	0x9830, 0xffffffff, 0x00000000,
+	0x9834, 0xf00fffff, 0x00000400,
+	0x9838, 0x0002021c, 0x00020200,
+	0xc78, 0x00000080, 0x00000000,
+	0x5bb0, 0x000000f0, 0x00000070,
+	0x5bc0, 0xf0311fff, 0x80300000,
+	0x98f8, 0x73773777, 0x12010001,
+	0x350c, 0x00810000, 0x408af000,
+	0x7030, 0x31000111, 0x00000011,
+	0x2f48, 0x73773777, 0x12010001,
+	0x220c, 0x00007fb6, 0x0021a1b1,
+	0x2210, 0x00007fb6, 0x002021b1,
+	0x2180, 0x00007fb6, 0x00002191,
+	0x2218, 0x00007fb6, 0x002121b1,
+	0x221c, 0x00007fb6, 0x002021b1,
+	0x21dc, 0x00007fb6, 0x00002191,
+	0x21e0, 0x00007fb6, 0x00002191,
+	0x3628, 0x0000003f, 0x0000000a,
+	0x362c, 0x0000003f, 0x0000000a,
+	0x2ae4, 0x00073ffe, 0x000022a2,
+	0x240c, 0x000007ff, 0x00000000,
+	0x8a14, 0xf000003f, 0x00000007,
+	0x8bf0, 0x00002001, 0x00000001,
+	0x8b24, 0xffffffff, 0x00ffffff,
+	0x30a04, 0x0000ff0f, 0x00000000,
+	0x28a4c, 0x07ffffff, 0x06000000,
+	0x4d8, 0x00000fff, 0x00000100,
+	0x3e78, 0x00000001, 0x00000002,
+	0x9100, 0x03000000, 0x0362c688,
+	0x8c00, 0x000000ff, 0x00000001,
+	0xe40, 0x00001fff, 0x00001fff,
+	0x9060, 0x0000007f, 0x00000020,
+	0x9508, 0x00010000, 0x00010000,
+	0xac14, 0x000003ff, 0x000000f3,
+	0xac0c, 0xffffffff, 0x00001032
+};
+
+static const u32 bonaire_mgcg_cgcg_init[] =
+{
+	0xc420, 0xffffffff, 0xfffffffc,
+	0x30800, 0xffffffff, 0xe0000000,
+	0x3c2a0, 0xffffffff, 0x00000100,
+	0x3c208, 0xffffffff, 0x00000100,
+	0x3c2c0, 0xffffffff, 0xc0000100,
+	0x3c2c8, 0xffffffff, 0xc0000100,
+	0x3c2c4, 0xffffffff, 0xc0000100,
+	0x55e4, 0xffffffff, 0x00600100,
+	0x3c280, 0xffffffff, 0x00000100,
+	0x3c214, 0xffffffff, 0x06000100,
+	0x3c220, 0xffffffff, 0x00000100,
+	0x3c218, 0xffffffff, 0x06000100,
+	0x3c204, 0xffffffff, 0x00000100,
+	0x3c2e0, 0xffffffff, 0x00000100,
+	0x3c224, 0xffffffff, 0x00000100,
+	0x3c200, 0xffffffff, 0x00000100,
+	0x3c230, 0xffffffff, 0x00000100,
+	0x3c234, 0xffffffff, 0x00000100,
+	0x3c250, 0xffffffff, 0x00000100,
+	0x3c254, 0xffffffff, 0x00000100,
+	0x3c258, 0xffffffff, 0x00000100,
+	0x3c25c, 0xffffffff, 0x00000100,
+	0x3c260, 0xffffffff, 0x00000100,
+	0x3c27c, 0xffffffff, 0x00000100,
+	0x3c278, 0xffffffff, 0x00000100,
+	0x3c210, 0xffffffff, 0x06000100,
+	0x3c290, 0xffffffff, 0x00000100,
+	0x3c274, 0xffffffff, 0x00000100,
+	0x3c2b4, 0xffffffff, 0x00000100,
+	0x3c2b0, 0xffffffff, 0x00000100,
+	0x3c270, 0xffffffff, 0x00000100,
+	0x30800, 0xffffffff, 0xe0000000,
+	0x3c020, 0xffffffff, 0x00010000,
+	0x3c024, 0xffffffff, 0x00030002,
+	0x3c028, 0xffffffff, 0x00040007,
+	0x3c02c, 0xffffffff, 0x00060005,
+	0x3c030, 0xffffffff, 0x00090008,
+	0x3c034, 0xffffffff, 0x00010000,
+	0x3c038, 0xffffffff, 0x00030002,
+	0x3c03c, 0xffffffff, 0x00040007,
+	0x3c040, 0xffffffff, 0x00060005,
+	0x3c044, 0xffffffff, 0x00090008,
+	0x3c048, 0xffffffff, 0x00010000,
+	0x3c04c, 0xffffffff, 0x00030002,
+	0x3c050, 0xffffffff, 0x00040007,
+	0x3c054, 0xffffffff, 0x00060005,
+	0x3c058, 0xffffffff, 0x00090008,
+	0x3c05c, 0xffffffff, 0x00010000,
+	0x3c060, 0xffffffff, 0x00030002,
+	0x3c064, 0xffffffff, 0x00040007,
+	0x3c068, 0xffffffff, 0x00060005,
+	0x3c06c, 0xffffffff, 0x00090008,
+	0x3c070, 0xffffffff, 0x00010000,
+	0x3c074, 0xffffffff, 0x00030002,
+	0x3c078, 0xffffffff, 0x00040007,
+	0x3c07c, 0xffffffff, 0x00060005,
+	0x3c080, 0xffffffff, 0x00090008,
+	0x3c084, 0xffffffff, 0x00010000,
+	0x3c088, 0xffffffff, 0x00030002,
+	0x3c08c, 0xffffffff, 0x00040007,
+	0x3c090, 0xffffffff, 0x00060005,
+	0x3c094, 0xffffffff, 0x00090008,
+	0x3c098, 0xffffffff, 0x00010000,
+	0x3c09c, 0xffffffff, 0x00030002,
+	0x3c0a0, 0xffffffff, 0x00040007,
+	0x3c0a4, 0xffffffff, 0x00060005,
+	0x3c0a8, 0xffffffff, 0x00090008,
+	0x3c000, 0xffffffff, 0x96e00200,
+	0x8708, 0xffffffff, 0x00900100,
+	0xc424, 0xffffffff, 0x0020003f,
+	0x38, 0xffffffff, 0x0140001c,
+	0x3c, 0x000f0000, 0x000f0000,
+	0x220, 0xffffffff, 0xC060000C,
+	0x224, 0xc0000fff, 0x00000100,
+	0xf90, 0xffffffff, 0x00000100,
+	0xf98, 0x00000101, 0x00000000,
+	0x20a8, 0xffffffff, 0x00000104,
+	0x55e4, 0xff000fff, 0x00000100,
+	0x30cc, 0xc0000fff, 0x00000104,
+	0xc1e4, 0x00000001, 0x00000001,
+	0xd00c, 0xff000ff0, 0x00000100,
+	0xd80c, 0xff000ff0, 0x00000100
+};
+
+static const u32 spectre_golden_spm_registers[] =
+{
+	0x30800, 0xe0ffffff, 0xe0000000
+};
+
+static const u32 spectre_golden_common_registers[] =
+{
+	0xc770, 0xffffffff, 0x00000800,
+	0xc774, 0xffffffff, 0x00000800,
+	0xc798, 0xffffffff, 0x00007fbf,
+	0xc79c, 0xffffffff, 0x00007faf
+};
+
+static const u32 spectre_golden_registers[] =
+{
+	0x3c000, 0xffff1fff, 0x96940200,
+	0x3c00c, 0xffff0001, 0xff000000,
+	0x3c200, 0xfffc0fff, 0x00000100,
+	0x6ed8, 0x00010101, 0x00010000,
+	0x9834, 0xf00fffff, 0x00000400,
+	0x9838, 0xfffffffc, 0x00020200,
+	0x5bb0, 0x000000f0, 0x00000070,
+	0x5bc0, 0xf0311fff, 0x80300000,
+	0x98f8, 0x73773777, 0x12010001,
+	0x9b7c, 0x00ff0000, 0x00fc0000,
+	0x2f48, 0x73773777, 0x12010001,
+	0x8a14, 0xf000003f, 0x00000007,
+	0x8b24, 0xffffffff, 0x00ffffff,
+	0x28350, 0x3f3f3fff, 0x00000082,
+	0x28355, 0x0000003f, 0x00000000,
+	0x3e78, 0x00000001, 0x00000002,
+	0x913c, 0xffff03df, 0x00000004,
+	0xc768, 0x00000008, 0x00000008,
+	0x8c00, 0x000008ff, 0x00000800,
+	0x9508, 0x00010000, 0x00010000,
+	0xac0c, 0xffffffff, 0x54763210,
+	0x214f8, 0x01ff01ff, 0x00000002,
+	0x21498, 0x007ff800, 0x00200000,
+	0x2015c, 0xffffffff, 0x00000f40,
+	0x30934, 0xffffffff, 0x00000001
+};
+
+static const u32 spectre_mgcg_cgcg_init[] =
+{
+	0xc420, 0xffffffff, 0xfffffffc,
+	0x30800, 0xffffffff, 0xe0000000,
+	0x3c2a0, 0xffffffff, 0x00000100,
+	0x3c208, 0xffffffff, 0x00000100,
+	0x3c2c0, 0xffffffff, 0x00000100,
+	0x3c2c8, 0xffffffff, 0x00000100,
+	0x3c2c4, 0xffffffff, 0x00000100,
+	0x55e4, 0xffffffff, 0x00600100,
+	0x3c280, 0xffffffff, 0x00000100,
+	0x3c214, 0xffffffff, 0x06000100,
+	0x3c220, 0xffffffff, 0x00000100,
+	0x3c218, 0xffffffff, 0x06000100,
+	0x3c204, 0xffffffff, 0x00000100,
+	0x3c2e0, 0xffffffff, 0x00000100,
+	0x3c224, 0xffffffff, 0x00000100,
+	0x3c200, 0xffffffff, 0x00000100,
+	0x3c230, 0xffffffff, 0x00000100,
+	0x3c234, 0xffffffff, 0x00000100,
+	0x3c250, 0xffffffff, 0x00000100,
+	0x3c254, 0xffffffff, 0x00000100,
+	0x3c258, 0xffffffff, 0x00000100,
+	0x3c25c, 0xffffffff, 0x00000100,
+	0x3c260, 0xffffffff, 0x00000100,
+	0x3c27c, 0xffffffff, 0x00000100,
+	0x3c278, 0xffffffff, 0x00000100,
+	0x3c210, 0xffffffff, 0x06000100,
+	0x3c290, 0xffffffff, 0x00000100,
+	0x3c274, 0xffffffff, 0x00000100,
+	0x3c2b4, 0xffffffff, 0x00000100,
+	0x3c2b0, 0xffffffff, 0x00000100,
+	0x3c270, 0xffffffff, 0x00000100,
+	0x30800, 0xffffffff, 0xe0000000,
+	0x3c020, 0xffffffff, 0x00010000,
+	0x3c024, 0xffffffff, 0x00030002,
+	0x3c028, 0xffffffff, 0x00040007,
+	0x3c02c, 0xffffffff, 0x00060005,
+	0x3c030, 0xffffffff, 0x00090008,
+	0x3c034, 0xffffffff, 0x00010000,
+	0x3c038, 0xffffffff, 0x00030002,
+	0x3c03c, 0xffffffff, 0x00040007,
+	0x3c040, 0xffffffff, 0x00060005,
+	0x3c044, 0xffffffff, 0x00090008,
+	0x3c048, 0xffffffff, 0x00010000,
+	0x3c04c, 0xffffffff, 0x00030002,
+	0x3c050, 0xffffffff, 0x00040007,
+	0x3c054, 0xffffffff, 0x00060005,
+	0x3c058, 0xffffffff, 0x00090008,
+	0x3c05c, 0xffffffff, 0x00010000,
+	0x3c060, 0xffffffff, 0x00030002,
+	0x3c064, 0xffffffff, 0x00040007,
+	0x3c068, 0xffffffff, 0x00060005,
+	0x3c06c, 0xffffffff, 0x00090008,
+	0x3c070, 0xffffffff, 0x00010000,
+	0x3c074, 0xffffffff, 0x00030002,
+	0x3c078, 0xffffffff, 0x00040007,
+	0x3c07c, 0xffffffff, 0x00060005,
+	0x3c080, 0xffffffff, 0x00090008,
+	0x3c084, 0xffffffff, 0x00010000,
+	0x3c088, 0xffffffff, 0x00030002,
+	0x3c08c, 0xffffffff, 0x00040007,
+	0x3c090, 0xffffffff, 0x00060005,
+	0x3c094, 0xffffffff, 0x00090008,
+	0x3c098, 0xffffffff, 0x00010000,
+	0x3c09c, 0xffffffff, 0x00030002,
+	0x3c0a0, 0xffffffff, 0x00040007,
+	0x3c0a4, 0xffffffff, 0x00060005,
+	0x3c0a8, 0xffffffff, 0x00090008,
+	0x3c0ac, 0xffffffff, 0x00010000,
+	0x3c0b0, 0xffffffff, 0x00030002,
+	0x3c0b4, 0xffffffff, 0x00040007,
+	0x3c0b8, 0xffffffff, 0x00060005,
+	0x3c0bc, 0xffffffff, 0x00090008,
+	0x3c000, 0xffffffff, 0x96e00200,
+	0x8708, 0xffffffff, 0x00900100,
+	0xc424, 0xffffffff, 0x0020003f,
+	0x38, 0xffffffff, 0x0140001c,
+	0x3c, 0x000f0000, 0x000f0000,
+	0x220, 0xffffffff, 0xC060000C,
+	0x224, 0xc0000fff, 0x00000100,
+	0xf90, 0xffffffff, 0x00000100,
+	0xf98, 0x00000101, 0x00000000,
+	0x20a8, 0xffffffff, 0x00000104,
+	0x55e4, 0xff000fff, 0x00000100,
+	0x30cc, 0xc0000fff, 0x00000104,
+	0xc1e4, 0x00000001, 0x00000001,
+	0xd00c, 0xff000ff0, 0x00000100,
+	0xd80c, 0xff000ff0, 0x00000100
+};
+
+static const u32 kalindi_golden_spm_registers[] =
+{
+	0x30800, 0xe0ffffff, 0xe0000000
+};
+
+static const u32 kalindi_golden_common_registers[] =
+{
+	0xc770, 0xffffffff, 0x00000800,
+	0xc774, 0xffffffff, 0x00000800,
+	0xc798, 0xffffffff, 0x00007fbf,
+	0xc79c, 0xffffffff, 0x00007faf
+};
+
+static const u32 kalindi_golden_registers[] =
+{
+	0x3c000, 0xffffdfff, 0x6e944040,
+	0x55e4, 0xff607fff, 0xfc000100,
+	0x3c220, 0xff000fff, 0x00000100,
+	0x3c224, 0xff000fff, 0x00000100,
+	0x3c200, 0xfffc0fff, 0x00000100,
+	0x6ed8, 0x00010101, 0x00010000,
+	0x9830, 0xffffffff, 0x00000000,
+	0x9834, 0xf00fffff, 0x00000400,
+	0x5bb0, 0x000000f0, 0x00000070,
+	0x5bc0, 0xf0311fff, 0x80300000,
+	0x98f8, 0x73773777, 0x12010001,
+	0x98fc, 0xffffffff, 0x00000010,
+	0x9b7c, 0x00ff0000, 0x00fc0000,
+	0x8030, 0x00001f0f, 0x0000100a,
+	0x2f48, 0x73773777, 0x12010001,
+	0x2408, 0x000fffff, 0x000c007f,
+	0x8a14, 0xf000003f, 0x00000007,
+	0x8b24, 0x3fff3fff, 0x00ffcfff,
+	0x30a04, 0x0000ff0f, 0x00000000,
+	0x28a4c, 0x07ffffff, 0x06000000,
+	0x4d8, 0x00000fff, 0x00000100,
+	0x3e78, 0x00000001, 0x00000002,
+	0xc768, 0x00000008, 0x00000008,
+	0x8c00, 0x000000ff, 0x00000003,
+	0x214f8, 0x01ff01ff, 0x00000002,
+	0x21498, 0x007ff800, 0x00200000,
+	0x2015c, 0xffffffff, 0x00000f40,
+	0x88c4, 0x001f3ae3, 0x00000082,
+	0x88d4, 0x0000001f, 0x00000010,
+	0x30934, 0xffffffff, 0x00000000
+};
+
+static const u32 kalindi_mgcg_cgcg_init[] =
+{
+	0xc420, 0xffffffff, 0xfffffffc,
+	0x30800, 0xffffffff, 0xe0000000,
+	0x3c2a0, 0xffffffff, 0x00000100,
+	0x3c208, 0xffffffff, 0x00000100,
+	0x3c2c0, 0xffffffff, 0x00000100,
+	0x3c2c8, 0xffffffff, 0x00000100,
+	0x3c2c4, 0xffffffff, 0x00000100,
+	0x55e4, 0xffffffff, 0x00600100,
+	0x3c280, 0xffffffff, 0x00000100,
+	0x3c214, 0xffffffff, 0x06000100,
+	0x3c220, 0xffffffff, 0x00000100,
+	0x3c218, 0xffffffff, 0x06000100,
+	0x3c204, 0xffffffff, 0x00000100,
+	0x3c2e0, 0xffffffff, 0x00000100,
+	0x3c224, 0xffffffff, 0x00000100,
+	0x3c200, 0xffffffff, 0x00000100,
+	0x3c230, 0xffffffff, 0x00000100,
+	0x3c234, 0xffffffff, 0x00000100,
+	0x3c250, 0xffffffff, 0x00000100,
+	0x3c254, 0xffffffff, 0x00000100,
+	0x3c258, 0xffffffff, 0x00000100,
+	0x3c25c, 0xffffffff, 0x00000100,
+	0x3c260, 0xffffffff, 0x00000100,
+	0x3c27c, 0xffffffff, 0x00000100,
+	0x3c278, 0xffffffff, 0x00000100,
+	0x3c210, 0xffffffff, 0x06000100,
+	0x3c290, 0xffffffff, 0x00000100,
+	0x3c274, 0xffffffff, 0x00000100,
+	0x3c2b4, 0xffffffff, 0x00000100,
+	0x3c2b0, 0xffffffff, 0x00000100,
+	0x3c270, 0xffffffff, 0x00000100,
+	0x30800, 0xffffffff, 0xe0000000,
+	0x3c020, 0xffffffff, 0x00010000,
+	0x3c024, 0xffffffff, 0x00030002,
+	0x3c028, 0xffffffff, 0x00040007,
+	0x3c02c, 0xffffffff, 0x00060005,
+	0x3c030, 0xffffffff, 0x00090008,
+	0x3c034, 0xffffffff, 0x00010000,
+	0x3c038, 0xffffffff, 0x00030002,
+	0x3c03c, 0xffffffff, 0x00040007,
+	0x3c040, 0xffffffff, 0x00060005,
+	0x3c044, 0xffffffff, 0x00090008,
+	0x3c000, 0xffffffff, 0x96e00200,
+	0x8708, 0xffffffff, 0x00900100,
+	0xc424, 0xffffffff, 0x0020003f,
+	0x38, 0xffffffff, 0x0140001c,
+	0x3c, 0x000f0000, 0x000f0000,
+	0x220, 0xffffffff, 0xC060000C,
+	0x224, 0xc0000fff, 0x00000100,
+	0x20a8, 0xffffffff, 0x00000104,
+	0x55e4, 0xff000fff, 0x00000100,
+	0x30cc, 0xc0000fff, 0x00000104,
+	0xc1e4, 0x00000001, 0x00000001,
+	0xd00c, 0xff000ff0, 0x00000100,
+	0xd80c, 0xff000ff0, 0x00000100
+};
+
+static void cik_init_golden_registers(struct radeon_device *rdev)
+{
+	switch (rdev->family) {
+	case CHIP_BONAIRE:
+		radeon_program_register_sequence(rdev,
+						 bonaire_mgcg_cgcg_init,
+						 (const u32)ARRAY_SIZE(bonaire_mgcg_cgcg_init));
+		radeon_program_register_sequence(rdev,
+						 bonaire_golden_registers,
+						 (const u32)ARRAY_SIZE(bonaire_golden_registers));
+		radeon_program_register_sequence(rdev,
+						 bonaire_golden_common_registers,
+						 (const u32)ARRAY_SIZE(bonaire_golden_common_registers));
+		radeon_program_register_sequence(rdev,
+						 bonaire_golden_spm_registers,
+						 (const u32)ARRAY_SIZE(bonaire_golden_spm_registers));
+		break;
+	case CHIP_KABINI:
+		radeon_program_register_sequence(rdev,
+						 kalindi_mgcg_cgcg_init,
+						 (const u32)ARRAY_SIZE(kalindi_mgcg_cgcg_init));
+		radeon_program_register_sequence(rdev,
+						 kalindi_golden_registers,
+						 (const u32)ARRAY_SIZE(kalindi_golden_registers));
+		radeon_program_register_sequence(rdev,
+						 kalindi_golden_common_registers,
+						 (const u32)ARRAY_SIZE(kalindi_golden_common_registers));
+		radeon_program_register_sequence(rdev,
+						 kalindi_golden_spm_registers,
+						 (const u32)ARRAY_SIZE(kalindi_golden_spm_registers));
+		break;
+	case CHIP_KAVERI:
+		radeon_program_register_sequence(rdev,
+						 spectre_mgcg_cgcg_init,
+						 (const u32)ARRAY_SIZE(spectre_mgcg_cgcg_init));
+		radeon_program_register_sequence(rdev,
+						 spectre_golden_registers,
+						 (const u32)ARRAY_SIZE(spectre_golden_registers));
+		radeon_program_register_sequence(rdev,
+						 spectre_golden_common_registers,
+						 (const u32)ARRAY_SIZE(spectre_golden_common_registers));
+		radeon_program_register_sequence(rdev,
+						 spectre_golden_spm_registers,
+						 (const u32)ARRAY_SIZE(spectre_golden_spm_registers));
+		break;
+	default:
+		break;
+	}
+}
+
 /**
  * cik_get_xclk - get the xclk
  *
@@ -5719,6 +6152,9 @@ int cik_resume(struct radeon_device *rdev)
 	/* post card */
 	atom_asic_init(rdev->mode_info.atom_context);
 
+	/* init golden registers */
+	cik_init_golden_registers(rdev);
+
 	rdev->accel_working = true;
 	r = cik_startup(rdev);
 	if (r) {
@@ -5797,6 +6233,8 @@ int cik_init(struct radeon_device *rdev)
 		DRM_INFO("GPU not posted. posting now...\n");
 		atom_asic_init(rdev->mode_info.atom_context);
 	}
+	/* init golden registers */
+	cik_init_golden_registers(rdev);
 	/* Initialize scratch registers */
 	cik_scratch_init(rdev);
 	/* Initialize surface registers */
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 057/165] drm/radeon: add radeon_asic struct for CIK (v11)
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (56 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 056/165] drm/radeon/cik: add support for golden register init alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 058/165] drm/radeon: add cik tile mode array query alexdeucher
                   ` (55 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

v2: fix up for latest reset changes
v3: use CP for pt updates for now
v4: update for 2 level PTs
v5: update for ib_parse removal
v6: vm_flush api change
v7: rebase
v8: fix gfx ring function pointers
v9: fix vm_set_page function params
v10: update for compute changes
v11: cleanup for release

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/radeon_asic.c |  287 ++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/radeon/radeon_asic.h |   47 ++++++
 2 files changed, 334 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c
index 717b537..d60adb3 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.c
+++ b/drivers/gpu/drm/radeon/radeon_asic.c
@@ -1923,6 +1923,280 @@ static struct radeon_asic si_asic = {
 	},
 };
 
+static struct radeon_asic ci_asic = {
+	.init = &cik_init,
+	.fini = &cik_fini,
+	.suspend = &cik_suspend,
+	.resume = &cik_resume,
+	.asic_reset = &cik_asic_reset,
+	.vga_set_state = &r600_vga_set_state,
+	.ioctl_wait_idle = NULL,
+	.gui_idle = &r600_gui_idle,
+	.mc_wait_for_idle = &evergreen_mc_wait_for_idle,
+	.get_xclk = &cik_get_xclk,
+	.get_gpu_clock_counter = &cik_get_gpu_clock_counter,
+	.gart = {
+		.tlb_flush = &cik_pcie_gart_tlb_flush,
+		.set_page = &rs600_gart_set_page,
+	},
+	.vm = {
+		.init = &cik_vm_init,
+		.fini = &cik_vm_fini,
+		.pt_ring_index = R600_RING_TYPE_DMA_INDEX,
+		.set_page = &cik_vm_set_page,
+	},
+	.ring = {
+		[RADEON_RING_TYPE_GFX_INDEX] = {
+			.ib_execute = &cik_ring_ib_execute,
+			.ib_parse = &cik_ib_parse,
+			.emit_fence = &cik_fence_gfx_ring_emit,
+			.emit_semaphore = &cik_semaphore_ring_emit,
+			.cs_parse = NULL,
+			.ring_test = &cik_ring_test,
+			.ib_test = &cik_ib_test,
+			.is_lockup = &cik_gfx_is_lockup,
+			.vm_flush = &cik_vm_flush,
+		},
+		[CAYMAN_RING_TYPE_CP1_INDEX] = {
+			.ib_execute = &cik_ring_ib_execute,
+			.ib_parse = &cik_ib_parse,
+			.emit_fence = &cik_fence_compute_ring_emit,
+			.emit_semaphore = &cik_semaphore_ring_emit,
+			.cs_parse = NULL,
+			.ring_test = &cik_ring_test,
+			.ib_test = &cik_ib_test,
+			.is_lockup = &cik_gfx_is_lockup,
+			.vm_flush = &cik_vm_flush,
+		},
+		[CAYMAN_RING_TYPE_CP2_INDEX] = {
+			.ib_execute = &cik_ring_ib_execute,
+			.ib_parse = &cik_ib_parse,
+			.emit_fence = &cik_fence_compute_ring_emit,
+			.emit_semaphore = &cik_semaphore_ring_emit,
+			.cs_parse = NULL,
+			.ring_test = &cik_ring_test,
+			.ib_test = &cik_ib_test,
+			.is_lockup = &cik_gfx_is_lockup,
+			.vm_flush = &cik_vm_flush,
+		},
+		[R600_RING_TYPE_DMA_INDEX] = {
+			.ib_execute = &cik_sdma_ring_ib_execute,
+			.ib_parse = &cik_ib_parse,
+			.emit_fence = &cik_sdma_fence_ring_emit,
+			.emit_semaphore = &cik_sdma_semaphore_ring_emit,
+			.cs_parse = NULL,
+			.ring_test = &cik_sdma_ring_test,
+			.ib_test = &cik_sdma_ib_test,
+			.is_lockup = &cik_sdma_is_lockup,
+			.vm_flush = &cik_dma_vm_flush,
+		},
+		[CAYMAN_RING_TYPE_DMA1_INDEX] = {
+			.ib_execute = &cik_sdma_ring_ib_execute,
+			.ib_parse = &cik_ib_parse,
+			.emit_fence = &cik_sdma_fence_ring_emit,
+			.emit_semaphore = &cik_sdma_semaphore_ring_emit,
+			.cs_parse = NULL,
+			.ring_test = &cik_sdma_ring_test,
+			.ib_test = &cik_sdma_ib_test,
+			.is_lockup = &cik_sdma_is_lockup,
+			.vm_flush = &cik_dma_vm_flush,
+		},
+		[R600_RING_TYPE_UVD_INDEX] = {
+			.ib_execute = &r600_uvd_ib_execute,
+			.emit_fence = &r600_uvd_fence_emit,
+			.emit_semaphore = &cayman_uvd_semaphore_emit,
+			.cs_parse = &radeon_uvd_cs_parse,
+			.ring_test = &r600_uvd_ring_test,
+			.ib_test = &r600_uvd_ib_test,
+			.is_lockup = &radeon_ring_test_lockup,
+		}
+	},
+	.irq = {
+		.set = &cik_irq_set,
+		.process = &cik_irq_process,
+	},
+	.display = {
+		.bandwidth_update = &dce8_bandwidth_update,
+		.get_vblank_counter = &evergreen_get_vblank_counter,
+		.wait_for_vblank = &dce4_wait_for_vblank,
+	},
+	.copy = {
+		.blit = NULL,
+		.blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+		.dma = &cik_copy_dma,
+		.dma_ring_index = R600_RING_TYPE_DMA_INDEX,
+		.copy = &cik_copy_dma,
+		.copy_ring_index = R600_RING_TYPE_DMA_INDEX,
+	},
+	.surface = {
+		.set_reg = r600_set_surface_reg,
+		.clear_reg = r600_clear_surface_reg,
+	},
+	.hpd = {
+		.init = &evergreen_hpd_init,
+		.fini = &evergreen_hpd_fini,
+		.sense = &evergreen_hpd_sense,
+		.set_polarity = &evergreen_hpd_set_polarity,
+	},
+	.pm = {
+		.misc = &evergreen_pm_misc,
+		.prepare = &evergreen_pm_prepare,
+		.finish = &evergreen_pm_finish,
+		.init_profile = &sumo_pm_init_profile,
+		.get_dynpm_state = &r600_pm_get_dynpm_state,
+		.get_engine_clock = &radeon_atom_get_engine_clock,
+		.set_engine_clock = &radeon_atom_set_engine_clock,
+		.get_memory_clock = &radeon_atom_get_memory_clock,
+		.set_memory_clock = &radeon_atom_set_memory_clock,
+		.get_pcie_lanes = NULL,
+		.set_pcie_lanes = NULL,
+		.set_clock_gating = NULL,
+		.set_uvd_clocks = &cik_set_uvd_clocks,
+	},
+	.pflip = {
+		.pre_page_flip = &evergreen_pre_page_flip,
+		.page_flip = &evergreen_page_flip,
+		.post_page_flip = &evergreen_post_page_flip,
+	},
+};
+
+static struct radeon_asic kv_asic = {
+	.init = &cik_init,
+	.fini = &cik_fini,
+	.suspend = &cik_suspend,
+	.resume = &cik_resume,
+	.asic_reset = &cik_asic_reset,
+	.vga_set_state = &r600_vga_set_state,
+	.ioctl_wait_idle = NULL,
+	.gui_idle = &r600_gui_idle,
+	.mc_wait_for_idle = &evergreen_mc_wait_for_idle,
+	.get_xclk = &cik_get_xclk,
+	.get_gpu_clock_counter = &cik_get_gpu_clock_counter,
+	.gart = {
+		.tlb_flush = &cik_pcie_gart_tlb_flush,
+		.set_page = &rs600_gart_set_page,
+	},
+	.vm = {
+		.init = &cik_vm_init,
+		.fini = &cik_vm_fini,
+		.pt_ring_index = R600_RING_TYPE_DMA_INDEX,
+		.set_page = &cik_vm_set_page,
+	},
+	.ring = {
+		[RADEON_RING_TYPE_GFX_INDEX] = {
+			.ib_execute = &cik_ring_ib_execute,
+			.ib_parse = &cik_ib_parse,
+			.emit_fence = &cik_fence_gfx_ring_emit,
+			.emit_semaphore = &cik_semaphore_ring_emit,
+			.cs_parse = NULL,
+			.ring_test = &cik_ring_test,
+			.ib_test = &cik_ib_test,
+			.is_lockup = &cik_gfx_is_lockup,
+			.vm_flush = &cik_vm_flush,
+		},
+		[CAYMAN_RING_TYPE_CP1_INDEX] = {
+			.ib_execute = &cik_ring_ib_execute,
+			.ib_parse = &cik_ib_parse,
+			.emit_fence = &cik_fence_compute_ring_emit,
+			.emit_semaphore = &cik_semaphore_ring_emit,
+			.cs_parse = NULL,
+			.ring_test = &cik_ring_test,
+			.ib_test = &cik_ib_test,
+			.is_lockup = &cik_gfx_is_lockup,
+			.vm_flush = &cik_vm_flush,
+		},
+		[CAYMAN_RING_TYPE_CP2_INDEX] = {
+			.ib_execute = &cik_ring_ib_execute,
+			.ib_parse = &cik_ib_parse,
+			.emit_fence = &cik_fence_compute_ring_emit,
+			.emit_semaphore = &cik_semaphore_ring_emit,
+			.cs_parse = NULL,
+			.ring_test = &cik_ring_test,
+			.ib_test = &cik_ib_test,
+			.is_lockup = &cik_gfx_is_lockup,
+			.vm_flush = &cik_vm_flush,
+		},
+		[R600_RING_TYPE_DMA_INDEX] = {
+			.ib_execute = &cik_sdma_ring_ib_execute,
+			.ib_parse = &cik_ib_parse,
+			.emit_fence = &cik_sdma_fence_ring_emit,
+			.emit_semaphore = &cik_sdma_semaphore_ring_emit,
+			.cs_parse = NULL,
+			.ring_test = &cik_sdma_ring_test,
+			.ib_test = &cik_sdma_ib_test,
+			.is_lockup = &cik_sdma_is_lockup,
+			.vm_flush = &cik_dma_vm_flush,
+		},
+		[CAYMAN_RING_TYPE_DMA1_INDEX] = {
+			.ib_execute = &cik_sdma_ring_ib_execute,
+			.ib_parse = &cik_ib_parse,
+			.emit_fence = &cik_sdma_fence_ring_emit,
+			.emit_semaphore = &cik_sdma_semaphore_ring_emit,
+			.cs_parse = NULL,
+			.ring_test = &cik_sdma_ring_test,
+			.ib_test = &cik_sdma_ib_test,
+			.is_lockup = &cik_sdma_is_lockup,
+			.vm_flush = &cik_dma_vm_flush,
+		},
+		[R600_RING_TYPE_UVD_INDEX] = {
+			.ib_execute = &r600_uvd_ib_execute,
+			.emit_fence = &r600_uvd_fence_emit,
+			.emit_semaphore = &cayman_uvd_semaphore_emit,
+			.cs_parse = &radeon_uvd_cs_parse,
+			.ring_test = &r600_uvd_ring_test,
+			.ib_test = &r600_uvd_ib_test,
+			.is_lockup = &radeon_ring_test_lockup,
+		}
+	},
+	.irq = {
+		.set = &cik_irq_set,
+		.process = &cik_irq_process,
+	},
+	.display = {
+		.bandwidth_update = &dce8_bandwidth_update,
+		.get_vblank_counter = &evergreen_get_vblank_counter,
+		.wait_for_vblank = &dce4_wait_for_vblank,
+	},
+	.copy = {
+		.blit = NULL,
+		.blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+		.dma = &cik_copy_dma,
+		.dma_ring_index = R600_RING_TYPE_DMA_INDEX,
+		.copy = &cik_copy_dma,
+		.copy_ring_index = R600_RING_TYPE_DMA_INDEX,
+	},
+	.surface = {
+		.set_reg = r600_set_surface_reg,
+		.clear_reg = r600_clear_surface_reg,
+	},
+	.hpd = {
+		.init = &evergreen_hpd_init,
+		.fini = &evergreen_hpd_fini,
+		.sense = &evergreen_hpd_sense,
+		.set_polarity = &evergreen_hpd_set_polarity,
+	},
+	.pm = {
+		.misc = &evergreen_pm_misc,
+		.prepare = &evergreen_pm_prepare,
+		.finish = &evergreen_pm_finish,
+		.init_profile = &sumo_pm_init_profile,
+		.get_dynpm_state = &r600_pm_get_dynpm_state,
+		.get_engine_clock = &radeon_atom_get_engine_clock,
+		.set_engine_clock = &radeon_atom_set_engine_clock,
+		.get_memory_clock = &radeon_atom_get_memory_clock,
+		.set_memory_clock = &radeon_atom_set_memory_clock,
+		.get_pcie_lanes = NULL,
+		.set_pcie_lanes = NULL,
+		.set_clock_gating = NULL,
+		.set_uvd_clocks = &cik_set_uvd_clocks,
+	},
+	.pflip = {
+		.pre_page_flip = &evergreen_pre_page_flip,
+		.page_flip = &evergreen_page_flip,
+		.post_page_flip = &evergreen_post_page_flip,
+	},
+};
+
 /**
  * radeon_asic_init - register asic specific callbacks
  *
@@ -2086,6 +2360,19 @@ int radeon_asic_init(struct radeon_device *rdev)
 		else
 			rdev->has_uvd = true;
 		break;
+	case CHIP_BONAIRE:
+		rdev->asic = &ci_asic;
+		rdev->num_crtc = 6;
+		break;
+	case CHIP_KAVERI:
+	case CHIP_KABINI:
+		rdev->asic = &kv_asic;
+		/* set num crtcs */
+		if (rdev->family == CHIP_KAVERI)
+			rdev->num_crtc = 4;
+		else
+			rdev->num_crtc = 2;
+		break;
 	default:
 		/* FIXME: not supported yet */
 		return -EINVAL;
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index 3405742..4c2f51f 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -553,6 +553,9 @@ 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);
 
+/* DCE8 - CIK */
+void dce8_bandwidth_update(struct radeon_device *rdev);
+
 /*
  * cik
  */
@@ -562,5 +565,49 @@ uint32_t cik_pciep_rreg(struct radeon_device *rdev, uint32_t reg);
 void cik_pciep_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
 int cik_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk);
 int cik_uvd_resume(struct radeon_device *rdev);
+void cik_sdma_fence_ring_emit(struct radeon_device *rdev,
+			      struct radeon_fence *fence);
+void cik_sdma_semaphore_ring_emit(struct radeon_device *rdev,
+				  struct radeon_ring *ring,
+				  struct radeon_semaphore *semaphore,
+				  bool emit_wait);
+void cik_sdma_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib);
+int cik_copy_dma(struct radeon_device *rdev,
+		 uint64_t src_offset, uint64_t dst_offset,
+		 unsigned num_gpu_pages,
+		 struct radeon_fence **fence);
+int cik_sdma_ring_test(struct radeon_device *rdev, struct radeon_ring *ring);
+int cik_sdma_ib_test(struct radeon_device *rdev, struct radeon_ring *ring);
+bool cik_sdma_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring);
+void cik_fence_gfx_ring_emit(struct radeon_device *rdev,
+			     struct radeon_fence *fence);
+void cik_fence_compute_ring_emit(struct radeon_device *rdev,
+				 struct radeon_fence *fence);
+void cik_semaphore_ring_emit(struct radeon_device *rdev,
+			     struct radeon_ring *cp,
+			     struct radeon_semaphore *semaphore,
+			     bool emit_wait);
+void cik_pcie_gart_tlb_flush(struct radeon_device *rdev);
+int cik_init(struct radeon_device *rdev);
+void cik_fini(struct radeon_device *rdev);
+int cik_suspend(struct radeon_device *rdev);
+int cik_resume(struct radeon_device *rdev);
+bool cik_gfx_is_lockup(struct radeon_device *rdev, struct radeon_ring *cp);
+int cik_asic_reset(struct radeon_device *rdev);
+void cik_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib);
+int cik_ring_test(struct radeon_device *rdev, struct radeon_ring *ring);
+int cik_ib_test(struct radeon_device *rdev, struct radeon_ring *ring);
+int cik_irq_set(struct radeon_device *rdev);
+int cik_irq_process(struct radeon_device *rdev);
+int cik_vm_init(struct radeon_device *rdev);
+void cik_vm_fini(struct radeon_device *rdev);
+void cik_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm);
+void cik_vm_set_page(struct radeon_device *rdev,
+		     struct radeon_ib *ib,
+		     uint64_t pe,
+		     uint64_t addr, unsigned count,
+		     uint32_t incr, uint32_t flags);
+void cik_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm);
+int cik_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib);
 
 #endif
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 058/165] drm/radeon: add cik tile mode array query
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (57 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 057/165] drm/radeon: add radeon_asic struct for CIK (v11) alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 059/165] drm/radeon: add current Bonaire PCI ids alexdeucher
                   ` (54 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/cik.c        |    4 ++++
 drivers/gpu/drm/radeon/radeon.h     |    1 +
 drivers/gpu/drm/radeon/radeon_drv.c |    3 ++-
 drivers/gpu/drm/radeon/radeon_kms.c |   14 +++++++-------
 4 files changed, 14 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
index e899c44..2cf3521 100644
--- a/drivers/gpu/drm/radeon/cik.c
+++ b/drivers/gpu/drm/radeon/cik.c
@@ -1059,6 +1059,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev)
 				gb_tile_moden = 0;
 				break;
 			}
+			rdev->config.cik.tile_mode_array[reg_offset] = gb_tile_moden;
 			WREG32(GB_TILE_MODE0 + (reg_offset * 4), gb_tile_moden);
 		}
 		for (reg_offset = 0; reg_offset < num_secondary_tile_mode_states; reg_offset++) {
@@ -1277,6 +1278,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev)
 					gb_tile_moden = 0;
 					break;
 				}
+				rdev->config.cik.tile_mode_array[reg_offset] = gb_tile_moden;
 				WREG32(GB_TILE_MODE0 + (reg_offset * 4), gb_tile_moden);
 			}
 		} else if (num_rbs < 4) {
@@ -1402,6 +1404,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev)
 					gb_tile_moden = 0;
 					break;
 				}
+				rdev->config.cik.tile_mode_array[reg_offset] = gb_tile_moden;
 				WREG32(GB_TILE_MODE0 + (reg_offset * 4), gb_tile_moden);
 			}
 		}
@@ -1619,6 +1622,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev)
 				gb_tile_moden = 0;
 				break;
 			}
+			rdev->config.cik.tile_mode_array[reg_offset] = gb_tile_moden;
 			WREG32(GB_TILE_MODE0 + (reg_offset * 4), gb_tile_moden);
 		}
 		for (reg_offset = 0; reg_offset < num_secondary_tile_mode_states; reg_offset++) {
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index d40d506..83f62aa 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -1588,6 +1588,7 @@ struct cik_asic {
 	unsigned multi_gpu_tile_size;
 
 	unsigned tile_config;
+	uint32_t tile_mode_array[32];
 };
 
 union radeon_asic_config {
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c
index 094e7e5..02709e4 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -74,9 +74,10 @@
  *   2.31.0 - Add fastfb support for rs690
  *   2.32.0 - new info request for rings working
  *   2.33.0 - Add SI tiling mode array query
+ *   2.34.0 - Add CIK tiling mode array query
  */
 #define KMS_DRIVER_MAJOR	2
-#define KMS_DRIVER_MINOR	33
+#define KMS_DRIVER_MINOR	34
 #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);
diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c
index c650228..49ff3d1 100644
--- a/drivers/gpu/drm/radeon/radeon_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_kms.c
@@ -423,15 +423,15 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
 		break;
 	case RADEON_INFO_SI_TILE_MODE_ARRAY:
 		if (rdev->family >= CHIP_BONAIRE) {
-			DRM_DEBUG_KMS("tile mode array is not implemented yet\n");
+			value = rdev->config.cik.tile_mode_array;
+			value_size = sizeof(uint32_t)*32;
+		} else if (rdev->family >= CHIP_TAHITI) {
+			value = rdev->config.si.tile_mode_array;
+			value_size = sizeof(uint32_t)*32;
+		} else {
+			DRM_DEBUG_KMS("tile mode array is si+ only!\n");
 			return -EINVAL;
 		}
-		if (rdev->family < CHIP_TAHITI) {
-			DRM_DEBUG_KMS("tile mode array is si only!\n");
-			return -EINVAL;
-		}
-		value = rdev->config.si.tile_mode_array;
-		value_size = sizeof(uint32_t)*32;
 		break;
 	default:
 		DRM_DEBUG_KMS("Invalid request %d\n", info->request);
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 059/165] drm/radeon: add current Bonaire PCI ids
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (58 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 058/165] drm/radeon: add cik tile mode array query alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 060/165] drm/radeon: add current KB pci ids alexdeucher
                   ` (53 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 include/drm/drm_pciids.h |    8 ++++++++
 1 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/include/drm/drm_pciids.h b/include/drm/drm_pciids.h
index bb1bc48..23f89df 100644
--- a/include/drm/drm_pciids.h
+++ b/include/drm/drm_pciids.h
@@ -152,6 +152,14 @@
 	{0x1002, 0x6621, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x6623, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x6631, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6640, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6641, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6649, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6650, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6651, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6658, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x665c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x665d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x6660, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAINAN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x6663, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAINAN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x6664, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAINAN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 060/165] drm/radeon: add current KB pci ids
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (59 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 059/165] drm/radeon: add current Bonaire PCI ids alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 061/165] drm/radeon/kms: add accessors for RCU indirect space alexdeucher
                   ` (52 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 include/drm/drm_pciids.h |   16 ++++++++++++++++
 1 files changed, 16 insertions(+), 0 deletions(-)

diff --git a/include/drm/drm_pciids.h b/include/drm/drm_pciids.h
index 23f89df..34efaf6 100644
--- a/include/drm/drm_pciids.h
+++ b/include/drm/drm_pciids.h
@@ -588,6 +588,22 @@
 	{0x1002, 0x9808, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
 	{0x1002, 0x9809, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
 	{0x1002, 0x980A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x9830, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x9831, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x9832, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x9833, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x9834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x9835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x9836, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x9837, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x9838, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x9839, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x983a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x983b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x983c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x983d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x983e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x983f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
 	{0x1002, 0x9900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
 	{0x1002, 0x9901, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
 	{0x1002, 0x9903, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 061/165] drm/radeon/kms: add accessors for RCU indirect space
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (60 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 060/165] drm/radeon: add current KB pci ids alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 062/165] drm/radeon/evergreen: add indirect register accessors for CG registers alexdeucher
                   ` (51 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/evergreen.c |    6 ++----
 drivers/gpu/drm/radeon/r600_reg.h  |    3 +++
 drivers/gpu/drm/radeon/radeon.h    |   17 +++++++++++++++++
 3 files changed, 22 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
index 0f89ce3..9009dd4 100644
--- a/drivers/gpu/drm/radeon/evergreen.c
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -3120,10 +3120,8 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
 		u32 efuse_straps_4;
 		u32 efuse_straps_3;
 
-		WREG32(RCU_IND_INDEX, 0x204);
-		efuse_straps_4 = RREG32(RCU_IND_DATA);
-		WREG32(RCU_IND_INDEX, 0x203);
-		efuse_straps_3 = RREG32(RCU_IND_DATA);
+		efuse_straps_4 = RREG32_RCU(0x204);
+		efuse_straps_3 = RREG32_RCU(0x203);
 		tmp = (((efuse_straps_4 & 0xf) << 4) |
 		      ((efuse_straps_3 & 0xf0000000) >> 28));
 	} else {
diff --git a/drivers/gpu/drm/radeon/r600_reg.h b/drivers/gpu/drm/radeon/r600_reg.h
index 909219b..58c86cc 100644
--- a/drivers/gpu/drm/radeon/r600_reg.h
+++ b/drivers/gpu/drm/radeon/r600_reg.h
@@ -31,6 +31,9 @@
 #define R600_PCIE_PORT_INDEX                0x0038
 #define R600_PCIE_PORT_DATA                 0x003c
 
+#define R600_RCU_INDEX                      0x0100
+#define R600_RCU_DATA                       0x0104
+
 #define R600_MC_VM_FB_LOCATION			0x2180
 #define		R600_MC_FB_BASE_MASK			0x0000FFFF
 #define		R600_MC_FB_BASE_SHIFT			0
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 83f62aa..0814aa7 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -1851,6 +1851,8 @@ void cik_mm_wdoorbell(struct radeon_device *rdev, u32 offset, u32 v);
 #define WREG32_PCIE_PORT(reg, v) rdev->pciep_wreg(rdev, (reg), (v))
 #define RREG32_SMC(reg) tn_smc_rreg(rdev, (reg))
 #define WREG32_SMC(reg, v) tn_smc_wreg(rdev, (reg), (v))
+#define RREG32_RCU(reg) r600_rcu_rreg(rdev, (reg))
+#define WREG32_RCU(reg, v) r600_rcu_wreg(rdev, (reg), (v))
 #define WREG32_P(reg, val, mask)				\
 	do {							\
 		uint32_t tmp_ = RREG32(reg);			\
@@ -1907,6 +1909,21 @@ static inline void tn_smc_wreg(struct radeon_device *rdev, u32 reg, u32 v)
 	WREG32(TN_SMC_IND_DATA_0, (v));
 }
 
+static inline u32 r600_rcu_rreg(struct radeon_device *rdev, u32 reg)
+{
+	u32 r;
+
+	WREG32(R600_RCU_INDEX, ((reg) & 0x1fff));
+	r = RREG32(R600_RCU_DATA);
+	return r;
+}
+
+static inline void r600_rcu_wreg(struct radeon_device *rdev, u32 reg, u32 v)
+{
+	WREG32(R600_RCU_INDEX, ((reg) & 0x1fff));
+	WREG32(R600_RCU_DATA, (v));
+}
+
 void r100_pll_errata_after_index(struct radeon_device *rdev);
 
 
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 062/165] drm/radeon/evergreen: add indirect register accessors for CG registers
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (61 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 061/165] drm/radeon/kms: add accessors for RCU indirect space alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 063/165] drm/radeon: make get_temperature functions a callback alexdeucher
                   ` (50 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/evergreen_reg.h |    3 +++
 drivers/gpu/drm/radeon/radeon.h        |   17 +++++++++++++++++
 2 files changed, 20 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/radeon/evergreen_reg.h b/drivers/gpu/drm/radeon/evergreen_reg.h
index 50948ac..76630c6b 100644
--- a/drivers/gpu/drm/radeon/evergreen_reg.h
+++ b/drivers/gpu/drm/radeon/evergreen_reg.h
@@ -44,6 +44,9 @@
 #define EVERGREEN_AUDIO_PLL1_DIV			0x5b4
 #define EVERGREEN_AUDIO_PLL1_UNK			0x5bc
 
+#define EVERGREEN_CG_IND_ADDR                           0x8f8
+#define EVERGREEN_CG_IND_DATA                           0x8fc
+
 #define EVERGREEN_AUDIO_ENABLE				0x5e78
 #define EVERGREEN_AUDIO_VENDOR_ID			0x5ec0
 
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 0814aa7..e73c972 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -1853,6 +1853,8 @@ void cik_mm_wdoorbell(struct radeon_device *rdev, u32 offset, u32 v);
 #define WREG32_SMC(reg, v) tn_smc_wreg(rdev, (reg), (v))
 #define RREG32_RCU(reg) r600_rcu_rreg(rdev, (reg))
 #define WREG32_RCU(reg, v) r600_rcu_wreg(rdev, (reg), (v))
+#define RREG32_CG(reg) eg_cg_rreg(rdev, (reg))
+#define WREG32_CG(reg, v) eg_cg_wreg(rdev, (reg), (v))
 #define WREG32_P(reg, val, mask)				\
 	do {							\
 		uint32_t tmp_ = RREG32(reg);			\
@@ -1924,6 +1926,21 @@ static inline void r600_rcu_wreg(struct radeon_device *rdev, u32 reg, u32 v)
 	WREG32(R600_RCU_DATA, (v));
 }
 
+static inline u32 eg_cg_rreg(struct radeon_device *rdev, u32 reg)
+{
+	u32 r;
+
+	WREG32(EVERGREEN_CG_IND_ADDR, ((reg) & 0xffff));
+	r = RREG32(EVERGREEN_CG_IND_DATA);
+	return r;
+}
+
+static inline void eg_cg_wreg(struct radeon_device *rdev, u32 reg, u32 v)
+{
+	WREG32(EVERGREEN_CG_IND_ADDR, ((reg) & 0xffff));
+	WREG32(EVERGREEN_CG_IND_DATA, (v));
+}
+
 void r100_pll_errata_after_index(struct radeon_device *rdev);
 
 
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 063/165] drm/radeon: make get_temperature functions a callback
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (62 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 062/165] drm/radeon/evergreen: add indirect register accessors for CG registers alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 064/165] drm/radeon: add support for thermal sensor on tn alexdeucher
                   ` (49 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/radeon.h      |    7 ++-----
 drivers/gpu/drm/radeon/radeon_asic.c |    8 ++++++++
 drivers/gpu/drm/radeon/radeon_asic.h |    5 +++++
 drivers/gpu/drm/radeon/radeon_pm.c   |   26 ++++----------------------
 4 files changed, 19 insertions(+), 27 deletions(-)

diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index e73c972..40053c8 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -220,11 +220,6 @@ int radeon_atom_get_clock_dividers(struct radeon_device *rdev,
 				   struct atom_clock_dividers *dividers);
 void radeon_atom_set_voltage(struct radeon_device *rdev, u16 voltage_level, u8 voltage_type);
 void rs690_pm_info(struct radeon_device *rdev);
-extern int rv6xx_get_temp(struct radeon_device *rdev);
-extern int rv770_get_temp(struct radeon_device *rdev);
-extern int evergreen_get_temp(struct radeon_device *rdev);
-extern int sumo_get_temp(struct radeon_device *rdev);
-extern int si_get_temp(struct radeon_device *rdev);
 extern void evergreen_tiling_fields(unsigned tiling_flags, unsigned *bankw,
 				    unsigned *bankh, unsigned *mtaspect,
 				    unsigned *tile_split);
@@ -1396,6 +1391,7 @@ struct radeon_asic {
 		void (*set_pcie_lanes)(struct radeon_device *rdev, int lanes);
 		void (*set_clock_gating)(struct radeon_device *rdev, int enable);
 		int (*set_uvd_clocks)(struct radeon_device *rdev, u32 vclk, u32 dclk);
+		int (*get_temperature)(struct radeon_device *rdev);
 	} pm;
 	/* pageflipping */
 	struct {
@@ -2065,6 +2061,7 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v);
 #define radeon_set_pcie_lanes(rdev, l) (rdev)->asic->pm.set_pcie_lanes((rdev), (l))
 #define radeon_set_clock_gating(rdev, e) (rdev)->asic->pm.set_clock_gating((rdev), (e))
 #define radeon_set_uvd_clocks(rdev, v, d) (rdev)->asic->pm.set_uvd_clocks((rdev), (v), (d))
+#define radeon_get_temperature(rdev) (rdev)->asic->pm.get_temperature((rdev))
 #define radeon_set_surface_reg(rdev, r, f, p, o, s) ((rdev)->asic->surface.set_reg((rdev), (r), (f), (p), (o), (s)))
 #define radeon_clear_surface_reg(rdev, r) ((rdev)->asic->surface.clear_reg((rdev), (r)))
 #define radeon_bandwidth_update(rdev) (rdev)->asic->display.bandwidth_update((rdev))
diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c
index d60adb3..f127ea2 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.c
+++ b/drivers/gpu/drm/radeon/radeon_asic.c
@@ -1016,6 +1016,7 @@ static struct radeon_asic r600_asic = {
 		.get_pcie_lanes = &r600_get_pcie_lanes,
 		.set_pcie_lanes = &r600_set_pcie_lanes,
 		.set_clock_gating = NULL,
+		.get_temperature = &rv6xx_get_temp,
 	},
 	.pflip = {
 		.pre_page_flip = &rs600_pre_page_flip,
@@ -1104,6 +1105,7 @@ static struct radeon_asic rs780_asic = {
 		.get_pcie_lanes = NULL,
 		.set_pcie_lanes = NULL,
 		.set_clock_gating = NULL,
+		.get_temperature = &rv6xx_get_temp,
 	},
 	.pflip = {
 		.pre_page_flip = &rs600_pre_page_flip,
@@ -1202,6 +1204,7 @@ static struct radeon_asic rv770_asic = {
 		.set_pcie_lanes = &r600_set_pcie_lanes,
 		.set_clock_gating = &radeon_atom_set_clock_gating,
 		.set_uvd_clocks = &rv770_set_uvd_clocks,
+		.get_temperature = &rv770_get_temp,
 	},
 	.pflip = {
 		.pre_page_flip = &rs600_pre_page_flip,
@@ -1300,6 +1303,7 @@ static struct radeon_asic evergreen_asic = {
 		.set_pcie_lanes = &r600_set_pcie_lanes,
 		.set_clock_gating = NULL,
 		.set_uvd_clocks = &evergreen_set_uvd_clocks,
+		.get_temperature = &evergreen_get_temp,
 	},
 	.pflip = {
 		.pre_page_flip = &evergreen_pre_page_flip,
@@ -1398,6 +1402,7 @@ static struct radeon_asic sumo_asic = {
 		.set_pcie_lanes = NULL,
 		.set_clock_gating = NULL,
 		.set_uvd_clocks = &sumo_set_uvd_clocks,
+		.get_temperature = &sumo_get_temp,
 	},
 	.pflip = {
 		.pre_page_flip = &evergreen_pre_page_flip,
@@ -1496,6 +1501,7 @@ static struct radeon_asic btc_asic = {
 		.set_pcie_lanes = &r600_set_pcie_lanes,
 		.set_clock_gating = NULL,
 		.set_uvd_clocks = &evergreen_set_uvd_clocks,
+		.get_temperature = &evergreen_get_temp,
 	},
 	.pflip = {
 		.pre_page_flip = &evergreen_pre_page_flip,
@@ -1637,6 +1643,7 @@ static struct radeon_asic cayman_asic = {
 		.set_pcie_lanes = &r600_set_pcie_lanes,
 		.set_clock_gating = NULL,
 		.set_uvd_clocks = &evergreen_set_uvd_clocks,
+		.get_temperature = &evergreen_get_temp,
 	},
 	.pflip = {
 		.pre_page_flip = &evergreen_pre_page_flip,
@@ -1915,6 +1922,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,
+		.get_temperature = &si_get_temp,
 	},
 	.pflip = {
 		.pre_page_flip = &evergreen_pre_page_flip,
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index 4c2f51f..f1dcb07 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -395,6 +395,7 @@ void r600_kms_blit_copy(struct radeon_device *rdev,
 int r600_mc_wait_for_idle(struct radeon_device *rdev);
 u32 r600_get_xclk(struct radeon_device *rdev);
 uint64_t r600_get_gpu_clock_counter(struct radeon_device *rdev);
+int rv6xx_get_temp(struct radeon_device *rdev);
 
 /* uvd */
 int r600_uvd_init(struct radeon_device *rdev);
@@ -428,6 +429,7 @@ int rv770_copy_dma(struct radeon_device *rdev,
 u32 rv770_get_xclk(struct radeon_device *rdev);
 int rv770_uvd_resume(struct radeon_device *rdev);
 int rv770_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk);
+int rv770_get_temp(struct radeon_device *rdev);
 
 /*
  * evergreen
@@ -482,6 +484,8 @@ int evergreen_copy_dma(struct radeon_device *rdev,
 		       struct radeon_fence **fence);
 void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable);
 void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode);
+int evergreen_get_temp(struct radeon_device *rdev);
+int sumo_get_temp(struct radeon_device *rdev);
 
 /*
  * cayman
@@ -552,6 +556,7 @@ void si_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
 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_get_temp(struct radeon_device *rdev);
 
 /* DCE8 - CIK */
 void dce8_bandwidth_update(struct radeon_device *rdev);
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
index 788c64c..e8c1bea 100644
--- a/drivers/gpu/drm/radeon/radeon_pm.c
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
@@ -434,27 +434,10 @@ static ssize_t radeon_hwmon_show_temp(struct device *dev,
 	struct radeon_device *rdev = ddev->dev_private;
 	int temp;
 
-	switch (rdev->pm.int_thermal_type) {
-	case THERMAL_TYPE_RV6XX:
-		temp = rv6xx_get_temp(rdev);
-		break;
-	case THERMAL_TYPE_RV770:
-		temp = rv770_get_temp(rdev);
-		break;
-	case THERMAL_TYPE_EVERGREEN:
-	case THERMAL_TYPE_NI:
-		temp = evergreen_get_temp(rdev);
-		break;
-	case THERMAL_TYPE_SUMO:
-		temp = sumo_get_temp(rdev);
-		break;
-	case THERMAL_TYPE_SI:
-		temp = si_get_temp(rdev);
-		break;
-	default:
+	if (rdev->asic->pm.get_temperature)
+		temp = radeon_get_temperature(rdev);
+	else
 		temp = 0;
-		break;
-	}
 
 	return snprintf(buf, PAGE_SIZE, "%d\n", temp);
 }
@@ -492,8 +475,7 @@ static int radeon_hwmon_init(struct radeon_device *rdev)
 	case THERMAL_TYPE_NI:
 	case THERMAL_TYPE_SUMO:
 	case THERMAL_TYPE_SI:
-		/* No support for TN yet */
-		if (rdev->family == CHIP_ARUBA)
+		if (rdev->asic->pm.get_temperature == NULL)
 			return err;
 		rdev->pm.int_hwmon_dev = hwmon_device_register(rdev->dev);
 		if (IS_ERR(rdev->pm.int_hwmon_dev)) {
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 064/165] drm/radeon: add support for thermal sensor on tn
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (63 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 063/165] drm/radeon: make get_temperature functions a callback alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 065/165] drm/radeon/kms: move ucode defines to a separate header alexdeucher
                   ` (48 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/ni.c          |    8 ++++++++
 drivers/gpu/drm/radeon/nid.h         |    3 +++
 drivers/gpu/drm/radeon/radeon_asic.c |    1 +
 drivers/gpu/drm/radeon/radeon_asic.h |    1 +
 4 files changed, 13 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c
index 8458330..f889461 100644
--- a/drivers/gpu/drm/radeon/ni.c
+++ b/drivers/gpu/drm/radeon/ni.c
@@ -692,6 +692,14 @@ out:
 	return err;
 }
 
+int tn_get_temp(struct radeon_device *rdev)
+{
+	u32 temp = RREG32_SMC(TN_CURRENT_GNB_TEMP) & 0x7ff;
+	int actual_temp = (temp / 8) - 49;
+
+	return actual_temp * 1000;
+}
+
 /*
  * Core functions
  */
diff --git a/drivers/gpu/drm/radeon/nid.h b/drivers/gpu/drm/radeon/nid.h
index e226faf..7b8da52 100644
--- a/drivers/gpu/drm/radeon/nid.h
+++ b/drivers/gpu/drm/radeon/nid.h
@@ -489,6 +489,9 @@
 #       define CACHE_FLUSH_AND_INV_EVENT_TS                     (0x14 << 0)
 #       define CACHE_FLUSH_AND_INV_EVENT                        (0x16 << 0)
 
+/* TN SMU registers */
+#define	TN_CURRENT_GNB_TEMP				0x1F390
+
 /*
  * UVD
  */
diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c
index f127ea2..5736377 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.c
+++ b/drivers/gpu/drm/radeon/radeon_asic.c
@@ -1783,6 +1783,7 @@ static struct radeon_asic trinity_asic = {
 		.set_pcie_lanes = NULL,
 		.set_clock_gating = NULL,
 		.set_uvd_clocks = &sumo_set_uvd_clocks,
+		.get_temperature = &tn_get_temp,
 	},
 	.pflip = {
 		.pre_page_flip = &evergreen_pre_page_flip,
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index f1dcb07..8507cae 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -486,6 +486,7 @@ void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable);
 void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode);
 int evergreen_get_temp(struct radeon_device *rdev);
 int sumo_get_temp(struct radeon_device *rdev);
+int tn_get_temp(struct radeon_device *rdev);
 
 /*
  * cayman
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 065/165] drm/radeon/kms: move ucode defines to a separate header
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (64 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 064/165] drm/radeon: add support for thermal sensor on tn alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 066/165] drm/radeon: properly set up the RLC on ON/LN/TN (v3) alexdeucher
                   ` (47 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Avoids confusion and duplication.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/evergreen.c    |    4 +--
 drivers/gpu/drm/radeon/ni.c           |   13 +--------
 drivers/gpu/drm/radeon/r600.c         |   25 +++++------------
 drivers/gpu/drm/radeon/radeon_ucode.h |   47 +++++++++++++++++++++++++++++++++
 4 files changed, 56 insertions(+), 33 deletions(-)
 create mode 100644 drivers/gpu/drm/radeon/radeon_ucode.h

diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
index 9009dd4..6b559cb5 100644
--- a/drivers/gpu/drm/radeon/evergreen.c
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -33,9 +33,7 @@
 #include "avivod.h"
 #include "evergreen_reg.h"
 #include "evergreen_blit_shaders.h"
-
-#define EVERGREEN_PFP_UCODE_SIZE 1120
-#define EVERGREEN_PM4_UCODE_SIZE 1376
+#include "radeon_ucode.h"
 
 static const u32 crtc_offsets[6] =
 {
diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c
index f889461..9284346 100644
--- a/drivers/gpu/drm/radeon/ni.c
+++ b/drivers/gpu/drm/radeon/ni.c
@@ -33,6 +33,7 @@
 #include "atom.h"
 #include "ni_reg.h"
 #include "cayman_blit_shaders.h"
+#include "radeon_ucode.h"
 
 extern bool evergreen_is_display_hung(struct radeon_device *rdev);
 extern void evergreen_print_gpu_status_regs(struct radeon_device *rdev);
@@ -47,18 +48,6 @@ extern void evergreen_pcie_gen2_enable(struct radeon_device *rdev);
 extern void si_rlc_fini(struct radeon_device *rdev);
 extern int si_rlc_init(struct radeon_device *rdev);
 
-#define EVERGREEN_PFP_UCODE_SIZE 1120
-#define EVERGREEN_PM4_UCODE_SIZE 1376
-#define EVERGREEN_RLC_UCODE_SIZE 768
-#define BTC_MC_UCODE_SIZE 6024
-
-#define CAYMAN_PFP_UCODE_SIZE 2176
-#define CAYMAN_PM4_UCODE_SIZE 2176
-#define CAYMAN_RLC_UCODE_SIZE 1024
-#define CAYMAN_MC_UCODE_SIZE 6037
-
-#define ARUBA_RLC_UCODE_SIZE 1536
-
 /* Firmware Names */
 MODULE_FIRMWARE("radeon/BARTS_pfp.bin");
 MODULE_FIRMWARE("radeon/BARTS_me.bin");
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index 6948eb8..6089261 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -38,18 +38,7 @@
 #include "r600d.h"
 #include "atom.h"
 #include "avivod.h"
-
-#define PFP_UCODE_SIZE 576
-#define PM4_UCODE_SIZE 1792
-#define RLC_UCODE_SIZE 768
-#define R700_PFP_UCODE_SIZE 848
-#define R700_PM4_UCODE_SIZE 1360
-#define R700_RLC_UCODE_SIZE 1024
-#define EVERGREEN_PFP_UCODE_SIZE 1120
-#define EVERGREEN_PM4_UCODE_SIZE 1376
-#define EVERGREEN_RLC_UCODE_SIZE 768
-#define CAYMAN_RLC_UCODE_SIZE 1024
-#define ARUBA_RLC_UCODE_SIZE 1536
+#include "radeon_ucode.h"
 
 /* Firmware Names */
 MODULE_FIRMWARE("radeon/R600_pfp.bin");
@@ -2246,9 +2235,9 @@ int r600_init_microcode(struct radeon_device *rdev)
 		me_req_size = R700_PM4_UCODE_SIZE * 4;
 		rlc_req_size = R700_RLC_UCODE_SIZE * 4;
 	} else {
-		pfp_req_size = PFP_UCODE_SIZE * 4;
-		me_req_size = PM4_UCODE_SIZE * 12;
-		rlc_req_size = RLC_UCODE_SIZE * 4;
+		pfp_req_size = R600_PFP_UCODE_SIZE * 4;
+		me_req_size = R600_PM4_UCODE_SIZE * 12;
+		rlc_req_size = R600_RLC_UCODE_SIZE * 4;
 	}
 
 	DRM_INFO("Loading %s Microcode\n", chip_name);
@@ -2331,13 +2320,13 @@ static int r600_cp_load_microcode(struct radeon_device *rdev)
 
 	fw_data = (const __be32 *)rdev->me_fw->data;
 	WREG32(CP_ME_RAM_WADDR, 0);
-	for (i = 0; i < PM4_UCODE_SIZE * 3; i++)
+	for (i = 0; i < R600_PM4_UCODE_SIZE * 3; i++)
 		WREG32(CP_ME_RAM_DATA,
 		       be32_to_cpup(fw_data++));
 
 	fw_data = (const __be32 *)rdev->pfp_fw->data;
 	WREG32(CP_PFP_UCODE_ADDR, 0);
-	for (i = 0; i < PFP_UCODE_SIZE; i++)
+	for (i = 0; i < R600_PFP_UCODE_SIZE; i++)
 		WREG32(CP_PFP_UCODE_DATA,
 		       be32_to_cpup(fw_data++));
 
@@ -3839,7 +3828,7 @@ static int r600_rlc_init(struct radeon_device *rdev)
 			WREG32(RLC_UCODE_DATA, be32_to_cpup(fw_data++));
 		}
 	} else {
-		for (i = 0; i < RLC_UCODE_SIZE; i++) {
+		for (i = 0; i < R600_RLC_UCODE_SIZE; i++) {
 			WREG32(RLC_UCODE_ADDR, i);
 			WREG32(RLC_UCODE_DATA, be32_to_cpup(fw_data++));
 		}
diff --git a/drivers/gpu/drm/radeon/radeon_ucode.h b/drivers/gpu/drm/radeon/radeon_ucode.h
new file mode 100644
index 0000000..d2642b0
--- /dev/null
+++ b/drivers/gpu/drm/radeon/radeon_ucode.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2012 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef __RADEON_UCODE_H__
+#define __RADEON_UCODE_H__
+
+/* CP */
+#define R600_PFP_UCODE_SIZE          576
+#define R600_PM4_UCODE_SIZE          1792
+#define R700_PFP_UCODE_SIZE          848
+#define R700_PM4_UCODE_SIZE          1360
+#define EVERGREEN_PFP_UCODE_SIZE     1120
+#define EVERGREEN_PM4_UCODE_SIZE     1376
+#define CAYMAN_PFP_UCODE_SIZE        2176
+#define CAYMAN_PM4_UCODE_SIZE        2176
+
+/* RLC */
+#define R600_RLC_UCODE_SIZE          768
+#define R700_RLC_UCODE_SIZE          1024
+#define EVERGREEN_RLC_UCODE_SIZE     768
+#define CAYMAN_RLC_UCODE_SIZE        1024
+#define ARUBA_RLC_UCODE_SIZE         1536
+
+/* MC */
+#define BTC_MC_UCODE_SIZE            6024
+#define CAYMAN_MC_UCODE_SIZE         6037
+
+#endif
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 066/165] drm/radeon: properly set up the RLC on ON/LN/TN (v3)
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (65 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 065/165] drm/radeon/kms: move ucode defines to a separate header alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 067/165] drm/radeon/kms: add atom helper functions for dpm (v3) alexdeucher
                   ` (46 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

This is required for certain advanced functionality.

v2: save/restore list takes dword offsets
v3: rebase on gpu reset changes

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/clearstate_cayman.h    | 1081 +++++++++++++++++++++++++
 drivers/gpu/drm/radeon/clearstate_defs.h      |   44 +
 drivers/gpu/drm/radeon/clearstate_evergreen.h | 1080 ++++++++++++++++++++++++
 drivers/gpu/drm/radeon/evergreen.c            |  339 ++++++++
 drivers/gpu/drm/radeon/evergreend.h           |   19 +
 drivers/gpu/drm/radeon/ni.c                   |  141 ++++-
 drivers/gpu/drm/radeon/r600.c                 |   43 +-
 drivers/gpu/drm/radeon/r600d.h                |    4 -
 drivers/gpu/drm/radeon/radeon.h               |   13 +-
 9 files changed, 2721 insertions(+), 43 deletions(-)
 create mode 100644 drivers/gpu/drm/radeon/clearstate_cayman.h
 create mode 100644 drivers/gpu/drm/radeon/clearstate_defs.h
 create mode 100644 drivers/gpu/drm/radeon/clearstate_evergreen.h

diff --git a/drivers/gpu/drm/radeon/clearstate_cayman.h b/drivers/gpu/drm/radeon/clearstate_cayman.h
new file mode 100644
index 0000000..c003394
--- /dev/null
+++ b/drivers/gpu/drm/radeon/clearstate_cayman.h
@@ -0,0 +1,1081 @@
+/*
+ * Copyright 2012 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+static const u32 SECT_CONTEXT_def_1[] =
+{
+    0x00000000, // DB_RENDER_CONTROL
+    0x00000000, // DB_COUNT_CONTROL
+    0x00000000, // DB_DEPTH_VIEW
+    0x00000000, // DB_RENDER_OVERRIDE
+    0x00000000, // DB_RENDER_OVERRIDE2
+    0x00000000, // DB_HTILE_DATA_BASE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // DB_STENCIL_CLEAR
+    0x00000000, // DB_DEPTH_CLEAR
+    0x00000000, // PA_SC_SCREEN_SCISSOR_TL
+    0x40004000, // PA_SC_SCREEN_SCISSOR_BR
+    0, // HOLE
+    0x00000000, // DB_DEPTH_INFO
+    0x00000000, // DB_Z_INFO
+    0x00000000, // DB_STENCIL_INFO
+    0x00000000, // DB_Z_READ_BASE
+    0x00000000, // DB_STENCIL_READ_BASE
+    0x00000000, // DB_Z_WRITE_BASE
+    0x00000000, // DB_STENCIL_WRITE_BASE
+    0x00000000, // DB_DEPTH_SIZE
+    0x00000000, // DB_DEPTH_SLICE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_0
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_1
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_2
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_3
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_4
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_5
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_6
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_7
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_8
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_9
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_10
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_11
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_12
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_13
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_14
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_15
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_0
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_1
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_2
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_3
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_4
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_5
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_6
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_7
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_8
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_9
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_10
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_11
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_12
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_13
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_14
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_15
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_0
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_1
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_2
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_3
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_4
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_5
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_6
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_7
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_8
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_9
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_10
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_11
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_12
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_13
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_14
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_15
+    0x00000000, // PA_SC_WINDOW_OFFSET
+    0x80000000, // PA_SC_WINDOW_SCISSOR_TL
+    0x40004000, // PA_SC_WINDOW_SCISSOR_BR
+    0x0000ffff, // PA_SC_CLIPRECT_RULE
+    0x00000000, // PA_SC_CLIPRECT_0_TL
+    0x40004000, // PA_SC_CLIPRECT_0_BR
+    0x00000000, // PA_SC_CLIPRECT_1_TL
+    0x40004000, // PA_SC_CLIPRECT_1_BR
+    0x00000000, // PA_SC_CLIPRECT_2_TL
+    0x40004000, // PA_SC_CLIPRECT_2_BR
+    0x00000000, // PA_SC_CLIPRECT_3_TL
+    0x40004000, // PA_SC_CLIPRECT_3_BR
+    0xaa99aaaa, // PA_SC_EDGERULE
+    0x00000000, // PA_SU_HARDWARE_SCREEN_OFFSET
+    0xffffffff, // CB_TARGET_MASK
+    0xffffffff, // CB_SHADER_MASK
+    0x80000000, // PA_SC_GENERIC_SCISSOR_TL
+    0x40004000, // PA_SC_GENERIC_SCISSOR_BR
+    0x00000000, // COHER_DEST_BASE_0
+    0x00000000, // COHER_DEST_BASE_1
+    0x80000000, // PA_SC_VPORT_SCISSOR_0_TL
+    0x40004000, // PA_SC_VPORT_SCISSOR_0_BR
+    0x80000000, // PA_SC_VPORT_SCISSOR_1_TL
+    0x40004000, // PA_SC_VPORT_SCISSOR_1_BR
+    0x80000000, // PA_SC_VPORT_SCISSOR_2_TL
+    0x40004000, // PA_SC_VPORT_SCISSOR_2_BR
+    0x80000000, // PA_SC_VPORT_SCISSOR_3_TL
+    0x40004000, // PA_SC_VPORT_SCISSOR_3_BR
+    0x80000000, // PA_SC_VPORT_SCISSOR_4_TL
+    0x40004000, // PA_SC_VPORT_SCISSOR_4_BR
+    0x80000000, // PA_SC_VPORT_SCISSOR_5_TL
+    0x40004000, // PA_SC_VPORT_SCISSOR_5_BR
+    0x80000000, // PA_SC_VPORT_SCISSOR_6_TL
+    0x40004000, // PA_SC_VPORT_SCISSOR_6_BR
+    0x80000000, // PA_SC_VPORT_SCISSOR_7_TL
+    0x40004000, // PA_SC_VPORT_SCISSOR_7_BR
+    0x80000000, // PA_SC_VPORT_SCISSOR_8_TL
+    0x40004000, // PA_SC_VPORT_SCISSOR_8_BR
+    0x80000000, // PA_SC_VPORT_SCISSOR_9_TL
+    0x40004000, // PA_SC_VPORT_SCISSOR_9_BR
+    0x80000000, // PA_SC_VPORT_SCISSOR_10_TL
+    0x40004000, // PA_SC_VPORT_SCISSOR_10_BR
+    0x80000000, // PA_SC_VPORT_SCISSOR_11_TL
+    0x40004000, // PA_SC_VPORT_SCISSOR_11_BR
+    0x80000000, // PA_SC_VPORT_SCISSOR_12_TL
+    0x40004000, // PA_SC_VPORT_SCISSOR_12_BR
+    0x80000000, // PA_SC_VPORT_SCISSOR_13_TL
+    0x40004000, // PA_SC_VPORT_SCISSOR_13_BR
+    0x80000000, // PA_SC_VPORT_SCISSOR_14_TL
+    0x40004000, // PA_SC_VPORT_SCISSOR_14_BR
+    0x80000000, // PA_SC_VPORT_SCISSOR_15_TL
+    0x40004000, // PA_SC_VPORT_SCISSOR_15_BR
+    0x00000000, // PA_SC_VPORT_ZMIN_0
+    0x3f800000, // PA_SC_VPORT_ZMAX_0
+    0x00000000, // PA_SC_VPORT_ZMIN_1
+    0x3f800000, // PA_SC_VPORT_ZMAX_1
+    0x00000000, // PA_SC_VPORT_ZMIN_2
+    0x3f800000, // PA_SC_VPORT_ZMAX_2
+    0x00000000, // PA_SC_VPORT_ZMIN_3
+    0x3f800000, // PA_SC_VPORT_ZMAX_3
+    0x00000000, // PA_SC_VPORT_ZMIN_4
+    0x3f800000, // PA_SC_VPORT_ZMAX_4
+    0x00000000, // PA_SC_VPORT_ZMIN_5
+    0x3f800000, // PA_SC_VPORT_ZMAX_5
+    0x00000000, // PA_SC_VPORT_ZMIN_6
+    0x3f800000, // PA_SC_VPORT_ZMAX_6
+    0x00000000, // PA_SC_VPORT_ZMIN_7
+    0x3f800000, // PA_SC_VPORT_ZMAX_7
+    0x00000000, // PA_SC_VPORT_ZMIN_8
+    0x3f800000, // PA_SC_VPORT_ZMAX_8
+    0x00000000, // PA_SC_VPORT_ZMIN_9
+    0x3f800000, // PA_SC_VPORT_ZMAX_9
+    0x00000000, // PA_SC_VPORT_ZMIN_10
+    0x3f800000, // PA_SC_VPORT_ZMAX_10
+    0x00000000, // PA_SC_VPORT_ZMIN_11
+    0x3f800000, // PA_SC_VPORT_ZMAX_11
+    0x00000000, // PA_SC_VPORT_ZMIN_12
+    0x3f800000, // PA_SC_VPORT_ZMAX_12
+    0x00000000, // PA_SC_VPORT_ZMIN_13
+    0x3f800000, // PA_SC_VPORT_ZMAX_13
+    0x00000000, // PA_SC_VPORT_ZMIN_14
+    0x3f800000, // PA_SC_VPORT_ZMAX_14
+    0x00000000, // PA_SC_VPORT_ZMIN_15
+    0x3f800000, // PA_SC_VPORT_ZMAX_15
+    0x00000000, // SX_MISC
+    0x00000000, // SX_SURFACE_SYNC
+    0x00000000, // SX_SCATTER_EXPORT_BASE
+    0x00000000, // SX_SCATTER_EXPORT_SIZE
+    0x00000000, // CP_PERFMON_CNTX_CNTL
+    0x00000000, // CP_RINGID
+    0x00000000, // CP_VMID
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // SQ_VTX_SEMANTIC_0
+    0x00000000, // SQ_VTX_SEMANTIC_1
+    0x00000000, // SQ_VTX_SEMANTIC_2
+    0x00000000, // SQ_VTX_SEMANTIC_3
+    0x00000000, // SQ_VTX_SEMANTIC_4
+    0x00000000, // SQ_VTX_SEMANTIC_5
+    0x00000000, // SQ_VTX_SEMANTIC_6
+    0x00000000, // SQ_VTX_SEMANTIC_7
+    0x00000000, // SQ_VTX_SEMANTIC_8
+    0x00000000, // SQ_VTX_SEMANTIC_9
+    0x00000000, // SQ_VTX_SEMANTIC_10
+    0x00000000, // SQ_VTX_SEMANTIC_11
+    0x00000000, // SQ_VTX_SEMANTIC_12
+    0x00000000, // SQ_VTX_SEMANTIC_13
+    0x00000000, // SQ_VTX_SEMANTIC_14
+    0x00000000, // SQ_VTX_SEMANTIC_15
+    0x00000000, // SQ_VTX_SEMANTIC_16
+    0x00000000, // SQ_VTX_SEMANTIC_17
+    0x00000000, // SQ_VTX_SEMANTIC_18
+    0x00000000, // SQ_VTX_SEMANTIC_19
+    0x00000000, // SQ_VTX_SEMANTIC_20
+    0x00000000, // SQ_VTX_SEMANTIC_21
+    0x00000000, // SQ_VTX_SEMANTIC_22
+    0x00000000, // SQ_VTX_SEMANTIC_23
+    0x00000000, // SQ_VTX_SEMANTIC_24
+    0x00000000, // SQ_VTX_SEMANTIC_25
+    0x00000000, // SQ_VTX_SEMANTIC_26
+    0x00000000, // SQ_VTX_SEMANTIC_27
+    0x00000000, // SQ_VTX_SEMANTIC_28
+    0x00000000, // SQ_VTX_SEMANTIC_29
+    0x00000000, // SQ_VTX_SEMANTIC_30
+    0x00000000, // SQ_VTX_SEMANTIC_31
+    0xffffffff, // VGT_MAX_VTX_INDX
+    0x00000000, // VGT_MIN_VTX_INDX
+    0x00000000, // VGT_INDX_OFFSET
+    0x00000000, // VGT_MULTI_PRIM_IB_RESET_INDX
+    0x00000000, // SX_ALPHA_TEST_CONTROL
+    0x00000000, // CB_BLEND_RED
+    0x00000000, // CB_BLEND_GREEN
+    0x00000000, // CB_BLEND_BLUE
+    0x00000000, // CB_BLEND_ALPHA
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // DB_STENCILREFMASK
+    0x00000000, // DB_STENCILREFMASK_BF
+    0x00000000, // SX_ALPHA_REF
+    0x00000000, // PA_CL_VPORT_XSCALE
+    0x00000000, // PA_CL_VPORT_XOFFSET
+    0x00000000, // PA_CL_VPORT_YSCALE
+    0x00000000, // PA_CL_VPORT_YOFFSET
+    0x00000000, // PA_CL_VPORT_ZSCALE
+    0x00000000, // PA_CL_VPORT_ZOFFSET
+    0x00000000, // PA_CL_VPORT_XSCALE_1
+    0x00000000, // PA_CL_VPORT_XOFFSET_1
+    0x00000000, // PA_CL_VPORT_YSCALE_1
+    0x00000000, // PA_CL_VPORT_YOFFSET_1
+    0x00000000, // PA_CL_VPORT_ZSCALE_1
+    0x00000000, // PA_CL_VPORT_ZOFFSET_1
+    0x00000000, // PA_CL_VPORT_XSCALE_2
+    0x00000000, // PA_CL_VPORT_XOFFSET_2
+    0x00000000, // PA_CL_VPORT_YSCALE_2
+    0x00000000, // PA_CL_VPORT_YOFFSET_2
+    0x00000000, // PA_CL_VPORT_ZSCALE_2
+    0x00000000, // PA_CL_VPORT_ZOFFSET_2
+    0x00000000, // PA_CL_VPORT_XSCALE_3
+    0x00000000, // PA_CL_VPORT_XOFFSET_3
+    0x00000000, // PA_CL_VPORT_YSCALE_3
+    0x00000000, // PA_CL_VPORT_YOFFSET_3
+    0x00000000, // PA_CL_VPORT_ZSCALE_3
+    0x00000000, // PA_CL_VPORT_ZOFFSET_3
+    0x00000000, // PA_CL_VPORT_XSCALE_4
+    0x00000000, // PA_CL_VPORT_XOFFSET_4
+    0x00000000, // PA_CL_VPORT_YSCALE_4
+    0x00000000, // PA_CL_VPORT_YOFFSET_4
+    0x00000000, // PA_CL_VPORT_ZSCALE_4
+    0x00000000, // PA_CL_VPORT_ZOFFSET_4
+    0x00000000, // PA_CL_VPORT_XSCALE_5
+    0x00000000, // PA_CL_VPORT_XOFFSET_5
+    0x00000000, // PA_CL_VPORT_YSCALE_5
+    0x00000000, // PA_CL_VPORT_YOFFSET_5
+    0x00000000, // PA_CL_VPORT_ZSCALE_5
+    0x00000000, // PA_CL_VPORT_ZOFFSET_5
+    0x00000000, // PA_CL_VPORT_XSCALE_6
+    0x00000000, // PA_CL_VPORT_XOFFSET_6
+    0x00000000, // PA_CL_VPORT_YSCALE_6
+    0x00000000, // PA_CL_VPORT_YOFFSET_6
+    0x00000000, // PA_CL_VPORT_ZSCALE_6
+    0x00000000, // PA_CL_VPORT_ZOFFSET_6
+    0x00000000, // PA_CL_VPORT_XSCALE_7
+    0x00000000, // PA_CL_VPORT_XOFFSET_7
+    0x00000000, // PA_CL_VPORT_YSCALE_7
+    0x00000000, // PA_CL_VPORT_YOFFSET_7
+    0x00000000, // PA_CL_VPORT_ZSCALE_7
+    0x00000000, // PA_CL_VPORT_ZOFFSET_7
+    0x00000000, // PA_CL_VPORT_XSCALE_8
+    0x00000000, // PA_CL_VPORT_XOFFSET_8
+    0x00000000, // PA_CL_VPORT_YSCALE_8
+    0x00000000, // PA_CL_VPORT_YOFFSET_8
+    0x00000000, // PA_CL_VPORT_ZSCALE_8
+    0x00000000, // PA_CL_VPORT_ZOFFSET_8
+    0x00000000, // PA_CL_VPORT_XSCALE_9
+    0x00000000, // PA_CL_VPORT_XOFFSET_9
+    0x00000000, // PA_CL_VPORT_YSCALE_9
+    0x00000000, // PA_CL_VPORT_YOFFSET_9
+    0x00000000, // PA_CL_VPORT_ZSCALE_9
+    0x00000000, // PA_CL_VPORT_ZOFFSET_9
+    0x00000000, // PA_CL_VPORT_XSCALE_10
+    0x00000000, // PA_CL_VPORT_XOFFSET_10
+    0x00000000, // PA_CL_VPORT_YSCALE_10
+    0x00000000, // PA_CL_VPORT_YOFFSET_10
+    0x00000000, // PA_CL_VPORT_ZSCALE_10
+    0x00000000, // PA_CL_VPORT_ZOFFSET_10
+    0x00000000, // PA_CL_VPORT_XSCALE_11
+    0x00000000, // PA_CL_VPORT_XOFFSET_11
+    0x00000000, // PA_CL_VPORT_YSCALE_11
+    0x00000000, // PA_CL_VPORT_YOFFSET_11
+    0x00000000, // PA_CL_VPORT_ZSCALE_11
+    0x00000000, // PA_CL_VPORT_ZOFFSET_11
+    0x00000000, // PA_CL_VPORT_XSCALE_12
+    0x00000000, // PA_CL_VPORT_XOFFSET_12
+    0x00000000, // PA_CL_VPORT_YSCALE_12
+    0x00000000, // PA_CL_VPORT_YOFFSET_12
+    0x00000000, // PA_CL_VPORT_ZSCALE_12
+    0x00000000, // PA_CL_VPORT_ZOFFSET_12
+    0x00000000, // PA_CL_VPORT_XSCALE_13
+    0x00000000, // PA_CL_VPORT_XOFFSET_13
+    0x00000000, // PA_CL_VPORT_YSCALE_13
+    0x00000000, // PA_CL_VPORT_YOFFSET_13
+    0x00000000, // PA_CL_VPORT_ZSCALE_13
+    0x00000000, // PA_CL_VPORT_ZOFFSET_13
+    0x00000000, // PA_CL_VPORT_XSCALE_14
+    0x00000000, // PA_CL_VPORT_XOFFSET_14
+    0x00000000, // PA_CL_VPORT_YSCALE_14
+    0x00000000, // PA_CL_VPORT_YOFFSET_14
+    0x00000000, // PA_CL_VPORT_ZSCALE_14
+    0x00000000, // PA_CL_VPORT_ZOFFSET_14
+    0x00000000, // PA_CL_VPORT_XSCALE_15
+    0x00000000, // PA_CL_VPORT_XOFFSET_15
+    0x00000000, // PA_CL_VPORT_YSCALE_15
+    0x00000000, // PA_CL_VPORT_YOFFSET_15
+    0x00000000, // PA_CL_VPORT_ZSCALE_15
+    0x00000000, // PA_CL_VPORT_ZOFFSET_15
+    0x00000000, // PA_CL_UCP_0_X
+    0x00000000, // PA_CL_UCP_0_Y
+    0x00000000, // PA_CL_UCP_0_Z
+    0x00000000, // PA_CL_UCP_0_W
+    0x00000000, // PA_CL_UCP_1_X
+    0x00000000, // PA_CL_UCP_1_Y
+    0x00000000, // PA_CL_UCP_1_Z
+    0x00000000, // PA_CL_UCP_1_W
+    0x00000000, // PA_CL_UCP_2_X
+    0x00000000, // PA_CL_UCP_2_Y
+    0x00000000, // PA_CL_UCP_2_Z
+    0x00000000, // PA_CL_UCP_2_W
+    0x00000000, // PA_CL_UCP_3_X
+    0x00000000, // PA_CL_UCP_3_Y
+    0x00000000, // PA_CL_UCP_3_Z
+    0x00000000, // PA_CL_UCP_3_W
+    0x00000000, // PA_CL_UCP_4_X
+    0x00000000, // PA_CL_UCP_4_Y
+    0x00000000, // PA_CL_UCP_4_Z
+    0x00000000, // PA_CL_UCP_4_W
+    0x00000000, // PA_CL_UCP_5_X
+    0x00000000, // PA_CL_UCP_5_Y
+    0x00000000, // PA_CL_UCP_5_Z
+    0x00000000, // PA_CL_UCP_5_W
+    0x00000000, // SPI_VS_OUT_ID_0
+    0x00000000, // SPI_VS_OUT_ID_1
+    0x00000000, // SPI_VS_OUT_ID_2
+    0x00000000, // SPI_VS_OUT_ID_3
+    0x00000000, // SPI_VS_OUT_ID_4
+    0x00000000, // SPI_VS_OUT_ID_5
+    0x00000000, // SPI_VS_OUT_ID_6
+    0x00000000, // SPI_VS_OUT_ID_7
+    0x00000000, // SPI_VS_OUT_ID_8
+    0x00000000, // SPI_VS_OUT_ID_9
+    0x00000000, // SPI_PS_INPUT_CNTL_0
+    0x00000000, // SPI_PS_INPUT_CNTL_1
+    0x00000000, // SPI_PS_INPUT_CNTL_2
+    0x00000000, // SPI_PS_INPUT_CNTL_3
+    0x00000000, // SPI_PS_INPUT_CNTL_4
+    0x00000000, // SPI_PS_INPUT_CNTL_5
+    0x00000000, // SPI_PS_INPUT_CNTL_6
+    0x00000000, // SPI_PS_INPUT_CNTL_7
+    0x00000000, // SPI_PS_INPUT_CNTL_8
+    0x00000000, // SPI_PS_INPUT_CNTL_9
+    0x00000000, // SPI_PS_INPUT_CNTL_10
+    0x00000000, // SPI_PS_INPUT_CNTL_11
+    0x00000000, // SPI_PS_INPUT_CNTL_12
+    0x00000000, // SPI_PS_INPUT_CNTL_13
+    0x00000000, // SPI_PS_INPUT_CNTL_14
+    0x00000000, // SPI_PS_INPUT_CNTL_15
+    0x00000000, // SPI_PS_INPUT_CNTL_16
+    0x00000000, // SPI_PS_INPUT_CNTL_17
+    0x00000000, // SPI_PS_INPUT_CNTL_18
+    0x00000000, // SPI_PS_INPUT_CNTL_19
+    0x00000000, // SPI_PS_INPUT_CNTL_20
+    0x00000000, // SPI_PS_INPUT_CNTL_21
+    0x00000000, // SPI_PS_INPUT_CNTL_22
+    0x00000000, // SPI_PS_INPUT_CNTL_23
+    0x00000000, // SPI_PS_INPUT_CNTL_24
+    0x00000000, // SPI_PS_INPUT_CNTL_25
+    0x00000000, // SPI_PS_INPUT_CNTL_26
+    0x00000000, // SPI_PS_INPUT_CNTL_27
+    0x00000000, // SPI_PS_INPUT_CNTL_28
+    0x00000000, // SPI_PS_INPUT_CNTL_29
+    0x00000000, // SPI_PS_INPUT_CNTL_30
+    0x00000000, // SPI_PS_INPUT_CNTL_31
+    0x00000000, // SPI_VS_OUT_CONFIG
+    0x00000001, // SPI_THREAD_GROUPING
+    0x00000002, // SPI_PS_IN_CONTROL_0
+    0x00000000, // SPI_PS_IN_CONTROL_1
+    0x00000000, // SPI_INTERP_CONTROL_0
+    0x00000000, // SPI_INPUT_Z
+    0x00000000, // SPI_FOG_CNTL
+    0x00000000, // SPI_BARYC_CNTL
+    0x00000000, // SPI_PS_IN_CONTROL_2
+    0x00000000, // SPI_COMPUTE_INPUT_CNTL
+    0x00000000, // SPI_COMPUTE_NUM_THREAD_X
+    0x00000000, // SPI_COMPUTE_NUM_THREAD_Y
+    0x00000000, // SPI_COMPUTE_NUM_THREAD_Z
+    0x00000000, // SPI_GPR_MGMT
+    0x00000000, // SPI_LDS_MGMT
+    0x00000000, // SPI_STACK_MGMT
+    0x00000000, // SPI_WAVE_MGMT_1
+    0x00000000, // SPI_WAVE_MGMT_2
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // GDS_ADDR_BASE
+    0x00003fff, // GDS_ADDR_SIZE
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // GDS_ORDERED_COUNT
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // GDS_APPEND_CONSUME_UAV0
+    0x00000000, // GDS_APPEND_CONSUME_UAV1
+    0x00000000, // GDS_APPEND_CONSUME_UAV2
+    0x00000000, // GDS_APPEND_CONSUME_UAV3
+    0x00000000, // GDS_APPEND_CONSUME_UAV4
+    0x00000000, // GDS_APPEND_CONSUME_UAV5
+    0x00000000, // GDS_APPEND_CONSUME_UAV6
+    0x00000000, // GDS_APPEND_CONSUME_UAV7
+    0x00000000, // GDS_APPEND_CONSUME_UAV8
+    0x00000000, // GDS_APPEND_CONSUME_UAV9
+    0x00000000, // GDS_APPEND_CONSUME_UAV10
+    0x00000000, // GDS_APPEND_CONSUME_UAV11
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // CB_BLEND0_CONTROL
+    0x00000000, // CB_BLEND1_CONTROL
+    0x00000000, // CB_BLEND2_CONTROL
+    0x00000000, // CB_BLEND3_CONTROL
+    0x00000000, // CB_BLEND4_CONTROL
+    0x00000000, // CB_BLEND5_CONTROL
+    0x00000000, // CB_BLEND6_CONTROL
+    0x00000000, // CB_BLEND7_CONTROL
+};
+static const u32 SECT_CONTEXT_def_2[] =
+{
+    0x00000000, // PA_CL_POINT_X_RAD
+    0x00000000, // PA_CL_POINT_Y_RAD
+    0x00000000, // PA_CL_POINT_SIZE
+    0x00000000, // PA_CL_POINT_CULL_RAD
+    0x00000000, // VGT_DMA_BASE_HI
+    0x00000000, // VGT_DMA_BASE
+};
+static const u32 SECT_CONTEXT_def_3[] =
+{
+    0x00000000, // DB_DEPTH_CONTROL
+    0x00000000, // DB_EQAA
+    0x00000000, // CB_COLOR_CONTROL
+    0x00000200, // DB_SHADER_CONTROL
+    0x00000000, // PA_CL_CLIP_CNTL
+    0x00000000, // PA_SU_SC_MODE_CNTL
+    0x00000000, // PA_CL_VTE_CNTL
+    0x00000000, // PA_CL_VS_OUT_CNTL
+    0x00000000, // PA_CL_NANINF_CNTL
+    0x00000000, // PA_SU_LINE_STIPPLE_CNTL
+    0x00000000, // PA_SU_LINE_STIPPLE_SCALE
+    0x00000000, // PA_SU_PRIM_FILTER_CNTL
+    0x00000000, // SQ_LSTMP_RING_ITEMSIZE
+    0x00000000, // SQ_HSTMP_RING_ITEMSIZE
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // SQ_PGM_START_PS
+    0x00000000, // SQ_PGM_RESOURCES_PS
+    0x00000000, // SQ_PGM_RESOURCES_2_PS
+    0x00000000, // SQ_PGM_EXPORTS_PS
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // SQ_PGM_START_VS
+    0x00000000, // SQ_PGM_RESOURCES_VS
+    0x00000000, // SQ_PGM_RESOURCES_2_VS
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // SQ_PGM_START_GS
+    0x00000000, // SQ_PGM_RESOURCES_GS
+    0x00000000, // SQ_PGM_RESOURCES_2_GS
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // SQ_PGM_START_ES
+    0x00000000, // SQ_PGM_RESOURCES_ES
+    0x00000000, // SQ_PGM_RESOURCES_2_ES
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // SQ_PGM_START_FS
+    0x00000000, // SQ_PGM_RESOURCES_FS
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // SQ_PGM_START_HS
+    0x00000000, // SQ_PGM_RESOURCES_HS
+    0x00000000, // SQ_PGM_RESOURCES_2_HS
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // SQ_PGM_START_LS
+    0x00000000, // SQ_PGM_RESOURCES_LS
+    0x00000000, // SQ_PGM_RESOURCES_2_LS
+};
+static const u32 SECT_CONTEXT_def_4[] =
+{
+    0x00000000, // SQ_LDS_ALLOC
+    0x00000000, // SQ_LDS_ALLOC_PS
+    0x00000000, // SQ_VTX_SEMANTIC_CLEAR
+    0, // HOLE
+    0x00000000, // SQ_THREAD_TRACE_CTRL
+    0, // HOLE
+    0x00000000, // SQ_ESGS_RING_ITEMSIZE
+    0x00000000, // SQ_GSVS_RING_ITEMSIZE
+    0x00000000, // SQ_ESTMP_RING_ITEMSIZE
+    0x00000000, // SQ_GSTMP_RING_ITEMSIZE
+    0x00000000, // SQ_VSTMP_RING_ITEMSIZE
+    0x00000000, // SQ_PSTMP_RING_ITEMSIZE
+    0, // HOLE
+    0x00000000, // SQ_GS_VERT_ITEMSIZE
+    0x00000000, // SQ_GS_VERT_ITEMSIZE_1
+    0x00000000, // SQ_GS_VERT_ITEMSIZE_2
+    0x00000000, // SQ_GS_VERT_ITEMSIZE_3
+    0x00000000, // SQ_GSVS_RING_OFFSET_1
+    0x00000000, // SQ_GSVS_RING_OFFSET_2
+    0x00000000, // SQ_GSVS_RING_OFFSET_3
+    0x00000000, // SQ_GWS_RING_OFFSET
+    0, // HOLE
+    0x00000000, // SQ_ALU_CONST_CACHE_PS_0
+    0x00000000, // SQ_ALU_CONST_CACHE_PS_1
+    0x00000000, // SQ_ALU_CONST_CACHE_PS_2
+    0x00000000, // SQ_ALU_CONST_CACHE_PS_3
+    0x00000000, // SQ_ALU_CONST_CACHE_PS_4
+    0x00000000, // SQ_ALU_CONST_CACHE_PS_5
+    0x00000000, // SQ_ALU_CONST_CACHE_PS_6
+    0x00000000, // SQ_ALU_CONST_CACHE_PS_7
+    0x00000000, // SQ_ALU_CONST_CACHE_PS_8
+    0x00000000, // SQ_ALU_CONST_CACHE_PS_9
+    0x00000000, // SQ_ALU_CONST_CACHE_PS_10
+    0x00000000, // SQ_ALU_CONST_CACHE_PS_11
+    0x00000000, // SQ_ALU_CONST_CACHE_PS_12
+    0x00000000, // SQ_ALU_CONST_CACHE_PS_13
+    0x00000000, // SQ_ALU_CONST_CACHE_PS_14
+    0x00000000, // SQ_ALU_CONST_CACHE_PS_15
+    0x00000000, // SQ_ALU_CONST_CACHE_VS_0
+    0x00000000, // SQ_ALU_CONST_CACHE_VS_1
+    0x00000000, // SQ_ALU_CONST_CACHE_VS_2
+    0x00000000, // SQ_ALU_CONST_CACHE_VS_3
+    0x00000000, // SQ_ALU_CONST_CACHE_VS_4
+    0x00000000, // SQ_ALU_CONST_CACHE_VS_5
+    0x00000000, // SQ_ALU_CONST_CACHE_VS_6
+    0x00000000, // SQ_ALU_CONST_CACHE_VS_7
+    0x00000000, // SQ_ALU_CONST_CACHE_VS_8
+    0x00000000, // SQ_ALU_CONST_CACHE_VS_9
+    0x00000000, // SQ_ALU_CONST_CACHE_VS_10
+    0x00000000, // SQ_ALU_CONST_CACHE_VS_11
+    0x00000000, // SQ_ALU_CONST_CACHE_VS_12
+    0x00000000, // SQ_ALU_CONST_CACHE_VS_13
+    0x00000000, // SQ_ALU_CONST_CACHE_VS_14
+    0x00000000, // SQ_ALU_CONST_CACHE_VS_15
+    0x00000000, // SQ_ALU_CONST_CACHE_GS_0
+    0x00000000, // SQ_ALU_CONST_CACHE_GS_1
+    0x00000000, // SQ_ALU_CONST_CACHE_GS_2
+    0x00000000, // SQ_ALU_CONST_CACHE_GS_3
+    0x00000000, // SQ_ALU_CONST_CACHE_GS_4
+    0x00000000, // SQ_ALU_CONST_CACHE_GS_5
+    0x00000000, // SQ_ALU_CONST_CACHE_GS_6
+    0x00000000, // SQ_ALU_CONST_CACHE_GS_7
+    0x00000000, // SQ_ALU_CONST_CACHE_GS_8
+    0x00000000, // SQ_ALU_CONST_CACHE_GS_9
+    0x00000000, // SQ_ALU_CONST_CACHE_GS_10
+    0x00000000, // SQ_ALU_CONST_CACHE_GS_11
+    0x00000000, // SQ_ALU_CONST_CACHE_GS_12
+    0x00000000, // SQ_ALU_CONST_CACHE_GS_13
+    0x00000000, // SQ_ALU_CONST_CACHE_GS_14
+    0x00000000, // SQ_ALU_CONST_CACHE_GS_15
+    0x00000000, // PA_SU_POINT_SIZE
+    0x00000000, // PA_SU_POINT_MINMAX
+    0x00000000, // PA_SU_LINE_CNTL
+    0x00000000, // PA_SC_LINE_STIPPLE
+    0x00000000, // VGT_OUTPUT_PATH_CNTL
+    0x00000000, // VGT_HOS_CNTL
+    0x00000000, // VGT_HOS_MAX_TESS_LEVEL
+    0x00000000, // VGT_HOS_MIN_TESS_LEVEL
+    0x00000000, // VGT_HOS_REUSE_DEPTH
+    0x00000000, // VGT_GROUP_PRIM_TYPE
+    0x00000000, // VGT_GROUP_FIRST_DECR
+    0x00000000, // VGT_GROUP_DECR
+    0x00000000, // VGT_GROUP_VECT_0_CNTL
+    0x00000000, // VGT_GROUP_VECT_1_CNTL
+    0x00000000, // VGT_GROUP_VECT_0_FMT_CNTL
+    0x00000000, // VGT_GROUP_VECT_1_FMT_CNTL
+    0x00000000, // VGT_GS_MODE
+    0, // HOLE
+    0x00000000, // PA_SC_MODE_CNTL_0
+    0x00000000, // PA_SC_MODE_CNTL_1
+    0x00000000, // VGT_ENHANCE
+    0x00000100, // VGT_GS_PER_ES
+    0x00000080, // VGT_ES_PER_GS
+    0x00000002, // VGT_GS_PER_VS
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // VGT_GS_OUT_PRIM_TYPE
+    0x00000000, // IA_ENHANCE
+};
+static const u32 SECT_CONTEXT_def_5[] =
+{
+    0x00000000, // VGT_DMA_MAX_SIZE
+    0x00000000, // VGT_DMA_INDEX_TYPE
+    0, // HOLE
+    0x00000000, // VGT_PRIMITIVEID_EN
+    0x00000000, // VGT_DMA_NUM_INSTANCES
+};
+static const u32 SECT_CONTEXT_def_6[] =
+{
+    0x00000000, // VGT_MULTI_PRIM_IB_RESET_EN
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // VGT_INSTANCE_STEP_RATE_0
+    0x00000000, // VGT_INSTANCE_STEP_RATE_1
+    0x000000ff, // IA_MULTI_VGT_PARAM
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // VGT_REUSE_OFF
+    0x00000000, // VGT_VTX_CNT_EN
+    0x00000000, // DB_HTILE_SURFACE
+    0x00000000, // DB_SRESULTS_COMPARE_STATE0
+    0x00000000, // DB_SRESULTS_COMPARE_STATE1
+    0x00000000, // DB_PRELOAD_CONTROL
+    0, // HOLE
+    0x00000000, // VGT_STRMOUT_BUFFER_SIZE_0
+    0x00000000, // VGT_STRMOUT_VTX_STRIDE_0
+    0x00000000, // VGT_STRMOUT_BUFFER_BASE_0
+    0x00000000, // VGT_STRMOUT_BUFFER_OFFSET_0
+    0x00000000, // VGT_STRMOUT_BUFFER_SIZE_1
+    0x00000000, // VGT_STRMOUT_VTX_STRIDE_1
+    0x00000000, // VGT_STRMOUT_BUFFER_BASE_1
+    0x00000000, // VGT_STRMOUT_BUFFER_OFFSET_1
+    0x00000000, // VGT_STRMOUT_BUFFER_SIZE_2
+    0x00000000, // VGT_STRMOUT_VTX_STRIDE_2
+    0x00000000, // VGT_STRMOUT_BUFFER_BASE_2
+    0x00000000, // VGT_STRMOUT_BUFFER_OFFSET_2
+    0x00000000, // VGT_STRMOUT_BUFFER_SIZE_3
+    0x00000000, // VGT_STRMOUT_VTX_STRIDE_3
+    0x00000000, // VGT_STRMOUT_BUFFER_BASE_3
+    0x00000000, // VGT_STRMOUT_BUFFER_OFFSET_3
+    0x00000000, // VGT_STRMOUT_BASE_OFFSET_0
+    0x00000000, // VGT_STRMOUT_BASE_OFFSET_1
+    0x00000000, // VGT_STRMOUT_BASE_OFFSET_2
+    0x00000000, // VGT_STRMOUT_BASE_OFFSET_3
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // VGT_STRMOUT_DRAW_OPAQUE_OFFSET
+    0x00000000, // VGT_STRMOUT_DRAW_OPAQUE_BUFFER_FILLED_SIZE
+    0x00000000, // VGT_STRMOUT_DRAW_OPAQUE_VERTEX_STRIDE
+    0, // HOLE
+    0x00000000, // VGT_GS_MAX_VERT_OUT
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // VGT_STRMOUT_BASE_OFFSET_HI_0
+    0x00000000, // VGT_STRMOUT_BASE_OFFSET_HI_1
+    0x00000000, // VGT_STRMOUT_BASE_OFFSET_HI_2
+    0x00000000, // VGT_STRMOUT_BASE_OFFSET_HI_3
+    0x00000000, // VGT_SHADER_STAGES_EN
+    0x00000000, // VGT_LS_HS_CONFIG
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // VGT_TF_PARAM
+    0x00000000, // DB_ALPHA_TO_MASK
+};
+static const u32 SECT_CONTEXT_def_7[] =
+{
+    0x00000000, // PA_SU_POLY_OFFSET_DB_FMT_CNTL
+    0x00000000, // PA_SU_POLY_OFFSET_CLAMP
+    0x00000000, // PA_SU_POLY_OFFSET_FRONT_SCALE
+    0x00000000, // PA_SU_POLY_OFFSET_FRONT_OFFSET
+    0x00000000, // PA_SU_POLY_OFFSET_BACK_SCALE
+    0x00000000, // PA_SU_POLY_OFFSET_BACK_OFFSET
+    0x00000000, // VGT_GS_INSTANCE_CNT
+    0x00000000, // VGT_STRMOUT_CONFIG
+    0x00000000, // VGT_STRMOUT_BUFFER_CONFIG
+    0x00000000, // CB_IMMED0_BASE
+    0x00000000, // CB_IMMED1_BASE
+    0x00000000, // CB_IMMED2_BASE
+    0x00000000, // CB_IMMED3_BASE
+    0x00000000, // CB_IMMED4_BASE
+    0x00000000, // CB_IMMED5_BASE
+    0x00000000, // CB_IMMED6_BASE
+    0x00000000, // CB_IMMED7_BASE
+    0x00000000, // CB_IMMED8_BASE
+    0x00000000, // CB_IMMED9_BASE
+    0x00000000, // CB_IMMED10_BASE
+    0x00000000, // CB_IMMED11_BASE
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // PA_SC_CENTROID_PRIORITY_0
+    0x00000000, // PA_SC_CENTROID_PRIORITY_1
+    0x00001000, // PA_SC_LINE_CNTL
+    0x00000000, // PA_SC_AA_CONFIG
+    0x00000005, // PA_SU_VTX_CNTL
+    0x3f800000, // PA_CL_GB_VERT_CLIP_ADJ
+    0x3f800000, // PA_CL_GB_VERT_DISC_ADJ
+    0x3f800000, // PA_CL_GB_HORZ_CLIP_ADJ
+    0x3f800000, // PA_CL_GB_HORZ_DISC_ADJ
+    0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_0
+    0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_1
+    0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_2
+    0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_3
+    0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y0_0
+    0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y0_1
+    0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y0_2
+    0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y0_3
+    0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y1_0
+    0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y1_1
+    0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y1_2
+    0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y1_3
+    0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y1_0
+    0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y1_1
+    0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y1_2
+    0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y1_3
+    0xffffffff, // PA_SC_AA_MASK_X0Y0_X1Y0
+    0xffffffff, // PA_SC_AA_MASK_X0Y1_X1Y1
+    0x00000000, // CB_CLRCMP_CONTROL
+    0x00000000, // CB_CLRCMP_SRC
+    0x00000000, // CB_CLRCMP_DST
+    0x00000000, // CB_CLRCMP_MSK
+    0, // HOLE
+    0, // HOLE
+    0x0000000e, // VGT_VERTEX_REUSE_BLOCK_CNTL
+    0x00000010, // VGT_OUT_DEALLOC_CNTL
+    0x00000000, // CB_COLOR0_BASE
+    0x00000000, // CB_COLOR0_PITCH
+    0x00000000, // CB_COLOR0_SLICE
+    0x00000000, // CB_COLOR0_VIEW
+    0x00000000, // CB_COLOR0_INFO
+    0x00000000, // CB_COLOR0_ATTRIB
+    0x00000000, // CB_COLOR0_DIM
+    0x00000000, // CB_COLOR0_CMASK
+    0x00000000, // CB_COLOR0_CMASK_SLICE
+    0x00000000, // CB_COLOR0_FMASK
+    0x00000000, // CB_COLOR0_FMASK_SLICE
+    0x00000000, // CB_COLOR0_CLEAR_WORD0
+    0x00000000, // CB_COLOR0_CLEAR_WORD1
+    0x00000000, // CB_COLOR0_CLEAR_WORD2
+    0x00000000, // CB_COLOR0_CLEAR_WORD3
+    0x00000000, // CB_COLOR1_BASE
+    0x00000000, // CB_COLOR1_PITCH
+    0x00000000, // CB_COLOR1_SLICE
+    0x00000000, // CB_COLOR1_VIEW
+    0x00000000, // CB_COLOR1_INFO
+    0x00000000, // CB_COLOR1_ATTRIB
+    0x00000000, // CB_COLOR1_DIM
+    0x00000000, // CB_COLOR1_CMASK
+    0x00000000, // CB_COLOR1_CMASK_SLICE
+    0x00000000, // CB_COLOR1_FMASK
+    0x00000000, // CB_COLOR1_FMASK_SLICE
+    0x00000000, // CB_COLOR1_CLEAR_WORD0
+    0x00000000, // CB_COLOR1_CLEAR_WORD1
+    0x00000000, // CB_COLOR1_CLEAR_WORD2
+    0x00000000, // CB_COLOR1_CLEAR_WORD3
+    0x00000000, // CB_COLOR2_BASE
+    0x00000000, // CB_COLOR2_PITCH
+    0x00000000, // CB_COLOR2_SLICE
+    0x00000000, // CB_COLOR2_VIEW
+    0x00000000, // CB_COLOR2_INFO
+    0x00000000, // CB_COLOR2_ATTRIB
+    0x00000000, // CB_COLOR2_DIM
+    0x00000000, // CB_COLOR2_CMASK
+    0x00000000, // CB_COLOR2_CMASK_SLICE
+    0x00000000, // CB_COLOR2_FMASK
+    0x00000000, // CB_COLOR2_FMASK_SLICE
+    0x00000000, // CB_COLOR2_CLEAR_WORD0
+    0x00000000, // CB_COLOR2_CLEAR_WORD1
+    0x00000000, // CB_COLOR2_CLEAR_WORD2
+    0x00000000, // CB_COLOR2_CLEAR_WORD3
+    0x00000000, // CB_COLOR3_BASE
+    0x00000000, // CB_COLOR3_PITCH
+    0x00000000, // CB_COLOR3_SLICE
+    0x00000000, // CB_COLOR3_VIEW
+    0x00000000, // CB_COLOR3_INFO
+    0x00000000, // CB_COLOR3_ATTRIB
+    0x00000000, // CB_COLOR3_DIM
+    0x00000000, // CB_COLOR3_CMASK
+    0x00000000, // CB_COLOR3_CMASK_SLICE
+    0x00000000, // CB_COLOR3_FMASK
+    0x00000000, // CB_COLOR3_FMASK_SLICE
+    0x00000000, // CB_COLOR3_CLEAR_WORD0
+    0x00000000, // CB_COLOR3_CLEAR_WORD1
+    0x00000000, // CB_COLOR3_CLEAR_WORD2
+    0x00000000, // CB_COLOR3_CLEAR_WORD3
+    0x00000000, // CB_COLOR4_BASE
+    0x00000000, // CB_COLOR4_PITCH
+    0x00000000, // CB_COLOR4_SLICE
+    0x00000000, // CB_COLOR4_VIEW
+    0x00000000, // CB_COLOR4_INFO
+    0x00000000, // CB_COLOR4_ATTRIB
+    0x00000000, // CB_COLOR4_DIM
+    0x00000000, // CB_COLOR4_CMASK
+    0x00000000, // CB_COLOR4_CMASK_SLICE
+    0x00000000, // CB_COLOR4_FMASK
+    0x00000000, // CB_COLOR4_FMASK_SLICE
+    0x00000000, // CB_COLOR4_CLEAR_WORD0
+    0x00000000, // CB_COLOR4_CLEAR_WORD1
+    0x00000000, // CB_COLOR4_CLEAR_WORD2
+    0x00000000, // CB_COLOR4_CLEAR_WORD3
+    0x00000000, // CB_COLOR5_BASE
+    0x00000000, // CB_COLOR5_PITCH
+    0x00000000, // CB_COLOR5_SLICE
+    0x00000000, // CB_COLOR5_VIEW
+    0x00000000, // CB_COLOR5_INFO
+    0x00000000, // CB_COLOR5_ATTRIB
+    0x00000000, // CB_COLOR5_DIM
+    0x00000000, // CB_COLOR5_CMASK
+    0x00000000, // CB_COLOR5_CMASK_SLICE
+    0x00000000, // CB_COLOR5_FMASK
+    0x00000000, // CB_COLOR5_FMASK_SLICE
+    0x00000000, // CB_COLOR5_CLEAR_WORD0
+    0x00000000, // CB_COLOR5_CLEAR_WORD1
+    0x00000000, // CB_COLOR5_CLEAR_WORD2
+    0x00000000, // CB_COLOR5_CLEAR_WORD3
+    0x00000000, // CB_COLOR6_BASE
+    0x00000000, // CB_COLOR6_PITCH
+    0x00000000, // CB_COLOR6_SLICE
+    0x00000000, // CB_COLOR6_VIEW
+    0x00000000, // CB_COLOR6_INFO
+    0x00000000, // CB_COLOR6_ATTRIB
+    0x00000000, // CB_COLOR6_DIM
+    0x00000000, // CB_COLOR6_CMASK
+    0x00000000, // CB_COLOR6_CMASK_SLICE
+    0x00000000, // CB_COLOR6_FMASK
+    0x00000000, // CB_COLOR6_FMASK_SLICE
+    0x00000000, // CB_COLOR6_CLEAR_WORD0
+    0x00000000, // CB_COLOR6_CLEAR_WORD1
+    0x00000000, // CB_COLOR6_CLEAR_WORD2
+    0x00000000, // CB_COLOR6_CLEAR_WORD3
+    0x00000000, // CB_COLOR7_BASE
+    0x00000000, // CB_COLOR7_PITCH
+    0x00000000, // CB_COLOR7_SLICE
+    0x00000000, // CB_COLOR7_VIEW
+    0x00000000, // CB_COLOR7_INFO
+    0x00000000, // CB_COLOR7_ATTRIB
+    0x00000000, // CB_COLOR7_DIM
+    0x00000000, // CB_COLOR7_CMASK
+    0x00000000, // CB_COLOR7_CMASK_SLICE
+    0x00000000, // CB_COLOR7_FMASK
+    0x00000000, // CB_COLOR7_FMASK_SLICE
+    0x00000000, // CB_COLOR7_CLEAR_WORD0
+    0x00000000, // CB_COLOR7_CLEAR_WORD1
+    0x00000000, // CB_COLOR7_CLEAR_WORD2
+    0x00000000, // CB_COLOR7_CLEAR_WORD3
+    0x00000000, // CB_COLOR8_BASE
+    0x00000000, // CB_COLOR8_PITCH
+    0x00000000, // CB_COLOR8_SLICE
+    0x00000000, // CB_COLOR8_VIEW
+    0x00000000, // CB_COLOR8_INFO
+    0x00000000, // CB_COLOR8_ATTRIB
+    0x00000000, // CB_COLOR8_DIM
+    0x00000000, // CB_COLOR9_BASE
+    0x00000000, // CB_COLOR9_PITCH
+    0x00000000, // CB_COLOR9_SLICE
+    0x00000000, // CB_COLOR9_VIEW
+    0x00000000, // CB_COLOR9_INFO
+    0x00000000, // CB_COLOR9_ATTRIB
+    0x00000000, // CB_COLOR9_DIM
+    0x00000000, // CB_COLOR10_BASE
+    0x00000000, // CB_COLOR10_PITCH
+    0x00000000, // CB_COLOR10_SLICE
+    0x00000000, // CB_COLOR10_VIEW
+    0x00000000, // CB_COLOR10_INFO
+    0x00000000, // CB_COLOR10_ATTRIB
+    0x00000000, // CB_COLOR10_DIM
+    0x00000000, // CB_COLOR11_BASE
+    0x00000000, // CB_COLOR11_PITCH
+    0x00000000, // CB_COLOR11_SLICE
+    0x00000000, // CB_COLOR11_VIEW
+    0x00000000, // CB_COLOR11_INFO
+    0x00000000, // CB_COLOR11_ATTRIB
+    0x00000000, // CB_COLOR11_DIM
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // SQ_ALU_CONST_CACHE_HS_0
+    0x00000000, // SQ_ALU_CONST_CACHE_HS_1
+    0x00000000, // SQ_ALU_CONST_CACHE_HS_2
+    0x00000000, // SQ_ALU_CONST_CACHE_HS_3
+    0x00000000, // SQ_ALU_CONST_CACHE_HS_4
+    0x00000000, // SQ_ALU_CONST_CACHE_HS_5
+    0x00000000, // SQ_ALU_CONST_CACHE_HS_6
+    0x00000000, // SQ_ALU_CONST_CACHE_HS_7
+    0x00000000, // SQ_ALU_CONST_CACHE_HS_8
+    0x00000000, // SQ_ALU_CONST_CACHE_HS_9
+    0x00000000, // SQ_ALU_CONST_CACHE_HS_10
+    0x00000000, // SQ_ALU_CONST_CACHE_HS_11
+    0x00000000, // SQ_ALU_CONST_CACHE_HS_12
+    0x00000000, // SQ_ALU_CONST_CACHE_HS_13
+    0x00000000, // SQ_ALU_CONST_CACHE_HS_14
+    0x00000000, // SQ_ALU_CONST_CACHE_HS_15
+    0x00000000, // SQ_ALU_CONST_CACHE_LS_0
+    0x00000000, // SQ_ALU_CONST_CACHE_LS_1
+    0x00000000, // SQ_ALU_CONST_CACHE_LS_2
+    0x00000000, // SQ_ALU_CONST_CACHE_LS_3
+    0x00000000, // SQ_ALU_CONST_CACHE_LS_4
+    0x00000000, // SQ_ALU_CONST_CACHE_LS_5
+    0x00000000, // SQ_ALU_CONST_CACHE_LS_6
+    0x00000000, // SQ_ALU_CONST_CACHE_LS_7
+    0x00000000, // SQ_ALU_CONST_CACHE_LS_8
+    0x00000000, // SQ_ALU_CONST_CACHE_LS_9
+    0x00000000, // SQ_ALU_CONST_CACHE_LS_10
+    0x00000000, // SQ_ALU_CONST_CACHE_LS_11
+    0x00000000, // SQ_ALU_CONST_CACHE_LS_12
+    0x00000000, // SQ_ALU_CONST_CACHE_LS_13
+    0x00000000, // SQ_ALU_CONST_CACHE_LS_14
+    0x00000000, // SQ_ALU_CONST_CACHE_LS_15
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_0
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_1
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_2
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_3
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_4
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_5
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_6
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_7
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_8
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_9
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_10
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_11
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_12
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_13
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_14
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_15
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_0
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_1
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_2
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_3
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_4
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_5
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_6
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_7
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_8
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_9
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_10
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_11
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_12
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_13
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_14
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_15
+};
+static const struct cs_extent_def SECT_CONTEXT_defs[] =
+{
+    {SECT_CONTEXT_def_1, 0x0000a000, 488 },
+    {SECT_CONTEXT_def_2, 0x0000a1f5, 6 },
+    {SECT_CONTEXT_def_3, 0x0000a200, 55 },
+    {SECT_CONTEXT_def_4, 0x0000a23a, 99 },
+    {SECT_CONTEXT_def_5, 0x0000a29e, 5 },
+    {SECT_CONTEXT_def_6, 0x0000a2a5, 56 },
+    {SECT_CONTEXT_def_7, 0x0000a2de, 290 },
+    { 0, 0, 0 }
+};
+static const u32 SECT_CLEAR_def_1[] =
+{
+    0xffffffff, // SQ_TEX_SAMPLER_CLEAR
+    0xffffffff, // SQ_TEX_RESOURCE_CLEAR
+    0xffffffff, // SQ_LOOP_BOOL_CLEAR
+};
+static const struct cs_extent_def SECT_CLEAR_defs[] =
+{
+    {SECT_CLEAR_def_1, 0x0000ffc0, 3 },
+    { 0, 0, 0 }
+};
+static const u32 SECT_CTRLCONST_def_1[] =
+{
+    0x00000000, // SQ_VTX_BASE_VTX_LOC
+    0x00000000, // SQ_VTX_START_INST_LOC
+};
+static const struct cs_extent_def SECT_CTRLCONST_defs[] =
+{
+    {SECT_CTRLCONST_def_1, 0x0000f3fc, 2 },
+    { 0, 0, 0 }
+};
+struct cs_section_def cayman_cs_data[] = {
+    { SECT_CONTEXT_defs, SECT_CONTEXT },
+    { SECT_CLEAR_defs, SECT_CLEAR },
+    { SECT_CTRLCONST_defs, SECT_CTRLCONST },
+    { 0, SECT_NONE }
+};
diff --git a/drivers/gpu/drm/radeon/clearstate_defs.h b/drivers/gpu/drm/radeon/clearstate_defs.h
new file mode 100644
index 0000000..3eda707
--- /dev/null
+++ b/drivers/gpu/drm/radeon/clearstate_defs.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2012 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef CLEARSTATE_DEFS_H
+#define CLEARSTATE_DEFS_H
+
+enum section_id {
+    SECT_NONE,
+    SECT_CONTEXT,
+    SECT_CLEAR,
+    SECT_CTRLCONST
+};
+
+struct cs_extent_def {
+    const unsigned int *extent;
+    const unsigned int reg_index;
+    const unsigned int reg_count;
+};
+
+struct cs_section_def {
+    const struct cs_extent_def *section;
+    const enum section_id id;
+};
+
+#endif
diff --git a/drivers/gpu/drm/radeon/clearstate_evergreen.h b/drivers/gpu/drm/radeon/clearstate_evergreen.h
new file mode 100644
index 0000000..4791d85
--- /dev/null
+++ b/drivers/gpu/drm/radeon/clearstate_evergreen.h
@@ -0,0 +1,1080 @@
+/*
+ * Copyright 2012 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+static const u32 SECT_CONTEXT_def_1[] =
+{
+    0x00000000, // DB_RENDER_CONTROL
+    0x00000000, // DB_COUNT_CONTROL
+    0x00000000, // DB_DEPTH_VIEW
+    0x00000000, // DB_RENDER_OVERRIDE
+    0x00000000, // DB_RENDER_OVERRIDE2
+    0x00000000, // DB_HTILE_DATA_BASE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // DB_STENCIL_CLEAR
+    0x00000000, // DB_DEPTH_CLEAR
+    0x00000000, // PA_SC_SCREEN_SCISSOR_TL
+    0x40004000, // PA_SC_SCREEN_SCISSOR_BR
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // DB_Z_INFO
+    0x00000000, // DB_STENCIL_INFO
+    0x00000000, // DB_Z_READ_BASE
+    0x00000000, // DB_STENCIL_READ_BASE
+    0x00000000, // DB_Z_WRITE_BASE
+    0x00000000, // DB_STENCIL_WRITE_BASE
+    0x00000000, // DB_DEPTH_SIZE
+    0x00000000, // DB_DEPTH_SLICE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_0
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_1
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_2
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_3
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_4
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_5
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_6
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_7
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_8
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_9
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_10
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_11
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_12
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_13
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_14
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_15
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_0
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_1
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_2
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_3
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_4
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_5
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_6
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_7
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_8
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_9
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_10
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_11
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_12
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_13
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_14
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_15
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_0
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_1
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_2
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_3
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_4
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_5
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_6
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_7
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_8
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_9
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_10
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_11
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_12
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_13
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_14
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_15
+    0x00000000, // PA_SC_WINDOW_OFFSET
+    0x80000000, // PA_SC_WINDOW_SCISSOR_TL
+    0x40004000, // PA_SC_WINDOW_SCISSOR_BR
+    0x0000ffff, // PA_SC_CLIPRECT_RULE
+    0x00000000, // PA_SC_CLIPRECT_0_TL
+    0x40004000, // PA_SC_CLIPRECT_0_BR
+    0x00000000, // PA_SC_CLIPRECT_1_TL
+    0x40004000, // PA_SC_CLIPRECT_1_BR
+    0x00000000, // PA_SC_CLIPRECT_2_TL
+    0x40004000, // PA_SC_CLIPRECT_2_BR
+    0x00000000, // PA_SC_CLIPRECT_3_TL
+    0x40004000, // PA_SC_CLIPRECT_3_BR
+    0xaa99aaaa, // PA_SC_EDGERULE
+    0x00000000, // PA_SU_HARDWARE_SCREEN_OFFSET
+    0xffffffff, // CB_TARGET_MASK
+    0xffffffff, // CB_SHADER_MASK
+    0x80000000, // PA_SC_GENERIC_SCISSOR_TL
+    0x40004000, // PA_SC_GENERIC_SCISSOR_BR
+    0x00000000, // COHER_DEST_BASE_0
+    0x00000000, // COHER_DEST_BASE_1
+    0x80000000, // PA_SC_VPORT_SCISSOR_0_TL
+    0x40004000, // PA_SC_VPORT_SCISSOR_0_BR
+    0x80000000, // PA_SC_VPORT_SCISSOR_1_TL
+    0x40004000, // PA_SC_VPORT_SCISSOR_1_BR
+    0x80000000, // PA_SC_VPORT_SCISSOR_2_TL
+    0x40004000, // PA_SC_VPORT_SCISSOR_2_BR
+    0x80000000, // PA_SC_VPORT_SCISSOR_3_TL
+    0x40004000, // PA_SC_VPORT_SCISSOR_3_BR
+    0x80000000, // PA_SC_VPORT_SCISSOR_4_TL
+    0x40004000, // PA_SC_VPORT_SCISSOR_4_BR
+    0x80000000, // PA_SC_VPORT_SCISSOR_5_TL
+    0x40004000, // PA_SC_VPORT_SCISSOR_5_BR
+    0x80000000, // PA_SC_VPORT_SCISSOR_6_TL
+    0x40004000, // PA_SC_VPORT_SCISSOR_6_BR
+    0x80000000, // PA_SC_VPORT_SCISSOR_7_TL
+    0x40004000, // PA_SC_VPORT_SCISSOR_7_BR
+    0x80000000, // PA_SC_VPORT_SCISSOR_8_TL
+    0x40004000, // PA_SC_VPORT_SCISSOR_8_BR
+    0x80000000, // PA_SC_VPORT_SCISSOR_9_TL
+    0x40004000, // PA_SC_VPORT_SCISSOR_9_BR
+    0x80000000, // PA_SC_VPORT_SCISSOR_10_TL
+    0x40004000, // PA_SC_VPORT_SCISSOR_10_BR
+    0x80000000, // PA_SC_VPORT_SCISSOR_11_TL
+    0x40004000, // PA_SC_VPORT_SCISSOR_11_BR
+    0x80000000, // PA_SC_VPORT_SCISSOR_12_TL
+    0x40004000, // PA_SC_VPORT_SCISSOR_12_BR
+    0x80000000, // PA_SC_VPORT_SCISSOR_13_TL
+    0x40004000, // PA_SC_VPORT_SCISSOR_13_BR
+    0x80000000, // PA_SC_VPORT_SCISSOR_14_TL
+    0x40004000, // PA_SC_VPORT_SCISSOR_14_BR
+    0x80000000, // PA_SC_VPORT_SCISSOR_15_TL
+    0x40004000, // PA_SC_VPORT_SCISSOR_15_BR
+    0x00000000, // PA_SC_VPORT_ZMIN_0
+    0x3f800000, // PA_SC_VPORT_ZMAX_0
+    0x00000000, // PA_SC_VPORT_ZMIN_1
+    0x3f800000, // PA_SC_VPORT_ZMAX_1
+    0x00000000, // PA_SC_VPORT_ZMIN_2
+    0x3f800000, // PA_SC_VPORT_ZMAX_2
+    0x00000000, // PA_SC_VPORT_ZMIN_3
+    0x3f800000, // PA_SC_VPORT_ZMAX_3
+    0x00000000, // PA_SC_VPORT_ZMIN_4
+    0x3f800000, // PA_SC_VPORT_ZMAX_4
+    0x00000000, // PA_SC_VPORT_ZMIN_5
+    0x3f800000, // PA_SC_VPORT_ZMAX_5
+    0x00000000, // PA_SC_VPORT_ZMIN_6
+    0x3f800000, // PA_SC_VPORT_ZMAX_6
+    0x00000000, // PA_SC_VPORT_ZMIN_7
+    0x3f800000, // PA_SC_VPORT_ZMAX_7
+    0x00000000, // PA_SC_VPORT_ZMIN_8
+    0x3f800000, // PA_SC_VPORT_ZMAX_8
+    0x00000000, // PA_SC_VPORT_ZMIN_9
+    0x3f800000, // PA_SC_VPORT_ZMAX_9
+    0x00000000, // PA_SC_VPORT_ZMIN_10
+    0x3f800000, // PA_SC_VPORT_ZMAX_10
+    0x00000000, // PA_SC_VPORT_ZMIN_11
+    0x3f800000, // PA_SC_VPORT_ZMAX_11
+    0x00000000, // PA_SC_VPORT_ZMIN_12
+    0x3f800000, // PA_SC_VPORT_ZMAX_12
+    0x00000000, // PA_SC_VPORT_ZMIN_13
+    0x3f800000, // PA_SC_VPORT_ZMAX_13
+    0x00000000, // PA_SC_VPORT_ZMIN_14
+    0x3f800000, // PA_SC_VPORT_ZMAX_14
+    0x00000000, // PA_SC_VPORT_ZMIN_15
+    0x3f800000, // PA_SC_VPORT_ZMAX_15
+    0x00000000, // SX_MISC
+    0x00000000, // SX_SURFACE_SYNC
+    0x00000000, // CP_PERFMON_CNTX_CNTL
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // SQ_VTX_SEMANTIC_0
+    0x00000000, // SQ_VTX_SEMANTIC_1
+    0x00000000, // SQ_VTX_SEMANTIC_2
+    0x00000000, // SQ_VTX_SEMANTIC_3
+    0x00000000, // SQ_VTX_SEMANTIC_4
+    0x00000000, // SQ_VTX_SEMANTIC_5
+    0x00000000, // SQ_VTX_SEMANTIC_6
+    0x00000000, // SQ_VTX_SEMANTIC_7
+    0x00000000, // SQ_VTX_SEMANTIC_8
+    0x00000000, // SQ_VTX_SEMANTIC_9
+    0x00000000, // SQ_VTX_SEMANTIC_10
+    0x00000000, // SQ_VTX_SEMANTIC_11
+    0x00000000, // SQ_VTX_SEMANTIC_12
+    0x00000000, // SQ_VTX_SEMANTIC_13
+    0x00000000, // SQ_VTX_SEMANTIC_14
+    0x00000000, // SQ_VTX_SEMANTIC_15
+    0x00000000, // SQ_VTX_SEMANTIC_16
+    0x00000000, // SQ_VTX_SEMANTIC_17
+    0x00000000, // SQ_VTX_SEMANTIC_18
+    0x00000000, // SQ_VTX_SEMANTIC_19
+    0x00000000, // SQ_VTX_SEMANTIC_20
+    0x00000000, // SQ_VTX_SEMANTIC_21
+    0x00000000, // SQ_VTX_SEMANTIC_22
+    0x00000000, // SQ_VTX_SEMANTIC_23
+    0x00000000, // SQ_VTX_SEMANTIC_24
+    0x00000000, // SQ_VTX_SEMANTIC_25
+    0x00000000, // SQ_VTX_SEMANTIC_26
+    0x00000000, // SQ_VTX_SEMANTIC_27
+    0x00000000, // SQ_VTX_SEMANTIC_28
+    0x00000000, // SQ_VTX_SEMANTIC_29
+    0x00000000, // SQ_VTX_SEMANTIC_30
+    0x00000000, // SQ_VTX_SEMANTIC_31
+    0xffffffff, // VGT_MAX_VTX_INDX
+    0x00000000, // VGT_MIN_VTX_INDX
+    0x00000000, // VGT_INDX_OFFSET
+    0x00000000, // VGT_MULTI_PRIM_IB_RESET_INDX
+    0x00000000, // SX_ALPHA_TEST_CONTROL
+    0x00000000, // CB_BLEND_RED
+    0x00000000, // CB_BLEND_GREEN
+    0x00000000, // CB_BLEND_BLUE
+    0x00000000, // CB_BLEND_ALPHA
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // DB_STENCILREFMASK
+    0x00000000, // DB_STENCILREFMASK_BF
+    0x00000000, // SX_ALPHA_REF
+    0x00000000, // PA_CL_VPORT_XSCALE
+    0x00000000, // PA_CL_VPORT_XOFFSET
+    0x00000000, // PA_CL_VPORT_YSCALE
+    0x00000000, // PA_CL_VPORT_YOFFSET
+    0x00000000, // PA_CL_VPORT_ZSCALE
+    0x00000000, // PA_CL_VPORT_ZOFFSET
+    0x00000000, // PA_CL_VPORT_XSCALE_1
+    0x00000000, // PA_CL_VPORT_XOFFSET_1
+    0x00000000, // PA_CL_VPORT_YSCALE_1
+    0x00000000, // PA_CL_VPORT_YOFFSET_1
+    0x00000000, // PA_CL_VPORT_ZSCALE_1
+    0x00000000, // PA_CL_VPORT_ZOFFSET_1
+    0x00000000, // PA_CL_VPORT_XSCALE_2
+    0x00000000, // PA_CL_VPORT_XOFFSET_2
+    0x00000000, // PA_CL_VPORT_YSCALE_2
+    0x00000000, // PA_CL_VPORT_YOFFSET_2
+    0x00000000, // PA_CL_VPORT_ZSCALE_2
+    0x00000000, // PA_CL_VPORT_ZOFFSET_2
+    0x00000000, // PA_CL_VPORT_XSCALE_3
+    0x00000000, // PA_CL_VPORT_XOFFSET_3
+    0x00000000, // PA_CL_VPORT_YSCALE_3
+    0x00000000, // PA_CL_VPORT_YOFFSET_3
+    0x00000000, // PA_CL_VPORT_ZSCALE_3
+    0x00000000, // PA_CL_VPORT_ZOFFSET_3
+    0x00000000, // PA_CL_VPORT_XSCALE_4
+    0x00000000, // PA_CL_VPORT_XOFFSET_4
+    0x00000000, // PA_CL_VPORT_YSCALE_4
+    0x00000000, // PA_CL_VPORT_YOFFSET_4
+    0x00000000, // PA_CL_VPORT_ZSCALE_4
+    0x00000000, // PA_CL_VPORT_ZOFFSET_4
+    0x00000000, // PA_CL_VPORT_XSCALE_5
+    0x00000000, // PA_CL_VPORT_XOFFSET_5
+    0x00000000, // PA_CL_VPORT_YSCALE_5
+    0x00000000, // PA_CL_VPORT_YOFFSET_5
+    0x00000000, // PA_CL_VPORT_ZSCALE_5
+    0x00000000, // PA_CL_VPORT_ZOFFSET_5
+    0x00000000, // PA_CL_VPORT_XSCALE_6
+    0x00000000, // PA_CL_VPORT_XOFFSET_6
+    0x00000000, // PA_CL_VPORT_YSCALE_6
+    0x00000000, // PA_CL_VPORT_YOFFSET_6
+    0x00000000, // PA_CL_VPORT_ZSCALE_6
+    0x00000000, // PA_CL_VPORT_ZOFFSET_6
+    0x00000000, // PA_CL_VPORT_XSCALE_7
+    0x00000000, // PA_CL_VPORT_XOFFSET_7
+    0x00000000, // PA_CL_VPORT_YSCALE_7
+    0x00000000, // PA_CL_VPORT_YOFFSET_7
+    0x00000000, // PA_CL_VPORT_ZSCALE_7
+    0x00000000, // PA_CL_VPORT_ZOFFSET_7
+    0x00000000, // PA_CL_VPORT_XSCALE_8
+    0x00000000, // PA_CL_VPORT_XOFFSET_8
+    0x00000000, // PA_CL_VPORT_YSCALE_8
+    0x00000000, // PA_CL_VPORT_YOFFSET_8
+    0x00000000, // PA_CL_VPORT_ZSCALE_8
+    0x00000000, // PA_CL_VPORT_ZOFFSET_8
+    0x00000000, // PA_CL_VPORT_XSCALE_9
+    0x00000000, // PA_CL_VPORT_XOFFSET_9
+    0x00000000, // PA_CL_VPORT_YSCALE_9
+    0x00000000, // PA_CL_VPORT_YOFFSET_9
+    0x00000000, // PA_CL_VPORT_ZSCALE_9
+    0x00000000, // PA_CL_VPORT_ZOFFSET_9
+    0x00000000, // PA_CL_VPORT_XSCALE_10
+    0x00000000, // PA_CL_VPORT_XOFFSET_10
+    0x00000000, // PA_CL_VPORT_YSCALE_10
+    0x00000000, // PA_CL_VPORT_YOFFSET_10
+    0x00000000, // PA_CL_VPORT_ZSCALE_10
+    0x00000000, // PA_CL_VPORT_ZOFFSET_10
+    0x00000000, // PA_CL_VPORT_XSCALE_11
+    0x00000000, // PA_CL_VPORT_XOFFSET_11
+    0x00000000, // PA_CL_VPORT_YSCALE_11
+    0x00000000, // PA_CL_VPORT_YOFFSET_11
+    0x00000000, // PA_CL_VPORT_ZSCALE_11
+    0x00000000, // PA_CL_VPORT_ZOFFSET_11
+    0x00000000, // PA_CL_VPORT_XSCALE_12
+    0x00000000, // PA_CL_VPORT_XOFFSET_12
+    0x00000000, // PA_CL_VPORT_YSCALE_12
+    0x00000000, // PA_CL_VPORT_YOFFSET_12
+    0x00000000, // PA_CL_VPORT_ZSCALE_12
+    0x00000000, // PA_CL_VPORT_ZOFFSET_12
+    0x00000000, // PA_CL_VPORT_XSCALE_13
+    0x00000000, // PA_CL_VPORT_XOFFSET_13
+    0x00000000, // PA_CL_VPORT_YSCALE_13
+    0x00000000, // PA_CL_VPORT_YOFFSET_13
+    0x00000000, // PA_CL_VPORT_ZSCALE_13
+    0x00000000, // PA_CL_VPORT_ZOFFSET_13
+    0x00000000, // PA_CL_VPORT_XSCALE_14
+    0x00000000, // PA_CL_VPORT_XOFFSET_14
+    0x00000000, // PA_CL_VPORT_YSCALE_14
+    0x00000000, // PA_CL_VPORT_YOFFSET_14
+    0x00000000, // PA_CL_VPORT_ZSCALE_14
+    0x00000000, // PA_CL_VPORT_ZOFFSET_14
+    0x00000000, // PA_CL_VPORT_XSCALE_15
+    0x00000000, // PA_CL_VPORT_XOFFSET_15
+    0x00000000, // PA_CL_VPORT_YSCALE_15
+    0x00000000, // PA_CL_VPORT_YOFFSET_15
+    0x00000000, // PA_CL_VPORT_ZSCALE_15
+    0x00000000, // PA_CL_VPORT_ZOFFSET_15
+    0x00000000, // PA_CL_UCP_0_X
+    0x00000000, // PA_CL_UCP_0_Y
+    0x00000000, // PA_CL_UCP_0_Z
+    0x00000000, // PA_CL_UCP_0_W
+    0x00000000, // PA_CL_UCP_1_X
+    0x00000000, // PA_CL_UCP_1_Y
+    0x00000000, // PA_CL_UCP_1_Z
+    0x00000000, // PA_CL_UCP_1_W
+    0x00000000, // PA_CL_UCP_2_X
+    0x00000000, // PA_CL_UCP_2_Y
+    0x00000000, // PA_CL_UCP_2_Z
+    0x00000000, // PA_CL_UCP_2_W
+    0x00000000, // PA_CL_UCP_3_X
+    0x00000000, // PA_CL_UCP_3_Y
+    0x00000000, // PA_CL_UCP_3_Z
+    0x00000000, // PA_CL_UCP_3_W
+    0x00000000, // PA_CL_UCP_4_X
+    0x00000000, // PA_CL_UCP_4_Y
+    0x00000000, // PA_CL_UCP_4_Z
+    0x00000000, // PA_CL_UCP_4_W
+    0x00000000, // PA_CL_UCP_5_X
+    0x00000000, // PA_CL_UCP_5_Y
+    0x00000000, // PA_CL_UCP_5_Z
+    0x00000000, // PA_CL_UCP_5_W
+    0x00000000, // SPI_VS_OUT_ID_0
+    0x00000000, // SPI_VS_OUT_ID_1
+    0x00000000, // SPI_VS_OUT_ID_2
+    0x00000000, // SPI_VS_OUT_ID_3
+    0x00000000, // SPI_VS_OUT_ID_4
+    0x00000000, // SPI_VS_OUT_ID_5
+    0x00000000, // SPI_VS_OUT_ID_6
+    0x00000000, // SPI_VS_OUT_ID_7
+    0x00000000, // SPI_VS_OUT_ID_8
+    0x00000000, // SPI_VS_OUT_ID_9
+    0x00000000, // SPI_PS_INPUT_CNTL_0
+    0x00000000, // SPI_PS_INPUT_CNTL_1
+    0x00000000, // SPI_PS_INPUT_CNTL_2
+    0x00000000, // SPI_PS_INPUT_CNTL_3
+    0x00000000, // SPI_PS_INPUT_CNTL_4
+    0x00000000, // SPI_PS_INPUT_CNTL_5
+    0x00000000, // SPI_PS_INPUT_CNTL_6
+    0x00000000, // SPI_PS_INPUT_CNTL_7
+    0x00000000, // SPI_PS_INPUT_CNTL_8
+    0x00000000, // SPI_PS_INPUT_CNTL_9
+    0x00000000, // SPI_PS_INPUT_CNTL_10
+    0x00000000, // SPI_PS_INPUT_CNTL_11
+    0x00000000, // SPI_PS_INPUT_CNTL_12
+    0x00000000, // SPI_PS_INPUT_CNTL_13
+    0x00000000, // SPI_PS_INPUT_CNTL_14
+    0x00000000, // SPI_PS_INPUT_CNTL_15
+    0x00000000, // SPI_PS_INPUT_CNTL_16
+    0x00000000, // SPI_PS_INPUT_CNTL_17
+    0x00000000, // SPI_PS_INPUT_CNTL_18
+    0x00000000, // SPI_PS_INPUT_CNTL_19
+    0x00000000, // SPI_PS_INPUT_CNTL_20
+    0x00000000, // SPI_PS_INPUT_CNTL_21
+    0x00000000, // SPI_PS_INPUT_CNTL_22
+    0x00000000, // SPI_PS_INPUT_CNTL_23
+    0x00000000, // SPI_PS_INPUT_CNTL_24
+    0x00000000, // SPI_PS_INPUT_CNTL_25
+    0x00000000, // SPI_PS_INPUT_CNTL_26
+    0x00000000, // SPI_PS_INPUT_CNTL_27
+    0x00000000, // SPI_PS_INPUT_CNTL_28
+    0x00000000, // SPI_PS_INPUT_CNTL_29
+    0x00000000, // SPI_PS_INPUT_CNTL_30
+    0x00000000, // SPI_PS_INPUT_CNTL_31
+    0x00000000, // SPI_VS_OUT_CONFIG
+    0x00000001, // SPI_THREAD_GROUPING
+    0x00000000, // SPI_PS_IN_CONTROL_0
+    0x00000000, // SPI_PS_IN_CONTROL_1
+    0x00000000, // SPI_INTERP_CONTROL_0
+    0x00000000, // SPI_INPUT_Z
+    0x00000000, // SPI_FOG_CNTL
+    0x00000000, // SPI_BARYC_CNTL
+    0x00000000, // SPI_PS_IN_CONTROL_2
+    0x00000000, // SPI_COMPUTE_INPUT_CNTL
+    0x00000000, // SPI_COMPUTE_NUM_THREAD_X
+    0x00000000, // SPI_COMPUTE_NUM_THREAD_Y
+    0x00000000, // SPI_COMPUTE_NUM_THREAD_Z
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // GDS_ADDR_BASE
+    0x00003fff, // GDS_ADDR_SIZE
+    0x00000001, // GDS_ORDERED_WAVE_PER_SE
+    0x00000000, // GDS_APPEND_CONSUME_UAV0
+    0x00000000, // GDS_APPEND_CONSUME_UAV1
+    0x00000000, // GDS_APPEND_CONSUME_UAV2
+    0x00000000, // GDS_APPEND_CONSUME_UAV3
+    0x00000000, // GDS_APPEND_CONSUME_UAV4
+    0x00000000, // GDS_APPEND_CONSUME_UAV5
+    0x00000000, // GDS_APPEND_CONSUME_UAV6
+    0x00000000, // GDS_APPEND_CONSUME_UAV7
+    0x00000000, // GDS_APPEND_CONSUME_UAV8
+    0x00000000, // GDS_APPEND_CONSUME_UAV9
+    0x00000000, // GDS_APPEND_CONSUME_UAV10
+    0x00000000, // GDS_APPEND_CONSUME_UAV11
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // CB_BLEND0_CONTROL
+    0x00000000, // CB_BLEND1_CONTROL
+    0x00000000, // CB_BLEND2_CONTROL
+    0x00000000, // CB_BLEND3_CONTROL
+    0x00000000, // CB_BLEND4_CONTROL
+    0x00000000, // CB_BLEND5_CONTROL
+    0x00000000, // CB_BLEND6_CONTROL
+    0x00000000, // CB_BLEND7_CONTROL
+};
+static const u32 SECT_CONTEXT_def_2[] =
+{
+    0x00000000, // PA_CL_POINT_X_RAD
+    0x00000000, // PA_CL_POINT_Y_RAD
+    0x00000000, // PA_CL_POINT_SIZE
+    0x00000000, // PA_CL_POINT_CULL_RAD
+    0x00000000, // VGT_DMA_BASE_HI
+    0x00000000, // VGT_DMA_BASE
+};
+static const u32 SECT_CONTEXT_def_3[] =
+{
+    0x00000000, // DB_DEPTH_CONTROL
+    0, // HOLE
+    0x00000000, // CB_COLOR_CONTROL
+    0x00000200, // DB_SHADER_CONTROL
+    0x00000000, // PA_CL_CLIP_CNTL
+    0x00000000, // PA_SU_SC_MODE_CNTL
+    0x00000000, // PA_CL_VTE_CNTL
+    0x00000000, // PA_CL_VS_OUT_CNTL
+    0x00000000, // PA_CL_NANINF_CNTL
+    0x00000000, // PA_SU_LINE_STIPPLE_CNTL
+    0x00000000, // PA_SU_LINE_STIPPLE_SCALE
+    0x00000000, // PA_SU_PRIM_FILTER_CNTL
+    0x00000000, // SQ_LSTMP_RING_ITEMSIZE
+    0x00000000, // SQ_HSTMP_RING_ITEMSIZE
+    0x00000000, // SQ_DYN_GPR_RESOURCE_LIMIT_1
+    0, // HOLE
+    0x00000000, // SQ_PGM_START_PS
+    0x00000000, // SQ_PGM_RESOURCES_PS
+    0x00000000, // SQ_PGM_RESOURCES_2_PS
+    0x00000000, // SQ_PGM_EXPORTS_PS
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // SQ_PGM_START_VS
+    0x00000000, // SQ_PGM_RESOURCES_VS
+    0x00000000, // SQ_PGM_RESOURCES_2_VS
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // SQ_PGM_START_GS
+    0x00000000, // SQ_PGM_RESOURCES_GS
+    0x00000000, // SQ_PGM_RESOURCES_2_GS
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // SQ_PGM_START_ES
+    0x00000000, // SQ_PGM_RESOURCES_ES
+    0x00000000, // SQ_PGM_RESOURCES_2_ES
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // SQ_PGM_START_FS
+    0x00000000, // SQ_PGM_RESOURCES_FS
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // SQ_PGM_START_HS
+    0x00000000, // SQ_PGM_RESOURCES_HS
+    0x00000000, // SQ_PGM_RESOURCES_2_HS
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // SQ_PGM_START_LS
+    0x00000000, // SQ_PGM_RESOURCES_LS
+    0x00000000, // SQ_PGM_RESOURCES_2_LS
+};
+static const u32 SECT_CONTEXT_def_4[] =
+{
+    0x00000000, // SQ_LDS_ALLOC
+    0x00000000, // SQ_LDS_ALLOC_PS
+    0x00000000, // SQ_VTX_SEMANTIC_CLEAR
+    0, // HOLE
+    0x00000000, // SQ_THREAD_TRACE_CTRL
+    0, // HOLE
+    0x00000000, // SQ_ESGS_RING_ITEMSIZE
+    0x00000000, // SQ_GSVS_RING_ITEMSIZE
+    0x00000000, // SQ_ESTMP_RING_ITEMSIZE
+    0x00000000, // SQ_GSTMP_RING_ITEMSIZE
+    0x00000000, // SQ_VSTMP_RING_ITEMSIZE
+    0x00000000, // SQ_PSTMP_RING_ITEMSIZE
+    0, // HOLE
+    0x00000000, // SQ_GS_VERT_ITEMSIZE
+    0x00000000, // SQ_GS_VERT_ITEMSIZE_1
+    0x00000000, // SQ_GS_VERT_ITEMSIZE_2
+    0x00000000, // SQ_GS_VERT_ITEMSIZE_3
+    0x00000000, // SQ_GSVS_RING_OFFSET_1
+    0x00000000, // SQ_GSVS_RING_OFFSET_2
+    0x00000000, // SQ_GSVS_RING_OFFSET_3
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // SQ_ALU_CONST_CACHE_PS_0
+    0x00000000, // SQ_ALU_CONST_CACHE_PS_1
+    0x00000000, // SQ_ALU_CONST_CACHE_PS_2
+    0x00000000, // SQ_ALU_CONST_CACHE_PS_3
+    0x00000000, // SQ_ALU_CONST_CACHE_PS_4
+    0x00000000, // SQ_ALU_CONST_CACHE_PS_5
+    0x00000000, // SQ_ALU_CONST_CACHE_PS_6
+    0x00000000, // SQ_ALU_CONST_CACHE_PS_7
+    0x00000000, // SQ_ALU_CONST_CACHE_PS_8
+    0x00000000, // SQ_ALU_CONST_CACHE_PS_9
+    0x00000000, // SQ_ALU_CONST_CACHE_PS_10
+    0x00000000, // SQ_ALU_CONST_CACHE_PS_11
+    0x00000000, // SQ_ALU_CONST_CACHE_PS_12
+    0x00000000, // SQ_ALU_CONST_CACHE_PS_13
+    0x00000000, // SQ_ALU_CONST_CACHE_PS_14
+    0x00000000, // SQ_ALU_CONST_CACHE_PS_15
+    0x00000000, // SQ_ALU_CONST_CACHE_VS_0
+    0x00000000, // SQ_ALU_CONST_CACHE_VS_1
+    0x00000000, // SQ_ALU_CONST_CACHE_VS_2
+    0x00000000, // SQ_ALU_CONST_CACHE_VS_3
+    0x00000000, // SQ_ALU_CONST_CACHE_VS_4
+    0x00000000, // SQ_ALU_CONST_CACHE_VS_5
+    0x00000000, // SQ_ALU_CONST_CACHE_VS_6
+    0x00000000, // SQ_ALU_CONST_CACHE_VS_7
+    0x00000000, // SQ_ALU_CONST_CACHE_VS_8
+    0x00000000, // SQ_ALU_CONST_CACHE_VS_9
+    0x00000000, // SQ_ALU_CONST_CACHE_VS_10
+    0x00000000, // SQ_ALU_CONST_CACHE_VS_11
+    0x00000000, // SQ_ALU_CONST_CACHE_VS_12
+    0x00000000, // SQ_ALU_CONST_CACHE_VS_13
+    0x00000000, // SQ_ALU_CONST_CACHE_VS_14
+    0x00000000, // SQ_ALU_CONST_CACHE_VS_15
+    0x00000000, // SQ_ALU_CONST_CACHE_GS_0
+    0x00000000, // SQ_ALU_CONST_CACHE_GS_1
+    0x00000000, // SQ_ALU_CONST_CACHE_GS_2
+    0x00000000, // SQ_ALU_CONST_CACHE_GS_3
+    0x00000000, // SQ_ALU_CONST_CACHE_GS_4
+    0x00000000, // SQ_ALU_CONST_CACHE_GS_5
+    0x00000000, // SQ_ALU_CONST_CACHE_GS_6
+    0x00000000, // SQ_ALU_CONST_CACHE_GS_7
+    0x00000000, // SQ_ALU_CONST_CACHE_GS_8
+    0x00000000, // SQ_ALU_CONST_CACHE_GS_9
+    0x00000000, // SQ_ALU_CONST_CACHE_GS_10
+    0x00000000, // SQ_ALU_CONST_CACHE_GS_11
+    0x00000000, // SQ_ALU_CONST_CACHE_GS_12
+    0x00000000, // SQ_ALU_CONST_CACHE_GS_13
+    0x00000000, // SQ_ALU_CONST_CACHE_GS_14
+    0x00000000, // SQ_ALU_CONST_CACHE_GS_15
+    0x00000000, // PA_SU_POINT_SIZE
+    0x00000000, // PA_SU_POINT_MINMAX
+    0x00000000, // PA_SU_LINE_CNTL
+    0x00000000, // PA_SC_LINE_STIPPLE
+    0x00000000, // VGT_OUTPUT_PATH_CNTL
+    0x00000000, // VGT_HOS_CNTL
+    0x00000000, // VGT_HOS_MAX_TESS_LEVEL
+    0x00000000, // VGT_HOS_MIN_TESS_LEVEL
+    0x00000000, // VGT_HOS_REUSE_DEPTH
+    0x00000000, // VGT_GROUP_PRIM_TYPE
+    0x00000000, // VGT_GROUP_FIRST_DECR
+    0x00000000, // VGT_GROUP_DECR
+    0x00000000, // VGT_GROUP_VECT_0_CNTL
+    0x00000000, // VGT_GROUP_VECT_1_CNTL
+    0x00000000, // VGT_GROUP_VECT_0_FMT_CNTL
+    0x00000000, // VGT_GROUP_VECT_1_FMT_CNTL
+    0x00000000, // VGT_GS_MODE
+    0, // HOLE
+    0x00000000, // PA_SC_MODE_CNTL_0
+    0x00000000, // PA_SC_MODE_CNTL_1
+    0x00000000, // VGT_ENHANCE
+    0x00000000, // VGT_GS_PER_ES
+    0x00000000, // VGT_ES_PER_GS
+    0x00000000, // VGT_GS_PER_VS
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // VGT_GS_OUT_PRIM_TYPE
+};
+static const u32 SECT_CONTEXT_def_5[] =
+{
+    0x00000000, // VGT_DMA_MAX_SIZE
+    0x00000000, // VGT_DMA_INDEX_TYPE
+    0, // HOLE
+    0x00000000, // VGT_PRIMITIVEID_EN
+    0x00000000, // VGT_DMA_NUM_INSTANCES
+};
+static const u32 SECT_CONTEXT_def_6[] =
+{
+    0x00000000, // VGT_MULTI_PRIM_IB_RESET_EN
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // VGT_INSTANCE_STEP_RATE_0
+    0x00000000, // VGT_INSTANCE_STEP_RATE_1
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // VGT_REUSE_OFF
+    0x00000000, // VGT_VTX_CNT_EN
+    0x00000000, // DB_HTILE_SURFACE
+    0x00000000, // DB_SRESULTS_COMPARE_STATE0
+    0x00000000, // DB_SRESULTS_COMPARE_STATE1
+    0x00000000, // DB_PRELOAD_CONTROL
+    0, // HOLE
+    0x00000000, // VGT_STRMOUT_BUFFER_SIZE_0
+    0x00000000, // VGT_STRMOUT_VTX_STRIDE_0
+    0x00000000, // VGT_STRMOUT_BUFFER_BASE_0
+    0x00000000, // VGT_STRMOUT_BUFFER_OFFSET_0
+    0x00000000, // VGT_STRMOUT_BUFFER_SIZE_1
+    0x00000000, // VGT_STRMOUT_VTX_STRIDE_1
+    0x00000000, // VGT_STRMOUT_BUFFER_BASE_1
+    0x00000000, // VGT_STRMOUT_BUFFER_OFFSET_1
+    0x00000000, // VGT_STRMOUT_BUFFER_SIZE_2
+    0x00000000, // VGT_STRMOUT_VTX_STRIDE_2
+    0x00000000, // VGT_STRMOUT_BUFFER_BASE_2
+    0x00000000, // VGT_STRMOUT_BUFFER_OFFSET_2
+    0x00000000, // VGT_STRMOUT_BUFFER_SIZE_3
+    0x00000000, // VGT_STRMOUT_VTX_STRIDE_3
+    0x00000000, // VGT_STRMOUT_BUFFER_BASE_3
+    0x00000000, // VGT_STRMOUT_BUFFER_OFFSET_3
+    0x00000000, // VGT_STRMOUT_BASE_OFFSET_0
+    0x00000000, // VGT_STRMOUT_BASE_OFFSET_1
+    0x00000000, // VGT_STRMOUT_BASE_OFFSET_2
+    0x00000000, // VGT_STRMOUT_BASE_OFFSET_3
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // VGT_STRMOUT_DRAW_OPAQUE_OFFSET
+    0x00000000, // VGT_STRMOUT_DRAW_OPAQUE_BUFFER_FILLED_SIZE
+    0x00000000, // VGT_STRMOUT_DRAW_OPAQUE_VERTEX_STRIDE
+    0, // HOLE
+    0x00000000, // VGT_GS_MAX_VERT_OUT
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // VGT_STRMOUT_BASE_OFFSET_HI_0
+    0x00000000, // VGT_STRMOUT_BASE_OFFSET_HI_1
+    0x00000000, // VGT_STRMOUT_BASE_OFFSET_HI_2
+    0x00000000, // VGT_STRMOUT_BASE_OFFSET_HI_3
+    0x00000000, // VGT_SHADER_STAGES_EN
+    0x00000000, // VGT_LS_HS_CONFIG
+    0x00000000, // VGT_LS_SIZE
+    0x00000000, // VGT_HS_SIZE
+    0x00000000, // VGT_LS_HS_ALLOC
+    0x00000000, // VGT_HS_PATCH_CONST
+    0x00000000, // VGT_TF_PARAM
+    0x00000000, // DB_ALPHA_TO_MASK
+};
+static const u32 SECT_CONTEXT_def_7[] =
+{
+    0x00000000, // PA_SU_POLY_OFFSET_DB_FMT_CNTL
+    0x00000000, // PA_SU_POLY_OFFSET_CLAMP
+    0x00000000, // PA_SU_POLY_OFFSET_FRONT_SCALE
+    0x00000000, // PA_SU_POLY_OFFSET_FRONT_OFFSET
+    0x00000000, // PA_SU_POLY_OFFSET_BACK_SCALE
+    0x00000000, // PA_SU_POLY_OFFSET_BACK_OFFSET
+    0x00000000, // VGT_GS_INSTANCE_CNT
+    0x00000000, // VGT_STRMOUT_CONFIG
+    0x00000000, // VGT_STRMOUT_BUFFER_CONFIG
+    0x00000000, // CB_IMMED0_BASE
+    0x00000000, // CB_IMMED1_BASE
+    0x00000000, // CB_IMMED2_BASE
+    0x00000000, // CB_IMMED3_BASE
+    0x00000000, // CB_IMMED4_BASE
+    0x00000000, // CB_IMMED5_BASE
+    0x00000000, // CB_IMMED6_BASE
+    0x00000000, // CB_IMMED7_BASE
+    0x00000000, // CB_IMMED8_BASE
+    0x00000000, // CB_IMMED9_BASE
+    0x00000000, // CB_IMMED10_BASE
+    0x00000000, // CB_IMMED11_BASE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0x00001000, // PA_SC_LINE_CNTL
+    0x00000000, // PA_SC_AA_CONFIG
+    0x00000005, // PA_SU_VTX_CNTL
+    0x3f800000, // PA_CL_GB_VERT_CLIP_ADJ
+    0x3f800000, // PA_CL_GB_VERT_DISC_ADJ
+    0x3f800000, // PA_CL_GB_HORZ_CLIP_ADJ
+    0x3f800000, // PA_CL_GB_HORZ_DISC_ADJ
+    0x00000000, // PA_SC_AA_SAMPLE_LOCS_0
+    0x00000000, // PA_SC_AA_SAMPLE_LOCS_1
+    0x00000000, // PA_SC_AA_SAMPLE_LOCS_2
+    0x00000000, // PA_SC_AA_SAMPLE_LOCS_3
+    0x00000000, // PA_SC_AA_SAMPLE_LOCS_4
+    0x00000000, // PA_SC_AA_SAMPLE_LOCS_5
+    0x00000000, // PA_SC_AA_SAMPLE_LOCS_6
+    0x00000000, // PA_SC_AA_SAMPLE_LOCS_7
+    0xffffffff, // PA_SC_AA_MASK
+    0x00000000, // CB_CLRCMP_CONTROL
+    0x00000000, // CB_CLRCMP_SRC
+    0x00000000, // CB_CLRCMP_DST
+    0x00000000, // CB_CLRCMP_MSK
+    0, // HOLE
+    0, // HOLE
+    0x0000000e, // VGT_VERTEX_REUSE_BLOCK_CNTL
+    0x00000010, // VGT_OUT_DEALLOC_CNTL
+    0x00000000, // CB_COLOR0_BASE
+    0x00000000, // CB_COLOR0_PITCH
+    0x00000000, // CB_COLOR0_SLICE
+    0x00000000, // CB_COLOR0_VIEW
+    0x00000000, // CB_COLOR0_INFO
+    0x00000000, // CB_COLOR0_ATTRIB
+    0x00000000, // CB_COLOR0_DIM
+    0x00000000, // CB_COLOR0_CMASK
+    0x00000000, // CB_COLOR0_CMASK_SLICE
+    0x00000000, // CB_COLOR0_FMASK
+    0x00000000, // CB_COLOR0_FMASK_SLICE
+    0x00000000, // CB_COLOR0_CLEAR_WORD0
+    0x00000000, // CB_COLOR0_CLEAR_WORD1
+    0x00000000, // CB_COLOR0_CLEAR_WORD2
+    0x00000000, // CB_COLOR0_CLEAR_WORD3
+    0x00000000, // CB_COLOR1_BASE
+    0x00000000, // CB_COLOR1_PITCH
+    0x00000000, // CB_COLOR1_SLICE
+    0x00000000, // CB_COLOR1_VIEW
+    0x00000000, // CB_COLOR1_INFO
+    0x00000000, // CB_COLOR1_ATTRIB
+    0x00000000, // CB_COLOR1_DIM
+    0x00000000, // CB_COLOR1_CMASK
+    0x00000000, // CB_COLOR1_CMASK_SLICE
+    0x00000000, // CB_COLOR1_FMASK
+    0x00000000, // CB_COLOR1_FMASK_SLICE
+    0x00000000, // CB_COLOR1_CLEAR_WORD0
+    0x00000000, // CB_COLOR1_CLEAR_WORD1
+    0x00000000, // CB_COLOR1_CLEAR_WORD2
+    0x00000000, // CB_COLOR1_CLEAR_WORD3
+    0x00000000, // CB_COLOR2_BASE
+    0x00000000, // CB_COLOR2_PITCH
+    0x00000000, // CB_COLOR2_SLICE
+    0x00000000, // CB_COLOR2_VIEW
+    0x00000000, // CB_COLOR2_INFO
+    0x00000000, // CB_COLOR2_ATTRIB
+    0x00000000, // CB_COLOR2_DIM
+    0x00000000, // CB_COLOR2_CMASK
+    0x00000000, // CB_COLOR2_CMASK_SLICE
+    0x00000000, // CB_COLOR2_FMASK
+    0x00000000, // CB_COLOR2_FMASK_SLICE
+    0x00000000, // CB_COLOR2_CLEAR_WORD0
+    0x00000000, // CB_COLOR2_CLEAR_WORD1
+    0x00000000, // CB_COLOR2_CLEAR_WORD2
+    0x00000000, // CB_COLOR2_CLEAR_WORD3
+    0x00000000, // CB_COLOR3_BASE
+    0x00000000, // CB_COLOR3_PITCH
+    0x00000000, // CB_COLOR3_SLICE
+    0x00000000, // CB_COLOR3_VIEW
+    0x00000000, // CB_COLOR3_INFO
+    0x00000000, // CB_COLOR3_ATTRIB
+    0x00000000, // CB_COLOR3_DIM
+    0x00000000, // CB_COLOR3_CMASK
+    0x00000000, // CB_COLOR3_CMASK_SLICE
+    0x00000000, // CB_COLOR3_FMASK
+    0x00000000, // CB_COLOR3_FMASK_SLICE
+    0x00000000, // CB_COLOR3_CLEAR_WORD0
+    0x00000000, // CB_COLOR3_CLEAR_WORD1
+    0x00000000, // CB_COLOR3_CLEAR_WORD2
+    0x00000000, // CB_COLOR3_CLEAR_WORD3
+    0x00000000, // CB_COLOR4_BASE
+    0x00000000, // CB_COLOR4_PITCH
+    0x00000000, // CB_COLOR4_SLICE
+    0x00000000, // CB_COLOR4_VIEW
+    0x00000000, // CB_COLOR4_INFO
+    0x00000000, // CB_COLOR4_ATTRIB
+    0x00000000, // CB_COLOR4_DIM
+    0x00000000, // CB_COLOR4_CMASK
+    0x00000000, // CB_COLOR4_CMASK_SLICE
+    0x00000000, // CB_COLOR4_FMASK
+    0x00000000, // CB_COLOR4_FMASK_SLICE
+    0x00000000, // CB_COLOR4_CLEAR_WORD0
+    0x00000000, // CB_COLOR4_CLEAR_WORD1
+    0x00000000, // CB_COLOR4_CLEAR_WORD2
+    0x00000000, // CB_COLOR4_CLEAR_WORD3
+    0x00000000, // CB_COLOR5_BASE
+    0x00000000, // CB_COLOR5_PITCH
+    0x00000000, // CB_COLOR5_SLICE
+    0x00000000, // CB_COLOR5_VIEW
+    0x00000000, // CB_COLOR5_INFO
+    0x00000000, // CB_COLOR5_ATTRIB
+    0x00000000, // CB_COLOR5_DIM
+    0x00000000, // CB_COLOR5_CMASK
+    0x00000000, // CB_COLOR5_CMASK_SLICE
+    0x00000000, // CB_COLOR5_FMASK
+    0x00000000, // CB_COLOR5_FMASK_SLICE
+    0x00000000, // CB_COLOR5_CLEAR_WORD0
+    0x00000000, // CB_COLOR5_CLEAR_WORD1
+    0x00000000, // CB_COLOR5_CLEAR_WORD2
+    0x00000000, // CB_COLOR5_CLEAR_WORD3
+    0x00000000, // CB_COLOR6_BASE
+    0x00000000, // CB_COLOR6_PITCH
+    0x00000000, // CB_COLOR6_SLICE
+    0x00000000, // CB_COLOR6_VIEW
+    0x00000000, // CB_COLOR6_INFO
+    0x00000000, // CB_COLOR6_ATTRIB
+    0x00000000, // CB_COLOR6_DIM
+    0x00000000, // CB_COLOR6_CMASK
+    0x00000000, // CB_COLOR6_CMASK_SLICE
+    0x00000000, // CB_COLOR6_FMASK
+    0x00000000, // CB_COLOR6_FMASK_SLICE
+    0x00000000, // CB_COLOR6_CLEAR_WORD0
+    0x00000000, // CB_COLOR6_CLEAR_WORD1
+    0x00000000, // CB_COLOR6_CLEAR_WORD2
+    0x00000000, // CB_COLOR6_CLEAR_WORD3
+    0x00000000, // CB_COLOR7_BASE
+    0x00000000, // CB_COLOR7_PITCH
+    0x00000000, // CB_COLOR7_SLICE
+    0x00000000, // CB_COLOR7_VIEW
+    0x00000000, // CB_COLOR7_INFO
+    0x00000000, // CB_COLOR7_ATTRIB
+    0x00000000, // CB_COLOR7_DIM
+    0x00000000, // CB_COLOR7_CMASK
+    0x00000000, // CB_COLOR7_CMASK_SLICE
+    0x00000000, // CB_COLOR7_FMASK
+    0x00000000, // CB_COLOR7_FMASK_SLICE
+    0x00000000, // CB_COLOR7_CLEAR_WORD0
+    0x00000000, // CB_COLOR7_CLEAR_WORD1
+    0x00000000, // CB_COLOR7_CLEAR_WORD2
+    0x00000000, // CB_COLOR7_CLEAR_WORD3
+    0x00000000, // CB_COLOR8_BASE
+    0x00000000, // CB_COLOR8_PITCH
+    0x00000000, // CB_COLOR8_SLICE
+    0x00000000, // CB_COLOR8_VIEW
+    0x00000000, // CB_COLOR8_INFO
+    0x00000000, // CB_COLOR8_ATTRIB
+    0x00000000, // CB_COLOR8_DIM
+    0x00000000, // CB_COLOR9_BASE
+    0x00000000, // CB_COLOR9_PITCH
+    0x00000000, // CB_COLOR9_SLICE
+    0x00000000, // CB_COLOR9_VIEW
+    0x00000000, // CB_COLOR9_INFO
+    0x00000000, // CB_COLOR9_ATTRIB
+    0x00000000, // CB_COLOR9_DIM
+    0x00000000, // CB_COLOR10_BASE
+    0x00000000, // CB_COLOR10_PITCH
+    0x00000000, // CB_COLOR10_SLICE
+    0x00000000, // CB_COLOR10_VIEW
+    0x00000000, // CB_COLOR10_INFO
+    0x00000000, // CB_COLOR10_ATTRIB
+    0x00000000, // CB_COLOR10_DIM
+    0x00000000, // CB_COLOR11_BASE
+    0x00000000, // CB_COLOR11_PITCH
+    0x00000000, // CB_COLOR11_SLICE
+    0x00000000, // CB_COLOR11_VIEW
+    0x00000000, // CB_COLOR11_INFO
+    0x00000000, // CB_COLOR11_ATTRIB
+    0x00000000, // CB_COLOR11_DIM
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // SQ_ALU_CONST_CACHE_HS_0
+    0x00000000, // SQ_ALU_CONST_CACHE_HS_1
+    0x00000000, // SQ_ALU_CONST_CACHE_HS_2
+    0x00000000, // SQ_ALU_CONST_CACHE_HS_3
+    0x00000000, // SQ_ALU_CONST_CACHE_HS_4
+    0x00000000, // SQ_ALU_CONST_CACHE_HS_5
+    0x00000000, // SQ_ALU_CONST_CACHE_HS_6
+    0x00000000, // SQ_ALU_CONST_CACHE_HS_7
+    0x00000000, // SQ_ALU_CONST_CACHE_HS_8
+    0x00000000, // SQ_ALU_CONST_CACHE_HS_9
+    0x00000000, // SQ_ALU_CONST_CACHE_HS_10
+    0x00000000, // SQ_ALU_CONST_CACHE_HS_11
+    0x00000000, // SQ_ALU_CONST_CACHE_HS_12
+    0x00000000, // SQ_ALU_CONST_CACHE_HS_13
+    0x00000000, // SQ_ALU_CONST_CACHE_HS_14
+    0x00000000, // SQ_ALU_CONST_CACHE_HS_15
+    0x00000000, // SQ_ALU_CONST_CACHE_LS_0
+    0x00000000, // SQ_ALU_CONST_CACHE_LS_1
+    0x00000000, // SQ_ALU_CONST_CACHE_LS_2
+    0x00000000, // SQ_ALU_CONST_CACHE_LS_3
+    0x00000000, // SQ_ALU_CONST_CACHE_LS_4
+    0x00000000, // SQ_ALU_CONST_CACHE_LS_5
+    0x00000000, // SQ_ALU_CONST_CACHE_LS_6
+    0x00000000, // SQ_ALU_CONST_CACHE_LS_7
+    0x00000000, // SQ_ALU_CONST_CACHE_LS_8
+    0x00000000, // SQ_ALU_CONST_CACHE_LS_9
+    0x00000000, // SQ_ALU_CONST_CACHE_LS_10
+    0x00000000, // SQ_ALU_CONST_CACHE_LS_11
+    0x00000000, // SQ_ALU_CONST_CACHE_LS_12
+    0x00000000, // SQ_ALU_CONST_CACHE_LS_13
+    0x00000000, // SQ_ALU_CONST_CACHE_LS_14
+    0x00000000, // SQ_ALU_CONST_CACHE_LS_15
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_0
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_1
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_2
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_3
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_4
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_5
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_6
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_7
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_8
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_9
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_10
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_11
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_12
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_13
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_14
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_15
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_0
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_1
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_2
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_3
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_4
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_5
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_6
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_7
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_8
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_9
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_10
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_11
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_12
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_13
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_14
+    0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_15
+};
+static const struct cs_extent_def SECT_CONTEXT_defs[] =
+{
+    {SECT_CONTEXT_def_1, 0x0000a000, 488 },
+    {SECT_CONTEXT_def_2, 0x0000a1f5, 6 },
+    {SECT_CONTEXT_def_3, 0x0000a200, 55 },
+    {SECT_CONTEXT_def_4, 0x0000a23a, 98 },
+    {SECT_CONTEXT_def_5, 0x0000a29e, 5 },
+    {SECT_CONTEXT_def_6, 0x0000a2a5, 56 },
+    {SECT_CONTEXT_def_7, 0x0000a2de, 290 },
+    { 0, 0, 0 }
+};
+static const u32 SECT_CLEAR_def_1[] =
+{
+    0xffffffff, // SQ_TEX_SAMPLER_CLEAR
+    0xffffffff, // SQ_TEX_RESOURCE_CLEAR
+    0xffffffff, // SQ_LOOP_BOOL_CLEAR
+};
+static const struct cs_extent_def SECT_CLEAR_defs[] =
+{
+    {SECT_CLEAR_def_1, 0x0000ffc0, 3 },
+    { 0, 0, 0 }
+};
+static const u32 SECT_CTRLCONST_def_1[] =
+{
+    0x00000000, // SQ_VTX_BASE_VTX_LOC
+    0x00000000, // SQ_VTX_START_INST_LOC
+};
+static const struct cs_extent_def SECT_CTRLCONST_defs[] =
+{
+    {SECT_CTRLCONST_def_1, 0x0000f3fc, 2 },
+    { 0, 0, 0 }
+};
+struct cs_section_def evergreen_cs_data[] = {
+    { SECT_CONTEXT_defs, SECT_CONTEXT },
+    { SECT_CLEAR_defs, SECT_CLEAR },
+    { SECT_CTRLCONST_defs, SECT_CTRLCONST },
+    { 0, SECT_NONE }
+};
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
index 6b559cb5..b9f64f0 100644
--- a/drivers/gpu/drm/radeon/evergreen.c
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -45,6 +45,94 @@ static const u32 crtc_offsets[6] =
 	EVERGREEN_CRTC5_REGISTER_OFFSET
 };
 
+#include "clearstate_evergreen.h"
+
+static u32 sumo_rlc_save_restore_register_list[] =
+{
+	0x98fc,
+	0x9830,
+	0x9834,
+	0x9838,
+	0x9870,
+	0x9874,
+	0x8a14,
+	0x8b24,
+	0x8bcc,
+	0x8b10,
+	0x8d00,
+	0x8d04,
+	0x8c00,
+	0x8c04,
+	0x8c08,
+	0x8c0c,
+	0x8d8c,
+	0x8c20,
+	0x8c24,
+	0x8c28,
+	0x8c18,
+	0x8c1c,
+	0x8cf0,
+	0x8e2c,
+	0x8e38,
+	0x8c30,
+	0x9508,
+	0x9688,
+	0x9608,
+	0x960c,
+	0x9610,
+	0x9614,
+	0x88c4,
+	0x88d4,
+	0xa008,
+	0x900c,
+	0x9100,
+	0x913c,
+	0x98f8,
+	0x98f4,
+	0x9b7c,
+	0x3f8c,
+	0x8950,
+	0x8954,
+	0x8a18,
+	0x8b28,
+	0x9144,
+	0x9148,
+	0x914c,
+	0x3f90,
+	0x3f94,
+	0x915c,
+	0x9160,
+	0x9178,
+	0x917c,
+	0x9180,
+	0x918c,
+	0x9190,
+	0x9194,
+	0x9198,
+	0x919c,
+	0x91a8,
+	0x91ac,
+	0x91b0,
+	0x91b4,
+	0x91b8,
+	0x91c4,
+	0x91c8,
+	0x91cc,
+	0x91d0,
+	0x91d4,
+	0x91e0,
+	0x91e4,
+	0x91ec,
+	0x91f0,
+	0x91f4,
+	0x9200,
+	0x9204,
+	0x929c,
+	0x9150,
+	0x802c,
+};
+static u32 sumo_rlc_save_restore_register_list_size = ARRAY_SIZE(sumo_rlc_save_restore_register_list);
+
 static void evergreen_gpu_init(struct radeon_device *rdev);
 void evergreen_fini(struct radeon_device *rdev);
 void evergreen_pcie_gen2_enable(struct radeon_device *rdev);
@@ -3723,6 +3811,241 @@ bool evergreen_dma_is_lockup(struct radeon_device *rdev, struct radeon_ring *rin
 	return radeon_ring_test_lockup(rdev, ring);
 }
 
+/*
+ * RLC
+ */
+#define RLC_SAVE_RESTORE_LIST_END_MARKER    0x00000000
+#define RLC_CLEAR_STATE_END_MARKER          0x00000001
+
+void sumo_rlc_fini(struct radeon_device *rdev)
+{
+	int r;
+
+	/* save restore block */
+	if (rdev->rlc.save_restore_obj) {
+		r = radeon_bo_reserve(rdev->rlc.save_restore_obj, false);
+		if (unlikely(r != 0))
+			dev_warn(rdev->dev, "(%d) reserve RLC sr bo failed\n", r);
+		radeon_bo_unpin(rdev->rlc.save_restore_obj);
+		radeon_bo_unreserve(rdev->rlc.save_restore_obj);
+
+		radeon_bo_unref(&rdev->rlc.save_restore_obj);
+		rdev->rlc.save_restore_obj = NULL;
+	}
+
+	/* clear state block */
+	if (rdev->rlc.clear_state_obj) {
+		r = radeon_bo_reserve(rdev->rlc.clear_state_obj, false);
+		if (unlikely(r != 0))
+			dev_warn(rdev->dev, "(%d) reserve RLC c bo failed\n", r);
+		radeon_bo_unpin(rdev->rlc.clear_state_obj);
+		radeon_bo_unreserve(rdev->rlc.clear_state_obj);
+
+		radeon_bo_unref(&rdev->rlc.clear_state_obj);
+		rdev->rlc.clear_state_obj = NULL;
+	}
+}
+
+int sumo_rlc_init(struct radeon_device *rdev)
+{
+	u32 *src_ptr;
+	volatile u32 *dst_ptr;
+	u32 dws, data, i, j, k, reg_num;
+	u32 reg_list_num, reg_list_hdr_blk_index, reg_list_blk_index;
+	u64 reg_list_mc_addr;
+	struct cs_section_def *cs_data;
+	int r;
+
+	src_ptr = rdev->rlc.reg_list;
+	dws = rdev->rlc.reg_list_size;
+	cs_data = rdev->rlc.cs_data;
+
+	/* save restore block */
+	if (rdev->rlc.save_restore_obj == NULL) {
+		r = radeon_bo_create(rdev, dws * 4, PAGE_SIZE, true,
+				     RADEON_GEM_DOMAIN_VRAM, NULL, &rdev->rlc.save_restore_obj);
+		if (r) {
+			dev_warn(rdev->dev, "(%d) create RLC sr bo failed\n", r);
+			return r;
+		}
+	}
+
+	r = radeon_bo_reserve(rdev->rlc.save_restore_obj, false);
+	if (unlikely(r != 0)) {
+		sumo_rlc_fini(rdev);
+		return r;
+	}
+	r = radeon_bo_pin(rdev->rlc.save_restore_obj, RADEON_GEM_DOMAIN_VRAM,
+			  &rdev->rlc.save_restore_gpu_addr);
+	if (r) {
+		radeon_bo_unreserve(rdev->rlc.save_restore_obj);
+		dev_warn(rdev->dev, "(%d) pin RLC sr bo failed\n", r);
+		sumo_rlc_fini(rdev);
+		return r;
+	}
+	r = radeon_bo_kmap(rdev->rlc.save_restore_obj, (void **)&rdev->rlc.sr_ptr);
+	if (r) {
+		dev_warn(rdev->dev, "(%d) map RLC sr bo failed\n", r);
+		sumo_rlc_fini(rdev);
+		return r;
+	}
+	/* write the sr buffer */
+	dst_ptr = rdev->rlc.sr_ptr;
+	/* format:
+	 * dw0: (reg2 << 16) | reg1
+	 * dw1: reg1 save space
+	 * dw2: reg2 save space
+	 */
+	for (i = 0; i < dws; i++) {
+		data = src_ptr[i] >> 2;
+		i++;
+		if (i < dws)
+			data |= (src_ptr[i] >> 2) << 16;
+		j = (((i - 1) * 3) / 2);
+		dst_ptr[j] = data;
+	}
+	j = ((i * 3) / 2);
+	dst_ptr[j] = RLC_SAVE_RESTORE_LIST_END_MARKER;
+
+	radeon_bo_kunmap(rdev->rlc.save_restore_obj);
+	radeon_bo_unreserve(rdev->rlc.save_restore_obj);
+
+	/* clear state block */
+	reg_list_num = 0;
+	dws = 0;
+	for (i = 0; cs_data[i].section != NULL; i++) {
+		for (j = 0; cs_data[i].section[j].extent != NULL; j++) {
+			reg_list_num++;
+			dws += cs_data[i].section[j].reg_count;
+		}
+	}
+	reg_list_blk_index = (3 * reg_list_num + 2);
+	dws += reg_list_blk_index;
+
+	if (rdev->rlc.clear_state_obj == NULL) {
+		r = radeon_bo_create(rdev, dws * 4, PAGE_SIZE, true,
+				     RADEON_GEM_DOMAIN_VRAM, NULL, &rdev->rlc.clear_state_obj);
+		if (r) {
+			dev_warn(rdev->dev, "(%d) create RLC c bo failed\n", r);
+			sumo_rlc_fini(rdev);
+			return r;
+		}
+	}
+	r = radeon_bo_reserve(rdev->rlc.clear_state_obj, false);
+	if (unlikely(r != 0)) {
+		sumo_rlc_fini(rdev);
+		return r;
+	}
+	r = radeon_bo_pin(rdev->rlc.clear_state_obj, RADEON_GEM_DOMAIN_VRAM,
+			  &rdev->rlc.clear_state_gpu_addr);
+	if (r) {
+
+		radeon_bo_unreserve(rdev->rlc.clear_state_obj);
+		dev_warn(rdev->dev, "(%d) pin RLC c bo failed\n", r);
+		sumo_rlc_fini(rdev);
+		return r;
+	}
+	r = radeon_bo_kmap(rdev->rlc.clear_state_obj, (void **)&rdev->rlc.cs_ptr);
+	if (r) {
+		dev_warn(rdev->dev, "(%d) map RLC c bo failed\n", r);
+		sumo_rlc_fini(rdev);
+		return r;
+	}
+	/* set up the cs buffer */
+	dst_ptr = rdev->rlc.cs_ptr;
+	reg_list_hdr_blk_index = 0;
+	reg_list_mc_addr = rdev->rlc.clear_state_gpu_addr + (reg_list_blk_index * 4);
+	data = upper_32_bits(reg_list_mc_addr);
+	dst_ptr[reg_list_hdr_blk_index] = data;
+	reg_list_hdr_blk_index++;
+	for (i = 0; cs_data[i].section != NULL; i++) {
+		for (j = 0; cs_data[i].section[j].extent != NULL; j++) {
+			reg_num = cs_data[i].section[j].reg_count;
+			data = reg_list_mc_addr & 0xffffffff;
+			dst_ptr[reg_list_hdr_blk_index] = data;
+			reg_list_hdr_blk_index++;
+
+			data = (cs_data[i].section[j].reg_index * 4) & 0xffffffff;
+			dst_ptr[reg_list_hdr_blk_index] = data;
+			reg_list_hdr_blk_index++;
+
+			data = 0x08000000 | (reg_num * 4);
+			dst_ptr[reg_list_hdr_blk_index] = data;
+			reg_list_hdr_blk_index++;
+
+			for (k = 0; k < reg_num; k++) {
+				data = cs_data[i].section[j].extent[k];
+				dst_ptr[reg_list_blk_index + k] = data;
+			}
+			reg_list_mc_addr += reg_num * 4;
+			reg_list_blk_index += reg_num;
+		}
+	}
+	dst_ptr[reg_list_hdr_blk_index] = RLC_CLEAR_STATE_END_MARKER;
+
+	radeon_bo_kunmap(rdev->rlc.clear_state_obj);
+	radeon_bo_unreserve(rdev->rlc.clear_state_obj);
+
+	return 0;
+}
+
+static void evergreen_rlc_start(struct radeon_device *rdev)
+{
+	if (rdev->flags & RADEON_IS_IGP)
+		WREG32(RLC_CNTL, RLC_ENABLE | GFX_POWER_GATING_ENABLE | GFX_POWER_GATING_SRC);
+	else
+		WREG32(RLC_CNTL, RLC_ENABLE);
+}
+
+int evergreen_rlc_resume(struct radeon_device *rdev)
+{
+	u32 i;
+	const __be32 *fw_data;
+
+	if (!rdev->rlc_fw)
+		return -EINVAL;
+
+	r600_rlc_stop(rdev);
+
+	WREG32(RLC_HB_CNTL, 0);
+
+	if (rdev->flags & RADEON_IS_IGP) {
+		WREG32(TN_RLC_SAVE_AND_RESTORE_BASE, rdev->rlc.save_restore_gpu_addr >> 8);
+		WREG32(TN_RLC_CLEAR_STATE_RESTORE_BASE, rdev->rlc.clear_state_gpu_addr >> 8);
+	} else {
+		WREG32(RLC_HB_BASE, 0);
+		WREG32(RLC_HB_RPTR, 0);
+		WREG32(RLC_HB_WPTR, 0);
+	}
+	WREG32(RLC_HB_WPTR_LSB_ADDR, 0);
+	WREG32(RLC_HB_WPTR_MSB_ADDR, 0);
+	WREG32(RLC_MC_CNTL, 0);
+	WREG32(RLC_UCODE_CNTL, 0);
+
+	fw_data = (const __be32 *)rdev->rlc_fw->data;
+	if (rdev->family >= CHIP_ARUBA) {
+		for (i = 0; i < ARUBA_RLC_UCODE_SIZE; i++) {
+			WREG32(RLC_UCODE_ADDR, i);
+			WREG32(RLC_UCODE_DATA, be32_to_cpup(fw_data++));
+		}
+	} else if (rdev->family >= CHIP_CAYMAN) {
+		for (i = 0; i < CAYMAN_RLC_UCODE_SIZE; i++) {
+			WREG32(RLC_UCODE_ADDR, i);
+			WREG32(RLC_UCODE_DATA, be32_to_cpup(fw_data++));
+		}
+	} else {
+		for (i = 0; i < EVERGREEN_RLC_UCODE_SIZE; i++) {
+			WREG32(RLC_UCODE_ADDR, i);
+			WREG32(RLC_UCODE_DATA, be32_to_cpup(fw_data++));
+		}
+	}
+	WREG32(RLC_UCODE_ADDR, 0);
+
+	evergreen_rlc_start(rdev);
+
+	return 0;
+}
+
 /* Interrupts */
 
 u32 evergreen_get_vblank_counter(struct radeon_device *rdev, int crtc)
@@ -4721,6 +5044,18 @@ static int evergreen_startup(struct radeon_device *rdev)
 		dev_warn(rdev->dev, "failed blitter (%d) falling back to memcpy\n", r);
 	}
 
+	/* allocate rlc buffers */
+	if (rdev->flags & RADEON_IS_IGP) {
+		rdev->rlc.reg_list = sumo_rlc_save_restore_register_list;
+		rdev->rlc.reg_list_size = sumo_rlc_save_restore_register_list_size;
+		rdev->rlc.cs_data = evergreen_cs_data;
+		r = sumo_rlc_init(rdev);
+		if (r) {
+			DRM_ERROR("Failed to init rlc BOs!\n");
+			return r;
+		}
+	}
+
 	/* allocate wb buffer */
 	r = radeon_wb_init(rdev);
 	if (r)
@@ -4952,6 +5287,8 @@ int evergreen_init(struct radeon_device *rdev)
 		r700_cp_fini(rdev);
 		r600_dma_fini(rdev);
 		r600_irq_fini(rdev);
+		if (rdev->flags & RADEON_IS_IGP)
+			sumo_rlc_fini(rdev);
 		radeon_wb_fini(rdev);
 		radeon_ib_pool_fini(rdev);
 		radeon_irq_kms_fini(rdev);
@@ -4980,6 +5317,8 @@ void evergreen_fini(struct radeon_device *rdev)
 	r700_cp_fini(rdev);
 	r600_dma_fini(rdev);
 	r600_irq_fini(rdev);
+	if (rdev->flags & RADEON_IS_IGP)
+		sumo_rlc_fini(rdev);
 	radeon_wb_fini(rdev);
 	radeon_ib_pool_fini(rdev);
 	radeon_irq_kms_fini(rdev);
diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h
index 75c0563..8603b7c 100644
--- a/drivers/gpu/drm/radeon/evergreend.h
+++ b/drivers/gpu/drm/radeon/evergreend.h
@@ -90,6 +90,25 @@
 #define CG_VCLK_STATUS                                  0x61c
 #define	CG_SCRATCH1					0x820
 
+#define RLC_CNTL                                        0x3f00
+#       define RLC_ENABLE                               (1 << 0)
+#       define GFX_POWER_GATING_ENABLE                  (1 << 7)
+#       define GFX_POWER_GATING_SRC                     (1 << 8)
+#define RLC_HB_BASE                                       0x3f10
+#define RLC_HB_CNTL                                       0x3f0c
+#define RLC_HB_RPTR                                       0x3f20
+#define RLC_HB_WPTR                                       0x3f1c
+#define RLC_HB_WPTR_LSB_ADDR                              0x3f14
+#define RLC_HB_WPTR_MSB_ADDR                              0x3f18
+#define RLC_MC_CNTL                                       0x3f44
+#define RLC_UCODE_CNTL                                    0x3f48
+#define RLC_UCODE_ADDR                                    0x3f2c
+#define RLC_UCODE_DATA                                    0x3f30
+
+/* new for TN */
+#define TN_RLC_SAVE_AND_RESTORE_BASE                      0x3f10
+#define TN_RLC_CLEAR_STATE_RESTORE_BASE                   0x3f20
+
 #define GRBM_GFX_INDEX          			0x802C
 #define		INSTANCE_INDEX(x)			((x) << 0)
 #define		SE_INDEX(x)     			((x) << 16)
diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c
index 9284346..c73d713 100644
--- a/drivers/gpu/drm/radeon/ni.c
+++ b/drivers/gpu/drm/radeon/ni.c
@@ -34,6 +34,134 @@
 #include "ni_reg.h"
 #include "cayman_blit_shaders.h"
 #include "radeon_ucode.h"
+#include "clearstate_cayman.h"
+
+static u32 tn_rlc_save_restore_register_list[] =
+{
+	0x98fc,
+	0x98f0,
+	0x9834,
+	0x9838,
+	0x9870,
+	0x9874,
+	0x8a14,
+	0x8b24,
+	0x8bcc,
+	0x8b10,
+	0x8c30,
+	0x8d00,
+	0x8d04,
+	0x8c00,
+	0x8c04,
+	0x8c10,
+	0x8c14,
+	0x8d8c,
+	0x8cf0,
+	0x8e38,
+	0x9508,
+	0x9688,
+	0x9608,
+	0x960c,
+	0x9610,
+	0x9614,
+	0x88c4,
+	0x8978,
+	0x88d4,
+	0x900c,
+	0x9100,
+	0x913c,
+	0x90e8,
+	0x9354,
+	0xa008,
+	0x98f8,
+	0x9148,
+	0x914c,
+	0x3f94,
+	0x98f4,
+	0x9b7c,
+	0x3f8c,
+	0x8950,
+	0x8954,
+	0x8a18,
+	0x8b28,
+	0x9144,
+	0x3f90,
+	0x915c,
+	0x9160,
+	0x9178,
+	0x917c,
+	0x9180,
+	0x918c,
+	0x9190,
+	0x9194,
+	0x9198,
+	0x919c,
+	0x91a8,
+	0x91ac,
+	0x91b0,
+	0x91b4,
+	0x91b8,
+	0x91c4,
+	0x91c8,
+	0x91cc,
+	0x91d0,
+	0x91d4,
+	0x91e0,
+	0x91e4,
+	0x91ec,
+	0x91f0,
+	0x91f4,
+	0x9200,
+	0x9204,
+	0x929c,
+	0x8030,
+	0x9150,
+	0x9a60,
+	0x920c,
+	0x9210,
+	0x9228,
+	0x922c,
+	0x9244,
+	0x9248,
+	0x91e8,
+	0x9294,
+	0x9208,
+	0x9224,
+	0x9240,
+	0x9220,
+	0x923c,
+	0x9258,
+	0x9744,
+	0xa200,
+	0xa204,
+	0xa208,
+	0xa20c,
+	0x8d58,
+	0x9030,
+	0x9034,
+	0x9038,
+	0x903c,
+	0x9040,
+	0x9654,
+	0x897c,
+	0xa210,
+	0xa214,
+	0x9868,
+	0xa02c,
+	0x9664,
+	0x9698,
+	0x949c,
+	0x8e10,
+	0x8e18,
+	0x8c50,
+	0x8c58,
+	0x8c60,
+	0x8c68,
+	0x89b4,
+	0x9830,
+	0x802c,
+};
+static u32 tn_rlc_save_restore_register_list_size = ARRAY_SIZE(tn_rlc_save_restore_register_list);
 
 extern bool evergreen_is_display_hung(struct radeon_device *rdev);
 extern void evergreen_print_gpu_status_regs(struct radeon_device *rdev);
@@ -45,8 +173,8 @@ extern void evergreen_irq_suspend(struct radeon_device *rdev);
 extern int evergreen_mc_init(struct radeon_device *rdev);
 extern void evergreen_fix_pci_max_read_req_size(struct radeon_device *rdev);
 extern void evergreen_pcie_gen2_enable(struct radeon_device *rdev);
-extern void si_rlc_fini(struct radeon_device *rdev);
-extern int si_rlc_init(struct radeon_device *rdev);
+extern void sumo_rlc_fini(struct radeon_device *rdev);
+extern int sumo_rlc_init(struct radeon_device *rdev);
 
 /* Firmware Names */
 MODULE_FIRMWARE("radeon/BARTS_pfp.bin");
@@ -1969,7 +2097,10 @@ static int cayman_startup(struct radeon_device *rdev)
 
 	/* allocate rlc buffers */
 	if (rdev->flags & RADEON_IS_IGP) {
-		r = si_rlc_init(rdev);
+		rdev->rlc.reg_list = tn_rlc_save_restore_register_list;
+		rdev->rlc.reg_list_size = tn_rlc_save_restore_register_list_size;
+		rdev->rlc.cs_data = cayman_cs_data;
+		r = sumo_rlc_init(rdev);
 		if (r) {
 			DRM_ERROR("Failed to init rlc BOs!\n");
 			return r;
@@ -2226,7 +2357,7 @@ int cayman_init(struct radeon_device *rdev)
 		cayman_dma_fini(rdev);
 		r600_irq_fini(rdev);
 		if (rdev->flags & RADEON_IS_IGP)
-			si_rlc_fini(rdev);
+			sumo_rlc_fini(rdev);
 		radeon_wb_fini(rdev);
 		radeon_ib_pool_fini(rdev);
 		radeon_vm_manager_fini(rdev);
@@ -2257,7 +2388,7 @@ void cayman_fini(struct radeon_device *rdev)
 	cayman_dma_fini(rdev);
 	r600_irq_fini(rdev);
 	if (rdev->flags & RADEON_IS_IGP)
-		si_rlc_fini(rdev);
+		sumo_rlc_fini(rdev);
 	radeon_wb_fini(rdev);
 	radeon_vm_manager_fini(rdev);
 	radeon_ib_pool_fini(rdev);
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index 6089261..4678ed1 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -97,6 +97,7 @@ static void r600_gpu_init(struct radeon_device *rdev);
 void r600_fini(struct radeon_device *rdev);
 void r600_irq_disable(struct radeon_device *rdev);
 static void r600_pcie_gen2_enable(struct radeon_device *rdev);
+extern int evergreen_rlc_resume(struct radeon_device *rdev);
 
 /**
  * r600_get_xclk - get the xclk
@@ -3778,7 +3779,7 @@ static void r600_rlc_start(struct radeon_device *rdev)
 	WREG32(RLC_CNTL, RLC_ENABLE);
 }
 
-static int r600_rlc_init(struct radeon_device *rdev)
+static int r600_rlc_resume(struct radeon_device *rdev)
 {
 	u32 i;
 	const __be32 *fw_data;
@@ -3790,39 +3791,16 @@ static int r600_rlc_init(struct radeon_device *rdev)
 
 	WREG32(RLC_HB_CNTL, 0);
 
-	if (rdev->family == CHIP_ARUBA) {
-		WREG32(TN_RLC_SAVE_AND_RESTORE_BASE, rdev->rlc.save_restore_gpu_addr >> 8);
-		WREG32(TN_RLC_CLEAR_STATE_RESTORE_BASE, rdev->rlc.clear_state_gpu_addr >> 8);
-	}
-	if (rdev->family <= CHIP_CAYMAN) {
-		WREG32(RLC_HB_BASE, 0);
-		WREG32(RLC_HB_RPTR, 0);
-		WREG32(RLC_HB_WPTR, 0);
-	}
-	if (rdev->family <= CHIP_CAICOS) {
-		WREG32(RLC_HB_WPTR_LSB_ADDR, 0);
-		WREG32(RLC_HB_WPTR_MSB_ADDR, 0);
-	}
+	WREG32(RLC_HB_BASE, 0);
+	WREG32(RLC_HB_RPTR, 0);
+	WREG32(RLC_HB_WPTR, 0);
+	WREG32(RLC_HB_WPTR_LSB_ADDR, 0);
+	WREG32(RLC_HB_WPTR_MSB_ADDR, 0);
 	WREG32(RLC_MC_CNTL, 0);
 	WREG32(RLC_UCODE_CNTL, 0);
 
 	fw_data = (const __be32 *)rdev->rlc_fw->data;
-	if (rdev->family >= CHIP_ARUBA) {
-		for (i = 0; i < ARUBA_RLC_UCODE_SIZE; i++) {
-			WREG32(RLC_UCODE_ADDR, i);
-			WREG32(RLC_UCODE_DATA, be32_to_cpup(fw_data++));
-		}
-	} else if (rdev->family >= CHIP_CAYMAN) {
-		for (i = 0; i < CAYMAN_RLC_UCODE_SIZE; i++) {
-			WREG32(RLC_UCODE_ADDR, i);
-			WREG32(RLC_UCODE_DATA, be32_to_cpup(fw_data++));
-		}
-	} else if (rdev->family >= CHIP_CEDAR) {
-		for (i = 0; i < EVERGREEN_RLC_UCODE_SIZE; i++) {
-			WREG32(RLC_UCODE_ADDR, i);
-			WREG32(RLC_UCODE_DATA, be32_to_cpup(fw_data++));
-		}
-	} else if (rdev->family >= CHIP_RV770) {
+	if (rdev->family >= CHIP_RV770) {
 		for (i = 0; i < R700_RLC_UCODE_SIZE; i++) {
 			WREG32(RLC_UCODE_ADDR, i);
 			WREG32(RLC_UCODE_DATA, be32_to_cpup(fw_data++));
@@ -3936,7 +3914,10 @@ int r600_irq_init(struct radeon_device *rdev)
 	r600_disable_interrupts(rdev);
 
 	/* init rlc */
-	ret = r600_rlc_init(rdev);
+	if (rdev->family >= CHIP_CEDAR)
+		ret = evergreen_rlc_resume(rdev);
+	else
+		ret = r600_rlc_resume(rdev);
 	if (ret) {
 		r600_ih_ring_fini(rdev);
 		return ret;
diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h
index 79df558..a3f926c 100644
--- a/drivers/gpu/drm/radeon/r600d.h
+++ b/drivers/gpu/drm/radeon/r600d.h
@@ -684,10 +684,6 @@
 #define RLC_UCODE_ADDR                                    0x3f2c
 #define RLC_UCODE_DATA                                    0x3f30
 
-/* new for TN */
-#define TN_RLC_SAVE_AND_RESTORE_BASE                      0x3f10
-#define TN_RLC_CLEAR_STATE_RESTORE_BASE                   0x3f20
-
 #define SRBM_SOFT_RESET                                   0xe60
 #       define SOFT_RESET_DMA                             (1 << 12)
 #       define SOFT_RESET_RLC                             (1 << 13)
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 40053c8..f4cb768 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -826,15 +826,22 @@ struct r600_blit {
 };
 
 /*
- * SI RLC stuff
+ * RLC stuff
  */
-struct si_rlc {
+#include "clearstate_defs.h"
+
+struct radeon_rlc {
 	/* for power gating */
 	struct radeon_bo	*save_restore_obj;
 	uint64_t		save_restore_gpu_addr;
+	volatile uint32_t	*sr_ptr;
+	u32                     *reg_list;
+	u32                     reg_list_size;
 	/* for clear state */
 	struct radeon_bo	*clear_state_obj;
 	uint64_t		clear_state_gpu_addr;
+	volatile uint32_t	*cs_ptr;
+	struct cs_section_def   *cs_data;
 };
 
 int radeon_ib_get(struct radeon_device *rdev, int ring,
@@ -1774,7 +1781,7 @@ struct radeon_device {
 	struct r600_vram_scratch vram_scratch;
 	int msi_enabled; /* msi enabled */
 	struct r600_ih ih; /* r6/700 interrupt ring */
-	struct si_rlc rlc;
+	struct radeon_rlc rlc;
 	struct radeon_mec mec;
 	struct work_struct hotplug_work;
 	struct work_struct audio_work;
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 067/165] drm/radeon/kms: add atom helper functions for dpm (v3)
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (66 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 066/165] drm/radeon: properly set up the RLC on ON/LN/TN (v3) alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 068/165] drm/radeon/kms: add new asic struct for rv6xx (v3) alexdeucher
                   ` (45 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

dpm needs access to atombios data and command tables
for setup and calculation of a number of parameters.

v2: endian fix
v3: fix mc reg table bug

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/radeon.h          |   33 ++
 drivers/gpu/drm/radeon/radeon_atombios.c |  660 +++++++++++++++++++++++++++++-
 drivers/gpu/drm/radeon/radeon_mode.h     |   57 +++
 3 files changed, 743 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index f4cb768..6c445f5 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -219,6 +219,39 @@ int radeon_atom_get_clock_dividers(struct radeon_device *rdev,
 				   bool strobe_mode,
 				   struct atom_clock_dividers *dividers);
 void radeon_atom_set_voltage(struct radeon_device *rdev, u16 voltage_level, u8 voltage_type);
+int radeon_atom_get_voltage_gpio_settings(struct radeon_device *rdev,
+					  u16 voltage_level, u8 voltage_type,
+					  u32 *gpio_value, u32 *gpio_mask);
+void radeon_atom_set_engine_dram_timings(struct radeon_device *rdev,
+					 u32 eng_clock, u32 mem_clock);
+int radeon_atom_get_voltage_step(struct radeon_device *rdev,
+				 u8 voltage_type, u16 *voltage_step);
+int radeon_atom_round_to_true_voltage(struct radeon_device *rdev,
+				      u8 voltage_type,
+				      u16 nominal_voltage,
+				      u16 *true_voltage);
+int radeon_atom_get_min_voltage(struct radeon_device *rdev,
+				u8 voltage_type, u16 *min_voltage);
+int radeon_atom_get_max_voltage(struct radeon_device *rdev,
+				u8 voltage_type, u16 *max_voltage);
+int radeon_atom_get_voltage_table(struct radeon_device *rdev,
+				  u8 voltage_type,
+				  struct atom_voltage_table *voltage_table);
+bool radeon_atom_is_voltage_gpio(struct radeon_device *rdev, u8 voltage_type);
+void radeon_atom_update_memory_dll(struct radeon_device *rdev,
+				   u32 mem_clock);
+void radeon_atom_set_ac_timing(struct radeon_device *rdev,
+			       u32 mem_clock);
+int radeon_atom_init_mc_reg_table(struct radeon_device *rdev,
+				  u8 module_index,
+				  struct atom_mc_reg_table *reg_table);
+int radeon_atom_get_memory_info(struct radeon_device *rdev,
+				u8 module_index, struct atom_memory_info *mem_info);
+int radeon_atom_get_mclk_range_table(struct radeon_device *rdev,
+				     bool gddr5, u8 module_index,
+				     struct atom_memory_clock_range_table *mclk_range_table);
+int radeon_atom_get_max_vddc(struct radeon_device *rdev, u8 voltage_type,
+			     u16 voltage_id, u16 *voltage);
 void rs690_pm_info(struct radeon_device *rdev);
 extern void evergreen_tiling_fields(unsigned tiling_flags, unsigned *bankw,
 				    unsigned *bankh, unsigned *mtaspect,
diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c
index bf3b924..90401fd 100644
--- a/drivers/gpu/drm/radeon/radeon_atombios.c
+++ b/drivers/gpu/drm/radeon/radeon_atombios.c
@@ -56,10 +56,6 @@ extern void
 radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_enum,
 			  uint32_t supported_device);
 
-/* local */
-static int radeon_atom_get_max_vddc(struct radeon_device *rdev, u8 voltage_type,
-				    u16 voltage_id, u16 *voltage);
-
 union atom_supported_devices {
 	struct _ATOM_SUPPORTED_DEVICES_INFO info;
 	struct _ATOM_SUPPORTED_DEVICES_INFO_2 info_2;
@@ -1516,6 +1512,10 @@ bool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev,
 						le16_to_cpu(ss_info->info_2.asSpreadSpectrum[i].usSpreadSpectrumPercentage);
 					ss->type = ss_info->info_2.asSpreadSpectrum[i].ucSpreadSpectrumMode;
 					ss->rate = le16_to_cpu(ss_info->info_2.asSpreadSpectrum[i].usSpreadRateIn10Hz);
+					if ((crev == 2) &&
+					    ((id == ASIC_INTERNAL_ENGINE_SS) ||
+					     (id == ASIC_INTERNAL_MEMORY_SS)))
+						ss->rate /= 100;
 					return true;
 				}
 			}
@@ -1530,6 +1530,9 @@ bool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev,
 						le16_to_cpu(ss_info->info_3.asSpreadSpectrum[i].usSpreadSpectrumPercentage);
 					ss->type = ss_info->info_3.asSpreadSpectrum[i].ucSpreadSpectrumMode;
 					ss->rate = le16_to_cpu(ss_info->info_3.asSpreadSpectrum[i].usSpreadRateIn10Hz);
+					if ((id == ASIC_INTERNAL_ENGINE_SS) ||
+					    (id == ASIC_INTERNAL_MEMORY_SS))
+						ss->rate /= 100;
 					if (rdev->flags & RADEON_IS_IGP)
 						radeon_atombios_get_igp_ss_overrides(rdev, ss, id);
 					return true;
@@ -2340,7 +2343,13 @@ static void radeon_atombios_parse_pplib_non_clock_info(struct radeon_device *rde
 			rdev->pm.default_vddc = rdev->pm.power_state[state_index].clock_info[0].voltage.voltage;
 			rdev->pm.default_vddci = rdev->pm.power_state[state_index].clock_info[0].voltage.vddci;
 		} else {
-			/* patch the table values with the default slck/mclk from firmware info */
+			u16 max_vddci = 0;
+
+			if (ASIC_IS_DCE4(rdev))
+				radeon_atom_get_max_voltage(rdev,
+							    SET_VOLTAGE_TYPE_ASIC_VDDCI,
+							    &max_vddci);
+			/* patch the table values with the default sclk/mclk from firmware info */
 			for (j = 0; j < mode_index; j++) {
 				rdev->pm.power_state[state_index].clock_info[j].mclk =
 					rdev->clock.default_mclk;
@@ -2349,6 +2358,9 @@ static void radeon_atombios_parse_pplib_non_clock_info(struct radeon_device *rde
 				if (vddc)
 					rdev->pm.power_state[state_index].clock_info[j].voltage.voltage =
 						vddc;
+				if (max_vddci)
+					rdev->pm.power_state[state_index].clock_info[j].voltage.vddci =
+						max_vddci;
 			}
 		}
 	}
@@ -2874,6 +2886,48 @@ void radeon_atom_set_memory_clock(struct radeon_device *rdev,
 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
 }
 
+void radeon_atom_set_engine_dram_timings(struct radeon_device *rdev,
+					 u32 eng_clock, u32 mem_clock)
+{
+	SET_ENGINE_CLOCK_PS_ALLOCATION args;
+	int index = GetIndexIntoMasterTable(COMMAND, DynamicMemorySettings);
+	u32 tmp;
+
+	memset(&args, 0, sizeof(args));
+
+	tmp = eng_clock & SET_CLOCK_FREQ_MASK;
+	tmp |= (COMPUTE_ENGINE_PLL_PARAM << 24);
+
+	args.ulTargetEngineClock = cpu_to_le32(tmp);
+	if (mem_clock)
+		args.sReserved.ulClock = cpu_to_le32(mem_clock & SET_CLOCK_FREQ_MASK);
+
+	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+}
+
+void radeon_atom_update_memory_dll(struct radeon_device *rdev,
+				   u32 mem_clock)
+{
+	u32 args;
+	int index = GetIndexIntoMasterTable(COMMAND, DynamicMemorySettings);
+
+	args = cpu_to_le32(mem_clock);	/* 10 khz */
+
+	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+}
+
+void radeon_atom_set_ac_timing(struct radeon_device *rdev,
+			       u32 mem_clock)
+{
+	SET_MEMORY_CLOCK_PS_ALLOCATION args;
+	int index = GetIndexIntoMasterTable(COMMAND, DynamicMemorySettings);
+	u32 tmp = mem_clock | (COMPUTE_MEMORY_PLL_PARAM << 24);
+
+	args.ulTargetMemoryClock = cpu_to_le32(tmp);	/* 10 khz */
+
+	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+}
+
 union set_voltage {
 	struct _SET_VOLTAGE_PS_ALLOCATION alloc;
 	struct _SET_VOLTAGE_PARAMETERS v1;
@@ -2918,8 +2972,8 @@ void radeon_atom_set_voltage(struct radeon_device *rdev, u16 voltage_level, u8 v
 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
 }
 
-static int radeon_atom_get_max_vddc(struct radeon_device *rdev, u8 voltage_type,
-				    u16 voltage_id, u16 *voltage)
+int radeon_atom_get_max_vddc(struct radeon_device *rdev, u8 voltage_type,
+			     u16 voltage_id, u16 *voltage)
 {
 	union set_voltage args;
 	int index = GetIndexIntoMasterTable(COMMAND, SetVoltage);
@@ -2957,6 +3011,598 @@ static int radeon_atom_get_max_vddc(struct radeon_device *rdev, u8 voltage_type,
 	return 0;
 }
 
+int radeon_atom_get_voltage_gpio_settings(struct radeon_device *rdev,
+					  u16 voltage_level, u8 voltage_type,
+					  u32 *gpio_value, u32 *gpio_mask)
+{
+	union set_voltage args;
+	int index = GetIndexIntoMasterTable(COMMAND, SetVoltage);
+	u8 frev, crev;
+
+	if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
+		return -EINVAL;
+
+	switch (crev) {
+	case 1:
+		return -EINVAL;
+	case 2:
+		args.v2.ucVoltageType = voltage_type;
+		args.v2.ucVoltageMode = SET_ASIC_VOLTAGE_MODE_GET_GPIOMASK;
+		args.v2.usVoltageLevel = cpu_to_le16(voltage_level);
+
+		atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+
+		*gpio_mask = le32_to_cpu(*(u32 *)&args.v2);
+
+		args.v2.ucVoltageType = voltage_type;
+		args.v2.ucVoltageMode = SET_ASIC_VOLTAGE_MODE_GET_GPIOVAL;
+		args.v2.usVoltageLevel = cpu_to_le16(voltage_level);
+
+		atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+
+		*gpio_value = le32_to_cpu(*(u32 *)&args.v2);
+		break;
+	default:
+		DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+union voltage_object_info {
+	struct  _ATOM_VOLTAGE_OBJECT_INFO v1;
+	struct  _ATOM_VOLTAGE_OBJECT_INFO_V2 v2;
+};
+
+bool
+radeon_atom_is_voltage_gpio(struct radeon_device *rdev, u8 voltage_type)
+{
+	int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo);
+	u8 frev, crev;
+	u16 data_offset, size;
+	int num_indices, i;
+	union voltage_object_info *voltage_info;
+
+	if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
+				   &frev, &crev, &data_offset)) {
+		voltage_info = (union voltage_object_info *)
+			(rdev->mode_info.atom_context->bios + data_offset);
+
+		switch (crev) {
+		case 1:
+			num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
+				sizeof(ATOM_VOLTAGE_OBJECT);
+
+			for (i = 0; i < num_indices; i++) {
+				if ((voltage_info->v1.asVoltageObj[i].ucVoltageType == voltage_type) &&
+				    (voltage_info->v1.asVoltageObj[i].asControl.ucVoltageControlId ==
+				     VOLTAGE_CONTROLLED_BY_GPIO))
+					return true;
+			}
+			break;
+		case 2:
+			num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
+				sizeof(ATOM_VOLTAGE_OBJECT_INFO_V2);
+
+			for (i = 0; i < num_indices; i++) {
+				if ((voltage_info->v2.asVoltageObj[i].ucVoltageType == voltage_type) &&
+				    (voltage_info->v2.asVoltageObj[i].asControl.ucVoltageControlId ==
+				     VOLTAGE_CONTROLLED_BY_GPIO))
+					return true;
+			}
+			break;
+		default:
+			DRM_ERROR("unknown voltage object table\n");
+			return false;
+		}
+
+	}
+	return false;
+}
+
+int radeon_atom_get_max_voltage(struct radeon_device *rdev,
+				u8 voltage_type, u16 *max_voltage)
+{
+	int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo);
+	u8 frev, crev;
+	u16 data_offset, size;
+	int num_indices, i;
+	union voltage_object_info *voltage_info;
+
+	if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
+				   &frev, &crev, &data_offset)) {
+		voltage_info = (union voltage_object_info *)
+			(rdev->mode_info.atom_context->bios + data_offset);
+
+		switch (crev) {
+		case 1:
+			num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
+				sizeof(ATOM_VOLTAGE_OBJECT);
+
+			for (i = 0; i < num_indices; i++) {
+				if (voltage_info->v1.asVoltageObj[i].ucVoltageType == voltage_type) {
+					ATOM_VOLTAGE_FORMULA *formula =
+						&voltage_info->v1.asVoltageObj[i].asFormula;
+					if (formula->ucFlag & 1)
+						*max_voltage =
+							le16_to_cpu(formula->usVoltageBaseLevel) +
+							 formula->ucNumOfVoltageEntries / 2 *
+							le16_to_cpu(formula->usVoltageStep);
+					else
+						*max_voltage =
+							le16_to_cpu(formula->usVoltageBaseLevel) +
+							(formula->ucNumOfVoltageEntries - 1) *
+							le16_to_cpu(formula->usVoltageStep);
+					return 0;
+				}
+			}
+			break;
+		case 2:
+			num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
+				sizeof(ATOM_VOLTAGE_OBJECT_INFO_V2);
+
+			for (i = 0; i < num_indices; i++) {
+				if (voltage_info->v2.asVoltageObj[i].ucVoltageType == voltage_type) {
+					ATOM_VOLTAGE_FORMULA_V2 *formula =
+						&voltage_info->v2.asVoltageObj[i].asFormula;
+					if (formula->ucNumOfVoltageEntries) {
+						*max_voltage =
+							le16_to_cpu(formula->asVIDAdjustEntries[
+									    formula->ucNumOfVoltageEntries - 1
+									    ].usVoltageValue);
+						return 0;
+					}
+				}
+			}
+			break;
+		default:
+			DRM_ERROR("unknown voltage object table\n");
+			return -EINVAL;
+		}
+
+	}
+	return -EINVAL;
+}
+
+int radeon_atom_get_min_voltage(struct radeon_device *rdev,
+				u8 voltage_type, u16 *min_voltage)
+{
+	int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo);
+	u8 frev, crev;
+	u16 data_offset, size;
+	int num_indices, i;
+	union voltage_object_info *voltage_info;
+
+	if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
+				   &frev, &crev, &data_offset)) {
+		voltage_info = (union voltage_object_info *)
+			(rdev->mode_info.atom_context->bios + data_offset);
+
+		switch (crev) {
+		case 1:
+			num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
+				sizeof(ATOM_VOLTAGE_OBJECT);
+
+			for (i = 0; i < num_indices; i++) {
+				if (voltage_info->v1.asVoltageObj[i].ucVoltageType == voltage_type) {
+					ATOM_VOLTAGE_FORMULA *formula =
+						&voltage_info->v1.asVoltageObj[i].asFormula;
+					*min_voltage =
+						le16_to_cpu(formula->usVoltageBaseLevel);
+					return 0;
+				}
+			}
+			break;
+		case 2:
+			num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
+				sizeof(ATOM_VOLTAGE_OBJECT_INFO_V2);
+
+			for (i = 0; i < num_indices; i++) {
+				if (voltage_info->v2.asVoltageObj[i].ucVoltageType == voltage_type) {
+					ATOM_VOLTAGE_FORMULA_V2 *formula =
+						&voltage_info->v2.asVoltageObj[i].asFormula;
+					if (formula->ucNumOfVoltageEntries) {
+						*min_voltage =
+							le16_to_cpu(formula->asVIDAdjustEntries[
+									    0
+									    ].usVoltageValue);
+						return 0;
+					}
+				}
+			}
+			break;
+		default:
+			DRM_ERROR("unknown voltage object table\n");
+			return -EINVAL;
+		}
+
+	}
+	return -EINVAL;
+}
+
+int radeon_atom_get_voltage_step(struct radeon_device *rdev,
+				 u8 voltage_type, u16 *voltage_step)
+{
+	int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo);
+	u8 frev, crev;
+	u16 data_offset, size;
+	int num_indices, i;
+	union voltage_object_info *voltage_info;
+
+	if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
+				   &frev, &crev, &data_offset)) {
+		voltage_info = (union voltage_object_info *)
+			(rdev->mode_info.atom_context->bios + data_offset);
+
+		switch (crev) {
+		case 1:
+			num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
+				sizeof(ATOM_VOLTAGE_OBJECT);
+
+			for (i = 0; i < num_indices; i++) {
+				if (voltage_info->v1.asVoltageObj[i].ucVoltageType == voltage_type) {
+					ATOM_VOLTAGE_FORMULA *formula =
+						&voltage_info->v1.asVoltageObj[i].asFormula;
+					if (formula->ucFlag & 1)
+						*voltage_step =
+							(le16_to_cpu(formula->usVoltageStep) + 1) / 2;
+					else
+						*voltage_step =
+							le16_to_cpu(formula->usVoltageStep);
+					return 0;
+				}
+			}
+			break;
+		case 2:
+			return -EINVAL;
+		default:
+			DRM_ERROR("unknown voltage object table\n");
+			return -EINVAL;
+		}
+
+	}
+	return -EINVAL;
+}
+
+int radeon_atom_round_to_true_voltage(struct radeon_device *rdev,
+				      u8 voltage_type,
+				      u16 nominal_voltage,
+				      u16 *true_voltage)
+{
+	u16 min_voltage, max_voltage, voltage_step;
+
+	if (radeon_atom_get_max_voltage(rdev, voltage_type, &max_voltage))
+		return -EINVAL;
+	if (radeon_atom_get_min_voltage(rdev, voltage_type, &min_voltage))
+		return -EINVAL;
+	if (radeon_atom_get_voltage_step(rdev, voltage_type, &voltage_step))
+		return -EINVAL;
+
+	if (nominal_voltage <= min_voltage)
+		*true_voltage = min_voltage;
+	else if (nominal_voltage >= max_voltage)
+		*true_voltage = max_voltage;
+	else
+		*true_voltage = min_voltage +
+			((nominal_voltage - min_voltage) / voltage_step) *
+			voltage_step;
+
+	return 0;
+}
+
+int radeon_atom_get_voltage_table(struct radeon_device *rdev,
+				  u8 voltage_type,
+				  struct atom_voltage_table *voltage_table)
+{
+	int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo);
+	u8 frev, crev;
+	u16 data_offset, size;
+	int num_indices, i, j, ret;
+	union voltage_object_info *voltage_info;
+
+	if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
+				   &frev, &crev, &data_offset)) {
+		voltage_info = (union voltage_object_info *)
+			(rdev->mode_info.atom_context->bios + data_offset);
+
+		switch (crev) {
+		case 1:
+			DRM_ERROR("old table version %d, %d\n", frev, crev);
+			return -EINVAL;
+		case 2:
+			num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
+				sizeof(ATOM_VOLTAGE_OBJECT_INFO_V2);
+
+			for (i = 0; i < num_indices; i++) {
+				if (voltage_info->v2.asVoltageObj[i].ucVoltageType == voltage_type) {
+					ATOM_VOLTAGE_FORMULA_V2 *formula =
+						&voltage_info->v2.asVoltageObj[i].asFormula;
+					if (formula->ucNumOfVoltageEntries > MAX_VOLTAGE_ENTRIES)
+						return -EINVAL;
+					for (j = 0; j < formula->ucNumOfVoltageEntries; j++) {
+						voltage_table->entries[j].value =
+							le16_to_cpu(formula->asVIDAdjustEntries[j].usVoltageValue);
+						ret = radeon_atom_get_voltage_gpio_settings(rdev,
+											    voltage_table->entries[j].value,
+											    voltage_type,
+											    &voltage_table->entries[j].smio_low,
+											    &voltage_table->mask_low);
+						if (ret)
+							return ret;
+					}
+					voltage_table->count = formula->ucNumOfVoltageEntries;
+					return 0;
+				}
+			}
+			break;
+		default:
+			DRM_ERROR("unknown voltage object table\n");
+			return -EINVAL;
+		}
+
+	}
+	return -EINVAL;
+}
+
+union vram_info {
+	struct _ATOM_VRAM_INFO_V3 v1_3;
+	struct _ATOM_VRAM_INFO_V4 v1_4;
+	struct _ATOM_VRAM_INFO_HEADER_V2_1 v2_1;
+};
+
+int radeon_atom_get_memory_info(struct radeon_device *rdev,
+				u8 module_index, struct atom_memory_info *mem_info)
+{
+	int index = GetIndexIntoMasterTable(DATA, VRAM_Info);
+	u8 frev, crev, i;
+	u16 data_offset, size;
+	union vram_info *vram_info;
+	u8 *p;
+
+	memset(mem_info, 0, sizeof(struct atom_memory_info));
+
+	if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
+				   &frev, &crev, &data_offset)) {
+		vram_info = (union vram_info *)
+			(rdev->mode_info.atom_context->bios + data_offset);
+		switch (frev) {
+		case 1:
+			switch (crev) {
+			case 3:
+				/* r6xx */
+				if (module_index < vram_info->v1_3.ucNumOfVRAMModule) {
+					ATOM_VRAM_MODULE_V3 *vram_module =
+						(ATOM_VRAM_MODULE_V3 *)vram_info->v1_3.aVramInfo;
+					p = (u8 *)vram_info->v1_3.aVramInfo;
+
+					for (i = 0; i < module_index; i++) {
+						vram_module = (ATOM_VRAM_MODULE_V3 *)p;
+						if (le16_to_cpu(vram_module->usSize) == 0)
+							return -EINVAL;
+						p += le16_to_cpu(vram_module->usSize);
+					}
+					mem_info->mem_vendor = vram_module->asMemory.ucMemoryVenderID & 0xf;
+					mem_info->mem_type = vram_module->asMemory.ucMemoryType & 0xf0;
+				} else
+					return -EINVAL;
+				break;
+			case 4:
+				/* r7xx, evergreen */
+				if (module_index < vram_info->v1_4.ucNumOfVRAMModule) {
+					ATOM_VRAM_MODULE_V4 *vram_module =
+						(ATOM_VRAM_MODULE_V4 *)vram_info->v1_4.aVramInfo;
+					p = (u8 *)vram_info->v1_4.aVramInfo;
+
+					for (i = 0; i < module_index; i++) {
+						vram_module = (ATOM_VRAM_MODULE_V4 *)p;
+						if (le16_to_cpu(vram_module->usModuleSize) == 0)
+							return -EINVAL;
+						p += le16_to_cpu(vram_module->usModuleSize);
+					}
+					mem_info->mem_vendor = vram_module->ucMemoryVenderID & 0xf;
+					mem_info->mem_type = vram_module->ucMemoryType & 0xf0;
+				} else
+					return -EINVAL;
+				break;
+			default:
+				DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
+				return -EINVAL;
+			}
+			break;
+		case 2:
+			switch (crev) {
+			case 1:
+				/* ni */
+				if (module_index < vram_info->v2_1.ucNumOfVRAMModule) {
+					ATOM_VRAM_MODULE_V7 *vram_module =
+						(ATOM_VRAM_MODULE_V7 *)vram_info->v2_1.aVramInfo;
+					p = (u8 *)vram_info->v2_1.aVramInfo;
+
+					for (i = 0; i < module_index; i++) {
+						vram_module = (ATOM_VRAM_MODULE_V7 *)p;
+						if (le16_to_cpu(vram_module->usModuleSize) == 0)
+							return -EINVAL;
+						p += le16_to_cpu(vram_module->usModuleSize);
+					}
+					mem_info->mem_vendor = vram_module->ucMemoryVenderID & 0xf;
+					mem_info->mem_type = vram_module->ucMemoryType & 0xf0;
+				} else
+					return -EINVAL;
+				break;
+			default:
+				DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
+				return -EINVAL;
+			}
+			break;
+		default:
+			DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
+			return -EINVAL;
+		}
+		return 0;
+	}
+	return -EINVAL;
+}
+
+int radeon_atom_get_mclk_range_table(struct radeon_device *rdev,
+				     bool gddr5, u8 module_index,
+				     struct atom_memory_clock_range_table *mclk_range_table)
+{
+	int index = GetIndexIntoMasterTable(DATA, VRAM_Info);
+	u8 frev, crev, i;
+	u16 data_offset, size;
+	union vram_info *vram_info;
+	u32 mem_timing_size = gddr5 ?
+		sizeof(ATOM_MEMORY_TIMING_FORMAT_V2) : sizeof(ATOM_MEMORY_TIMING_FORMAT);
+	u8 *p;
+
+	memset(mclk_range_table, 0, sizeof(struct atom_memory_clock_range_table));
+
+	if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
+				   &frev, &crev, &data_offset)) {
+		vram_info = (union vram_info *)
+			(rdev->mode_info.atom_context->bios + data_offset);
+		switch (frev) {
+		case 1:
+			switch (crev) {
+			case 3:
+				DRM_ERROR("old table version %d, %d\n", frev, crev);
+				return -EINVAL;
+			case 4:
+				/* r7xx, evergreen */
+				if (module_index < vram_info->v1_4.ucNumOfVRAMModule) {
+					ATOM_VRAM_MODULE_V4 *vram_module =
+						(ATOM_VRAM_MODULE_V4 *)vram_info->v1_4.aVramInfo;
+					ATOM_MEMORY_TIMING_FORMAT *format;
+					p = (u8 *)vram_info->v1_4.aVramInfo;
+
+					for (i = 0; i < module_index; i++) {
+						vram_module = (ATOM_VRAM_MODULE_V4 *)p;
+						if (le16_to_cpu(vram_module->usModuleSize) == 0)
+							return -EINVAL;
+						p += le16_to_cpu(vram_module->usModuleSize);
+					}
+					mclk_range_table->num_entries = (u8)
+						((vram_module->usModuleSize - offsetof(ATOM_VRAM_MODULE_V4, asMemTiming)) /
+						 mem_timing_size);
+					p = (u8 *)vram_module->asMemTiming;
+					for (i = 0; i < mclk_range_table->num_entries; i++) {
+						format = (ATOM_MEMORY_TIMING_FORMAT *)p;
+						mclk_range_table->mclk[i] = format->ulClkRange;
+						p += mem_timing_size;
+					}
+				} else
+					return -EINVAL;
+				break;
+			default:
+				DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
+				return -EINVAL;
+			}
+			break;
+		case 2:
+			DRM_ERROR("new table version %d, %d\n", frev, crev);
+			return -EINVAL;
+		default:
+			DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
+			return -EINVAL;
+		}
+		return 0;
+	}
+	return -EINVAL;
+}
+
+#define MEM_ID_MASK           0xff000000
+#define MEM_ID_SHIFT          24
+#define CLOCK_RANGE_MASK      0x00ffffff
+#define CLOCK_RANGE_SHIFT     0
+#define LOW_NIBBLE_MASK       0xf
+#define DATA_EQU_PREV         0
+#define DATA_FROM_TABLE       4
+
+int radeon_atom_init_mc_reg_table(struct radeon_device *rdev,
+				  u8 module_index,
+				  struct atom_mc_reg_table *reg_table)
+{
+	int index = GetIndexIntoMasterTable(DATA, VRAM_Info);
+	u8 frev, crev, num_entries, t_mem_id, num_ranges = 0;
+	u32 i = 0, j;
+	u16 data_offset, size;
+	union vram_info *vram_info;
+
+	memset(reg_table, 0, sizeof(struct atom_mc_reg_table));
+
+	if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
+				   &frev, &crev, &data_offset)) {
+		vram_info = (union vram_info *)
+			(rdev->mode_info.atom_context->bios + data_offset);
+		switch (frev) {
+		case 1:
+			DRM_ERROR("old table version %d, %d\n", frev, crev);
+			return -EINVAL;
+		case 2:
+			switch (crev) {
+			case 1:
+				if (module_index < vram_info->v2_1.ucNumOfVRAMModule) {
+					ATOM_INIT_REG_BLOCK *reg_block =
+						(ATOM_INIT_REG_BLOCK *)
+						((u8 *)vram_info + le16_to_cpu(vram_info->v2_1.usMemClkPatchTblOffset));
+					ATOM_MEMORY_SETTING_DATA_BLOCK *reg_data =
+						(ATOM_MEMORY_SETTING_DATA_BLOCK *)
+						((u8 *)reg_block + (2 * sizeof(u16)) +
+						 le16_to_cpu(reg_block->usRegIndexTblSize));
+					num_entries = (u8)((le16_to_cpu(reg_block->usRegIndexTblSize)) /
+							   sizeof(ATOM_INIT_REG_INDEX_FORMAT)) - 1;
+					if (num_entries > VBIOS_MC_REGISTER_ARRAY_SIZE)
+						return -EINVAL;
+					while (!(reg_block->asRegIndexBuf[i].ucPreRegDataLength & ACCESS_PLACEHOLDER) &&
+					      (i < num_entries)) {
+						reg_table->mc_reg_address[i].s1 =
+							(u16)(reg_block->asRegIndexBuf[i].usRegIndex);
+						reg_table->mc_reg_address[i].pre_reg_data =
+							(u8)(reg_block->asRegIndexBuf[i].ucPreRegDataLength);
+						i++;
+					}
+					reg_table->last = i;
+					while ((*(u32 *)reg_data != END_OF_REG_DATA_BLOCK) &&
+					       (num_ranges < VBIOS_MAX_AC_TIMING_ENTRIES)) {
+						t_mem_id = (u8)((*(u32 *)reg_data & MEM_ID_MASK) >> MEM_ID_SHIFT);
+						if (module_index == t_mem_id) {
+							reg_table->mc_reg_table_entry[num_ranges].mclk_max =
+								(u32)((*(u32 *)reg_data & CLOCK_RANGE_MASK) >> CLOCK_RANGE_SHIFT);
+							for (i = 0, j = 1; i < reg_table->last; i++) {
+								if ((reg_table->mc_reg_address[i].pre_reg_data & LOW_NIBBLE_MASK) == DATA_FROM_TABLE) {
+									reg_table->mc_reg_table_entry[num_ranges].mc_data[i] =
+										(u32)*((u32 *)reg_data + j);
+									j++;
+								} else if ((reg_table->mc_reg_address[i].pre_reg_data & LOW_NIBBLE_MASK) == DATA_EQU_PREV) {
+									reg_table->mc_reg_table_entry[num_ranges].mc_data[i] =
+										reg_table->mc_reg_table_entry[num_ranges].mc_data[i - 1];
+								}
+							}
+							num_ranges++;
+						}
+						reg_data += reg_block->usRegDataBlkSize;
+					}
+					if (*(u32 *)reg_data != END_OF_REG_DATA_BLOCK)
+						return -EINVAL;
+					reg_table->num_entries = num_ranges;
+				} else
+					return -EINVAL;
+				break;
+			default:
+				DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
+				return -EINVAL;
+			}
+			break;
+		default:
+			DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
+			return -EINVAL;
+		}
+		return 0;
+	}
+	return -EINVAL;
+}
+
 void radeon_atom_initialize_bios_scratch_regs(struct drm_device *dev)
 {
 	struct radeon_device *rdev = dev->dev_private;
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
index 576511f..5a1c69e 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -519,6 +519,63 @@ struct atom_clock_dividers {
 	u32 flags;
 };
 
+#define MEM_TYPE_GDDR5  0x50
+#define MEM_TYPE_GDDR4  0x40
+#define MEM_TYPE_GDDR3  0x30
+#define MEM_TYPE_DDR2   0x20
+#define MEM_TYPE_GDDR1  0x10
+#define MEM_TYPE_DDR3   0xb0
+#define MEM_TYPE_MASK   0xf0
+
+struct atom_memory_info {
+	u8 mem_vendor;
+	u8 mem_type;
+};
+
+#define MAX_AC_TIMING_ENTRIES 16
+
+struct atom_memory_clock_range_table
+{
+	u8 num_entries;
+	u8 rsv[3];
+	u32 mclk[MAX_AC_TIMING_ENTRIES];
+};
+
+#define VBIOS_MC_REGISTER_ARRAY_SIZE 32
+#define VBIOS_MAX_AC_TIMING_ENTRIES 20
+
+struct atom_mc_reg_entry {
+	u32 mclk_max;
+	u32 mc_data[VBIOS_MC_REGISTER_ARRAY_SIZE];
+};
+
+struct atom_mc_register_address {
+	u16 s1;
+	u8 pre_reg_data;
+};
+
+struct atom_mc_reg_table {
+	u8 last;
+	u8 num_entries;
+	struct atom_mc_reg_entry mc_reg_table_entry[VBIOS_MAX_AC_TIMING_ENTRIES];
+	struct atom_mc_register_address mc_reg_address[VBIOS_MC_REGISTER_ARRAY_SIZE];
+};
+
+#define MAX_VOLTAGE_ENTRIES 32
+
+struct atom_voltage_table_entry
+{
+	u16 value;
+	u32 smio_low;
+};
+
+struct atom_voltage_table
+{
+	u32 count;
+	u32 mask_low;
+	struct atom_voltage_table_entry entries[MAX_VOLTAGE_ENTRIES];
+};
+
 extern enum radeon_tv_std
 radeon_combios_get_tv_info(struct radeon_device *rdev);
 extern enum radeon_tv_std
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 068/165] drm/radeon/kms: add new asic struct for rv6xx (v3)
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (67 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 067/165] drm/radeon/kms: add atom helper functions for dpm (v3) alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 069/165] drm/radeon/kms: add common dpm infrastructure alexdeucher
                   ` (44 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Has a different dpm controller than r600.

v2: rebase on gpu reset changes
v3: rebase on get_xclk changes

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/radeon_asic.c |   96 ++++++++++++++++++++++++++++++++--
 1 files changed, 91 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c
index 5736377..d9c8e9a 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.c
+++ b/drivers/gpu/drm/radeon/radeon_asic.c
@@ -1025,6 +1025,93 @@ static struct radeon_asic r600_asic = {
 	},
 };
 
+static struct radeon_asic rv6xx_asic = {
+	.init = &r600_init,
+	.fini = &r600_fini,
+	.suspend = &r600_suspend,
+	.resume = &r600_resume,
+	.vga_set_state = &r600_vga_set_state,
+	.asic_reset = &r600_asic_reset,
+	.ioctl_wait_idle = r600_ioctl_wait_idle,
+	.gui_idle = &r600_gui_idle,
+	.mc_wait_for_idle = &r600_mc_wait_for_idle,
+	.get_xclk = &r600_get_xclk,
+	.get_gpu_clock_counter = &r600_get_gpu_clock_counter,
+	.gart = {
+		.tlb_flush = &r600_pcie_gart_tlb_flush,
+		.set_page = &rs600_gart_set_page,
+	},
+	.ring = {
+		[RADEON_RING_TYPE_GFX_INDEX] = {
+			.ib_execute = &r600_ring_ib_execute,
+			.emit_fence = &r600_fence_ring_emit,
+			.emit_semaphore = &r600_semaphore_ring_emit,
+			.cs_parse = &r600_cs_parse,
+			.ring_test = &r600_ring_test,
+			.ib_test = &r600_ib_test,
+			.is_lockup = &r600_gfx_is_lockup,
+		},
+		[R600_RING_TYPE_DMA_INDEX] = {
+			.ib_execute = &r600_dma_ring_ib_execute,
+			.emit_fence = &r600_dma_fence_ring_emit,
+			.emit_semaphore = &r600_dma_semaphore_ring_emit,
+			.cs_parse = &r600_dma_cs_parse,
+			.ring_test = &r600_dma_ring_test,
+			.ib_test = &r600_dma_ib_test,
+			.is_lockup = &r600_dma_is_lockup,
+		}
+	},
+	.irq = {
+		.set = &r600_irq_set,
+		.process = &r600_irq_process,
+	},
+	.display = {
+		.bandwidth_update = &rv515_bandwidth_update,
+		.get_vblank_counter = &rs600_get_vblank_counter,
+		.wait_for_vblank = &avivo_wait_for_vblank,
+		.set_backlight_level = &atombios_set_backlight_level,
+		.get_backlight_level = &atombios_get_backlight_level,
+	},
+	.copy = {
+		.blit = &r600_copy_blit,
+		.blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+		.dma = &r600_copy_dma,
+		.dma_ring_index = R600_RING_TYPE_DMA_INDEX,
+		.copy = &r600_copy_dma,
+		.copy_ring_index = R600_RING_TYPE_DMA_INDEX,
+	},
+	.surface = {
+		.set_reg = r600_set_surface_reg,
+		.clear_reg = r600_clear_surface_reg,
+	},
+	.hpd = {
+		.init = &r600_hpd_init,
+		.fini = &r600_hpd_fini,
+		.sense = &r600_hpd_sense,
+		.set_polarity = &r600_hpd_set_polarity,
+	},
+	.pm = {
+		.misc = &r600_pm_misc,
+		.prepare = &rs600_pm_prepare,
+		.finish = &rs600_pm_finish,
+		.init_profile = &r600_pm_init_profile,
+		.get_dynpm_state = &r600_pm_get_dynpm_state,
+		.get_engine_clock = &radeon_atom_get_engine_clock,
+		.set_engine_clock = &radeon_atom_set_engine_clock,
+		.get_memory_clock = &radeon_atom_get_memory_clock,
+		.set_memory_clock = &radeon_atom_set_memory_clock,
+		.get_pcie_lanes = &r600_get_pcie_lanes,
+		.set_pcie_lanes = &r600_set_pcie_lanes,
+		.set_clock_gating = NULL,
+		.get_temperature = &rv6xx_get_temp,
+	},
+	.pflip = {
+		.pre_page_flip = &rs600_pre_page_flip,
+		.page_flip = &rs600_page_flip,
+		.post_page_flip = &rs600_post_page_flip,
+	},
+};
+
 static struct radeon_asic rs780_asic = {
 	.init = &r600_init,
 	.fini = &r600_fini,
@@ -2286,16 +2373,15 @@ int radeon_asic_init(struct radeon_device *rdev)
 		rdev->asic = &r520_asic;
 		break;
 	case CHIP_R600:
+		rdev->asic = &r600_asic;
+		break;
 	case CHIP_RV610:
 	case CHIP_RV630:
 	case CHIP_RV620:
 	case CHIP_RV635:
 	case CHIP_RV670:
-		rdev->asic = &r600_asic;
-		if (rdev->family == CHIP_R600)
-			rdev->has_uvd = false;
-		else
-			rdev->has_uvd = true;
+		rdev->asic = &rv6xx_asic;
+		rdev->has_uvd = true;
 		break;
 	case CHIP_RS780:
 	case CHIP_RS880:
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 069/165] drm/radeon/kms: add common dpm infrastructure
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (68 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 068/165] drm/radeon/kms: add new asic struct for rv6xx (v3) alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 10:27   ` Jerome Glisse
  2013-06-27 13:52   ` K. Schnass
  2013-06-26 13:22 ` [PATCH 070/165] drm/radeon/kms: fix up rs780/rs880 display watermark calc for dpm alexdeucher
                   ` (43 subsequent siblings)
  113 siblings, 2 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

This adds the common dpm (dynamic power management)
infrastructure:
- dpm callbacks
- dpm init/fini/suspend/resume
- dpm power state selection

No device specific code is enabled yet.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/radeon.h     |  100 +++++++-
 drivers/gpu/drm/radeon/radeon_drv.c |    4 +
 drivers/gpu/drm/radeon/radeon_pm.c  |  496 ++++++++++++++++++++++++++++++++++-
 3 files changed, 591 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 6c445f5..c43673c 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -96,6 +96,7 @@ extern int radeon_pcie_gen2;
 extern int radeon_msi;
 extern int radeon_lockup_timeout;
 extern int radeon_fastfb;
+extern int radeon_dpm;
 
 /*
  * Copy from radeon_drv.h so we don't have to include both and have conflicting
@@ -1048,6 +1049,7 @@ struct radeon_wb {
 enum radeon_pm_method {
 	PM_METHOD_PROFILE,
 	PM_METHOD_DYNPM,
+	PM_METHOD_DPM,
 };
 
 enum radeon_dynpm_state {
@@ -1073,11 +1075,23 @@ enum radeon_voltage_type {
 };
 
 enum radeon_pm_state_type {
+	/* not used for dpm */
 	POWER_STATE_TYPE_DEFAULT,
 	POWER_STATE_TYPE_POWERSAVE,
+	/* user selectable states */
 	POWER_STATE_TYPE_BATTERY,
 	POWER_STATE_TYPE_BALANCED,
 	POWER_STATE_TYPE_PERFORMANCE,
+	/* internal states */
+	POWER_STATE_TYPE_INTERNAL_UVD,
+	POWER_STATE_TYPE_INTERNAL_UVD_SD,
+	POWER_STATE_TYPE_INTERNAL_UVD_HD,
+	POWER_STATE_TYPE_INTERNAL_UVD_HD2,
+	POWER_STATE_TYPE_INTERNAL_UVD_MVC,
+	POWER_STATE_TYPE_INTERNAL_BOOT,
+	POWER_STATE_TYPE_INTERNAL_THERMAL,
+	POWER_STATE_TYPE_INTERNAL_ACPI,
+	POWER_STATE_TYPE_INTERNAL_ULV,
 };
 
 enum radeon_pm_profile_type {
@@ -1106,12 +1120,16 @@ struct radeon_pm_profile {
 
 enum radeon_int_thermal_type {
 	THERMAL_TYPE_NONE,
+	THERMAL_TYPE_EXTERNAL,
+	THERMAL_TYPE_EXTERNAL_GPIO,
 	THERMAL_TYPE_RV6XX,
 	THERMAL_TYPE_RV770,
+	THERMAL_TYPE_ADT7473_WITH_INTERNAL,
 	THERMAL_TYPE_EVERGREEN,
 	THERMAL_TYPE_SUMO,
 	THERMAL_TYPE_NI,
 	THERMAL_TYPE_SI,
+	THERMAL_TYPE_EMC2103_WITH_INTERNAL,
 	THERMAL_TYPE_CI,
 };
 
@@ -1166,6 +1184,60 @@ struct radeon_power_state {
  */
 #define RADEON_MODE_OVERCLOCK_MARGIN 500 /* 5 MHz */
 
+struct radeon_ps {
+	u32 caps; /* vbios flags */
+	u32 class; /* vbios flags */
+	u32 class2; /* vbios flags */
+	/* UVD clocks */
+	u32 vclk;
+	u32 dclk;
+	/* asic priv */
+	void *ps_priv;
+};
+
+struct radeon_dpm_thermal {
+	/* thermal interrupt work */
+	struct work_struct work;
+	/* low temperature threshold */
+	int                min_temp;
+	/* high temperature threshold */
+	int                max_temp;
+	/* was interrupt low to high or high to low */
+	bool               high_to_low;
+};
+
+struct radeon_dpm {
+	struct radeon_ps        *ps;
+	/* number of valid power states */
+	int                     num_ps;
+	/* current power state that is active */
+	struct radeon_ps        *current_ps;
+	/* requested power state */
+	struct radeon_ps        *requested_ps;
+	/* boot up power state */
+	struct radeon_ps        *boot_ps;
+	/* default uvd power state */
+	struct radeon_ps        *uvd_ps;
+	enum radeon_pm_state_type state;
+	enum radeon_pm_state_type user_state;
+	u32                     platform_caps;
+	u32                     voltage_response_time;
+	u32                     backbias_response_time;
+	void                    *priv;
+	u32			new_active_crtcs;
+	int			new_active_crtc_count;
+	u32			current_active_crtcs;
+	int			current_active_crtc_count;
+	/* special states active */
+	bool                    thermal_active;
+	/* thermal handling */
+	struct radeon_dpm_thermal thermal;
+};
+
+void radeon_dpm_enable_power_state(struct radeon_device *rdev,
+				    enum radeon_pm_state_type dpm_state);
+
+
 struct radeon_pm {
 	struct mutex		mutex;
 	/* write locked while reprogramming mclk */
@@ -1219,6 +1291,9 @@ struct radeon_pm {
 	/* internal thermal controller on rv6xx+ */
 	enum radeon_int_thermal_type int_thermal_type;
 	struct device	        *int_hwmon_dev;
+	/* dpm */
+	bool                    dpm_enabled;
+	struct radeon_dpm       dpm;
 };
 
 int radeon_pm_get_type_index(struct radeon_device *rdev,
@@ -1416,7 +1491,7 @@ struct radeon_asic {
 		bool (*sense)(struct radeon_device *rdev, enum radeon_hpd_id hpd);
 		void (*set_polarity)(struct radeon_device *rdev, enum radeon_hpd_id hpd);
 	} hpd;
-	/* power management */
+	/* static power management */
 	struct {
 		void (*misc)(struct radeon_device *rdev);
 		void (*prepare)(struct radeon_device *rdev);
@@ -1433,6 +1508,19 @@ struct radeon_asic {
 		int (*set_uvd_clocks)(struct radeon_device *rdev, u32 vclk, u32 dclk);
 		int (*get_temperature)(struct radeon_device *rdev);
 	} pm;
+	/* dynamic power management */
+	struct {
+		int (*init)(struct radeon_device *rdev);
+		void (*setup_asic)(struct radeon_device *rdev);
+		int (*enable)(struct radeon_device *rdev);
+		void (*disable)(struct radeon_device *rdev);
+		int (*set_power_state)(struct radeon_device *rdev);
+		void (*display_configuration_changed)(struct radeon_device *rdev);
+		void (*fini)(struct radeon_device *rdev);
+		u32 (*get_sclk)(struct radeon_device *rdev, bool low);
+		u32 (*get_mclk)(struct radeon_device *rdev, bool low);
+		void (*print_power_state)(struct radeon_device *rdev, struct radeon_ps *ps);
+	} dpm;
 	/* pageflipping */
 	struct {
 		void (*pre_page_flip)(struct radeon_device *rdev, int crtc);
@@ -2122,6 +2210,16 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v);
 #define radeon_mc_wait_for_idle(rdev) (rdev)->asic->mc_wait_for_idle((rdev))
 #define radeon_get_xclk(rdev) (rdev)->asic->get_xclk((rdev))
 #define radeon_get_gpu_clock_counter(rdev) (rdev)->asic->get_gpu_clock_counter((rdev))
+#define radeon_dpm_init(rdev) rdev->asic->dpm.init((rdev))
+#define radeon_dpm_setup_asic(rdev) rdev->asic->dpm.setup_asic((rdev))
+#define radeon_dpm_enable(rdev) rdev->asic->dpm.enable((rdev))
+#define radeon_dpm_disable(rdev) rdev->asic->dpm.disable((rdev))
+#define radeon_dpm_set_power_state(rdev) rdev->asic->dpm.set_power_state((rdev))
+#define radeon_dpm_display_configuration_changed(rdev) rdev->asic->dpm.display_configuration_changed((rdev))
+#define radeon_dpm_fini(rdev) rdev->asic->dpm.fini((rdev))
+#define radeon_dpm_get_sclk(rdev, l) rdev->asic->dpm.get_sclk((rdev), (l))
+#define radeon_dpm_get_mclk(rdev, l) rdev->asic->dpm.get_mclk((rdev), (l))
+#define radeon_dpm_print_power_state(rdev, ps) rdev->asic->dpm.print_power_state((rdev), (ps))
 
 /* Common functions */
 /* AGP */
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c
index 02709e4..00cc52e 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -165,6 +165,7 @@ int radeon_pcie_gen2 = -1;
 int radeon_msi = -1;
 int radeon_lockup_timeout = 10000;
 int radeon_fastfb = 0;
+int radeon_dpm = -1;
 
 MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers");
 module_param_named(no_wb, radeon_no_wb, int, 0444);
@@ -220,6 +221,9 @@ module_param_named(lockup_timeout, radeon_lockup_timeout, int, 0444);
 MODULE_PARM_DESC(fastfb, "Direct FB access for IGP chips (0 = disable, 1 = enable)");
 module_param_named(fastfb, radeon_fastfb, int, 0444);
 
+MODULE_PARM_DESC(dpm, "DPM support (1 = enable, 0 = disable, -1 = auto)");
+module_param_named(dpm, radeon_dpm, int, 0444);
+
 static struct pci_device_id pciidlist[] = {
 	radeon_PCI_IDS
 };
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
index e8c1bea..4f5422e 100644
--- a/drivers/gpu/drm/radeon/radeon_pm.c
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
@@ -388,7 +388,8 @@ static ssize_t radeon_get_pm_method(struct device *dev,
 	int pm = rdev->pm.pm_method;
 
 	return snprintf(buf, PAGE_SIZE, "%s\n",
-			(pm == PM_METHOD_DYNPM) ? "dynpm" : "profile");
+			(pm == PM_METHOD_DYNPM) ? "dynpm" :
+			(pm == PM_METHOD_PROFILE) ? "profile" : "dpm");
 }
 
 static ssize_t radeon_set_pm_method(struct device *dev,
@@ -399,6 +400,11 @@ static ssize_t radeon_set_pm_method(struct device *dev,
 	struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
 	struct radeon_device *rdev = ddev->dev_private;
 
+	/* we don't support the legacy modes with dpm */
+	if (rdev->pm.pm_method == PM_METHOD_DPM) {
+		count = -EINVAL;
+		goto fail;
+	}
 
 	if (strncmp("dynpm", buf, strlen("dynpm")) == 0) {
 		mutex_lock(&rdev->pm.mutex);
@@ -423,8 +429,48 @@ fail:
 	return count;
 }
 
+static ssize_t radeon_get_dpm_state(struct device *dev,
+				    struct device_attribute *attr,
+				    char *buf)
+{
+	struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
+	struct radeon_device *rdev = ddev->dev_private;
+	enum radeon_pm_state_type pm = rdev->pm.dpm.user_state;
+
+	return snprintf(buf, PAGE_SIZE, "%s\n",
+			(pm == POWER_STATE_TYPE_BATTERY) ? "battery" :
+			(pm == POWER_STATE_TYPE_BALANCED) ? "balanced" : "performance");
+}
+
+static ssize_t radeon_set_dpm_state(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf,
+				    size_t count)
+{
+	struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
+	struct radeon_device *rdev = ddev->dev_private;
+
+	mutex_lock(&rdev->pm.mutex);
+	if (strncmp("battery", buf, strlen("battery")) == 0)
+		rdev->pm.dpm.user_state = POWER_STATE_TYPE_BATTERY;
+	else if (strncmp("balanced", buf, strlen("balanced")) == 0)
+		rdev->pm.dpm.user_state = POWER_STATE_TYPE_BALANCED;
+	else if (strncmp("performance", buf, strlen("performance")) == 0)
+		rdev->pm.dpm.user_state = POWER_STATE_TYPE_PERFORMANCE;
+	else {
+		mutex_unlock(&rdev->pm.mutex);
+		count = -EINVAL;
+		goto fail;
+	}
+	mutex_unlock(&rdev->pm.mutex);
+	radeon_pm_compute_clocks(rdev);
+fail:
+	return count;
+}
+
 static DEVICE_ATTR(power_profile, S_IRUGO | S_IWUSR, radeon_get_pm_profile, radeon_set_pm_profile);
 static DEVICE_ATTR(power_method, S_IRUGO | S_IWUSR, radeon_get_pm_method, radeon_set_pm_method);
+static DEVICE_ATTR(power_dpm_state, S_IRUGO | S_IWUSR, radeon_get_dpm_state, radeon_set_dpm_state);
 
 static ssize_t radeon_hwmon_show_temp(struct device *dev,
 				      struct device_attribute *attr,
@@ -508,7 +554,228 @@ static void radeon_hwmon_fini(struct radeon_device *rdev)
 	}
 }
 
-void radeon_pm_suspend(struct radeon_device *rdev)
+static void radeon_dpm_thermal_work_handler(struct work_struct *work)
+{
+	struct radeon_device *rdev =
+		container_of(work, struct radeon_device,
+			     pm.dpm.thermal.work);
+	/* switch to the thermal state */
+	enum radeon_pm_state_type dpm_state = POWER_STATE_TYPE_INTERNAL_THERMAL;
+
+	if (!rdev->pm.dpm_enabled)
+		return;
+
+	if (rdev->asic->pm.get_temperature) {
+		int temp = radeon_get_temperature(rdev);
+
+		if (temp < rdev->pm.dpm.thermal.min_temp)
+			/* switch back the user state */
+			dpm_state = rdev->pm.dpm.user_state;
+	} else {
+		if (rdev->pm.dpm.thermal.high_to_low)
+			/* switch back the user state */
+			dpm_state = rdev->pm.dpm.user_state;
+	}
+	radeon_dpm_enable_power_state(rdev, dpm_state);
+}
+
+static struct radeon_ps *radeon_dpm_pick_power_state(struct radeon_device *rdev,
+						     enum radeon_pm_state_type dpm_state)
+{
+	int i;
+	struct radeon_ps *ps;
+	u32 ui_class;
+
+restart_search:
+	/* balanced states don't exist at the moment */
+	if (dpm_state == POWER_STATE_TYPE_BALANCED)
+		dpm_state = POWER_STATE_TYPE_PERFORMANCE;
+
+	/* Pick the best power state based on current conditions */
+	for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
+		ps = &rdev->pm.dpm.ps[i];
+		ui_class = ps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK;
+		switch (dpm_state) {
+		/* user states */
+		case POWER_STATE_TYPE_BATTERY:
+			if (ui_class == ATOM_PPLIB_CLASSIFICATION_UI_BATTERY) {
+				if (ps->caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) {
+					if (rdev->pm.dpm.new_active_crtc_count < 2)
+						return ps;
+				} else
+					return ps;
+			}
+			break;
+		case POWER_STATE_TYPE_BALANCED:
+			if (ui_class == ATOM_PPLIB_CLASSIFICATION_UI_BALANCED) {
+				if (ps->caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) {
+					if (rdev->pm.dpm.new_active_crtc_count < 2)
+						return ps;
+				} else
+					return ps;
+			}
+			break;
+		case POWER_STATE_TYPE_PERFORMANCE:
+			if (ui_class == ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE) {
+				if (ps->caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) {
+					if (rdev->pm.dpm.new_active_crtc_count < 2)
+						return ps;
+				} else
+					return ps;
+			}
+			break;
+		/* internal states */
+		case POWER_STATE_TYPE_INTERNAL_UVD:
+			return rdev->pm.dpm.uvd_ps;
+		case POWER_STATE_TYPE_INTERNAL_UVD_SD:
+			if (ps->class & ATOM_PPLIB_CLASSIFICATION_SDSTATE)
+				return ps;
+			break;
+		case POWER_STATE_TYPE_INTERNAL_UVD_HD:
+			if (ps->class & ATOM_PPLIB_CLASSIFICATION_HDSTATE)
+				return ps;
+			break;
+		case POWER_STATE_TYPE_INTERNAL_UVD_HD2:
+			if (ps->class & ATOM_PPLIB_CLASSIFICATION_HD2STATE)
+				return ps;
+			break;
+		case POWER_STATE_TYPE_INTERNAL_UVD_MVC:
+			if (ps->class2 & ATOM_PPLIB_CLASSIFICATION2_MVC)
+				return ps;
+			break;
+		case POWER_STATE_TYPE_INTERNAL_BOOT:
+			return rdev->pm.dpm.boot_ps;
+		case POWER_STATE_TYPE_INTERNAL_THERMAL:
+			if (ps->class & ATOM_PPLIB_CLASSIFICATION_THERMAL)
+				return ps;
+			break;
+		case POWER_STATE_TYPE_INTERNAL_ACPI:
+			if (ps->class & ATOM_PPLIB_CLASSIFICATION_ACPI)
+				return ps;
+			break;
+		case POWER_STATE_TYPE_INTERNAL_ULV:
+			if (ps->class2 & ATOM_PPLIB_CLASSIFICATION2_ULV)
+				return ps;
+			break;
+		default:
+			break;
+		}
+	}
+	/* use a fallback state if we didn't match */
+	switch (dpm_state) {
+	case POWER_STATE_TYPE_INTERNAL_UVD_SD:
+	case POWER_STATE_TYPE_INTERNAL_UVD_HD:
+	case POWER_STATE_TYPE_INTERNAL_UVD_HD2:
+	case POWER_STATE_TYPE_INTERNAL_UVD_MVC:
+		return rdev->pm.dpm.uvd_ps;
+	case POWER_STATE_TYPE_INTERNAL_THERMAL:
+		dpm_state = POWER_STATE_TYPE_INTERNAL_ACPI;
+		goto restart_search;
+	case POWER_STATE_TYPE_INTERNAL_ACPI:
+		dpm_state = POWER_STATE_TYPE_BATTERY;
+		goto restart_search;
+	case POWER_STATE_TYPE_BATTERY:
+		dpm_state = POWER_STATE_TYPE_PERFORMANCE;
+		goto restart_search;
+	default:
+		break;
+	}
+
+	return NULL;
+}
+
+static void radeon_dpm_change_power_state_locked(struct radeon_device *rdev)
+{
+	int i;
+	struct radeon_ps *ps;
+	enum radeon_pm_state_type dpm_state;
+
+	/* if dpm init failed */
+	if (!rdev->pm.dpm_enabled)
+		return;
+
+	if (rdev->pm.dpm.user_state != rdev->pm.dpm.state) {
+		/* add other state override checks here */
+		if (!rdev->pm.dpm.thermal_active)
+			rdev->pm.dpm.state = rdev->pm.dpm.user_state;
+	}
+	dpm_state = rdev->pm.dpm.state;
+
+	ps = radeon_dpm_pick_power_state(rdev, dpm_state);
+	if (ps)
+		rdev->pm.dpm.requested_ps = ps;
+	else
+		return;
+
+	/* no need to reprogram if nothing changed */
+	if (rdev->pm.dpm.current_ps == rdev->pm.dpm.requested_ps) {
+		/* update display watermarks based on new power state */
+		if (rdev->pm.dpm.new_active_crtcs != rdev->pm.dpm.current_active_crtcs) {
+			radeon_bandwidth_update(rdev);
+			/* update displays */
+			radeon_dpm_display_configuration_changed(rdev);
+			rdev->pm.dpm.current_active_crtcs = rdev->pm.dpm.new_active_crtcs;
+			rdev->pm.dpm.current_active_crtc_count = rdev->pm.dpm.new_active_crtc_count;
+		}
+		return;
+	}
+
+	printk("switching from power state:\n");
+	radeon_dpm_print_power_state(rdev, rdev->pm.dpm.current_ps);
+	printk("switching to power state:\n");
+	radeon_dpm_print_power_state(rdev, rdev->pm.dpm.requested_ps);
+
+	mutex_lock(&rdev->ddev->struct_mutex);
+	down_write(&rdev->pm.mclk_lock);
+	mutex_lock(&rdev->ring_lock);
+
+	/* update display watermarks based on new power state */
+	radeon_bandwidth_update(rdev);
+	/* update displays */
+	radeon_dpm_display_configuration_changed(rdev);
+
+	rdev->pm.dpm.current_active_crtcs = rdev->pm.dpm.new_active_crtcs;
+	rdev->pm.dpm.current_active_crtc_count = rdev->pm.dpm.new_active_crtc_count;
+
+	/* wait for the rings to drain */
+	for (i = 0; i < RADEON_NUM_RINGS; i++) {
+		struct radeon_ring *ring = &rdev->ring[i];
+		if (ring->ready)
+			radeon_fence_wait_empty_locked(rdev, i);
+	}
+
+	/* program the new power state */
+	radeon_dpm_set_power_state(rdev);
+
+	/* update current power state */
+	rdev->pm.dpm.current_ps = rdev->pm.dpm.requested_ps;
+
+	mutex_unlock(&rdev->ring_lock);
+	up_write(&rdev->pm.mclk_lock);
+	mutex_unlock(&rdev->ddev->struct_mutex);
+}
+
+void radeon_dpm_enable_power_state(struct radeon_device *rdev,
+				   enum radeon_pm_state_type dpm_state)
+{
+	if (!rdev->pm.dpm_enabled)
+		return;
+
+	mutex_lock(&rdev->pm.mutex);
+	switch (dpm_state) {
+	case POWER_STATE_TYPE_INTERNAL_THERMAL:
+		rdev->pm.dpm.thermal_active = true;
+		break;
+	default:
+		rdev->pm.dpm.thermal_active = false;
+		break;
+	}
+	rdev->pm.dpm.state = dpm_state;
+	mutex_unlock(&rdev->pm.mutex);
+	radeon_pm_compute_clocks(rdev);
+}
+
+static void radeon_pm_suspend_old(struct radeon_device *rdev)
 {
 	mutex_lock(&rdev->pm.mutex);
 	if (rdev->pm.pm_method == PM_METHOD_DYNPM) {
@@ -520,7 +787,26 @@ void radeon_pm_suspend(struct radeon_device *rdev)
 	cancel_delayed_work_sync(&rdev->pm.dynpm_idle_work);
 }
 
-void radeon_pm_resume(struct radeon_device *rdev)
+static void radeon_pm_suspend_dpm(struct radeon_device *rdev)
+{
+	mutex_lock(&rdev->pm.mutex);
+	/* disable dpm */
+	radeon_dpm_disable(rdev);
+	/* reset the power state */
+	rdev->pm.dpm.current_ps = rdev->pm.dpm.requested_ps = rdev->pm.dpm.boot_ps;
+	rdev->pm.dpm_enabled = false;
+	mutex_unlock(&rdev->pm.mutex);
+}
+
+void radeon_pm_suspend(struct radeon_device *rdev)
+{
+	if (rdev->pm.pm_method == PM_METHOD_DPM)
+		radeon_pm_suspend_dpm(rdev);
+	else
+		radeon_pm_suspend_old(rdev);
+}
+
+static void radeon_pm_resume_old(struct radeon_device *rdev)
 {
 	/* set up the default clocks if the MC ucode is loaded */
 	if ((rdev->family >= CHIP_BARTS) &&
@@ -555,12 +841,50 @@ void radeon_pm_resume(struct radeon_device *rdev)
 	radeon_pm_compute_clocks(rdev);
 }
 
-int radeon_pm_init(struct radeon_device *rdev)
+static void radeon_pm_resume_dpm(struct radeon_device *rdev)
+{
+	int ret;
+
+	/* asic init will reset to the boot state */
+	mutex_lock(&rdev->pm.mutex);
+	rdev->pm.dpm.current_ps = rdev->pm.dpm.requested_ps = rdev->pm.dpm.boot_ps;
+	radeon_dpm_setup_asic(rdev);
+	ret = radeon_dpm_enable(rdev);
+	mutex_unlock(&rdev->pm.mutex);
+	if (ret) {
+		DRM_ERROR("radeon: dpm resume failed\n");
+		if ((rdev->family >= CHIP_BARTS) &&
+		    (rdev->family <= CHIP_CAYMAN) &&
+		    rdev->mc_fw) {
+			if (rdev->pm.default_vddc)
+				radeon_atom_set_voltage(rdev, rdev->pm.default_vddc,
+							SET_VOLTAGE_TYPE_ASIC_VDDC);
+			if (rdev->pm.default_vddci)
+				radeon_atom_set_voltage(rdev, rdev->pm.default_vddci,
+							SET_VOLTAGE_TYPE_ASIC_VDDCI);
+			if (rdev->pm.default_sclk)
+				radeon_set_engine_clock(rdev, rdev->pm.default_sclk);
+			if (rdev->pm.default_mclk)
+				radeon_set_memory_clock(rdev, rdev->pm.default_mclk);
+		}
+	} else {
+		rdev->pm.dpm_enabled = true;
+		radeon_pm_compute_clocks(rdev);
+	}
+}
+
+void radeon_pm_resume(struct radeon_device *rdev)
+{
+	if (rdev->pm.pm_method == PM_METHOD_DPM)
+		radeon_pm_resume_dpm(rdev);
+	else
+		radeon_pm_resume_old(rdev);
+}
+
+static int radeon_pm_init_old(struct radeon_device *rdev)
 {
 	int ret;
 
-	/* default to profile method */
-	rdev->pm.pm_method = PM_METHOD_PROFILE;
 	rdev->pm.profile = PM_PROFILE_DEFAULT;
 	rdev->pm.dynpm_state = DYNPM_STATE_DISABLED;
 	rdev->pm.dynpm_planned_action = DYNPM_ACTION_NONE;
@@ -622,7 +946,103 @@ int radeon_pm_init(struct radeon_device *rdev)
 	return 0;
 }
 
-void radeon_pm_fini(struct radeon_device *rdev)
+static void radeon_dpm_print_power_states(struct radeon_device *rdev)
+{
+	int i;
+
+	for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
+		printk("== power state %d ==\n", i);
+		radeon_dpm_print_power_state(rdev, &rdev->pm.dpm.ps[i]);
+	}
+}
+
+static int radeon_pm_init_dpm(struct radeon_device *rdev)
+{
+	int ret;
+
+	/* default to performance state */
+	rdev->pm.dpm.state = POWER_STATE_TYPE_PERFORMANCE;
+	rdev->pm.dpm.user_state = POWER_STATE_TYPE_PERFORMANCE;
+	rdev->pm.default_sclk = rdev->clock.default_sclk;
+	rdev->pm.default_mclk = rdev->clock.default_mclk;
+	rdev->pm.current_sclk = rdev->clock.default_sclk;
+	rdev->pm.current_mclk = rdev->clock.default_mclk;
+	rdev->pm.int_thermal_type = THERMAL_TYPE_NONE;
+
+	if (rdev->bios && rdev->is_atom_bios)
+		radeon_atombios_get_power_modes(rdev);
+	else
+		return -EINVAL;
+
+	/* set up the internal thermal sensor if applicable */
+	ret = radeon_hwmon_init(rdev);
+	if (ret)
+		return ret;
+
+	INIT_WORK(&rdev->pm.dpm.thermal.work, radeon_dpm_thermal_work_handler);
+	mutex_lock(&rdev->pm.mutex);
+	radeon_dpm_init(rdev);
+	rdev->pm.dpm.current_ps = rdev->pm.dpm.requested_ps = rdev->pm.dpm.boot_ps;
+	radeon_dpm_print_power_states(rdev);
+	radeon_dpm_setup_asic(rdev);
+	ret = radeon_dpm_enable(rdev);
+	mutex_unlock(&rdev->pm.mutex);
+	if (ret) {
+		rdev->pm.dpm_enabled = false;
+		if ((rdev->family >= CHIP_BARTS) &&
+		    (rdev->family <= CHIP_CAYMAN) &&
+		    rdev->mc_fw) {
+			if (rdev->pm.default_vddc)
+				radeon_atom_set_voltage(rdev, rdev->pm.default_vddc,
+							SET_VOLTAGE_TYPE_ASIC_VDDC);
+			if (rdev->pm.default_vddci)
+				radeon_atom_set_voltage(rdev, rdev->pm.default_vddci,
+							SET_VOLTAGE_TYPE_ASIC_VDDCI);
+			if (rdev->pm.default_sclk)
+				radeon_set_engine_clock(rdev, rdev->pm.default_sclk);
+			if (rdev->pm.default_mclk)
+				radeon_set_memory_clock(rdev, rdev->pm.default_mclk);
+		}
+		DRM_ERROR("radeon: dpm initialization failed\n");
+		return ret;
+	}
+	rdev->pm.dpm_enabled = true;
+	radeon_pm_compute_clocks(rdev);
+
+	if (rdev->pm.num_power_states > 1) {
+		ret = device_create_file(rdev->dev, &dev_attr_power_dpm_state);
+		if (ret)
+			DRM_ERROR("failed to create device file for dpm state\n");
+		/* XXX: these are noops for dpm but are here for backwards compat */
+		ret = device_create_file(rdev->dev, &dev_attr_power_profile);
+		if (ret)
+			DRM_ERROR("failed to create device file for power profile\n");
+		ret = device_create_file(rdev->dev, &dev_attr_power_method);
+		if (ret)
+			DRM_ERROR("failed to create device file for power method\n");
+		DRM_INFO("radeon: dpm initialized\n");
+	}
+
+	return 0;
+}
+
+int radeon_pm_init(struct radeon_device *rdev)
+{
+	/* enable dpm on rv6xx+ */
+	switch (rdev->family) {
+	default:
+		/* default to profile method */
+		rdev->pm.pm_method = PM_METHOD_PROFILE;
+		break;
+	}
+
+	if (rdev->pm.pm_method == PM_METHOD_DPM)
+		return radeon_pm_init_dpm(rdev);
+	else
+		return radeon_pm_init_old(rdev);
+}
+
+static void radeon_pm_fini_old(struct radeon_device *rdev)
 {
 	if (rdev->pm.num_power_states > 1) {
 		mutex_lock(&rdev->pm.mutex);
@@ -650,7 +1070,35 @@ void radeon_pm_fini(struct radeon_device *rdev)
 	radeon_hwmon_fini(rdev);
 }
 
-void radeon_pm_compute_clocks(struct radeon_device *rdev)
+static void radeon_pm_fini_dpm(struct radeon_device *rdev)
+{
+	if (rdev->pm.num_power_states > 1) {
+		mutex_lock(&rdev->pm.mutex);
+		radeon_dpm_disable(rdev);
+		mutex_unlock(&rdev->pm.mutex);
+
+		device_remove_file(rdev->dev, &dev_attr_power_dpm_state);
+		/* XXX backwards compat */
+		device_remove_file(rdev->dev, &dev_attr_power_profile);
+		device_remove_file(rdev->dev, &dev_attr_power_method);
+	}
+	radeon_dpm_fini(rdev);
+
+	if (rdev->pm.power_state)
+		kfree(rdev->pm.power_state);
+
+	radeon_hwmon_fini(rdev);
+}
+
+void radeon_pm_fini(struct radeon_device *rdev)
+{
+	if (rdev->pm.pm_method == PM_METHOD_DPM)
+		radeon_pm_fini_dpm(rdev);
+	else
+		radeon_pm_fini_old(rdev);
+}
+
+static void radeon_pm_compute_clocks_old(struct radeon_device *rdev)
 {
 	struct drm_device *ddev = rdev->ddev;
 	struct drm_crtc *crtc;
@@ -721,6 +1169,38 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev)
 	mutex_unlock(&rdev->pm.mutex);
 }
 
+static void radeon_pm_compute_clocks_dpm(struct radeon_device *rdev)
+{
+	struct drm_device *ddev = rdev->ddev;
+	struct drm_crtc *crtc;
+	struct radeon_crtc *radeon_crtc;
+
+	mutex_lock(&rdev->pm.mutex);
+
+	rdev->pm.dpm.new_active_crtcs = 0;
+	rdev->pm.dpm.new_active_crtc_count = 0;
+	list_for_each_entry(crtc,
+		&ddev->mode_config.crtc_list, head) {
+		radeon_crtc = to_radeon_crtc(crtc);
+		if (crtc->enabled) {
+			rdev->pm.dpm.new_active_crtcs |= (1 << radeon_crtc->crtc_id);
+			rdev->pm.dpm.new_active_crtc_count++;
+		}
+	}
+
+	radeon_dpm_change_power_state_locked(rdev);
+
+	mutex_unlock(&rdev->pm.mutex);
+}
+
+void radeon_pm_compute_clocks(struct radeon_device *rdev)
+{
+	if (rdev->pm.pm_method == PM_METHOD_DPM)
+		radeon_pm_compute_clocks_dpm(rdev);
+	else
+		radeon_pm_compute_clocks_old(rdev);
+}
+
 static bool radeon_pm_in_vbl(struct radeon_device *rdev)
 {
 	int  crtc, vpos, hpos, vbl_status;
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 070/165] drm/radeon/kms: fix up rs780/rs880 display watermark calc for dpm
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (69 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 069/165] drm/radeon/kms: add common dpm infrastructure alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 071/165] drm/radeon/kms: fix up 6xx/7xx " alexdeucher
                   ` (42 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

calculate the low and high watermarks based on the low and high
clocks for the current power state.  The dynamic pm hw will select
the appropriate watermark based on the internal dpm state.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/rs690.c |  291 +++++++++++++++++++++++-----------------
 1 files changed, 167 insertions(+), 124 deletions(-)

diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c
index 55880d5..d8ddfb3 100644
--- a/drivers/gpu/drm/radeon/rs690.c
+++ b/drivers/gpu/drm/radeon/rs690.c
@@ -248,13 +248,16 @@ struct rs690_watermark {
 };
 
 static void rs690_crtc_bandwidth_compute(struct radeon_device *rdev,
-				  struct radeon_crtc *crtc,
-				  struct rs690_watermark *wm)
+					 struct radeon_crtc *crtc,
+					 struct rs690_watermark *wm,
+					 bool low)
 {
 	struct drm_display_mode *mode = &crtc->base.mode;
 	fixed20_12 a, b, c;
 	fixed20_12 pclk, request_fifo_depth, tolerable_latency, estimated_width;
 	fixed20_12 consumption_time, line_time, chunk_time, read_delay_latency;
+	fixed20_12 sclk, core_bandwidth, max_bandwidth;
+	u32 selected_sclk;
 
 	if (!crtc->base.enabled) {
 		/* FIXME: wouldn't it better to set priority mark to maximum */
@@ -262,6 +265,21 @@ static void rs690_crtc_bandwidth_compute(struct radeon_device *rdev,
 		return;
 	}
 
+	if (((rdev->family == CHIP_RS780) || (rdev->family == CHIP_RS880)) &&
+	    (rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled)
+		selected_sclk = radeon_dpm_get_sclk(rdev, low);
+	else
+		selected_sclk = rdev->pm.current_sclk;
+
+	/* sclk in Mhz */
+	a.full = dfixed_const(100);
+	sclk.full = dfixed_const(selected_sclk);
+	sclk.full = dfixed_div(sclk, a);
+
+	/* core_bandwidth = sclk(Mhz) * 16 */
+	a.full = dfixed_const(16);
+	core_bandwidth.full = dfixed_div(rdev->pm.sclk, a);
+
 	if (crtc->vsc.full > dfixed_const(2))
 		wm->num_line_pair.full = dfixed_const(2);
 	else
@@ -322,36 +340,36 @@ static void rs690_crtc_bandwidth_compute(struct radeon_device *rdev,
 	wm->active_time.full = dfixed_div(wm->active_time, a);
 
 	/* Maximun bandwidth is the minimun bandwidth of all component */
-	rdev->pm.max_bandwidth = rdev->pm.core_bandwidth;
+	max_bandwidth = core_bandwidth;
 	if (rdev->mc.igp_sideport_enabled) {
-		if (rdev->pm.max_bandwidth.full > rdev->pm.sideport_bandwidth.full &&
+		if (max_bandwidth.full > rdev->pm.sideport_bandwidth.full &&
 			rdev->pm.sideport_bandwidth.full)
-			rdev->pm.max_bandwidth = rdev->pm.sideport_bandwidth;
+			max_bandwidth = rdev->pm.sideport_bandwidth;
 		read_delay_latency.full = dfixed_const(370 * 800 * 1000);
 		read_delay_latency.full = dfixed_div(read_delay_latency,
 			rdev->pm.igp_sideport_mclk);
 	} else {
-		if (rdev->pm.max_bandwidth.full > rdev->pm.k8_bandwidth.full &&
+		if (max_bandwidth.full > rdev->pm.k8_bandwidth.full &&
 			rdev->pm.k8_bandwidth.full)
-			rdev->pm.max_bandwidth = rdev->pm.k8_bandwidth;
-		if (rdev->pm.max_bandwidth.full > rdev->pm.ht_bandwidth.full &&
+			max_bandwidth = rdev->pm.k8_bandwidth;
+		if (max_bandwidth.full > rdev->pm.ht_bandwidth.full &&
 			rdev->pm.ht_bandwidth.full)
-			rdev->pm.max_bandwidth = rdev->pm.ht_bandwidth;
+			max_bandwidth = rdev->pm.ht_bandwidth;
 		read_delay_latency.full = dfixed_const(5000);
 	}
 
 	/* sclk = system clocks(ns) = 1000 / max_bandwidth / 16 */
 	a.full = dfixed_const(16);
-	rdev->pm.sclk.full = dfixed_mul(rdev->pm.max_bandwidth, a);
+	sclk.full = dfixed_mul(max_bandwidth, a);
 	a.full = dfixed_const(1000);
-	rdev->pm.sclk.full = dfixed_div(a, rdev->pm.sclk);
+	sclk.full = dfixed_div(a, sclk);
 	/* Determine chunk time
 	 * ChunkTime = the time it takes the DCP to send one chunk of data
 	 * to the LB which consists of pipeline delay and inter chunk gap
 	 * sclk = system clock(ns)
 	 */
 	a.full = dfixed_const(256 * 13);
-	chunk_time.full = dfixed_mul(rdev->pm.sclk, a);
+	chunk_time.full = dfixed_mul(sclk, a);
 	a.full = dfixed_const(10);
 	chunk_time.full = dfixed_div(chunk_time, a);
 
@@ -415,175 +433,200 @@ static void rs690_crtc_bandwidth_compute(struct radeon_device *rdev,
 	}
 }
 
-void rs690_bandwidth_update(struct radeon_device *rdev)
+static void rs690_compute_mode_priority(struct radeon_device *rdev,
+					struct rs690_watermark *wm0,
+					struct rs690_watermark *wm1,
+					struct drm_display_mode *mode0,
+					struct drm_display_mode *mode1,
+					u32 *d1mode_priority_a_cnt,
+					u32 *d2mode_priority_a_cnt)
 {
-	struct drm_display_mode *mode0 = NULL;
-	struct drm_display_mode *mode1 = NULL;
-	struct rs690_watermark wm0;
-	struct rs690_watermark wm1;
-	u32 tmp;
-	u32 d1mode_priority_a_cnt = S_006548_D1MODE_PRIORITY_A_OFF(1);
-	u32 d2mode_priority_a_cnt = S_006548_D1MODE_PRIORITY_A_OFF(1);
 	fixed20_12 priority_mark02, priority_mark12, fill_rate;
 	fixed20_12 a, b;
 
-	radeon_update_display_priority(rdev);
-
-	if (rdev->mode_info.crtcs[0]->base.enabled)
-		mode0 = &rdev->mode_info.crtcs[0]->base.mode;
-	if (rdev->mode_info.crtcs[1]->base.enabled)
-		mode1 = &rdev->mode_info.crtcs[1]->base.mode;
-	/*
-	 * Set display0/1 priority up in the memory controller for
-	 * modes if the user specifies HIGH for displaypriority
-	 * option.
-	 */
-	if ((rdev->disp_priority == 2) &&
-	    ((rdev->family == CHIP_RS690) || (rdev->family == CHIP_RS740))) {
-		tmp = RREG32_MC(R_000104_MC_INIT_MISC_LAT_TIMER);
-		tmp &= C_000104_MC_DISP0R_INIT_LAT;
-		tmp &= C_000104_MC_DISP1R_INIT_LAT;
-		if (mode0)
-			tmp |= S_000104_MC_DISP0R_INIT_LAT(1);
-		if (mode1)
-			tmp |= S_000104_MC_DISP1R_INIT_LAT(1);
-		WREG32_MC(R_000104_MC_INIT_MISC_LAT_TIMER, tmp);
-	}
-	rs690_line_buffer_adjust(rdev, mode0, mode1);
-
-	if ((rdev->family == CHIP_RS690) || (rdev->family == CHIP_RS740))
-		WREG32(R_006C9C_DCP_CONTROL, 0);
-	if ((rdev->family == CHIP_RS780) || (rdev->family == CHIP_RS880))
-		WREG32(R_006C9C_DCP_CONTROL, 2);
-
-	rs690_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[0], &wm0);
-	rs690_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[1], &wm1);
-
-	tmp = (wm0.lb_request_fifo_depth - 1);
-	tmp |= (wm1.lb_request_fifo_depth - 1) << 16;
-	WREG32(R_006D58_LB_MAX_REQ_OUTSTANDING, tmp);
+	*d1mode_priority_a_cnt = S_006548_D1MODE_PRIORITY_A_OFF(1);
+	*d2mode_priority_a_cnt = S_006548_D1MODE_PRIORITY_A_OFF(1);
 
 	if (mode0 && mode1) {
-		if (dfixed_trunc(wm0.dbpp) > 64)
-			a.full = dfixed_mul(wm0.dbpp, wm0.num_line_pair);
+		if (dfixed_trunc(wm0->dbpp) > 64)
+			a.full = dfixed_mul(wm0->dbpp, wm0->num_line_pair);
 		else
-			a.full = wm0.num_line_pair.full;
-		if (dfixed_trunc(wm1.dbpp) > 64)
-			b.full = dfixed_mul(wm1.dbpp, wm1.num_line_pair);
+			a.full = wm0->num_line_pair.full;
+		if (dfixed_trunc(wm1->dbpp) > 64)
+			b.full = dfixed_mul(wm1->dbpp, wm1->num_line_pair);
 		else
-			b.full = wm1.num_line_pair.full;
+			b.full = wm1->num_line_pair.full;
 		a.full += b.full;
-		fill_rate.full = dfixed_div(wm0.sclk, a);
-		if (wm0.consumption_rate.full > fill_rate.full) {
-			b.full = wm0.consumption_rate.full - fill_rate.full;
-			b.full = dfixed_mul(b, wm0.active_time);
-			a.full = dfixed_mul(wm0.worst_case_latency,
-						wm0.consumption_rate);
+		fill_rate.full = dfixed_div(wm0->sclk, a);
+		if (wm0->consumption_rate.full > fill_rate.full) {
+			b.full = wm0->consumption_rate.full - fill_rate.full;
+			b.full = dfixed_mul(b, wm0->active_time);
+			a.full = dfixed_mul(wm0->worst_case_latency,
+						wm0->consumption_rate);
 			a.full = a.full + b.full;
 			b.full = dfixed_const(16 * 1000);
 			priority_mark02.full = dfixed_div(a, b);
 		} else {
-			a.full = dfixed_mul(wm0.worst_case_latency,
-						wm0.consumption_rate);
+			a.full = dfixed_mul(wm0->worst_case_latency,
+						wm0->consumption_rate);
 			b.full = dfixed_const(16 * 1000);
 			priority_mark02.full = dfixed_div(a, b);
 		}
-		if (wm1.consumption_rate.full > fill_rate.full) {
-			b.full = wm1.consumption_rate.full - fill_rate.full;
-			b.full = dfixed_mul(b, wm1.active_time);
-			a.full = dfixed_mul(wm1.worst_case_latency,
-						wm1.consumption_rate);
+		if (wm1->consumption_rate.full > fill_rate.full) {
+			b.full = wm1->consumption_rate.full - fill_rate.full;
+			b.full = dfixed_mul(b, wm1->active_time);
+			a.full = dfixed_mul(wm1->worst_case_latency,
+						wm1->consumption_rate);
 			a.full = a.full + b.full;
 			b.full = dfixed_const(16 * 1000);
 			priority_mark12.full = dfixed_div(a, b);
 		} else {
-			a.full = dfixed_mul(wm1.worst_case_latency,
-						wm1.consumption_rate);
+			a.full = dfixed_mul(wm1->worst_case_latency,
+						wm1->consumption_rate);
 			b.full = dfixed_const(16 * 1000);
 			priority_mark12.full = dfixed_div(a, b);
 		}
-		if (wm0.priority_mark.full > priority_mark02.full)
-			priority_mark02.full = wm0.priority_mark.full;
+		if (wm0->priority_mark.full > priority_mark02.full)
+			priority_mark02.full = wm0->priority_mark.full;
 		if (dfixed_trunc(priority_mark02) < 0)
 			priority_mark02.full = 0;
-		if (wm0.priority_mark_max.full > priority_mark02.full)
-			priority_mark02.full = wm0.priority_mark_max.full;
-		if (wm1.priority_mark.full > priority_mark12.full)
-			priority_mark12.full = wm1.priority_mark.full;
+		if (wm0->priority_mark_max.full > priority_mark02.full)
+			priority_mark02.full = wm0->priority_mark_max.full;
+		if (wm1->priority_mark.full > priority_mark12.full)
+			priority_mark12.full = wm1->priority_mark.full;
 		if (dfixed_trunc(priority_mark12) < 0)
 			priority_mark12.full = 0;
-		if (wm1.priority_mark_max.full > priority_mark12.full)
-			priority_mark12.full = wm1.priority_mark_max.full;
-		d1mode_priority_a_cnt = dfixed_trunc(priority_mark02);
-		d2mode_priority_a_cnt = dfixed_trunc(priority_mark12);
+		if (wm1->priority_mark_max.full > priority_mark12.full)
+			priority_mark12.full = wm1->priority_mark_max.full;
+		*d1mode_priority_a_cnt = dfixed_trunc(priority_mark02);
+		*d2mode_priority_a_cnt = dfixed_trunc(priority_mark12);
 		if (rdev->disp_priority == 2) {
-			d1mode_priority_a_cnt |= S_006548_D1MODE_PRIORITY_A_ALWAYS_ON(1);
-			d2mode_priority_a_cnt |= S_006D48_D2MODE_PRIORITY_A_ALWAYS_ON(1);
+			*d1mode_priority_a_cnt |= S_006548_D1MODE_PRIORITY_A_ALWAYS_ON(1);
+			*d2mode_priority_a_cnt |= S_006D48_D2MODE_PRIORITY_A_ALWAYS_ON(1);
 		}
 	} else if (mode0) {
-		if (dfixed_trunc(wm0.dbpp) > 64)
-			a.full = dfixed_mul(wm0.dbpp, wm0.num_line_pair);
+		if (dfixed_trunc(wm0->dbpp) > 64)
+			a.full = dfixed_mul(wm0->dbpp, wm0->num_line_pair);
 		else
-			a.full = wm0.num_line_pair.full;
-		fill_rate.full = dfixed_div(wm0.sclk, a);
-		if (wm0.consumption_rate.full > fill_rate.full) {
-			b.full = wm0.consumption_rate.full - fill_rate.full;
-			b.full = dfixed_mul(b, wm0.active_time);
-			a.full = dfixed_mul(wm0.worst_case_latency,
-						wm0.consumption_rate);
+			a.full = wm0->num_line_pair.full;
+		fill_rate.full = dfixed_div(wm0->sclk, a);
+		if (wm0->consumption_rate.full > fill_rate.full) {
+			b.full = wm0->consumption_rate.full - fill_rate.full;
+			b.full = dfixed_mul(b, wm0->active_time);
+			a.full = dfixed_mul(wm0->worst_case_latency,
+						wm0->consumption_rate);
 			a.full = a.full + b.full;
 			b.full = dfixed_const(16 * 1000);
 			priority_mark02.full = dfixed_div(a, b);
 		} else {
-			a.full = dfixed_mul(wm0.worst_case_latency,
-						wm0.consumption_rate);
+			a.full = dfixed_mul(wm0->worst_case_latency,
+						wm0->consumption_rate);
 			b.full = dfixed_const(16 * 1000);
 			priority_mark02.full = dfixed_div(a, b);
 		}
-		if (wm0.priority_mark.full > priority_mark02.full)
-			priority_mark02.full = wm0.priority_mark.full;
+		if (wm0->priority_mark.full > priority_mark02.full)
+			priority_mark02.full = wm0->priority_mark.full;
 		if (dfixed_trunc(priority_mark02) < 0)
 			priority_mark02.full = 0;
-		if (wm0.priority_mark_max.full > priority_mark02.full)
-			priority_mark02.full = wm0.priority_mark_max.full;
-		d1mode_priority_a_cnt = dfixed_trunc(priority_mark02);
+		if (wm0->priority_mark_max.full > priority_mark02.full)
+			priority_mark02.full = wm0->priority_mark_max.full;
+		*d1mode_priority_a_cnt = dfixed_trunc(priority_mark02);
 		if (rdev->disp_priority == 2)
-			d1mode_priority_a_cnt |= S_006548_D1MODE_PRIORITY_A_ALWAYS_ON(1);
+			*d1mode_priority_a_cnt |= S_006548_D1MODE_PRIORITY_A_ALWAYS_ON(1);
 	} else if (mode1) {
-		if (dfixed_trunc(wm1.dbpp) > 64)
-			a.full = dfixed_mul(wm1.dbpp, wm1.num_line_pair);
+		if (dfixed_trunc(wm1->dbpp) > 64)
+			a.full = dfixed_mul(wm1->dbpp, wm1->num_line_pair);
 		else
-			a.full = wm1.num_line_pair.full;
-		fill_rate.full = dfixed_div(wm1.sclk, a);
-		if (wm1.consumption_rate.full > fill_rate.full) {
-			b.full = wm1.consumption_rate.full - fill_rate.full;
-			b.full = dfixed_mul(b, wm1.active_time);
-			a.full = dfixed_mul(wm1.worst_case_latency,
-						wm1.consumption_rate);
+			a.full = wm1->num_line_pair.full;
+		fill_rate.full = dfixed_div(wm1->sclk, a);
+		if (wm1->consumption_rate.full > fill_rate.full) {
+			b.full = wm1->consumption_rate.full - fill_rate.full;
+			b.full = dfixed_mul(b, wm1->active_time);
+			a.full = dfixed_mul(wm1->worst_case_latency,
+						wm1->consumption_rate);
 			a.full = a.full + b.full;
 			b.full = dfixed_const(16 * 1000);
 			priority_mark12.full = dfixed_div(a, b);
 		} else {
-			a.full = dfixed_mul(wm1.worst_case_latency,
-						wm1.consumption_rate);
+			a.full = dfixed_mul(wm1->worst_case_latency,
+						wm1->consumption_rate);
 			b.full = dfixed_const(16 * 1000);
 			priority_mark12.full = dfixed_div(a, b);
 		}
-		if (wm1.priority_mark.full > priority_mark12.full)
-			priority_mark12.full = wm1.priority_mark.full;
+		if (wm1->priority_mark.full > priority_mark12.full)
+			priority_mark12.full = wm1->priority_mark.full;
 		if (dfixed_trunc(priority_mark12) < 0)
 			priority_mark12.full = 0;
-		if (wm1.priority_mark_max.full > priority_mark12.full)
-			priority_mark12.full = wm1.priority_mark_max.full;
-		d2mode_priority_a_cnt = dfixed_trunc(priority_mark12);
+		if (wm1->priority_mark_max.full > priority_mark12.full)
+			priority_mark12.full = wm1->priority_mark_max.full;
+		*d2mode_priority_a_cnt = dfixed_trunc(priority_mark12);
 		if (rdev->disp_priority == 2)
-			d2mode_priority_a_cnt |= S_006D48_D2MODE_PRIORITY_A_ALWAYS_ON(1);
+			*d2mode_priority_a_cnt |= S_006D48_D2MODE_PRIORITY_A_ALWAYS_ON(1);
 	}
+}
+
+void rs690_bandwidth_update(struct radeon_device *rdev)
+{
+	struct drm_display_mode *mode0 = NULL;
+	struct drm_display_mode *mode1 = NULL;
+	struct rs690_watermark wm0_high, wm0_low;
+	struct rs690_watermark wm1_high, wm1_low;
+	u32 tmp;
+	u32 d1mode_priority_a_cnt, d1mode_priority_b_cnt;
+	u32 d2mode_priority_a_cnt, d2mode_priority_b_cnt;
+
+	radeon_update_display_priority(rdev);
+
+	if (rdev->mode_info.crtcs[0]->base.enabled)
+		mode0 = &rdev->mode_info.crtcs[0]->base.mode;
+	if (rdev->mode_info.crtcs[1]->base.enabled)
+		mode1 = &rdev->mode_info.crtcs[1]->base.mode;
+	/*
+	 * Set display0/1 priority up in the memory controller for
+	 * modes if the user specifies HIGH for displaypriority
+	 * option.
+	 */
+	if ((rdev->disp_priority == 2) &&
+	    ((rdev->family == CHIP_RS690) || (rdev->family == CHIP_RS740))) {
+		tmp = RREG32_MC(R_000104_MC_INIT_MISC_LAT_TIMER);
+		tmp &= C_000104_MC_DISP0R_INIT_LAT;
+		tmp &= C_000104_MC_DISP1R_INIT_LAT;
+		if (mode0)
+			tmp |= S_000104_MC_DISP0R_INIT_LAT(1);
+		if (mode1)
+			tmp |= S_000104_MC_DISP1R_INIT_LAT(1);
+		WREG32_MC(R_000104_MC_INIT_MISC_LAT_TIMER, tmp);
+	}
+	rs690_line_buffer_adjust(rdev, mode0, mode1);
+
+	if ((rdev->family == CHIP_RS690) || (rdev->family == CHIP_RS740))
+		WREG32(R_006C9C_DCP_CONTROL, 0);
+	if ((rdev->family == CHIP_RS780) || (rdev->family == CHIP_RS880))
+		WREG32(R_006C9C_DCP_CONTROL, 2);
+
+	rs690_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[0], &wm0_high, false);
+	rs690_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[1], &wm1_high, false);
+
+	rs690_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[0], &wm0_low, true);
+	rs690_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[1], &wm1_low, true);
+
+	tmp = (wm0_high.lb_request_fifo_depth - 1);
+	tmp |= (wm1_high.lb_request_fifo_depth - 1) << 16;
+	WREG32(R_006D58_LB_MAX_REQ_OUTSTANDING, tmp);
+
+	rs690_compute_mode_priority(rdev,
+				    &wm0_high, &wm1_high,
+				    mode0, mode1,
+				    &d1mode_priority_a_cnt, &d2mode_priority_a_cnt);
+	rs690_compute_mode_priority(rdev,
+				    &wm0_low, &wm1_low,
+				    mode0, mode1,
+				    &d1mode_priority_b_cnt, &d2mode_priority_b_cnt);
 
 	WREG32(R_006548_D1MODE_PRIORITY_A_CNT, d1mode_priority_a_cnt);
-	WREG32(R_00654C_D1MODE_PRIORITY_B_CNT, d1mode_priority_a_cnt);
+	WREG32(R_00654C_D1MODE_PRIORITY_B_CNT, d1mode_priority_b_cnt);
 	WREG32(R_006D48_D2MODE_PRIORITY_A_CNT, d2mode_priority_a_cnt);
-	WREG32(R_006D4C_D2MODE_PRIORITY_B_CNT, d2mode_priority_a_cnt);
+	WREG32(R_006D4C_D2MODE_PRIORITY_B_CNT, d2mode_priority_b_cnt);
 }
 
 uint32_t rs690_mc_rreg(struct radeon_device *rdev, uint32_t reg)
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 071/165] drm/radeon/kms: fix up 6xx/7xx display watermark calc for dpm
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (70 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 070/165] drm/radeon/kms: fix up rs780/rs880 display watermark calc for dpm alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 072/165] drm/radeon/kms: fix up dce4/5 " alexdeucher
                   ` (41 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Calculate the low and high watermarks based on the low and high
clocks for the current power state.  The dynamic pm hw will select
the appropriate watermark based on the internal dpm state.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/rv515.c |  224 +++++++++++++++++++++++----------------
 1 files changed, 132 insertions(+), 92 deletions(-)

diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c
index 21c7d7b..8ea1573 100644
--- a/drivers/gpu/drm/radeon/rv515.c
+++ b/drivers/gpu/drm/radeon/rv515.c
@@ -937,13 +937,16 @@ struct rv515_watermark {
 };
 
 static void rv515_crtc_bandwidth_compute(struct radeon_device *rdev,
-				  struct radeon_crtc *crtc,
-				  struct rv515_watermark *wm)
+					 struct radeon_crtc *crtc,
+					 struct rv515_watermark *wm,
+					 bool low)
 {
 	struct drm_display_mode *mode = &crtc->base.mode;
 	fixed20_12 a, b, c;
 	fixed20_12 pclk, request_fifo_depth, tolerable_latency, estimated_width;
 	fixed20_12 consumption_time, line_time, chunk_time, read_delay_latency;
+	fixed20_12 sclk;
+	u32 selected_sclk;
 
 	if (!crtc->base.enabled) {
 		/* FIXME: wouldn't it better to set priority mark to maximum */
@@ -951,6 +954,18 @@ static void rv515_crtc_bandwidth_compute(struct radeon_device *rdev,
 		return;
 	}
 
+	/* rv6xx, rv7xx */
+	if ((rdev->family >= CHIP_RV610) &&
+	    (rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled)
+		selected_sclk = radeon_dpm_get_sclk(rdev, low);
+	else
+		selected_sclk = rdev->pm.current_sclk;
+
+	/* sclk in Mhz */
+	a.full = dfixed_const(100);
+	sclk.full = dfixed_const(selected_sclk);
+	sclk.full = dfixed_div(sclk, a);
+
 	if (crtc->vsc.full > dfixed_const(2))
 		wm->num_line_pair.full = dfixed_const(2);
 	else
@@ -1016,7 +1031,7 @@ static void rv515_crtc_bandwidth_compute(struct radeon_device *rdev,
 	 * sclk = system clock(Mhz)
 	 */
 	a.full = dfixed_const(600 * 1000);
-	chunk_time.full = dfixed_div(a, rdev->pm.sclk);
+	chunk_time.full = dfixed_div(a, sclk);
 	read_delay_latency.full = dfixed_const(1000);
 
 	/* Determine the worst case latency
@@ -1077,152 +1092,177 @@ static void rv515_crtc_bandwidth_compute(struct radeon_device *rdev,
 	}
 }
 
-void rv515_bandwidth_avivo_update(struct radeon_device *rdev)
+static void rv515_compute_mode_priority(struct radeon_device *rdev,
+					struct rv515_watermark *wm0,
+					struct rv515_watermark *wm1,
+					struct drm_display_mode *mode0,
+					struct drm_display_mode *mode1,
+					u32 *d1mode_priority_a_cnt,
+					u32 *d2mode_priority_a_cnt)
 {
-	struct drm_display_mode *mode0 = NULL;
-	struct drm_display_mode *mode1 = NULL;
-	struct rv515_watermark wm0;
-	struct rv515_watermark wm1;
-	u32 tmp;
-	u32 d1mode_priority_a_cnt = MODE_PRIORITY_OFF;
-	u32 d2mode_priority_a_cnt = MODE_PRIORITY_OFF;
 	fixed20_12 priority_mark02, priority_mark12, fill_rate;
 	fixed20_12 a, b;
 
-	if (rdev->mode_info.crtcs[0]->base.enabled)
-		mode0 = &rdev->mode_info.crtcs[0]->base.mode;
-	if (rdev->mode_info.crtcs[1]->base.enabled)
-		mode1 = &rdev->mode_info.crtcs[1]->base.mode;
-	rs690_line_buffer_adjust(rdev, mode0, mode1);
-
-	rv515_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[0], &wm0);
-	rv515_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[1], &wm1);
-
-	tmp = wm0.lb_request_fifo_depth;
-	tmp |= wm1.lb_request_fifo_depth << 16;
-	WREG32(LB_MAX_REQ_OUTSTANDING, tmp);
+	*d1mode_priority_a_cnt = MODE_PRIORITY_OFF;
+	*d2mode_priority_a_cnt = MODE_PRIORITY_OFF;
 
 	if (mode0 && mode1) {
-		if (dfixed_trunc(wm0.dbpp) > 64)
-			a.full = dfixed_div(wm0.dbpp, wm0.num_line_pair);
+		if (dfixed_trunc(wm0->dbpp) > 64)
+			a.full = dfixed_div(wm0->dbpp, wm0->num_line_pair);
 		else
-			a.full = wm0.num_line_pair.full;
-		if (dfixed_trunc(wm1.dbpp) > 64)
-			b.full = dfixed_div(wm1.dbpp, wm1.num_line_pair);
+			a.full = wm0->num_line_pair.full;
+		if (dfixed_trunc(wm1->dbpp) > 64)
+			b.full = dfixed_div(wm1->dbpp, wm1->num_line_pair);
 		else
-			b.full = wm1.num_line_pair.full;
+			b.full = wm1->num_line_pair.full;
 		a.full += b.full;
-		fill_rate.full = dfixed_div(wm0.sclk, a);
-		if (wm0.consumption_rate.full > fill_rate.full) {
-			b.full = wm0.consumption_rate.full - fill_rate.full;
-			b.full = dfixed_mul(b, wm0.active_time);
+		fill_rate.full = dfixed_div(wm0->sclk, a);
+		if (wm0->consumption_rate.full > fill_rate.full) {
+			b.full = wm0->consumption_rate.full - fill_rate.full;
+			b.full = dfixed_mul(b, wm0->active_time);
 			a.full = dfixed_const(16);
 			b.full = dfixed_div(b, a);
-			a.full = dfixed_mul(wm0.worst_case_latency,
-						wm0.consumption_rate);
+			a.full = dfixed_mul(wm0->worst_case_latency,
+						wm0->consumption_rate);
 			priority_mark02.full = a.full + b.full;
 		} else {
-			a.full = dfixed_mul(wm0.worst_case_latency,
-						wm0.consumption_rate);
+			a.full = dfixed_mul(wm0->worst_case_latency,
+						wm0->consumption_rate);
 			b.full = dfixed_const(16 * 1000);
 			priority_mark02.full = dfixed_div(a, b);
 		}
-		if (wm1.consumption_rate.full > fill_rate.full) {
-			b.full = wm1.consumption_rate.full - fill_rate.full;
-			b.full = dfixed_mul(b, wm1.active_time);
+		if (wm1->consumption_rate.full > fill_rate.full) {
+			b.full = wm1->consumption_rate.full - fill_rate.full;
+			b.full = dfixed_mul(b, wm1->active_time);
 			a.full = dfixed_const(16);
 			b.full = dfixed_div(b, a);
-			a.full = dfixed_mul(wm1.worst_case_latency,
-						wm1.consumption_rate);
+			a.full = dfixed_mul(wm1->worst_case_latency,
+						wm1->consumption_rate);
 			priority_mark12.full = a.full + b.full;
 		} else {
-			a.full = dfixed_mul(wm1.worst_case_latency,
-						wm1.consumption_rate);
+			a.full = dfixed_mul(wm1->worst_case_latency,
+						wm1->consumption_rate);
 			b.full = dfixed_const(16 * 1000);
 			priority_mark12.full = dfixed_div(a, b);
 		}
-		if (wm0.priority_mark.full > priority_mark02.full)
-			priority_mark02.full = wm0.priority_mark.full;
+		if (wm0->priority_mark.full > priority_mark02.full)
+			priority_mark02.full = wm0->priority_mark.full;
 		if (dfixed_trunc(priority_mark02) < 0)
 			priority_mark02.full = 0;
-		if (wm0.priority_mark_max.full > priority_mark02.full)
-			priority_mark02.full = wm0.priority_mark_max.full;
-		if (wm1.priority_mark.full > priority_mark12.full)
-			priority_mark12.full = wm1.priority_mark.full;
+		if (wm0->priority_mark_max.full > priority_mark02.full)
+			priority_mark02.full = wm0->priority_mark_max.full;
+		if (wm1->priority_mark.full > priority_mark12.full)
+			priority_mark12.full = wm1->priority_mark.full;
 		if (dfixed_trunc(priority_mark12) < 0)
 			priority_mark12.full = 0;
-		if (wm1.priority_mark_max.full > priority_mark12.full)
-			priority_mark12.full = wm1.priority_mark_max.full;
-		d1mode_priority_a_cnt = dfixed_trunc(priority_mark02);
-		d2mode_priority_a_cnt = dfixed_trunc(priority_mark12);
+		if (wm1->priority_mark_max.full > priority_mark12.full)
+			priority_mark12.full = wm1->priority_mark_max.full;
+		*d1mode_priority_a_cnt = dfixed_trunc(priority_mark02);
+		*d2mode_priority_a_cnt = dfixed_trunc(priority_mark12);
 		if (rdev->disp_priority == 2) {
-			d1mode_priority_a_cnt |= MODE_PRIORITY_ALWAYS_ON;
-			d2mode_priority_a_cnt |= MODE_PRIORITY_ALWAYS_ON;
+			*d1mode_priority_a_cnt |= MODE_PRIORITY_ALWAYS_ON;
+			*d2mode_priority_a_cnt |= MODE_PRIORITY_ALWAYS_ON;
 		}
 	} else if (mode0) {
-		if (dfixed_trunc(wm0.dbpp) > 64)
-			a.full = dfixed_div(wm0.dbpp, wm0.num_line_pair);
+		if (dfixed_trunc(wm0->dbpp) > 64)
+			a.full = dfixed_div(wm0->dbpp, wm0->num_line_pair);
 		else
-			a.full = wm0.num_line_pair.full;
-		fill_rate.full = dfixed_div(wm0.sclk, a);
-		if (wm0.consumption_rate.full > fill_rate.full) {
-			b.full = wm0.consumption_rate.full - fill_rate.full;
-			b.full = dfixed_mul(b, wm0.active_time);
+			a.full = wm0->num_line_pair.full;
+		fill_rate.full = dfixed_div(wm0->sclk, a);
+		if (wm0->consumption_rate.full > fill_rate.full) {
+			b.full = wm0->consumption_rate.full - fill_rate.full;
+			b.full = dfixed_mul(b, wm0->active_time);
 			a.full = dfixed_const(16);
 			b.full = dfixed_div(b, a);
-			a.full = dfixed_mul(wm0.worst_case_latency,
-						wm0.consumption_rate);
+			a.full = dfixed_mul(wm0->worst_case_latency,
+						wm0->consumption_rate);
 			priority_mark02.full = a.full + b.full;
 		} else {
-			a.full = dfixed_mul(wm0.worst_case_latency,
-						wm0.consumption_rate);
+			a.full = dfixed_mul(wm0->worst_case_latency,
+						wm0->consumption_rate);
 			b.full = dfixed_const(16);
 			priority_mark02.full = dfixed_div(a, b);
 		}
-		if (wm0.priority_mark.full > priority_mark02.full)
-			priority_mark02.full = wm0.priority_mark.full;
+		if (wm0->priority_mark.full > priority_mark02.full)
+			priority_mark02.full = wm0->priority_mark.full;
 		if (dfixed_trunc(priority_mark02) < 0)
 			priority_mark02.full = 0;
-		if (wm0.priority_mark_max.full > priority_mark02.full)
-			priority_mark02.full = wm0.priority_mark_max.full;
-		d1mode_priority_a_cnt = dfixed_trunc(priority_mark02);
+		if (wm0->priority_mark_max.full > priority_mark02.full)
+			priority_mark02.full = wm0->priority_mark_max.full;
+		*d1mode_priority_a_cnt = dfixed_trunc(priority_mark02);
 		if (rdev->disp_priority == 2)
-			d1mode_priority_a_cnt |= MODE_PRIORITY_ALWAYS_ON;
+			*d1mode_priority_a_cnt |= MODE_PRIORITY_ALWAYS_ON;
 	} else if (mode1) {
-		if (dfixed_trunc(wm1.dbpp) > 64)
-			a.full = dfixed_div(wm1.dbpp, wm1.num_line_pair);
+		if (dfixed_trunc(wm1->dbpp) > 64)
+			a.full = dfixed_div(wm1->dbpp, wm1->num_line_pair);
 		else
-			a.full = wm1.num_line_pair.full;
-		fill_rate.full = dfixed_div(wm1.sclk, a);
-		if (wm1.consumption_rate.full > fill_rate.full) {
-			b.full = wm1.consumption_rate.full - fill_rate.full;
-			b.full = dfixed_mul(b, wm1.active_time);
+			a.full = wm1->num_line_pair.full;
+		fill_rate.full = dfixed_div(wm1->sclk, a);
+		if (wm1->consumption_rate.full > fill_rate.full) {
+			b.full = wm1->consumption_rate.full - fill_rate.full;
+			b.full = dfixed_mul(b, wm1->active_time);
 			a.full = dfixed_const(16);
 			b.full = dfixed_div(b, a);
-			a.full = dfixed_mul(wm1.worst_case_latency,
-						wm1.consumption_rate);
+			a.full = dfixed_mul(wm1->worst_case_latency,
+						wm1->consumption_rate);
 			priority_mark12.full = a.full + b.full;
 		} else {
-			a.full = dfixed_mul(wm1.worst_case_latency,
-						wm1.consumption_rate);
+			a.full = dfixed_mul(wm1->worst_case_latency,
+						wm1->consumption_rate);
 			b.full = dfixed_const(16 * 1000);
 			priority_mark12.full = dfixed_div(a, b);
 		}
-		if (wm1.priority_mark.full > priority_mark12.full)
-			priority_mark12.full = wm1.priority_mark.full;
+		if (wm1->priority_mark.full > priority_mark12.full)
+			priority_mark12.full = wm1->priority_mark.full;
 		if (dfixed_trunc(priority_mark12) < 0)
 			priority_mark12.full = 0;
-		if (wm1.priority_mark_max.full > priority_mark12.full)
-			priority_mark12.full = wm1.priority_mark_max.full;
-		d2mode_priority_a_cnt = dfixed_trunc(priority_mark12);
+		if (wm1->priority_mark_max.full > priority_mark12.full)
+			priority_mark12.full = wm1->priority_mark_max.full;
+		*d2mode_priority_a_cnt = dfixed_trunc(priority_mark12);
 		if (rdev->disp_priority == 2)
-			d2mode_priority_a_cnt |= MODE_PRIORITY_ALWAYS_ON;
+			*d2mode_priority_a_cnt |= MODE_PRIORITY_ALWAYS_ON;
 	}
+}
+
+void rv515_bandwidth_avivo_update(struct radeon_device *rdev)
+{
+	struct drm_display_mode *mode0 = NULL;
+	struct drm_display_mode *mode1 = NULL;
+	struct rv515_watermark wm0_high, wm0_low;
+	struct rv515_watermark wm1_high, wm1_low;
+	u32 tmp;
+	u32 d1mode_priority_a_cnt, d1mode_priority_b_cnt;
+	u32 d2mode_priority_a_cnt, d2mode_priority_b_cnt;
+
+	if (rdev->mode_info.crtcs[0]->base.enabled)
+		mode0 = &rdev->mode_info.crtcs[0]->base.mode;
+	if (rdev->mode_info.crtcs[1]->base.enabled)
+		mode1 = &rdev->mode_info.crtcs[1]->base.mode;
+	rs690_line_buffer_adjust(rdev, mode0, mode1);
+
+	rv515_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[0], &wm0_high, false);
+	rv515_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[1], &wm1_high, false);
+
+	rv515_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[0], &wm0_low, false);
+	rv515_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[1], &wm1_low, false);
+
+	tmp = wm0_high.lb_request_fifo_depth;
+	tmp |= wm1_high.lb_request_fifo_depth << 16;
+	WREG32(LB_MAX_REQ_OUTSTANDING, tmp);
+
+	rv515_compute_mode_priority(rdev,
+				    &wm0_high, &wm1_high,
+				    mode0, mode1,
+				    &d1mode_priority_a_cnt, &d2mode_priority_a_cnt);
+	rv515_compute_mode_priority(rdev,
+				    &wm0_low, &wm1_low,
+				    mode0, mode1,
+				    &d1mode_priority_b_cnt, &d2mode_priority_b_cnt);
 
 	WREG32(D1MODE_PRIORITY_A_CNT, d1mode_priority_a_cnt);
-	WREG32(D1MODE_PRIORITY_B_CNT, d1mode_priority_a_cnt);
+	WREG32(D1MODE_PRIORITY_B_CNT, d1mode_priority_b_cnt);
 	WREG32(D2MODE_PRIORITY_A_CNT, d2mode_priority_a_cnt);
-	WREG32(D2MODE_PRIORITY_B_CNT, d2mode_priority_a_cnt);
+	WREG32(D2MODE_PRIORITY_B_CNT, d2mode_priority_b_cnt);
 }
 
 void rv515_bandwidth_update(struct radeon_device *rdev)
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 072/165] drm/radeon/kms: fix up dce4/5 display watermark calc for dpm
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (71 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 071/165] drm/radeon/kms: fix up 6xx/7xx " alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 073/165] drm/radeon/kms: fix up dce6 " alexdeucher
                   ` (40 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Calculate the low and high watermarks based on the low and high
clocks for the current power state.  The dynamic pm hw will select
the appropriate watermark based on the internal dpm state.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/evergreen.c |   89 ++++++++++++++++++++++++++---------
 1 files changed, 66 insertions(+), 23 deletions(-)

diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
index b9f64f0..63a1e6e 100644
--- a/drivers/gpu/drm/radeon/evergreen.c
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -2122,7 +2122,8 @@ static void evergreen_program_watermarks(struct radeon_device *rdev,
 					 u32 lb_size, u32 num_heads)
 {
 	struct drm_display_mode *mode = &radeon_crtc->base.mode;
-	struct evergreen_wm_params wm;
+	struct evergreen_wm_params wm_low, wm_high;
+	u32 dram_channels;
 	u32 pixel_period;
 	u32 line_time = 0;
 	u32 latency_watermark_a = 0, latency_watermark_b = 0;
@@ -2138,39 +2139,81 @@ static void evergreen_program_watermarks(struct radeon_device *rdev,
 		line_time = min((u32)mode->crtc_htotal * pixel_period, (u32)65535);
 		priority_a_cnt = 0;
 		priority_b_cnt = 0;
+		dram_channels = evergreen_get_number_of_dram_channels(rdev);
+
+		/* watermark for high clocks */
+		if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) {
+			wm_high.yclk =
+				radeon_dpm_get_mclk(rdev, false) * 10;
+			wm_high.sclk =
+				radeon_dpm_get_sclk(rdev, false) * 10;
+		} else {
+			wm_high.yclk = rdev->pm.current_mclk * 10;
+			wm_high.sclk = rdev->pm.current_sclk * 10;
+		}
 
-		wm.yclk = rdev->pm.current_mclk * 10;
-		wm.sclk = rdev->pm.current_sclk * 10;
-		wm.disp_clk = mode->clock;
-		wm.src_width = mode->crtc_hdisplay;
-		wm.active_time = mode->crtc_hdisplay * pixel_period;
-		wm.blank_time = line_time - wm.active_time;
-		wm.interlaced = false;
+		wm_high.disp_clk = mode->clock;
+		wm_high.src_width = mode->crtc_hdisplay;
+		wm_high.active_time = mode->crtc_hdisplay * pixel_period;
+		wm_high.blank_time = line_time - wm_high.active_time;
+		wm_high.interlaced = false;
 		if (mode->flags & DRM_MODE_FLAG_INTERLACE)
-			wm.interlaced = true;
-		wm.vsc = radeon_crtc->vsc;
-		wm.vtaps = 1;
+			wm_high.interlaced = true;
+		wm_high.vsc = radeon_crtc->vsc;
+		wm_high.vtaps = 1;
 		if (radeon_crtc->rmx_type != RMX_OFF)
-			wm.vtaps = 2;
-		wm.bytes_per_pixel = 4; /* XXX: get this from fb config */
-		wm.lb_size = lb_size;
-		wm.dram_channels = evergreen_get_number_of_dram_channels(rdev);
-		wm.num_heads = num_heads;
+			wm_high.vtaps = 2;
+		wm_high.bytes_per_pixel = 4; /* XXX: get this from fb config */
+		wm_high.lb_size = lb_size;
+		wm_high.dram_channels = dram_channels;
+		wm_high.num_heads = num_heads;
+
+		/* watermark for low clocks */
+		if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) {
+			wm_low.yclk =
+				radeon_dpm_get_mclk(rdev, true) * 10;
+			wm_low.sclk =
+				radeon_dpm_get_sclk(rdev, true) * 10;
+		} else {
+			wm_low.yclk = rdev->pm.current_mclk * 10;
+			wm_low.sclk = rdev->pm.current_sclk * 10;
+		}
+
+		wm_low.disp_clk = mode->clock;
+		wm_low.src_width = mode->crtc_hdisplay;
+		wm_low.active_time = mode->crtc_hdisplay * pixel_period;
+		wm_low.blank_time = line_time - wm_low.active_time;
+		wm_low.interlaced = false;
+		if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+			wm_low.interlaced = true;
+		wm_low.vsc = radeon_crtc->vsc;
+		wm_low.vtaps = 1;
+		if (radeon_crtc->rmx_type != RMX_OFF)
+			wm_low.vtaps = 2;
+		wm_low.bytes_per_pixel = 4; /* XXX: get this from fb config */
+		wm_low.lb_size = lb_size;
+		wm_low.dram_channels = dram_channels;
+		wm_low.num_heads = num_heads;
 
 		/* set for high clocks */
-		latency_watermark_a = min(evergreen_latency_watermark(&wm), (u32)65535);
+		latency_watermark_a = min(evergreen_latency_watermark(&wm_high), (u32)65535);
 		/* set for low clocks */
-		/* wm.yclk = low clk; wm.sclk = low clk */
-		latency_watermark_b = min(evergreen_latency_watermark(&wm), (u32)65535);
+		latency_watermark_b = min(evergreen_latency_watermark(&wm_low), (u32)65535);
 
 		/* possibly force display priority to high */
 		/* should really do this at mode validation time... */
-		if (!evergreen_average_bandwidth_vs_dram_bandwidth_for_display(&wm) ||
-		    !evergreen_average_bandwidth_vs_available_bandwidth(&wm) ||
-		    !evergreen_check_latency_hiding(&wm) ||
+		if (!evergreen_average_bandwidth_vs_dram_bandwidth_for_display(&wm_high) ||
+		    !evergreen_average_bandwidth_vs_available_bandwidth(&wm_high) ||
+		    !evergreen_check_latency_hiding(&wm_high) ||
 		    (rdev->disp_priority == 2)) {
-			DRM_DEBUG_KMS("force priority to high\n");
+			DRM_DEBUG_KMS("force priority a to high\n");
 			priority_a_cnt |= PRIORITY_ALWAYS_ON;
+		}
+		if (!evergreen_average_bandwidth_vs_dram_bandwidth_for_display(&wm_low) ||
+		    !evergreen_average_bandwidth_vs_available_bandwidth(&wm_low) ||
+		    !evergreen_check_latency_hiding(&wm_low) ||
+		    (rdev->disp_priority == 2)) {
+			DRM_DEBUG_KMS("force priority b to high\n");
 			priority_b_cnt |= PRIORITY_ALWAYS_ON;
 		}
 
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 073/165] drm/radeon/kms: fix up dce6 display watermark calc for dpm
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (72 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 072/165] drm/radeon/kms: fix up dce4/5 " alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 074/165] drm/radeon/kms: add common r600 dpm functions alexdeucher
                   ` (39 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Calculate the low and high watermarks based on the low and high
clocks for the current power state.  The dynamic pm hw will select
the appropriate watermark based on the internal dpm state.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/si.c |   96 +++++++++++++++++++++++++++++++-----------
 1 files changed, 71 insertions(+), 25 deletions(-)

diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c
index 813a8a9..882509a 100644
--- a/drivers/gpu/drm/radeon/si.c
+++ b/drivers/gpu/drm/radeon/si.c
@@ -1792,7 +1792,8 @@ static void dce6_program_watermarks(struct radeon_device *rdev,
 					 u32 lb_size, u32 num_heads)
 {
 	struct drm_display_mode *mode = &radeon_crtc->base.mode;
-	struct dce6_wm_params wm;
+	struct dce6_wm_params wm_low, wm_high;
+	u32 dram_channels;
 	u32 pixel_period;
 	u32 line_time = 0;
 	u32 latency_watermark_a = 0, latency_watermark_b = 0;
@@ -1808,38 +1809,83 @@ static void dce6_program_watermarks(struct radeon_device *rdev,
 		priority_a_cnt = 0;
 		priority_b_cnt = 0;
 
-		wm.yclk = rdev->pm.current_mclk * 10;
-		wm.sclk = rdev->pm.current_sclk * 10;
-		wm.disp_clk = mode->clock;
-		wm.src_width = mode->crtc_hdisplay;
-		wm.active_time = mode->crtc_hdisplay * pixel_period;
-		wm.blank_time = line_time - wm.active_time;
-		wm.interlaced = false;
-		if (mode->flags & DRM_MODE_FLAG_INTERLACE)
-			wm.interlaced = true;
-		wm.vsc = radeon_crtc->vsc;
-		wm.vtaps = 1;
-		if (radeon_crtc->rmx_type != RMX_OFF)
-			wm.vtaps = 2;
-		wm.bytes_per_pixel = 4; /* XXX: get this from fb config */
-		wm.lb_size = lb_size;
 		if (rdev->family == CHIP_ARUBA)
-			wm.dram_channels = evergreen_get_number_of_dram_channels(rdev);
+			dram_channels = evergreen_get_number_of_dram_channels(rdev);
 		else
-			wm.dram_channels = si_get_number_of_dram_channels(rdev);
-		wm.num_heads = num_heads;
+			dram_channels = si_get_number_of_dram_channels(rdev);
+
+		/* watermark for high clocks */
+		if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) {
+			wm_high.yclk =
+				radeon_dpm_get_mclk(rdev, false) * 10;
+			wm_high.sclk =
+				radeon_dpm_get_sclk(rdev, false) * 10;
+		} else {
+			wm_high.yclk = rdev->pm.current_mclk * 10;
+			wm_high.sclk = rdev->pm.current_sclk * 10;
+		}
+
+		wm_high.disp_clk = mode->clock;
+		wm_high.src_width = mode->crtc_hdisplay;
+		wm_high.active_time = mode->crtc_hdisplay * pixel_period;
+		wm_high.blank_time = line_time - wm_high.active_time;
+		wm_high.interlaced = false;
+		if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+			wm_high.interlaced = true;
+		wm_high.vsc = radeon_crtc->vsc;
+		wm_high.vtaps = 1;
+		if (radeon_crtc->rmx_type != RMX_OFF)
+			wm_high.vtaps = 2;
+		wm_high.bytes_per_pixel = 4; /* XXX: get this from fb config */
+		wm_high.lb_size = lb_size;
+		wm_high.dram_channels = dram_channels;
+		wm_high.num_heads = num_heads;
+
+		/* watermark for low clocks */
+		if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) {
+			wm_low.yclk =
+				radeon_dpm_get_mclk(rdev, true) * 10;
+			wm_low.sclk =
+				radeon_dpm_get_sclk(rdev, true) * 10;
+		} else {
+			wm_low.yclk = rdev->pm.current_mclk * 10;
+			wm_low.sclk = rdev->pm.current_sclk * 10;
+		}
+
+		wm_low.disp_clk = mode->clock;
+		wm_low.src_width = mode->crtc_hdisplay;
+		wm_low.active_time = mode->crtc_hdisplay * pixel_period;
+		wm_low.blank_time = line_time - wm_low.active_time;
+		wm_low.interlaced = false;
+		if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+			wm_low.interlaced = true;
+		wm_low.vsc = radeon_crtc->vsc;
+		wm_low.vtaps = 1;
+		if (radeon_crtc->rmx_type != RMX_OFF)
+			wm_low.vtaps = 2;
+		wm_low.bytes_per_pixel = 4; /* XXX: get this from fb config */
+		wm_low.lb_size = lb_size;
+		wm_low.dram_channels = dram_channels;
+		wm_low.num_heads = num_heads;
 
 		/* set for high clocks */
-		latency_watermark_a = min(dce6_latency_watermark(&wm), (u32)65535);
+		latency_watermark_a = min(dce6_latency_watermark(&wm_high), (u32)65535);
 		/* set for low clocks */
-		/* wm.yclk = low clk; wm.sclk = low clk */
-		latency_watermark_b = min(dce6_latency_watermark(&wm), (u32)65535);
+		latency_watermark_b = min(dce6_latency_watermark(&wm_low), (u32)65535);
 
 		/* possibly force display priority to high */
 		/* should really do this at mode validation time... */
-		if (!dce6_average_bandwidth_vs_dram_bandwidth_for_display(&wm) ||
-		    !dce6_average_bandwidth_vs_available_bandwidth(&wm) ||
-		    !dce6_check_latency_hiding(&wm) ||
+		if (!dce6_average_bandwidth_vs_dram_bandwidth_for_display(&wm_high) ||
+		    !dce6_average_bandwidth_vs_available_bandwidth(&wm_high) ||
+		    !dce6_check_latency_hiding(&wm_high) ||
+		    (rdev->disp_priority == 2)) {
+			DRM_DEBUG_KMS("force priority to high\n");
+			priority_a_cnt |= PRIORITY_ALWAYS_ON;
+			priority_b_cnt |= PRIORITY_ALWAYS_ON;
+		}
+		if (!dce6_average_bandwidth_vs_dram_bandwidth_for_display(&wm_low) ||
+		    !dce6_average_bandwidth_vs_available_bandwidth(&wm_low) ||
+		    !dce6_check_latency_hiding(&wm_low) ||
 		    (rdev->disp_priority == 2)) {
 			DRM_DEBUG_KMS("force priority to high\n");
 			priority_a_cnt |= PRIORITY_ALWAYS_ON;
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 074/165] drm/radeon/kms: add common r600 dpm functions
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (73 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 073/165] drm/radeon/kms: fix up dce6 " alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 075/165] drm/radeon/kms: add dpm support for rs780/rs880 alexdeucher
                   ` (38 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

These are shared by rs780/rs880, rv6xx, and newer chips.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/Makefile   |    3 +-
 drivers/gpu/drm/radeon/r600_dpm.c |  678 +++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/radeon/r600_dpm.h |  210 ++++++++++++
 drivers/gpu/drm/radeon/r600d.h    |  213 ++++++++++++
 drivers/gpu/drm/radeon/radeon.h   |   13 +
 5 files changed, 1116 insertions(+), 1 deletions(-)
 create mode 100644 drivers/gpu/drm/radeon/r600_dpm.c
 create mode 100644 drivers/gpu/drm/radeon/r600_dpm.h

diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile
index 292fd25..a131a13 100644
--- a/drivers/gpu/drm/radeon/Makefile
+++ b/drivers/gpu/drm/radeon/Makefile
@@ -76,7 +76,8 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \
 	evergreen.o evergreen_cs.o evergreen_blit_shaders.o evergreen_blit_kms.o \
 	evergreen_hdmi.o radeon_trace_points.o ni.o cayman_blit_shaders.o \
 	atombios_encoders.o radeon_semaphore.o radeon_sa.o atombios_i2c.o si.o \
-	si_blit_shaders.o radeon_prime.o radeon_uvd.o cik.o cik_blit_shaders.o
+	si_blit_shaders.o radeon_prime.o radeon_uvd.o cik.o cik_blit_shaders.o \
+	r600_dpm.o
 
 radeon-$(CONFIG_COMPAT) += radeon_ioc32.o
 radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o
diff --git a/drivers/gpu/drm/radeon/r600_dpm.c b/drivers/gpu/drm/radeon/r600_dpm.c
new file mode 100644
index 0000000..91bc5ab
--- /dev/null
+++ b/drivers/gpu/drm/radeon/r600_dpm.c
@@ -0,0 +1,678 @@
+/*
+ * Copyright 2011 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Alex Deucher
+ */
+
+#include "drmP.h"
+#include "radeon.h"
+#include "r600d.h"
+#include "r600_dpm.h"
+#include "atom.h"
+
+const u32 r600_utc[R600_PM_NUMBER_OF_TC] =
+{
+	R600_UTC_DFLT_00,
+	R600_UTC_DFLT_01,
+	R600_UTC_DFLT_02,
+	R600_UTC_DFLT_03,
+	R600_UTC_DFLT_04,
+	R600_UTC_DFLT_05,
+	R600_UTC_DFLT_06,
+	R600_UTC_DFLT_07,
+	R600_UTC_DFLT_08,
+	R600_UTC_DFLT_09,
+	R600_UTC_DFLT_10,
+	R600_UTC_DFLT_11,
+	R600_UTC_DFLT_12,
+	R600_UTC_DFLT_13,
+	R600_UTC_DFLT_14,
+};
+
+const u32 r600_dtc[R600_PM_NUMBER_OF_TC] =
+{
+	R600_DTC_DFLT_00,
+	R600_DTC_DFLT_01,
+	R600_DTC_DFLT_02,
+	R600_DTC_DFLT_03,
+	R600_DTC_DFLT_04,
+	R600_DTC_DFLT_05,
+	R600_DTC_DFLT_06,
+	R600_DTC_DFLT_07,
+	R600_DTC_DFLT_08,
+	R600_DTC_DFLT_09,
+	R600_DTC_DFLT_10,
+	R600_DTC_DFLT_11,
+	R600_DTC_DFLT_12,
+	R600_DTC_DFLT_13,
+	R600_DTC_DFLT_14,
+};
+
+void r600_dpm_print_class_info(u32 class, u32 class2)
+{
+	printk("\tui class: ");
+	switch (class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) {
+	case ATOM_PPLIB_CLASSIFICATION_UI_NONE:
+	default:
+		printk("none\n");
+		break;
+	case ATOM_PPLIB_CLASSIFICATION_UI_BATTERY:
+		printk("battery\n");
+		break;
+	case ATOM_PPLIB_CLASSIFICATION_UI_BALANCED:
+		printk("balanced\n");
+		break;
+	case ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE:
+		printk("performance\n");
+		break;
+	}
+	printk("\tinternal class: ");
+	if (((class & ~ATOM_PPLIB_CLASSIFICATION_UI_MASK) == 0) &&
+	    (class2 == 0))
+		printk("none");
+	else {
+		if (class & ATOM_PPLIB_CLASSIFICATION_BOOT)
+			printk("boot ");
+		if (class & ATOM_PPLIB_CLASSIFICATION_THERMAL)
+			printk("thermal ");
+		if (class & ATOM_PPLIB_CLASSIFICATION_LIMITEDPOWERSOURCE)
+			printk("limited_pwr ");
+		if (class & ATOM_PPLIB_CLASSIFICATION_REST)
+			printk("rest ");
+		if (class & ATOM_PPLIB_CLASSIFICATION_FORCED)
+			printk("forced ");
+		if (class & ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE)
+			printk("3d_perf ");
+		if (class & ATOM_PPLIB_CLASSIFICATION_OVERDRIVETEMPLATE)
+			printk("ovrdrv ");
+		if (class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
+			printk("uvd ");
+		if (class & ATOM_PPLIB_CLASSIFICATION_3DLOW)
+			printk("3d_low ");
+		if (class & ATOM_PPLIB_CLASSIFICATION_ACPI)
+			printk("acpi ");
+		if (class & ATOM_PPLIB_CLASSIFICATION_HD2STATE)
+			printk("uvd_hd2 ");
+		if (class & ATOM_PPLIB_CLASSIFICATION_HDSTATE)
+			printk("uvd_hd ");
+		if (class & ATOM_PPLIB_CLASSIFICATION_SDSTATE)
+			printk("uvd_sd ");
+		if (class2 & ATOM_PPLIB_CLASSIFICATION2_LIMITEDPOWERSOURCE_2)
+			printk("limited_pwr2 ");
+		if (class2 & ATOM_PPLIB_CLASSIFICATION2_ULV)
+			printk("ulv ");
+		if (class2 & ATOM_PPLIB_CLASSIFICATION2_MVC)
+			printk("uvd_mvc ");
+	}
+	printk("\n");
+}
+
+void r600_dpm_print_cap_info(u32 caps)
+{
+	printk("\tcaps: ");
+	if (caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY)
+		printk("single_disp ");
+	if (caps & ATOM_PPLIB_SUPPORTS_VIDEO_PLAYBACK)
+		printk("video ");
+	if (caps & ATOM_PPLIB_DISALLOW_ON_DC)
+		printk("no_dc ");
+	printk("\n");
+}
+
+void r600_dpm_print_ps_status(struct radeon_device *rdev,
+			      struct radeon_ps *rps)
+{
+	printk("\tstatus: ");
+	if (rps == rdev->pm.dpm.current_ps)
+		printk("c ");
+	if (rps == rdev->pm.dpm.requested_ps)
+		printk("r ");
+	if (rps == rdev->pm.dpm.boot_ps)
+		printk("b ");
+	printk("\n");
+}
+
+void r600_calculate_u_and_p(u32 i, u32 r_c, u32 p_b,
+			    u32 *p, u32 *u)
+{
+	u32 b_c = 0;
+	u32 i_c;
+	u32 tmp;
+
+	i_c = (i * r_c) / 100;
+	tmp = i_c >> p_b;
+
+	while (tmp) {
+		b_c++;
+		tmp >>= 1;
+	}
+
+	*u = (b_c + 1) / 2;
+	*p = i_c / (1 << (2 * (*u)));
+}
+
+int r600_calculate_at(u32 t, u32 h, u32 fh, u32 fl, u32 *tl, u32 *th)
+{
+	u32 k, a, ah, al;
+	u32 t1;
+
+	if ((fl == 0) || (fh == 0) || (fl > fh))
+		return -EINVAL;
+
+	k = (100 * fh) / fl;
+	t1 = (t * (k - 100));
+	a = (1000 * (100 * h + t1)) / (10000 + (t1 / 100));
+	a = (a + 5) / 10;
+	ah = ((a * t) + 5000) / 10000;
+	al = a - ah;
+
+	*th = t - ah;
+	*tl = t + al;
+
+	return 0;
+}
+
+void r600_gfx_clockgating_enable(struct radeon_device *rdev, bool enable)
+{
+	int i;
+
+	if (enable) {
+		WREG32_P(SCLK_PWRMGT_CNTL, DYN_GFX_CLK_OFF_EN, ~DYN_GFX_CLK_OFF_EN);
+	} else {
+		WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_GFX_CLK_OFF_EN);
+
+		WREG32(CG_RLC_REQ_AND_RSP, 0x2);
+
+		for (i = 0; i < rdev->usec_timeout; i++) {
+			if (((RREG32(CG_RLC_REQ_AND_RSP) & CG_RLC_RSP_TYPE_MASK) >> CG_RLC_RSP_TYPE_SHIFT) == 1)
+				break;
+			udelay(1);
+		}
+
+		WREG32(CG_RLC_REQ_AND_RSP, 0x0);
+
+		WREG32(GRBM_PWR_CNTL, 0x1);
+		RREG32(GRBM_PWR_CNTL);
+	}
+}
+
+void r600_dynamicpm_enable(struct radeon_device *rdev, bool enable)
+{
+	if (enable)
+		WREG32_P(GENERAL_PWRMGT, GLOBAL_PWRMGT_EN, ~GLOBAL_PWRMGT_EN);
+	else
+		WREG32_P(GENERAL_PWRMGT, 0, ~GLOBAL_PWRMGT_EN);
+}
+
+void r600_enable_thermal_protection(struct radeon_device *rdev, bool enable)
+{
+	if (enable)
+		WREG32_P(GENERAL_PWRMGT, 0, ~THERMAL_PROTECTION_DIS);
+	else
+		WREG32_P(GENERAL_PWRMGT, THERMAL_PROTECTION_DIS, ~THERMAL_PROTECTION_DIS);
+}
+
+void r600_enable_acpi_pm(struct radeon_device *rdev)
+{
+	WREG32_P(GENERAL_PWRMGT, STATIC_PM_EN, ~STATIC_PM_EN);
+}
+
+void r600_enable_dynamic_pcie_gen2(struct radeon_device *rdev, bool enable)
+{
+	if (enable)
+		WREG32_P(GENERAL_PWRMGT, ENABLE_GEN2PCIE, ~ENABLE_GEN2PCIE);
+	else
+		WREG32_P(GENERAL_PWRMGT, 0, ~ENABLE_GEN2PCIE);
+}
+
+bool r600_dynamicpm_enabled(struct radeon_device *rdev)
+{
+	if (RREG32(GENERAL_PWRMGT) & GLOBAL_PWRMGT_EN)
+		return true;
+	else
+		return false;
+}
+
+void r600_enable_sclk_control(struct radeon_device *rdev, bool enable)
+{
+	if (enable)
+		WREG32_P(GENERAL_PWRMGT, 0, ~SCLK_PWRMGT_OFF);
+	else
+		WREG32_P(GENERAL_PWRMGT, SCLK_PWRMGT_OFF, ~SCLK_PWRMGT_OFF);
+}
+
+void r600_enable_mclk_control(struct radeon_device *rdev, bool enable)
+{
+	if (enable)
+		WREG32_P(MCLK_PWRMGT_CNTL, 0, ~MPLL_PWRMGT_OFF);
+	else
+		WREG32_P(MCLK_PWRMGT_CNTL, MPLL_PWRMGT_OFF, ~MPLL_PWRMGT_OFF);
+}
+
+void r600_enable_spll_bypass(struct radeon_device *rdev, bool enable)
+{
+	if (enable)
+		WREG32_P(CG_SPLL_FUNC_CNTL, SPLL_BYPASS_EN, ~SPLL_BYPASS_EN);
+	else
+		WREG32_P(CG_SPLL_FUNC_CNTL, 0, ~SPLL_BYPASS_EN);
+}
+
+void r600_wait_for_spll_change(struct radeon_device *rdev)
+{
+	int i;
+
+	for (i = 0; i < rdev->usec_timeout; i++) {
+		if (RREG32(CG_SPLL_FUNC_CNTL) & SPLL_CHG_STATUS)
+			break;
+		udelay(1);
+	}
+}
+
+void r600_set_bsp(struct radeon_device *rdev, u32 u, u32 p)
+{
+	WREG32(CG_BSP, BSP(p) | BSU(u));
+}
+
+void r600_set_at(struct radeon_device *rdev,
+		 u32 l_to_m, u32 m_to_h,
+		 u32 h_to_m, u32 m_to_l)
+{
+	WREG32(CG_RT, FLS(l_to_m) | FMS(m_to_h));
+	WREG32(CG_LT, FHS(h_to_m) | FMS(m_to_l));
+}
+
+void r600_set_tc(struct radeon_device *rdev,
+		 u32 index, u32 u_t, u32 d_t)
+{
+	WREG32(CG_FFCT_0 + (index * 4), UTC_0(u_t) | DTC_0(d_t));
+}
+
+void r600_select_td(struct radeon_device *rdev,
+		    enum r600_td td)
+{
+	if (td == R600_TD_AUTO)
+		WREG32_P(SCLK_PWRMGT_CNTL, 0, ~FIR_FORCE_TREND_SEL);
+	else
+		WREG32_P(SCLK_PWRMGT_CNTL, FIR_FORCE_TREND_SEL, ~FIR_FORCE_TREND_SEL);
+	if (td == R600_TD_UP)
+		WREG32_P(SCLK_PWRMGT_CNTL, 0, ~FIR_TREND_MODE);
+	if (td == R600_TD_DOWN)
+		WREG32_P(SCLK_PWRMGT_CNTL, FIR_TREND_MODE, ~FIR_TREND_MODE);
+}
+
+void r600_set_vrc(struct radeon_device *rdev, u32 vrv)
+{
+	WREG32(CG_FTV, vrv);
+}
+
+void r600_set_tpu(struct radeon_device *rdev, u32 u)
+{
+	WREG32_P(CG_TPC, TPU(u), ~TPU_MASK);
+}
+
+void r600_set_tpc(struct radeon_device *rdev, u32 c)
+{
+	WREG32_P(CG_TPC, TPCC(c), ~TPCC_MASK);
+}
+
+void r600_set_sstu(struct radeon_device *rdev, u32 u)
+{
+	WREG32_P(CG_SSP, CG_SSTU(u), ~CG_SSTU_MASK);
+}
+
+void r600_set_sst(struct radeon_device *rdev, u32 t)
+{
+	WREG32_P(CG_SSP, CG_SST(t), ~CG_SST_MASK);
+}
+
+void r600_set_git(struct radeon_device *rdev, u32 t)
+{
+	WREG32_P(CG_GIT, CG_GICST(t), ~CG_GICST_MASK);
+}
+
+void r600_set_fctu(struct radeon_device *rdev, u32 u)
+{
+	WREG32_P(CG_FC_T, FC_TU(u), ~FC_TU_MASK);
+}
+
+void r600_set_fct(struct radeon_device *rdev, u32 t)
+{
+	WREG32_P(CG_FC_T, FC_T(t), ~FC_T_MASK);
+}
+
+void r600_set_ctxcgtt3d_rphc(struct radeon_device *rdev, u32 p)
+{
+	WREG32_P(CG_CTX_CGTT3D_R, PHC(p), ~PHC_MASK);
+}
+
+void r600_set_ctxcgtt3d_rsdc(struct radeon_device *rdev, u32 s)
+{
+	WREG32_P(CG_CTX_CGTT3D_R, SDC(s), ~SDC_MASK);
+}
+
+void r600_set_vddc3d_oorsu(struct radeon_device *rdev, u32 u)
+{
+	WREG32_P(CG_VDDC3D_OOR, SU(u), ~SU_MASK);
+}
+
+void r600_set_vddc3d_oorphc(struct radeon_device *rdev, u32 p)
+{
+	WREG32_P(CG_VDDC3D_OOR, PHC(p), ~PHC_MASK);
+}
+
+void r600_set_vddc3d_oorsdc(struct radeon_device *rdev, u32 s)
+{
+	WREG32_P(CG_VDDC3D_OOR, SDC(s), ~SDC_MASK);
+}
+
+void r600_set_mpll_lock_time(struct radeon_device *rdev, u32 lock_time)
+{
+	WREG32_P(MPLL_TIME, MPLL_LOCK_TIME(lock_time), ~MPLL_LOCK_TIME_MASK);
+}
+
+void r600_set_mpll_reset_time(struct radeon_device *rdev, u32 reset_time)
+{
+	WREG32_P(MPLL_TIME, MPLL_RESET_TIME(reset_time), ~MPLL_RESET_TIME_MASK);
+}
+
+void r600_engine_clock_entry_enable(struct radeon_device *rdev,
+				    u32 index, bool enable)
+{
+	if (enable)
+		WREG32_P(SCLK_FREQ_SETTING_STEP_0_PART2 + (index * 4 * 2),
+			 STEP_0_SPLL_ENTRY_VALID, ~STEP_0_SPLL_ENTRY_VALID);
+	else
+		WREG32_P(SCLK_FREQ_SETTING_STEP_0_PART2 + (index * 4 * 2),
+			 0, ~STEP_0_SPLL_ENTRY_VALID);
+}
+
+void r600_engine_clock_entry_enable_pulse_skipping(struct radeon_device *rdev,
+						   u32 index, bool enable)
+{
+	if (enable)
+		WREG32_P(SCLK_FREQ_SETTING_STEP_0_PART2 + (index * 4 * 2),
+			 STEP_0_SPLL_STEP_ENABLE, ~STEP_0_SPLL_STEP_ENABLE);
+	else
+		WREG32_P(SCLK_FREQ_SETTING_STEP_0_PART2 + (index * 4 * 2),
+			 0, ~STEP_0_SPLL_STEP_ENABLE);
+}
+
+void r600_engine_clock_entry_enable_post_divider(struct radeon_device *rdev,
+						 u32 index, bool enable)
+{
+	if (enable)
+		WREG32_P(SCLK_FREQ_SETTING_STEP_0_PART2 + (index * 4 * 2),
+			 STEP_0_POST_DIV_EN, ~STEP_0_POST_DIV_EN);
+	else
+		WREG32_P(SCLK_FREQ_SETTING_STEP_0_PART2 + (index * 4 * 2),
+			 0, ~STEP_0_POST_DIV_EN);
+}
+
+void r600_engine_clock_entry_set_post_divider(struct radeon_device *rdev,
+					      u32 index, u32 divider)
+{
+	WREG32_P(SCLK_FREQ_SETTING_STEP_0_PART1 + (index * 4 * 2),
+		 STEP_0_SPLL_POST_DIV(divider), ~STEP_0_SPLL_POST_DIV_MASK);
+}
+
+void r600_engine_clock_entry_set_reference_divider(struct radeon_device *rdev,
+						   u32 index, u32 divider)
+{
+	WREG32_P(SCLK_FREQ_SETTING_STEP_0_PART1 + (index * 4 * 2),
+		 STEP_0_SPLL_REF_DIV(divider), ~STEP_0_SPLL_REF_DIV_MASK);
+}
+
+void r600_engine_clock_entry_set_feedback_divider(struct radeon_device *rdev,
+						  u32 index, u32 divider)
+{
+	WREG32_P(SCLK_FREQ_SETTING_STEP_0_PART1 + (index * 4 * 2),
+		 STEP_0_SPLL_FB_DIV(divider), ~STEP_0_SPLL_FB_DIV_MASK);
+}
+
+void r600_engine_clock_entry_set_step_time(struct radeon_device *rdev,
+					   u32 index, u32 step_time)
+{
+	WREG32_P(SCLK_FREQ_SETTING_STEP_0_PART1 + (index * 4 * 2),
+		 STEP_0_SPLL_STEP_TIME(step_time), ~STEP_0_SPLL_STEP_TIME_MASK);
+}
+
+void r600_vid_rt_set_ssu(struct radeon_device *rdev, u32 u)
+{
+	WREG32_P(VID_RT, SSTU(u), ~SSTU_MASK);
+}
+
+void r600_vid_rt_set_vru(struct radeon_device *rdev, u32 u)
+{
+	WREG32_P(VID_RT, VID_CRTU(u), ~VID_CRTU_MASK);
+}
+
+void r600_vid_rt_set_vrt(struct radeon_device *rdev, u32 rt)
+{
+	WREG32_P(VID_RT, VID_CRT(rt), ~VID_CRT_MASK);
+}
+
+void r600_voltage_control_enable_pins(struct radeon_device *rdev,
+				      u64 mask)
+{
+	WREG32(LOWER_GPIO_ENABLE, mask & 0xffffffff);
+	WREG32(UPPER_GPIO_ENABLE, upper_32_bits(mask));
+}
+
+
+void r600_voltage_control_program_voltages(struct radeon_device *rdev,
+					   enum r600_power_level index, u64 pins)
+{
+	u32 tmp, mask;
+	u32 ix = 3 - (3 & index);
+
+	WREG32(CTXSW_VID_LOWER_GPIO_CNTL + (ix * 4), pins & 0xffffffff);
+
+	mask = 7 << (3 * ix);
+	tmp = RREG32(VID_UPPER_GPIO_CNTL);
+	tmp = (tmp & ~mask) | ((pins >> (32 - (3 * ix))) & mask);
+	WREG32(VID_UPPER_GPIO_CNTL, tmp);
+}
+
+void r600_voltage_control_deactivate_static_control(struct radeon_device *rdev,
+						    u64 mask)
+{
+	u32 gpio;
+
+	gpio = RREG32(GPIOPAD_MASK);
+	gpio &= ~mask;
+	WREG32(GPIOPAD_MASK, gpio);
+
+	gpio = RREG32(GPIOPAD_EN);
+	gpio &= ~mask;
+	WREG32(GPIOPAD_EN, gpio);
+
+	gpio = RREG32(GPIOPAD_A);
+	gpio &= ~mask;
+	WREG32(GPIOPAD_A, gpio);
+}
+
+void r600_power_level_enable(struct radeon_device *rdev,
+			     enum r600_power_level index, bool enable)
+{
+	u32 ix = 3 - (3 & index);
+
+	if (enable)
+		WREG32_P(CTXSW_PROFILE_INDEX + (ix * 4), CTXSW_FREQ_STATE_ENABLE,
+			 ~CTXSW_FREQ_STATE_ENABLE);
+	else
+		WREG32_P(CTXSW_PROFILE_INDEX + (ix * 4), 0,
+			 ~CTXSW_FREQ_STATE_ENABLE);
+}
+
+void r600_power_level_set_voltage_index(struct radeon_device *rdev,
+					enum r600_power_level index, u32 voltage_index)
+{
+	u32 ix = 3 - (3 & index);
+
+	WREG32_P(CTXSW_PROFILE_INDEX + (ix * 4),
+		 CTXSW_FREQ_VIDS_CFG_INDEX(voltage_index), ~CTXSW_FREQ_VIDS_CFG_INDEX_MASK);
+}
+
+void r600_power_level_set_mem_clock_index(struct radeon_device *rdev,
+					  enum r600_power_level index, u32 mem_clock_index)
+{
+	u32 ix = 3 - (3 & index);
+
+	WREG32_P(CTXSW_PROFILE_INDEX + (ix * 4),
+		 CTXSW_FREQ_MCLK_CFG_INDEX(mem_clock_index), ~CTXSW_FREQ_MCLK_CFG_INDEX_MASK);
+}
+
+void r600_power_level_set_eng_clock_index(struct radeon_device *rdev,
+					  enum r600_power_level index, u32 eng_clock_index)
+{
+	u32 ix = 3 - (3 & index);
+
+	WREG32_P(CTXSW_PROFILE_INDEX + (ix * 4),
+		 CTXSW_FREQ_SCLK_CFG_INDEX(eng_clock_index), ~CTXSW_FREQ_SCLK_CFG_INDEX_MASK);
+}
+
+void r600_power_level_set_watermark_id(struct radeon_device *rdev,
+				       enum r600_power_level index,
+				       enum r600_display_watermark watermark_id)
+{
+	u32 ix = 3 - (3 & index);
+	u32 tmp = 0;
+
+	if (watermark_id == R600_DISPLAY_WATERMARK_HIGH)
+		tmp = CTXSW_FREQ_DISPLAY_WATERMARK;
+	WREG32_P(CTXSW_PROFILE_INDEX + (ix * 4), tmp, ~CTXSW_FREQ_DISPLAY_WATERMARK);
+}
+
+void r600_power_level_set_pcie_gen2(struct radeon_device *rdev,
+				    enum r600_power_level index, bool compatible)
+{
+	u32 ix = 3 - (3 & index);
+	u32 tmp = 0;
+
+	if (compatible)
+		tmp = CTXSW_FREQ_GEN2PCIE_VOLT;
+	WREG32_P(CTXSW_PROFILE_INDEX + (ix * 4), tmp, ~CTXSW_FREQ_GEN2PCIE_VOLT);
+}
+
+enum r600_power_level r600_power_level_get_current_index(struct radeon_device *rdev)
+{
+	u32 tmp;
+
+	tmp = RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK;
+	tmp >>= CURRENT_PROFILE_INDEX_SHIFT;
+	return tmp;
+}
+
+enum r600_power_level r600_power_level_get_target_index(struct radeon_device *rdev)
+{
+	u32 tmp;
+
+	tmp = RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & TARGET_PROFILE_INDEX_MASK;
+	tmp >>= TARGET_PROFILE_INDEX_SHIFT;
+	return tmp;
+}
+
+void r600_power_level_set_enter_index(struct radeon_device *rdev,
+				      enum r600_power_level index)
+{
+	WREG32_P(TARGET_AND_CURRENT_PROFILE_INDEX, DYN_PWR_ENTER_INDEX(index),
+		 ~DYN_PWR_ENTER_INDEX_MASK);
+}
+
+void r600_wait_for_power_level_unequal(struct radeon_device *rdev,
+				       enum r600_power_level index)
+{
+	int i;
+
+	for (i = 0; i < rdev->usec_timeout; i++) {
+		if (r600_power_level_get_target_index(rdev) != index)
+			break;
+		udelay(1);
+	}
+
+	for (i = 0; i < rdev->usec_timeout; i++) {
+		if (r600_power_level_get_current_index(rdev) != index)
+			break;
+		udelay(1);
+	}
+}
+
+void r600_wait_for_power_level(struct radeon_device *rdev,
+			       enum r600_power_level index)
+{
+	int i;
+
+	for (i = 0; i < rdev->usec_timeout; i++) {
+		if (r600_power_level_get_target_index(rdev) == index)
+			break;
+		udelay(1);
+	}
+
+	for (i = 0; i < rdev->usec_timeout; i++) {
+		if (r600_power_level_get_current_index(rdev) == index)
+			break;
+		udelay(1);
+	}
+}
+
+void r600_start_dpm(struct radeon_device *rdev)
+{
+	r600_enable_sclk_control(rdev, false);
+	r600_enable_mclk_control(rdev, false);
+
+	r600_dynamicpm_enable(rdev, true);
+
+	radeon_wait_for_vblank(rdev, 0);
+	radeon_wait_for_vblank(rdev, 1);
+
+	r600_enable_spll_bypass(rdev, true);
+	r600_wait_for_spll_change(rdev);
+	r600_enable_spll_bypass(rdev, false);
+	r600_wait_for_spll_change(rdev);
+
+	r600_enable_spll_bypass(rdev, true);
+	r600_wait_for_spll_change(rdev);
+	r600_enable_spll_bypass(rdev, false);
+	r600_wait_for_spll_change(rdev);
+
+	r600_enable_sclk_control(rdev, true);
+	r600_enable_mclk_control(rdev, true);
+}
+
+void r600_stop_dpm(struct radeon_device *rdev)
+{
+	r600_dynamicpm_enable(rdev, false);
+}
+
+bool r600_is_uvd_state(u32 class, u32 class2)
+{
+	if (class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
+		return true;
+	if (class & ATOM_PPLIB_CLASSIFICATION_HD2STATE)
+		return true;
+	if (class & ATOM_PPLIB_CLASSIFICATION_HDSTATE)
+		return true;
+	if (class & ATOM_PPLIB_CLASSIFICATION_SDSTATE)
+		return true;
+	if (class2 & ATOM_PPLIB_CLASSIFICATION2_MVC)
+		return true;
+	return false;
+}
diff --git a/drivers/gpu/drm/radeon/r600_dpm.h b/drivers/gpu/drm/radeon/r600_dpm.h
new file mode 100644
index 0000000..240a7ed
--- /dev/null
+++ b/drivers/gpu/drm/radeon/r600_dpm.h
@@ -0,0 +1,210 @@
+/*
+ * Copyright 2011 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef __R600_DPM_H__
+#define __R600_DPM_H__
+
+#define R600_ASI_DFLT                                10000
+#define R600_BSP_DFLT                                0x41EB
+#define R600_BSU_DFLT                                0x2
+#define R600_AH_DFLT                                 5
+#define R600_RLP_DFLT                                25
+#define R600_RMP_DFLT                                65
+#define R600_LHP_DFLT                                40
+#define R600_LMP_DFLT                                15
+#define R600_TD_DFLT                                 0
+#define R600_UTC_DFLT_00                             0x24
+#define R600_UTC_DFLT_01                             0x22
+#define R600_UTC_DFLT_02                             0x22
+#define R600_UTC_DFLT_03                             0x22
+#define R600_UTC_DFLT_04                             0x22
+#define R600_UTC_DFLT_05                             0x22
+#define R600_UTC_DFLT_06                             0x22
+#define R600_UTC_DFLT_07                             0x22
+#define R600_UTC_DFLT_08                             0x22
+#define R600_UTC_DFLT_09                             0x22
+#define R600_UTC_DFLT_10                             0x22
+#define R600_UTC_DFLT_11                             0x22
+#define R600_UTC_DFLT_12                             0x22
+#define R600_UTC_DFLT_13                             0x22
+#define R600_UTC_DFLT_14                             0x22
+#define R600_DTC_DFLT_00                             0x24
+#define R600_DTC_DFLT_01                             0x22
+#define R600_DTC_DFLT_02                             0x22
+#define R600_DTC_DFLT_03                             0x22
+#define R600_DTC_DFLT_04                             0x22
+#define R600_DTC_DFLT_05                             0x22
+#define R600_DTC_DFLT_06                             0x22
+#define R600_DTC_DFLT_07                             0x22
+#define R600_DTC_DFLT_08                             0x22
+#define R600_DTC_DFLT_09                             0x22
+#define R600_DTC_DFLT_10                             0x22
+#define R600_DTC_DFLT_11                             0x22
+#define R600_DTC_DFLT_12                             0x22
+#define R600_DTC_DFLT_13                             0x22
+#define R600_DTC_DFLT_14                             0x22
+#define R600_VRC_DFLT                                0x0000C003
+#define R600_VOLTAGERESPONSETIME_DFLT                1000
+#define R600_BACKBIASRESPONSETIME_DFLT               1000
+#define R600_VRU_DFLT                                0x3
+#define R600_SPLLSTEPTIME_DFLT                       0x1000
+#define R600_SPLLSTEPUNIT_DFLT                       0x3
+#define R600_TPU_DFLT                                0
+#define R600_TPC_DFLT                                0x200
+#define R600_SSTU_DFLT                               0
+#define R600_SST_DFLT                                0x00C8
+#define R600_GICST_DFLT                              0x200
+#define R600_FCT_DFLT                                0x0400
+#define R600_FCTU_DFLT                               0
+#define R600_CTXCGTT3DRPHC_DFLT                      0x20
+#define R600_CTXCGTT3DRSDC_DFLT                      0x40
+#define R600_VDDC3DOORPHC_DFLT                       0x100
+#define R600_VDDC3DOORSDC_DFLT                       0x7
+#define R600_VDDC3DOORSU_DFLT                        0
+#define R600_MPLLLOCKTIME_DFLT                       100
+#define R600_MPLLRESETTIME_DFLT                      150
+#define R600_VCOSTEPPCT_DFLT                          20
+#define R600_ENDINGVCOSTEPPCT_DFLT                    5
+#define R600_REFERENCEDIVIDER_DFLT                    4
+
+#define R600_PM_NUMBER_OF_TC 15
+#define R600_PM_NUMBER_OF_SCLKS 20
+#define R600_PM_NUMBER_OF_MCLKS 4
+#define R600_PM_NUMBER_OF_VOLTAGE_LEVELS 4
+#define R600_PM_NUMBER_OF_ACTIVITY_LEVELS 3
+
+enum r600_power_level {
+	R600_POWER_LEVEL_LOW = 0,
+	R600_POWER_LEVEL_MEDIUM = 1,
+	R600_POWER_LEVEL_HIGH = 2,
+	R600_POWER_LEVEL_CTXSW = 3,
+};
+
+enum r600_td {
+	R600_TD_AUTO,
+	R600_TD_UP,
+	R600_TD_DOWN,
+};
+
+enum r600_display_watermark {
+	R600_DISPLAY_WATERMARK_LOW = 0,
+	R600_DISPLAY_WATERMARK_HIGH = 1,
+};
+
+enum r600_display_gap
+{
+    R600_PM_DISPLAY_GAP_VBLANK_OR_WM = 0,
+    R600_PM_DISPLAY_GAP_VBLANK       = 1,
+    R600_PM_DISPLAY_GAP_WATERMARK    = 2,
+    R600_PM_DISPLAY_GAP_IGNORE       = 3,
+};
+
+extern const u32 r600_utc[R600_PM_NUMBER_OF_TC];
+extern const u32 r600_dtc[R600_PM_NUMBER_OF_TC];
+
+void r600_dpm_print_class_info(u32 class, u32 class2);
+void r600_dpm_print_cap_info(u32 caps);
+void r600_dpm_print_ps_status(struct radeon_device *rdev,
+			      struct radeon_ps *rps);
+bool r600_is_uvd_state(u32 class, u32 class2);
+void r600_calculate_u_and_p(u32 i, u32 r_c, u32 p_b,
+			    u32 *p, u32 *u);
+int r600_calculate_at(u32 t, u32 h, u32 fh, u32 fl, u32 *tl, u32 *th);
+void r600_gfx_clockgating_enable(struct radeon_device *rdev, bool enable);
+void r600_dynamicpm_enable(struct radeon_device *rdev, bool enable);
+void r600_enable_thermal_protection(struct radeon_device *rdev, bool enable);
+void r600_enable_acpi_pm(struct radeon_device *rdev);
+void r600_enable_dynamic_pcie_gen2(struct radeon_device *rdev, bool enable);
+bool r600_dynamicpm_enabled(struct radeon_device *rdev);
+void r600_enable_sclk_control(struct radeon_device *rdev, bool enable);
+void r600_enable_mclk_control(struct radeon_device *rdev, bool enable);
+void r600_enable_spll_bypass(struct radeon_device *rdev, bool enable);
+void r600_wait_for_spll_change(struct radeon_device *rdev);
+void r600_set_bsp(struct radeon_device *rdev, u32 u, u32 p);
+void r600_set_at(struct radeon_device *rdev,
+		 u32 l_to_m, u32 m_to_h,
+		 u32 h_to_m, u32 m_to_l);
+void r600_set_tc(struct radeon_device *rdev, u32 index, u32 u_t, u32 d_t);
+void r600_select_td(struct radeon_device *rdev, enum r600_td td);
+void r600_set_vrc(struct radeon_device *rdev, u32 vrv);
+void r600_set_tpu(struct radeon_device *rdev, u32 u);
+void r600_set_tpc(struct radeon_device *rdev, u32 c);
+void r600_set_sstu(struct radeon_device *rdev, u32 u);
+void r600_set_sst(struct radeon_device *rdev, u32 t);
+void r600_set_git(struct radeon_device *rdev, u32 t);
+void r600_set_fctu(struct radeon_device *rdev, u32 u);
+void r600_set_fct(struct radeon_device *rdev, u32 t);
+void r600_set_ctxcgtt3d_rphc(struct radeon_device *rdev, u32 p);
+void r600_set_ctxcgtt3d_rsdc(struct radeon_device *rdev, u32 s);
+void r600_set_vddc3d_oorsu(struct radeon_device *rdev, u32 u);
+void r600_set_vddc3d_oorphc(struct radeon_device *rdev, u32 p);
+void r600_set_vddc3d_oorsdc(struct radeon_device *rdev, u32 s);
+void r600_set_mpll_lock_time(struct radeon_device *rdev, u32 lock_time);
+void r600_set_mpll_reset_time(struct radeon_device *rdev, u32 reset_time);
+void r600_engine_clock_entry_enable(struct radeon_device *rdev,
+				    u32 index, bool enable);
+void r600_engine_clock_entry_enable_pulse_skipping(struct radeon_device *rdev,
+						   u32 index, bool enable);
+void r600_engine_clock_entry_enable_post_divider(struct radeon_device *rdev,
+						 u32 index, bool enable);
+void r600_engine_clock_entry_set_post_divider(struct radeon_device *rdev,
+					      u32 index, u32 divider);
+void r600_engine_clock_entry_set_reference_divider(struct radeon_device *rdev,
+						   u32 index, u32 divider);
+void r600_engine_clock_entry_set_feedback_divider(struct radeon_device *rdev,
+						  u32 index, u32 divider);
+void r600_engine_clock_entry_set_step_time(struct radeon_device *rdev,
+					   u32 index, u32 step_time);
+void r600_vid_rt_set_ssu(struct radeon_device *rdev, u32 u);
+void r600_vid_rt_set_vru(struct radeon_device *rdev, u32 u);
+void r600_vid_rt_set_vrt(struct radeon_device *rdev, u32 rt);
+void r600_voltage_control_enable_pins(struct radeon_device *rdev,
+				      u64 mask);
+void r600_voltage_control_program_voltages(struct radeon_device *rdev,
+					   enum r600_power_level index, u64 pins);
+void r600_voltage_control_deactivate_static_control(struct radeon_device *rdev,
+						    u64 mask);
+void r600_power_level_enable(struct radeon_device *rdev,
+			     enum r600_power_level index, bool enable);
+void r600_power_level_set_voltage_index(struct radeon_device *rdev,
+					enum r600_power_level index, u32 voltage_index);
+void r600_power_level_set_mem_clock_index(struct radeon_device *rdev,
+					  enum r600_power_level index, u32 mem_clock_index);
+void r600_power_level_set_eng_clock_index(struct radeon_device *rdev,
+					  enum r600_power_level index, u32 eng_clock_index);
+void r600_power_level_set_watermark_id(struct radeon_device *rdev,
+				       enum r600_power_level index,
+				       enum r600_display_watermark watermark_id);
+void r600_power_level_set_pcie_gen2(struct radeon_device *rdev,
+				    enum r600_power_level index, bool compatible);
+enum r600_power_level r600_power_level_get_current_index(struct radeon_device *rdev);
+enum r600_power_level r600_power_level_get_target_index(struct radeon_device *rdev);
+void r600_power_level_set_enter_index(struct radeon_device *rdev,
+				      enum r600_power_level index);
+void r600_wait_for_power_level_unequal(struct radeon_device *rdev,
+				       enum r600_power_level index);
+void r600_wait_for_power_level(struct radeon_device *rdev,
+			       enum r600_power_level index);
+void r600_start_dpm(struct radeon_device *rdev);
+void r600_stop_dpm(struct radeon_device *rdev);
+
+#endif
diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h
index a3f926c..d6d385a 100644
--- a/drivers/gpu/drm/radeon/r600d.h
+++ b/drivers/gpu/drm/radeon/r600d.h
@@ -1144,6 +1144,219 @@
 #       define AFMT_AZ_FORMAT_WTRIG_ACK      (1 << 29)
 #       define AFMT_AZ_AUDIO_ENABLE_CHG_ACK  (1 << 30)
 
+/* Power management */
+#define CG_SPLL_FUNC_CNTL                                 0x600
+#       define SPLL_RESET                                (1 << 0)
+#       define SPLL_SLEEP                                (1 << 1)
+#       define SPLL_REF_DIV(x)                           ((x) << 2)
+#       define SPLL_REF_DIV_MASK                         (7 << 2)
+#       define SPLL_FB_DIV(x)                            ((x) << 5)
+#       define SPLL_FB_DIV_MASK                          (0xff << 5)
+#       define SPLL_PULSEEN                              (1 << 13)
+#       define SPLL_PULSENUM(x)                          ((x) << 14)
+#       define SPLL_PULSENUM_MASK                        (3 << 14)
+#       define SPLL_SW_HILEN(x)                          ((x) << 16)
+#       define SPLL_SW_HILEN_MASK                        (0xf << 16)
+#       define SPLL_SW_LOLEN(x)                          ((x) << 20)
+#       define SPLL_SW_LOLEN_MASK                        (0xf << 20)
+#       define SPLL_DIVEN                                (1 << 24)
+#       define SPLL_BYPASS_EN                            (1 << 25)
+#       define SPLL_CHG_STATUS                           (1 << 29)
+#       define SPLL_CTLREQ                               (1 << 30)
+#       define SPLL_CTLACK                               (1 << 31)
+
+#define GENERAL_PWRMGT                                    0x618
+#       define GLOBAL_PWRMGT_EN                           (1 << 0)
+#       define STATIC_PM_EN                               (1 << 1)
+#       define MOBILE_SU                                  (1 << 2)
+#       define THERMAL_PROTECTION_DIS                     (1 << 3)
+#       define THERMAL_PROTECTION_TYPE                    (1 << 4)
+#       define ENABLE_GEN2PCIE                            (1 << 5)
+#       define SW_GPIO_INDEX(x)                           ((x) << 6)
+#       define SW_GPIO_INDEX_MASK                         (3 << 6)
+#       define LOW_VOLT_D2_ACPI                           (1 << 8)
+#       define LOW_VOLT_D3_ACPI                           (1 << 9)
+#       define VOLT_PWRMGT_EN                             (1 << 10)
+#define CG_TPC                                            0x61c
+#       define TPCC(x)                                    ((x) << 0)
+#       define TPCC_MASK                                  (0x7fffff << 0)
+#       define TPU(x)                                     ((x) << 23)
+#       define TPU_MASK                                   (0x1f << 23)
+#define SCLK_PWRMGT_CNTL                                  0x620
+#       define SCLK_PWRMGT_OFF                            (1 << 0)
+#       define SCLK_TURNOFF                               (1 << 1)
+#       define SPLL_TURNOFF                               (1 << 2)
+#       define SU_SCLK_USE_BCLK                           (1 << 3)
+#       define DYNAMIC_GFX_ISLAND_PWR_DOWN                (1 << 4)
+#       define DYNAMIC_GFX_ISLAND_PWR_LP                  (1 << 5)
+#       define CLK_TURN_ON_STAGGER                        (1 << 6)
+#       define CLK_TURN_OFF_STAGGER                       (1 << 7)
+#       define FIR_FORCE_TREND_SEL                        (1 << 8)
+#       define FIR_TREND_MODE                             (1 << 9)
+#       define DYN_GFX_CLK_OFF_EN                         (1 << 10)
+#       define VDDC3D_TURNOFF_D1                          (1 << 11)
+#       define VDDC3D_TURNOFF_D2                          (1 << 12)
+#       define VDDC3D_TURNOFF_D3                          (1 << 13)
+#       define SPLL_TURNOFF_D2                            (1 << 14)
+#       define SCLK_LOW_D1                                (1 << 15)
+#       define DYN_GFX_CLK_OFF_MC_EN                      (1 << 16)
+#define MCLK_PWRMGT_CNTL                                  0x624
+#       define MPLL_PWRMGT_OFF                            (1 << 0)
+#       define YCLK_TURNOFF                               (1 << 1)
+#       define MPLL_TURNOFF                               (1 << 2)
+#       define SU_MCLK_USE_BCLK                           (1 << 3)
+#       define DLL_READY                                  (1 << 4)
+#       define MC_BUSY                                    (1 << 5)
+#       define MC_INT_CNTL                                (1 << 7)
+#       define MRDCKA_SLEEP                               (1 << 8)
+#       define MRDCKB_SLEEP                               (1 << 9)
+#       define MRDCKC_SLEEP                               (1 << 10)
+#       define MRDCKD_SLEEP                               (1 << 11)
+#       define MRDCKE_SLEEP                               (1 << 12)
+#       define MRDCKF_SLEEP                               (1 << 13)
+#       define MRDCKG_SLEEP                               (1 << 14)
+#       define MRDCKH_SLEEP                               (1 << 15)
+#       define MRDCKA_RESET                               (1 << 16)
+#       define MRDCKB_RESET                               (1 << 17)
+#       define MRDCKC_RESET                               (1 << 18)
+#       define MRDCKD_RESET                               (1 << 19)
+#       define MRDCKE_RESET                               (1 << 20)
+#       define MRDCKF_RESET                               (1 << 21)
+#       define MRDCKG_RESET                               (1 << 22)
+#       define MRDCKH_RESET                               (1 << 23)
+#       define DLL_READY_READ                             (1 << 24)
+#       define USE_DISPLAY_GAP                            (1 << 25)
+#       define USE_DISPLAY_URGENT_NORMAL                  (1 << 26)
+#       define USE_DISPLAY_GAP_CTXSW                      (1 << 27)
+#       define MPLL_TURNOFF_D2                            (1 << 28)
+#       define USE_DISPLAY_URGENT_CTXSW                   (1 << 29)
+
+#define MPLL_TIME                                         0x634
+#       define MPLL_LOCK_TIME(x)                          ((x) << 0)
+#       define MPLL_LOCK_TIME_MASK                        (0xffff << 0)
+#       define MPLL_RESET_TIME(x)                         ((x) << 16)
+#       define MPLL_RESET_TIME_MASK                       (0xffff << 16)
+
+#define SCLK_FREQ_SETTING_STEP_0_PART1                    0x648
+#       define STEP_0_SPLL_POST_DIV(x)                    ((x) << 0)
+#       define STEP_0_SPLL_POST_DIV_MASK                  (0xff << 0)
+#       define STEP_0_SPLL_FB_DIV(x)                      ((x) << 8)
+#       define STEP_0_SPLL_FB_DIV_MASK                    (0xff << 8)
+#       define STEP_0_SPLL_REF_DIV(x)                     ((x) << 16)
+#       define STEP_0_SPLL_REF_DIV_MASK                   (7 << 16)
+#       define STEP_0_SPLL_STEP_TIME(x)                   ((x) << 19)
+#       define STEP_0_SPLL_STEP_TIME_MASK                 (0x1fff << 19)
+#define SCLK_FREQ_SETTING_STEP_0_PART2                    0x64c
+#       define STEP_0_PULSE_HIGH_CNT(x)                   ((x) << 0)
+#       define STEP_0_PULSE_HIGH_CNT_MASK                 (0x1ff << 0)
+#       define STEP_0_POST_DIV_EN                         (1 << 9)
+#       define STEP_0_SPLL_STEP_ENABLE                    (1 << 30)
+#       define STEP_0_SPLL_ENTRY_VALID                    (1 << 31)
+
+#define VID_RT                                            0x6f8
+#       define VID_CRT(x)                                 ((x) << 0)
+#       define VID_CRT_MASK                               (0x1fff << 0)
+#       define VID_CRTU(x)                                ((x) << 13)
+#       define VID_CRTU_MASK                              (7 << 13)
+#       define SSTU(x)                                    ((x) << 16)
+#       define SSTU_MASK                                  (7 << 16)
+#define CTXSW_PROFILE_INDEX                               0x6fc
+#       define CTXSW_FREQ_VIDS_CFG_INDEX(x)               ((x) << 0)
+#       define CTXSW_FREQ_VIDS_CFG_INDEX_MASK             (3 << 0)
+#       define CTXSW_FREQ_VIDS_CFG_INDEX_SHIFT            0
+#       define CTXSW_FREQ_MCLK_CFG_INDEX(x)               ((x) << 2)
+#       define CTXSW_FREQ_MCLK_CFG_INDEX_MASK             (3 << 2)
+#       define CTXSW_FREQ_MCLK_CFG_INDEX_SHIFT            2
+#       define CTXSW_FREQ_SCLK_CFG_INDEX(x)               ((x) << 4)
+#       define CTXSW_FREQ_SCLK_CFG_INDEX_MASK             (0x1f << 4)
+#       define CTXSW_FREQ_SCLK_CFG_INDEX_SHIFT            4
+#       define CTXSW_FREQ_STATE_SPLL_RESET_EN             (1 << 9)
+#       define CTXSW_FREQ_STATE_ENABLE                    (1 << 10)
+#       define CTXSW_FREQ_DISPLAY_WATERMARK               (1 << 11)
+#       define CTXSW_FREQ_GEN2PCIE_VOLT                   (1 << 12)
+
+#define TARGET_AND_CURRENT_PROFILE_INDEX                  0x70c
+#       define TARGET_PROFILE_INDEX_MASK                  (3 << 0)
+#       define TARGET_PROFILE_INDEX_SHIFT                 0
+#       define CURRENT_PROFILE_INDEX_MASK                 (3 << 2)
+#       define CURRENT_PROFILE_INDEX_SHIFT                2
+#       define DYN_PWR_ENTER_INDEX(x)                     ((x) << 4)
+#       define DYN_PWR_ENTER_INDEX_MASK                   (3 << 4)
+#       define DYN_PWR_ENTER_INDEX_SHIFT                  4
+#       define CURR_MCLK_INDEX_MASK                       (3 << 6)
+#       define CURR_MCLK_INDEX_SHIFT                      6
+#       define CURR_SCLK_INDEX_MASK                       (0x1f << 8)
+#       define CURR_SCLK_INDEX_SHIFT                      8
+#       define CURR_VID_INDEX_MASK                        (3 << 13)
+#       define CURR_VID_INDEX_SHIFT                       13
+
+#define LOWER_GPIO_ENABLE                                 0x710
+#define UPPER_GPIO_ENABLE                                 0x714
+#define CTXSW_VID_LOWER_GPIO_CNTL                         0x718
+
+#define VID_UPPER_GPIO_CNTL                               0x740
+#define CG_CTX_CGTT3D_R                                   0x744
+#       define PHC(x)                                     ((x) << 0)
+#       define PHC_MASK                                   (0x1ff << 0)
+#       define SDC(x)                                     ((x) << 9)
+#       define SDC_MASK                                   (0x3fff << 9)
+#define CG_VDDC3D_OOR                                     0x748
+#       define SU(x)                                      ((x) << 23)
+#       define SU_MASK                                    (0xf << 23)
+#define CG_FTV                                            0x74c
+#define CG_FFCT_0                                         0x750
+#       define UTC_0(x)                                   ((x) << 0)
+#       define UTC_0_MASK                                 (0x3ff << 0)
+#       define DTC_0(x)                                   ((x) << 10)
+#       define DTC_0_MASK                                 (0x3ff << 10)
+
+#define CG_BSP                                            0x78c
+#       define BSP(x)                                     ((x) << 0)
+#       define BSP_MASK                                   (0xffff << 0)
+#       define BSU(x)                                     ((x) << 16)
+#       define BSU_MASK                                   (0xf << 16)
+#define CG_RT                                             0x790
+#       define FLS(x)                                     ((x) << 0)
+#       define FLS_MASK                                   (0xffff << 0)
+#       define FMS(x)                                     ((x) << 16)
+#       define FMS_MASK                                   (0xffff << 16)
+#define CG_LT                                             0x794
+#       define FHS(x)                                     ((x) << 0)
+#       define FHS_MASK                                   (0xffff << 0)
+#define CG_GIT                                            0x798
+#       define CG_GICST(x)                                ((x) << 0)
+#       define CG_GICST_MASK                              (0xffff << 0)
+#       define CG_GIPOT(x)                                ((x) << 16)
+#       define CG_GIPOT_MASK                              (0xffff << 16)
+
+#define CG_SSP                                            0x7a8
+#       define CG_SST(x)                                  ((x) << 0)
+#       define CG_SST_MASK                                (0xffff << 0)
+#       define CG_SSTU(x)                                 ((x) << 16)
+#       define CG_SSTU_MASK                               (0xf << 16)
+
+#define CG_RLC_REQ_AND_RSP                                0x7c4
+#       define RLC_CG_REQ_TYPE_MASK                       0xf
+#       define RLC_CG_REQ_TYPE_SHIFT                      0
+#       define CG_RLC_RSP_TYPE_MASK                       0xf0
+#       define CG_RLC_RSP_TYPE_SHIFT                      4
+
+#define CG_FC_T                                           0x7cc
+#       define FC_T(x)                                    ((x) << 0)
+#       define FC_T_MASK                                  (0xffff << 0)
+#       define FC_TU(x)                                   ((x) << 16)
+#       define FC_TU_MASK                                 (0x1f << 16)
+
+#define GPIOPAD_MASK                                      0x1798
+#define GPIOPAD_A                                         0x179c
+#define GPIOPAD_EN                                        0x17a0
+
+#define GRBM_PWR_CNTL                                     0x800c
+#       define REQ_TYPE_MASK                              0xf
+#       define REQ_TYPE_SHIFT                             0
+#       define RSP_TYPE_MASK                              0xf0
+#       define RSP_TYPE_SHIFT                             4
+
 /*
  * UVD
  */
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index c43673c..7adc7a1 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -1184,6 +1184,19 @@ struct radeon_power_state {
  */
 #define RADEON_MODE_OVERCLOCK_MARGIN 500 /* 5 MHz */
 
+enum radeon_dpm_auto_throttle_src {
+	RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL,
+	RADEON_DPM_AUTO_THROTTLE_SRC_EXTERNAL
+};
+
+enum radeon_dpm_event_src {
+	RADEON_DPM_EVENT_SRC_ANALOG = 0,
+	RADEON_DPM_EVENT_SRC_EXTERNAL = 1,
+	RADEON_DPM_EVENT_SRC_DIGITAL = 2,
+	RADEON_DPM_EVENT_SRC_ANALOG_OR_EXTERNAL = 3,
+	RADEON_DPM_EVENT_SRC_DIGIAL_OR_EXTERNAL = 4
+};
+
 struct radeon_ps {
 	u32 caps; /* vbios flags */
 	u32 class; /* vbios flags */
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 075/165] drm/radeon/kms: add dpm support for rs780/rs880
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (74 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 074/165] drm/radeon/kms: add common r600 dpm functions alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 10:46   ` Jerome Glisse
  2013-06-26 13:22 ` [PATCH 076/165] drm/radeon/kms: add dpm support for rv6xx alexdeucher
                   ` (37 subsequent siblings)
  113 siblings, 1 reply; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

This adds dpm support for rs780/rs880 asics.  This includes:
- clockgating
- dynamic engine clock scaling
- dynamic voltage scaling

set radeon.dpm=1 to enable it.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/Makefile      |    2 +-
 drivers/gpu/drm/radeon/radeon_asic.c |   12 +
 drivers/gpu/drm/radeon/radeon_asic.h |   12 +
 drivers/gpu/drm/radeon/radeon_pm.c   |    7 +
 drivers/gpu/drm/radeon/rs780_dpm.c   |  894 ++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/radeon/rs780_dpm.h   |  109 ++++
 drivers/gpu/drm/radeon/rs780d.h      |  168 +++++++
 7 files changed, 1203 insertions(+), 1 deletions(-)
 create mode 100644 drivers/gpu/drm/radeon/rs780_dpm.c
 create mode 100644 drivers/gpu/drm/radeon/rs780_dpm.h
 create mode 100644 drivers/gpu/drm/radeon/rs780d.h

diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile
index a131a13..e44b046 100644
--- a/drivers/gpu/drm/radeon/Makefile
+++ b/drivers/gpu/drm/radeon/Makefile
@@ -77,7 +77,7 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \
 	evergreen_hdmi.o radeon_trace_points.o ni.o cayman_blit_shaders.o \
 	atombios_encoders.o radeon_semaphore.o radeon_sa.o atombios_i2c.o si.o \
 	si_blit_shaders.o radeon_prime.o radeon_uvd.o cik.o cik_blit_shaders.o \
-	r600_dpm.o
+	r600_dpm.o rs780_dpm.o
 
 radeon-$(CONFIG_COMPAT) += radeon_ioc32.o
 radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o
diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c
index d9c8e9a..db3c930 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.c
+++ b/drivers/gpu/drm/radeon/radeon_asic.c
@@ -1194,6 +1194,18 @@ static struct radeon_asic rs780_asic = {
 		.set_clock_gating = NULL,
 		.get_temperature = &rv6xx_get_temp,
 	},
+	.dpm = {
+		.init = &rs780_dpm_init,
+		.setup_asic = &rs780_dpm_setup_asic,
+		.enable = &rs780_dpm_enable,
+		.disable = &rs780_dpm_disable,
+		.set_power_state = &rs780_dpm_set_power_state,
+		.display_configuration_changed = &rs780_dpm_display_configuration_changed,
+		.fini = &rs780_dpm_fini,
+		.get_sclk = &rs780_dpm_get_sclk,
+		.get_mclk = &rs780_dpm_get_mclk,
+		.print_power_state = &rs780_dpm_print_power_state,
+	},
 	.pflip = {
 		.pre_page_flip = &rs600_pre_page_flip,
 		.page_flip = &rs600_page_flip,
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index 8507cae..134bf57 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -396,6 +396,18 @@ int r600_mc_wait_for_idle(struct radeon_device *rdev);
 u32 r600_get_xclk(struct radeon_device *rdev);
 uint64_t r600_get_gpu_clock_counter(struct radeon_device *rdev);
 int rv6xx_get_temp(struct radeon_device *rdev);
+/* rs780 dpm */
+int rs780_dpm_init(struct radeon_device *rdev);
+int rs780_dpm_enable(struct radeon_device *rdev);
+void rs780_dpm_disable(struct radeon_device *rdev);
+int rs780_dpm_set_power_state(struct radeon_device *rdev);
+void rs780_dpm_setup_asic(struct radeon_device *rdev);
+void rs780_dpm_display_configuration_changed(struct radeon_device *rdev);
+void rs780_dpm_fini(struct radeon_device *rdev);
+u32 rs780_dpm_get_sclk(struct radeon_device *rdev, bool low);
+u32 rs780_dpm_get_mclk(struct radeon_device *rdev, bool low);
+void rs780_dpm_print_power_state(struct radeon_device *rdev,
+				 struct radeon_ps *ps);
 
 /* uvd */
 int r600_uvd_init(struct radeon_device *rdev);
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
index 4f5422e..853a8a2 100644
--- a/drivers/gpu/drm/radeon/radeon_pm.c
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
@@ -1030,6 +1030,13 @@ int radeon_pm_init(struct radeon_device *rdev)
 {
 	/* enable dpm on rv6xx+ */
 	switch (rdev->family) {
+	case CHIP_RS780:
+	case CHIP_RS880:
+		if (radeon_dpm == 1)
+			rdev->pm.pm_method = PM_METHOD_DPM;
+		else
+			rdev->pm.pm_method = PM_METHOD_PROFILE;
+		break;
 	default:
 		/* default to profile method */
 		rdev->pm.pm_method = PM_METHOD_PROFILE;
diff --git a/drivers/gpu/drm/radeon/rs780_dpm.c b/drivers/gpu/drm/radeon/rs780_dpm.c
new file mode 100644
index 0000000..f594900
--- /dev/null
+++ b/drivers/gpu/drm/radeon/rs780_dpm.c
@@ -0,0 +1,894 @@
+/*
+ * Copyright 2011 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Alex Deucher
+ */
+
+#include "drmP.h"
+#include "radeon.h"
+#include "rs780d.h"
+#include "r600_dpm.h"
+#include "rs780_dpm.h"
+#include "atom.h"
+
+static struct igp_ps *rs780_get_ps(struct radeon_ps *rps)
+{
+	struct igp_ps *ps = rps->ps_priv;
+
+	return ps;
+}
+
+static struct igp_power_info *rs780_get_pi(struct radeon_device *rdev)
+{
+	struct igp_power_info *pi = rdev->pm.dpm.priv;
+
+	return pi;
+}
+
+static void rs780_get_pm_mode_parameters(struct radeon_device *rdev)
+{
+	struct igp_power_info *pi = rs780_get_pi(rdev);
+	struct radeon_mode_info *minfo = &rdev->mode_info;
+	struct drm_crtc *crtc;
+	struct radeon_crtc *radeon_crtc;
+	int i;
+
+	/* defaults */
+	pi->crtc_id = 0;
+	pi->refresh_rate = 60;
+
+	for (i = 0; i < rdev->num_crtc; i++) {
+		crtc = (struct drm_crtc *)minfo->crtcs[i];
+		if (crtc && crtc->enabled) {
+			radeon_crtc = to_radeon_crtc(crtc);
+			pi->crtc_id = radeon_crtc->crtc_id;
+			if (crtc->mode.htotal && crtc->mode.vtotal)
+				pi->refresh_rate =
+					(crtc->mode.clock * 1000) /
+					(crtc->mode.htotal * crtc->mode.vtotal);
+			break;
+		}
+	}
+}
+
+static void rs780_voltage_scaling_enable(struct radeon_device *rdev, bool enable);
+
+static int rs780_initialize_dpm_power_state(struct radeon_device *rdev)
+{
+	struct atom_clock_dividers dividers;
+	struct igp_ps *default_state = rs780_get_ps(rdev->pm.dpm.boot_ps);
+	int i, ret;
+
+	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
+					     default_state->sclk_low, false, &dividers);
+	if (ret)
+		return ret;
+
+	r600_engine_clock_entry_set_reference_divider(rdev, 0, dividers.ref_div);
+	r600_engine_clock_entry_set_feedback_divider(rdev, 0, dividers.fb_div);
+	r600_engine_clock_entry_set_post_divider(rdev, 0, dividers.post_div);
+
+	if (dividers.enable_post_div)
+		r600_engine_clock_entry_enable_post_divider(rdev, 0, true);
+	else
+		r600_engine_clock_entry_enable_post_divider(rdev, 0, false);
+
+	r600_engine_clock_entry_set_step_time(rdev, 0, R600_SST_DFLT);
+	r600_engine_clock_entry_enable_pulse_skipping(rdev, 0, false);
+
+	r600_engine_clock_entry_enable(rdev, 0, true);
+	for (i = 1; i < R600_PM_NUMBER_OF_SCLKS; i++)
+		r600_engine_clock_entry_enable(rdev, i, false);
+
+	r600_enable_mclk_control(rdev, false);
+	r600_voltage_control_enable_pins(rdev, 0);
+
+	return 0;
+}
+
+static int rs780_initialize_dpm_parameters(struct radeon_device *rdev)
+{
+	int ret = 0;
+	int i;
+
+	r600_set_bsp(rdev, R600_BSU_DFLT, R600_BSP_DFLT);
+
+	r600_set_at(rdev, 0, 0, 0, 0);
+
+	r600_set_git(rdev, R600_GICST_DFLT);
+
+	for (i = 0; i < R600_PM_NUMBER_OF_TC; i++)
+		r600_set_tc(rdev, i, 0, 0);
+
+	r600_select_td(rdev, R600_TD_DFLT);
+	r600_set_vrc(rdev, 0);
+
+	r600_set_tpu(rdev, R600_TPU_DFLT);
+	r600_set_tpc(rdev, R600_TPC_DFLT);
+
+	r600_set_sstu(rdev, R600_SSTU_DFLT);
+	r600_set_sst(rdev, R600_SST_DFLT);
+
+	r600_set_fctu(rdev, R600_FCTU_DFLT);
+	r600_set_fct(rdev, R600_FCT_DFLT);
+
+	r600_set_vddc3d_oorsu(rdev, R600_VDDC3DOORSU_DFLT);
+	r600_set_vddc3d_oorphc(rdev, R600_VDDC3DOORPHC_DFLT);
+	r600_set_vddc3d_oorsdc(rdev, R600_VDDC3DOORSDC_DFLT);
+	r600_set_ctxcgtt3d_rphc(rdev, R600_CTXCGTT3DRPHC_DFLT);
+	r600_set_ctxcgtt3d_rsdc(rdev, R600_CTXCGTT3DRSDC_DFLT);
+
+	r600_vid_rt_set_vru(rdev, R600_VRU_DFLT);
+	r600_vid_rt_set_vrt(rdev, R600_VOLTAGERESPONSETIME_DFLT);
+	r600_vid_rt_set_ssu(rdev, R600_SPLLSTEPUNIT_DFLT);
+
+	ret = rs780_initialize_dpm_power_state(rdev);
+
+	r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_LOW,     0);
+	r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_MEDIUM,  0);
+	r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_HIGH,    0);
+
+	r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_LOW,    0);
+	r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_MEDIUM, 0);
+	r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_HIGH,   0);
+
+	r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_LOW,    0);
+	r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_MEDIUM, 0);
+	r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_HIGH,   0);
+
+	r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_LOW,    R600_DISPLAY_WATERMARK_HIGH);
+	r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_MEDIUM, R600_DISPLAY_WATERMARK_HIGH);
+	r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_HIGH,   R600_DISPLAY_WATERMARK_HIGH);
+
+	r600_power_level_enable(rdev, R600_POWER_LEVEL_CTXSW, false);
+	r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, false);
+	r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, false);
+	r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true);
+
+	r600_power_level_set_enter_index(rdev, R600_POWER_LEVEL_LOW);
+
+	r600_set_vrc(rdev, RS780_CGFTV_DFLT);
+
+	return ret;
+}
+
+static void rs780_start_dpm(struct radeon_device *rdev)
+{
+	r600_enable_sclk_control(rdev, false);
+	r600_enable_mclk_control(rdev, false);
+
+	r600_dynamicpm_enable(rdev, true);
+
+	radeon_wait_for_vblank(rdev, 0);
+	radeon_wait_for_vblank(rdev, 1);
+
+	r600_enable_spll_bypass(rdev, true);
+	r600_wait_for_spll_change(rdev);
+	r600_enable_spll_bypass(rdev, false);
+	r600_wait_for_spll_change(rdev);
+
+	r600_enable_spll_bypass(rdev, true);
+	r600_wait_for_spll_change(rdev);
+	r600_enable_spll_bypass(rdev, false);
+	r600_wait_for_spll_change(rdev);
+
+	r600_enable_sclk_control(rdev, true);
+}
+
+
+static void rs780_preset_ranges_slow_clk_fbdiv_en(struct radeon_device *rdev)
+{
+	WREG32_P(FVTHROT_SLOW_CLK_FEEDBACK_DIV_REG1, RANGE_SLOW_CLK_FEEDBACK_DIV_EN,
+		 ~RANGE_SLOW_CLK_FEEDBACK_DIV_EN);
+
+	WREG32_P(FVTHROT_SLOW_CLK_FEEDBACK_DIV_REG1,
+		 RANGE0_SLOW_CLK_FEEDBACK_DIV(RS780_SLOWCLKFEEDBACKDIV_DFLT),
+		 ~RANGE0_SLOW_CLK_FEEDBACK_DIV_MASK);
+}
+
+static void rs780_preset_starting_fbdiv(struct radeon_device *rdev)
+{
+	u32 fbdiv = (RREG32(CG_SPLL_FUNC_CNTL) & SPLL_FB_DIV_MASK) >> SPLL_FB_DIV_SHIFT;
+
+	WREG32_P(FVTHROT_FBDIV_REG1, STARTING_FEEDBACK_DIV(fbdiv),
+		 ~STARTING_FEEDBACK_DIV_MASK);
+
+	WREG32_P(FVTHROT_FBDIV_REG2, FORCED_FEEDBACK_DIV(fbdiv),
+		 ~FORCED_FEEDBACK_DIV_MASK);
+
+	WREG32_P(FVTHROT_FBDIV_REG1, FORCE_FEEDBACK_DIV, ~FORCE_FEEDBACK_DIV);
+}
+
+static void rs780_voltage_scaling_init(struct radeon_device *rdev)
+{
+	struct igp_power_info *pi = rs780_get_pi(rdev);
+	struct drm_device *dev = rdev->ddev;
+	u32 fv_throt_pwm_fb_div_range[3];
+	u32 fv_throt_pwm_range[4];
+
+	if (dev->pdev->device == 0x9614) {
+		fv_throt_pwm_fb_div_range[0] = RS780D_FVTHROTPWMFBDIVRANGEREG0_DFLT;
+		fv_throt_pwm_fb_div_range[1] = RS780D_FVTHROTPWMFBDIVRANGEREG1_DFLT;
+		fv_throt_pwm_fb_div_range[2] = RS780D_FVTHROTPWMFBDIVRANGEREG2_DFLT;
+	} else if ((dev->pdev->device == 0x9714) ||
+		   (dev->pdev->device == 0x9715)) {
+		fv_throt_pwm_fb_div_range[0] = RS880D_FVTHROTPWMFBDIVRANGEREG0_DFLT;
+		fv_throt_pwm_fb_div_range[1] = RS880D_FVTHROTPWMFBDIVRANGEREG1_DFLT;
+		fv_throt_pwm_fb_div_range[2] = RS880D_FVTHROTPWMFBDIVRANGEREG2_DFLT;
+	} else {
+		fv_throt_pwm_fb_div_range[0] = RS780_FVTHROTPWMFBDIVRANGEREG0_DFLT;
+		fv_throt_pwm_fb_div_range[1] = RS780_FVTHROTPWMFBDIVRANGEREG1_DFLT;
+		fv_throt_pwm_fb_div_range[2] = RS780_FVTHROTPWMFBDIVRANGEREG2_DFLT;
+	}
+
+	if (pi->pwm_voltage_control) {
+		fv_throt_pwm_range[0] = pi->min_voltage;
+		fv_throt_pwm_range[1] = pi->min_voltage;
+		fv_throt_pwm_range[2] = pi->max_voltage;
+		fv_throt_pwm_range[3] = pi->max_voltage;
+	} else {
+		fv_throt_pwm_range[0] = pi->invert_pwm_required ?
+			RS780_FVTHROTPWMRANGE3_GPIO_DFLT : RS780_FVTHROTPWMRANGE0_GPIO_DFLT;
+		fv_throt_pwm_range[1] = pi->invert_pwm_required ?
+			RS780_FVTHROTPWMRANGE2_GPIO_DFLT : RS780_FVTHROTPWMRANGE1_GPIO_DFLT;
+		fv_throt_pwm_range[2] = pi->invert_pwm_required ?
+			RS780_FVTHROTPWMRANGE1_GPIO_DFLT : RS780_FVTHROTPWMRANGE2_GPIO_DFLT;
+		fv_throt_pwm_range[3] = pi->invert_pwm_required ?
+			RS780_FVTHROTPWMRANGE0_GPIO_DFLT : RS780_FVTHROTPWMRANGE3_GPIO_DFLT;
+	}
+
+	WREG32_P(FVTHROT_PWM_CTRL_REG0,
+		 STARTING_PWM_HIGHTIME(pi->max_voltage),
+		 ~STARTING_PWM_HIGHTIME_MASK);
+
+	WREG32_P(FVTHROT_PWM_CTRL_REG0,
+		 NUMBER_OF_CYCLES_IN_PERIOD(pi->num_of_cycles_in_period),
+		 ~NUMBER_OF_CYCLES_IN_PERIOD_MASK);
+
+	WREG32_P(FVTHROT_PWM_CTRL_REG0, FORCE_STARTING_PWM_HIGHTIME,
+		 ~FORCE_STARTING_PWM_HIGHTIME);
+
+	if (pi->invert_pwm_required)
+		WREG32_P(FVTHROT_PWM_CTRL_REG0, INVERT_PWM_WAVEFORM, ~INVERT_PWM_WAVEFORM);
+	else
+		WREG32_P(FVTHROT_PWM_CTRL_REG0, 0, ~INVERT_PWM_WAVEFORM);
+
+	rs780_voltage_scaling_enable(rdev, true);
+
+	WREG32(FVTHROT_PWM_CTRL_REG1,
+	       (MIN_PWM_HIGHTIME(pi->min_voltage) |
+		MAX_PWM_HIGHTIME(pi->max_voltage)));
+
+	WREG32(FVTHROT_PWM_US_REG0, RS780_FVTHROTPWMUSREG0_DFLT);
+	WREG32(FVTHROT_PWM_US_REG1, RS780_FVTHROTPWMUSREG1_DFLT);
+	WREG32(FVTHROT_PWM_DS_REG0, RS780_FVTHROTPWMDSREG0_DFLT);
+	WREG32(FVTHROT_PWM_DS_REG1, RS780_FVTHROTPWMDSREG1_DFLT);
+
+	WREG32_P(FVTHROT_PWM_FEEDBACK_DIV_REG1,
+		 RANGE0_PWM_FEEDBACK_DIV(fv_throt_pwm_fb_div_range[0]),
+		 ~RANGE0_PWM_FEEDBACK_DIV_MASK);
+
+	WREG32(FVTHROT_PWM_FEEDBACK_DIV_REG2,
+	       (RANGE1_PWM_FEEDBACK_DIV(fv_throt_pwm_fb_div_range[1]) |
+		RANGE2_PWM_FEEDBACK_DIV(fv_throt_pwm_fb_div_range[2])));
+
+	WREG32(FVTHROT_PWM_FEEDBACK_DIV_REG3,
+	       (RANGE0_PWM(fv_throt_pwm_range[1]) |
+		RANGE1_PWM(fv_throt_pwm_range[2])));
+	WREG32(FVTHROT_PWM_FEEDBACK_DIV_REG4,
+	       (RANGE2_PWM(fv_throt_pwm_range[1]) |
+		RANGE3_PWM(fv_throt_pwm_range[2])));
+}
+
+static void rs780_clk_scaling_enable(struct radeon_device *rdev, bool enable)
+{
+	if (enable)
+		WREG32_P(FVTHROT_CNTRL_REG, ENABLE_FV_THROT | ENABLE_FV_UPDATE,
+			 ~(ENABLE_FV_THROT | ENABLE_FV_UPDATE));
+	else
+		WREG32_P(FVTHROT_CNTRL_REG, 0,
+			 ~(ENABLE_FV_THROT | ENABLE_FV_UPDATE));
+}
+
+static void rs780_voltage_scaling_enable(struct radeon_device *rdev, bool enable)
+{
+	if (enable)
+		WREG32_P(FVTHROT_CNTRL_REG, ENABLE_FV_THROT_IO, ~ENABLE_FV_THROT_IO);
+	else
+		WREG32_P(FVTHROT_CNTRL_REG, 0, ~ENABLE_FV_THROT_IO);
+}
+
+static void rs780_set_engine_clock_wfc(struct radeon_device *rdev)
+{
+	WREG32(FVTHROT_UTC0, RS780_FVTHROTUTC0_DFLT);
+	WREG32(FVTHROT_UTC1, RS780_FVTHROTUTC1_DFLT);
+	WREG32(FVTHROT_UTC2, RS780_FVTHROTUTC2_DFLT);
+	WREG32(FVTHROT_UTC3, RS780_FVTHROTUTC3_DFLT);
+	WREG32(FVTHROT_UTC4, RS780_FVTHROTUTC4_DFLT);
+
+	WREG32(FVTHROT_DTC0, RS780_FVTHROTDTC0_DFLT);
+	WREG32(FVTHROT_DTC1, RS780_FVTHROTDTC1_DFLT);
+	WREG32(FVTHROT_DTC2, RS780_FVTHROTDTC2_DFLT);
+	WREG32(FVTHROT_DTC3, RS780_FVTHROTDTC3_DFLT);
+	WREG32(FVTHROT_DTC4, RS780_FVTHROTDTC4_DFLT);
+}
+
+static void rs780_set_engine_clock_sc(struct radeon_device *rdev)
+{
+	WREG32_P(FVTHROT_FBDIV_REG2,
+		 FB_DIV_TIMER_VAL(RS780_FBDIVTIMERVAL_DFLT),
+		 ~FB_DIV_TIMER_VAL_MASK);
+
+	WREG32_P(FVTHROT_CNTRL_REG,
+		 REFRESH_RATE_DIVISOR(0) | MINIMUM_CIP(0xf),
+		 ~(REFRESH_RATE_DIVISOR_MASK | MINIMUM_CIP_MASK));
+}
+
+static void rs780_set_engine_clock_tdc(struct radeon_device *rdev)
+{
+	WREG32_P(FVTHROT_CNTRL_REG, 0, ~(FORCE_TREND_SEL | TREND_SEL_MODE));
+}
+
+static void rs780_set_engine_clock_ssc(struct radeon_device *rdev)
+{
+	WREG32(FVTHROT_FB_US_REG0, RS780_FVTHROTFBUSREG0_DFLT);
+	WREG32(FVTHROT_FB_US_REG1, RS780_FVTHROTFBUSREG1_DFLT);
+	WREG32(FVTHROT_FB_DS_REG0, RS780_FVTHROTFBDSREG0_DFLT);
+	WREG32(FVTHROT_FB_DS_REG1, RS780_FVTHROTFBDSREG1_DFLT);
+
+	WREG32_P(FVTHROT_FBDIV_REG1, MAX_FEEDBACK_STEP(1), ~MAX_FEEDBACK_STEP_MASK);
+}
+
+static void rs780_program_at(struct radeon_device *rdev)
+{
+	struct igp_power_info *pi = rs780_get_pi(rdev);
+
+	WREG32(FVTHROT_TARGET_REG, 30000000 / pi->refresh_rate);
+	WREG32(FVTHROT_CB1, 1000000 * 5 / pi->refresh_rate);
+	WREG32(FVTHROT_CB2, 1000000 * 10 / pi->refresh_rate);
+	WREG32(FVTHROT_CB3, 1000000 * 30 / pi->refresh_rate);
+	WREG32(FVTHROT_CB4, 1000000 * 50 / pi->refresh_rate);
+}
+
+static void rs780_disable_vbios_powersaving(struct radeon_device *rdev)
+{
+	WREG32_P(CG_INTGFX_MISC, 0, ~0xFFF00000);
+}
+
+static void rs780_force_voltage_to_high(struct radeon_device *rdev)
+{
+	struct igp_power_info *pi = rs780_get_pi(rdev);
+	struct igp_ps *current_state = rs780_get_ps(rdev->pm.dpm.current_ps);
+
+	if ((current_state->max_voltage == RS780_VDDC_LEVEL_HIGH) &&
+	    (current_state->min_voltage == RS780_VDDC_LEVEL_HIGH))
+		return;
+
+	WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL);
+
+	udelay(1);
+
+	WREG32_P(FVTHROT_PWM_CTRL_REG0,
+		 STARTING_PWM_HIGHTIME(pi->max_voltage),
+		 ~STARTING_PWM_HIGHTIME_MASK);
+
+	WREG32_P(FVTHROT_PWM_CTRL_REG0,
+		 FORCE_STARTING_PWM_HIGHTIME, ~FORCE_STARTING_PWM_HIGHTIME);
+
+	WREG32_P(FVTHROT_PWM_FEEDBACK_DIV_REG1, 0,
+		~RANGE_PWM_FEEDBACK_DIV_EN);
+
+	udelay(1);
+
+	WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
+}
+
+static int rs780_set_engine_clock_scaling(struct radeon_device *rdev)
+{
+	struct atom_clock_dividers min_dividers, max_dividers, current_max_dividers;
+	struct igp_ps *new_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
+	struct igp_ps *old_state = rs780_get_ps(rdev->pm.dpm.current_ps);
+	int ret;
+
+	if ((new_state->sclk_high == old_state->sclk_high) &&
+	    (new_state->sclk_low == old_state->sclk_low))
+		return 0;
+
+	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
+					     new_state->sclk_low, false, &min_dividers);
+	if (ret)
+		return ret;
+
+	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
+					     new_state->sclk_high, false, &max_dividers);
+	if (ret)
+		return ret;
+
+	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
+					     old_state->sclk_high, false, &current_max_dividers);
+	if (ret)
+		return ret;
+
+	WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL);
+
+	WREG32_P(FVTHROT_FBDIV_REG2, FORCED_FEEDBACK_DIV(max_dividers.fb_div),
+		 ~FORCED_FEEDBACK_DIV_MASK);
+	WREG32_P(FVTHROT_FBDIV_REG1, STARTING_FEEDBACK_DIV(max_dividers.fb_div),
+		 ~STARTING_FEEDBACK_DIV_MASK);
+	WREG32_P(FVTHROT_FBDIV_REG1, FORCE_FEEDBACK_DIV, ~FORCE_FEEDBACK_DIV);
+
+	udelay(100);
+
+	WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
+
+	if (max_dividers.fb_div > min_dividers.fb_div) {
+		WREG32_P(FVTHROT_FBDIV_REG0,
+			 MIN_FEEDBACK_DIV(min_dividers.fb_div) |
+			 MAX_FEEDBACK_DIV(max_dividers.fb_div),
+			 ~(MIN_FEEDBACK_DIV_MASK | MAX_FEEDBACK_DIV_MASK));
+
+		WREG32_P(FVTHROT_FBDIV_REG1, 0, ~FORCE_FEEDBACK_DIV);
+	}
+
+	return 0;
+}
+
+static void rs780_set_engine_clock_spc(struct radeon_device *rdev)
+{
+	struct igp_ps *new_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
+	struct igp_ps *old_state = rs780_get_ps(rdev->pm.dpm.current_ps);
+	struct igp_power_info *pi = rs780_get_pi(rdev);
+
+	if ((new_state->sclk_high == old_state->sclk_high) &&
+	    (new_state->sclk_low == old_state->sclk_low))
+		return;
+
+	if (pi->crtc_id == 0)
+		WREG32_P(CG_INTGFX_MISC, 0, ~FVTHROT_VBLANK_SEL);
+	else
+		WREG32_P(CG_INTGFX_MISC, FVTHROT_VBLANK_SEL, ~FVTHROT_VBLANK_SEL);
+
+}
+
+static void rs780_activate_engine_clk_scaling(struct radeon_device *rdev)
+{
+	struct igp_ps *new_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
+	struct igp_ps *old_state = rs780_get_ps(rdev->pm.dpm.current_ps);
+
+	if ((new_state->sclk_high == old_state->sclk_high) &&
+	    (new_state->sclk_low == old_state->sclk_low))
+		return;
+
+	rs780_clk_scaling_enable(rdev, true);
+}
+
+static u32 rs780_get_voltage_for_vddc_level(struct radeon_device *rdev,
+					    enum rs780_vddc_level vddc)
+{
+	struct igp_power_info *pi = rs780_get_pi(rdev);
+
+	if (vddc == RS780_VDDC_LEVEL_HIGH)
+		return pi->max_voltage;
+	else if (vddc == RS780_VDDC_LEVEL_LOW)
+		return pi->min_voltage;
+	else
+		return pi->max_voltage;
+}
+
+static void rs780_enable_voltage_scaling(struct radeon_device *rdev)
+{
+	struct igp_ps *new_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
+	struct igp_power_info *pi = rs780_get_pi(rdev);
+	enum rs780_vddc_level vddc_high, vddc_low;
+
+	udelay(100);
+
+	if ((new_state->max_voltage == RS780_VDDC_LEVEL_HIGH) &&
+	    (new_state->min_voltage == RS780_VDDC_LEVEL_HIGH))
+		return;
+
+	vddc_high = rs780_get_voltage_for_vddc_level(rdev,
+						     new_state->max_voltage);
+	vddc_low = rs780_get_voltage_for_vddc_level(rdev,
+						    new_state->min_voltage);
+
+	WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL);
+
+	udelay(1);
+	if (vddc_high > vddc_low) {
+		WREG32_P(FVTHROT_PWM_FEEDBACK_DIV_REG1,
+			 RANGE_PWM_FEEDBACK_DIV_EN, ~RANGE_PWM_FEEDBACK_DIV_EN);
+
+		WREG32_P(FVTHROT_PWM_CTRL_REG0, 0, ~FORCE_STARTING_PWM_HIGHTIME);
+	} else if (vddc_high == vddc_low) {
+		if (pi->max_voltage != vddc_high) {
+			WREG32_P(FVTHROT_PWM_CTRL_REG0,
+				 STARTING_PWM_HIGHTIME(vddc_high),
+				 ~STARTING_PWM_HIGHTIME_MASK);
+
+			WREG32_P(FVTHROT_PWM_CTRL_REG0,
+				 FORCE_STARTING_PWM_HIGHTIME,
+				 ~FORCE_STARTING_PWM_HIGHTIME);
+		}
+	}
+
+	WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
+}
+
+int rs780_dpm_enable(struct radeon_device *rdev)
+{
+	struct igp_power_info *pi = rs780_get_pi(rdev);
+
+	rs780_get_pm_mode_parameters(rdev);
+	rs780_disable_vbios_powersaving(rdev);
+
+	if (r600_dynamicpm_enabled(rdev))
+		return -EINVAL;
+	if (rs780_initialize_dpm_parameters(rdev))
+		return -EINVAL;
+	rs780_start_dpm(rdev);
+
+	rs780_preset_ranges_slow_clk_fbdiv_en(rdev);
+	rs780_preset_starting_fbdiv(rdev);
+	if (pi->voltage_control)
+		rs780_voltage_scaling_init(rdev);
+	rs780_clk_scaling_enable(rdev, true);
+	rs780_set_engine_clock_sc(rdev);
+	rs780_set_engine_clock_wfc(rdev);
+	rs780_program_at(rdev);
+	rs780_set_engine_clock_tdc(rdev);
+	rs780_set_engine_clock_ssc(rdev);
+
+	if (pi->gfx_clock_gating)
+		r600_gfx_clockgating_enable(rdev, true);
+
+	return 0;
+}
+
+void rs780_dpm_disable(struct radeon_device *rdev)
+{
+	struct igp_power_info *pi = rs780_get_pi(rdev);
+
+	r600_dynamicpm_enable(rdev, false);
+
+	rs780_clk_scaling_enable(rdev, false);
+	rs780_voltage_scaling_enable(rdev, false);
+
+	if (pi->gfx_clock_gating)
+		r600_gfx_clockgating_enable(rdev, false);
+}
+
+int rs780_dpm_set_power_state(struct radeon_device *rdev)
+{
+	struct igp_power_info *pi = rs780_get_pi(rdev);
+
+	rs780_get_pm_mode_parameters(rdev);
+
+	if (pi->voltage_control) {
+		rs780_force_voltage_to_high(rdev);
+		mdelay(5);
+	}
+
+	rs780_set_engine_clock_scaling(rdev);
+	rs780_set_engine_clock_spc(rdev);
+
+	rs780_activate_engine_clk_scaling(rdev);
+
+	if (pi->voltage_control)
+		rs780_enable_voltage_scaling(rdev);
+
+	return 0;
+}
+
+void rs780_dpm_setup_asic(struct radeon_device *rdev)
+{
+
+}
+
+void rs780_dpm_display_configuration_changed(struct radeon_device *rdev)
+{
+	rs780_get_pm_mode_parameters(rdev);
+	rs780_program_at(rdev);
+}
+
+union igp_info {
+	struct _ATOM_INTEGRATED_SYSTEM_INFO info;
+	struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2;
+};
+
+union power_info {
+	struct _ATOM_POWERPLAY_INFO info;
+	struct _ATOM_POWERPLAY_INFO_V2 info_2;
+	struct _ATOM_POWERPLAY_INFO_V3 info_3;
+	struct _ATOM_PPLIB_POWERPLAYTABLE pplib;
+	struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2;
+	struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3;
+};
+
+union pplib_clock_info {
+	struct _ATOM_PPLIB_R600_CLOCK_INFO r600;
+	struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780;
+	struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen;
+	struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo;
+};
+
+union pplib_power_state {
+	struct _ATOM_PPLIB_STATE v1;
+	struct _ATOM_PPLIB_STATE_V2 v2;
+};
+
+static void rs780_parse_pplib_non_clock_info(struct radeon_device *rdev,
+					     struct radeon_ps *rps,
+					     struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info,
+					     u8 table_rev)
+{
+	rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings);
+	rps->class = le16_to_cpu(non_clock_info->usClassification);
+	rps->class2 = le16_to_cpu(non_clock_info->usClassification2);
+
+	if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) {
+		rps->vclk = le32_to_cpu(non_clock_info->ulVCLK);
+		rps->dclk = le32_to_cpu(non_clock_info->ulDCLK);
+	} else if (r600_is_uvd_state(rps->class, rps->class2)) {
+		rps->vclk = RS780_DEFAULT_VCLK_FREQ;
+		rps->dclk = RS780_DEFAULT_DCLK_FREQ;
+	} else {
+		rps->vclk = 0;
+		rps->dclk = 0;
+	}
+
+	if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT)
+		rdev->pm.dpm.boot_ps = rps;
+	if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
+		rdev->pm.dpm.uvd_ps = rps;
+}
+
+static void rs780_parse_pplib_clock_info(struct radeon_device *rdev,
+					 struct radeon_ps *rps,
+					 union pplib_clock_info *clock_info)
+{
+	struct igp_ps *ps = rs780_get_ps(rps);
+	u32 sclk;
+
+	sclk = le16_to_cpu(clock_info->rs780.usLowEngineClockLow);
+	sclk |= clock_info->rs780.ucLowEngineClockHigh << 16;
+	ps->sclk_low = sclk;
+	sclk = le16_to_cpu(clock_info->rs780.usHighEngineClockLow);
+	sclk |= clock_info->rs780.ucHighEngineClockHigh << 16;
+	ps->sclk_high = sclk;
+	switch (le16_to_cpu(clock_info->rs780.usVDDC)) {
+	case ATOM_PPLIB_RS780_VOLTAGE_NONE:
+	default:
+		ps->min_voltage = RS780_VDDC_LEVEL_UNKNOWN;
+		ps->max_voltage = RS780_VDDC_LEVEL_UNKNOWN;
+		break;
+	case ATOM_PPLIB_RS780_VOLTAGE_LOW:
+		ps->min_voltage = RS780_VDDC_LEVEL_LOW;
+		ps->max_voltage = RS780_VDDC_LEVEL_LOW;
+		break;
+	case ATOM_PPLIB_RS780_VOLTAGE_HIGH:
+		ps->min_voltage = RS780_VDDC_LEVEL_HIGH;
+		ps->max_voltage = RS780_VDDC_LEVEL_HIGH;
+		break;
+	case ATOM_PPLIB_RS780_VOLTAGE_VARIABLE:
+		ps->min_voltage = RS780_VDDC_LEVEL_LOW;
+		ps->max_voltage = RS780_VDDC_LEVEL_HIGH;
+		break;
+	}
+	ps->flags = le32_to_cpu(clock_info->rs780.ulFlags);
+
+	if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) {
+		ps->sclk_low = rdev->clock.default_sclk;
+		ps->sclk_high = rdev->clock.default_sclk;
+		ps->min_voltage = RS780_VDDC_LEVEL_HIGH;
+		ps->max_voltage = RS780_VDDC_LEVEL_HIGH;
+	}
+}
+
+static int rs780_parse_power_table(struct radeon_device *rdev)
+{
+	struct radeon_mode_info *mode_info = &rdev->mode_info;
+	struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
+	union pplib_power_state *power_state;
+	int i;
+	union pplib_clock_info *clock_info;
+	union power_info *power_info;
+	int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
+        u16 data_offset;
+	u8 frev, crev;
+	struct igp_ps *ps;
+
+	if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
+				   &frev, &crev, &data_offset))
+		return -EINVAL;
+	power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
+
+	rdev->pm.dpm.ps = kzalloc(sizeof(struct radeon_ps) *
+				  power_info->pplib.ucNumStates, GFP_KERNEL);
+	if (!rdev->pm.dpm.ps)
+		return -ENOMEM;
+	rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps);
+	rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime);
+	rdev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime);
+
+	for (i = 0; i < power_info->pplib.ucNumStates; i++) {
+		power_state = (union pplib_power_state *)
+			(mode_info->atom_context->bios + data_offset +
+			 le16_to_cpu(power_info->pplib.usStateArrayOffset) +
+			 i * power_info->pplib.ucStateEntrySize);
+		non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
+			(mode_info->atom_context->bios + data_offset +
+			 le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset) +
+			 (power_state->v1.ucNonClockStateIndex *
+			  power_info->pplib.ucNonClockSize));
+		if (power_info->pplib.ucStateEntrySize - 1) {
+			clock_info = (union pplib_clock_info *)
+				(mode_info->atom_context->bios + data_offset +
+				 le16_to_cpu(power_info->pplib.usClockInfoArrayOffset) +
+				 (power_state->v1.ucClockStateIndices[0] *
+				  power_info->pplib.ucClockInfoSize));
+			ps = kzalloc(sizeof(struct igp_ps), GFP_KERNEL);
+			if (ps == NULL) {
+				kfree(rdev->pm.dpm.ps);
+				return -ENOMEM;
+			}
+			rdev->pm.dpm.ps[i].ps_priv = ps;
+			rs780_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i],
+							 non_clock_info,
+							 power_info->pplib.ucNonClockSize);
+			rs780_parse_pplib_clock_info(rdev,
+						     &rdev->pm.dpm.ps[i],
+						     clock_info);
+		}
+	}
+	rdev->pm.dpm.num_ps = power_info->pplib.ucNumStates;
+	return 0;
+}
+
+int rs780_dpm_init(struct radeon_device *rdev)
+{
+	struct igp_power_info *pi;
+	int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);
+	union igp_info *info;
+	u16 data_offset;
+	u8 frev, crev;
+	int ret;
+
+	pi = kzalloc(sizeof(struct igp_power_info), GFP_KERNEL);
+	if (pi == NULL)
+		return -ENOMEM;
+	rdev->pm.dpm.priv = pi;
+
+	ret = rs780_parse_power_table(rdev);
+	if (ret)
+		return ret;
+
+	pi->voltage_control = false;
+	pi->gfx_clock_gating = true;
+
+	if (atom_parse_data_header(rdev->mode_info.atom_context, index, NULL,
+				   &frev, &crev, &data_offset)) {
+		info = (union igp_info *)(rdev->mode_info.atom_context->bios + data_offset);
+
+		/* Get various system informations from bios */
+		switch (crev) {
+		case 1:
+			pi->num_of_cycles_in_period =
+				info->info.ucNumberOfCyclesInPeriod;
+			pi->num_of_cycles_in_period |=
+				info->info.ucNumberOfCyclesInPeriodHi << 8;
+			pi->invert_pwm_required =
+				(pi->num_of_cycles_in_period & 0x8000) ? true : false;
+			pi->boot_voltage = info->info.ucStartingPWM_HighTime;
+			pi->max_voltage = info->info.ucMaxNBVoltage;
+			pi->max_voltage |= info->info.ucMaxNBVoltageHigh << 8;
+			pi->min_voltage = info->info.ucMinNBVoltage;
+			pi->min_voltage |= info->info.ucMinNBVoltageHigh << 8;
+			pi->inter_voltage_low =
+				le16_to_cpu(info->info.usInterNBVoltageLow);
+			pi->inter_voltage_high =
+				le16_to_cpu(info->info.usInterNBVoltageHigh);
+			pi->voltage_control = true;
+			pi->bootup_uma_clk = info->info.usK8MemoryClock * 100;
+			break;
+		case 2:
+			pi->num_of_cycles_in_period =
+				le16_to_cpu(info->info_2.usNumberOfCyclesInPeriod);
+			pi->invert_pwm_required =
+				(pi->num_of_cycles_in_period & 0x8000) ? true : false;
+			pi->boot_voltage =
+				le16_to_cpu(info->info_2.usBootUpNBVoltage);
+			pi->max_voltage =
+				le16_to_cpu(info->info_2.usMaxNBVoltage);
+			pi->min_voltage =
+				le16_to_cpu(info->info_2.usMinNBVoltage);
+			pi->system_config =
+				le32_to_cpu(info->info_2.ulSystemConfig);
+			pi->pwm_voltage_control =
+				(pi->system_config & 0x4) ? true : false;
+			pi->voltage_control = true;
+			pi->bootup_uma_clk = le32_to_cpu(info->info_2.ulBootUpUMAClock);
+			break;
+		default:
+			DRM_ERROR("No integrated system info for your GPU\n");
+			return -EINVAL;
+		}
+		if (pi->min_voltage > pi->max_voltage)
+			pi->voltage_control = false;
+		if (pi->pwm_voltage_control) {
+			if ((pi->num_of_cycles_in_period == 0) ||
+			    (pi->max_voltage == 0) ||
+			    (pi->min_voltage == 0))
+				pi->voltage_control = false;
+		} else {
+			if ((pi->num_of_cycles_in_period == 0) ||
+			    (pi->max_voltage == 0))
+				pi->voltage_control = false;
+		}
+
+		return 0;
+	}
+	radeon_dpm_fini(rdev);
+	return -EINVAL;
+}
+
+void rs780_dpm_print_power_state(struct radeon_device *rdev,
+				 struct radeon_ps *rps)
+{
+	struct igp_ps *ps = rs780_get_ps(rps);
+
+	r600_dpm_print_class_info(rps->class, rps->class2);
+	r600_dpm_print_cap_info(rps->caps);
+	printk("\tuvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
+	printk("\t\tpower level 0    sclk: %u vddc_index: %d\n",
+	       ps->sclk_low, ps->min_voltage);
+	printk("\t\tpower level 1    sclk: %u vddc_index: %d\n",
+	       ps->sclk_high, ps->max_voltage);
+	r600_dpm_print_ps_status(rdev, rps);
+}
+
+void rs780_dpm_fini(struct radeon_device *rdev)
+{
+	int i;
+
+	for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
+		kfree(rdev->pm.dpm.ps[i].ps_priv);
+	}
+	kfree(rdev->pm.dpm.ps);
+	kfree(rdev->pm.dpm.priv);
+}
+
+u32 rs780_dpm_get_sclk(struct radeon_device *rdev, bool low)
+{
+	struct igp_ps *requested_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
+
+	if (low)
+		return requested_state->sclk_low;
+	else
+		return requested_state->sclk_high;
+}
+
+u32 rs780_dpm_get_mclk(struct radeon_device *rdev, bool low)
+{
+	struct igp_power_info *pi = rs780_get_pi(rdev);
+
+	return pi->bootup_uma_clk;
+}
diff --git a/drivers/gpu/drm/radeon/rs780_dpm.h b/drivers/gpu/drm/radeon/rs780_dpm.h
new file mode 100644
index 0000000..47a40b1
--- /dev/null
+++ b/drivers/gpu/drm/radeon/rs780_dpm.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2011 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef __RS780_DPM_H__
+#define __RS780_DPM_H__
+
+enum rs780_vddc_level {
+	RS780_VDDC_LEVEL_UNKNOWN = 0,
+	RS780_VDDC_LEVEL_LOW = 1,
+	RS780_VDDC_LEVEL_HIGH = 2,
+};
+
+struct igp_power_info {
+	/* flags */
+	bool invert_pwm_required;
+	bool pwm_voltage_control;
+	bool voltage_control;
+	bool gfx_clock_gating;
+	/* stored values */
+	u32 system_config;
+	u32 bootup_uma_clk;
+	u16 max_voltage;
+	u16 min_voltage;
+	u16 boot_voltage;
+	u16 inter_voltage_low;
+	u16 inter_voltage_high;
+	u16 num_of_cycles_in_period;
+	/* variable */
+	int crtc_id;
+	int refresh_rate;
+};
+
+struct igp_ps {
+	enum rs780_vddc_level min_voltage;
+	enum rs780_vddc_level max_voltage;
+	u32 sclk_low;
+	u32 sclk_high;
+	u32 flags;
+};
+
+#define RS780_CGFTV_DFLT                 0x0303000f
+#define RS780_FBDIVTIMERVAL_DFLT         0x2710
+
+#define RS780_FVTHROTUTC0_DFLT   0x04010040
+#define RS780_FVTHROTUTC1_DFLT   0x04010040
+#define RS780_FVTHROTUTC2_DFLT   0x04010040
+#define RS780_FVTHROTUTC3_DFLT   0x04010040
+#define RS780_FVTHROTUTC4_DFLT   0x04010040
+
+#define RS780_FVTHROTDTC0_DFLT 0x04010040
+#define RS780_FVTHROTDTC1_DFLT 0x04010040
+#define RS780_FVTHROTDTC2_DFLT 0x04010040
+#define RS780_FVTHROTDTC3_DFLT 0x04010040
+#define RS780_FVTHROTDTC4_DFLT 0x04010040
+
+#define RS780_FVTHROTFBUSREG0_DFLT       0x00001001
+#define RS780_FVTHROTFBUSREG1_DFLT       0x00002002
+#define RS780_FVTHROTFBDSREG0_DFLT       0x00004001
+#define RS780_FVTHROTFBDSREG1_DFLT       0x00020010
+
+#define RS780_FVTHROTPWMUSREG0_DFLT      0x00002001
+#define RS780_FVTHROTPWMUSREG1_DFLT      0x00004003
+#define RS780_FVTHROTPWMDSREG0_DFLT      0x00002001
+#define RS780_FVTHROTPWMDSREG1_DFLT      0x00004003
+
+#define RS780_FVTHROTPWMFBDIVRANGEREG0_DFLT  0x37
+#define RS780_FVTHROTPWMFBDIVRANGEREG1_DFLT  0x4b
+#define RS780_FVTHROTPWMFBDIVRANGEREG2_DFLT  0x8b
+
+#define RS780D_FVTHROTPWMFBDIVRANGEREG0_DFLT  0x8b
+#define RS780D_FVTHROTPWMFBDIVRANGEREG1_DFLT  0x8c
+#define RS780D_FVTHROTPWMFBDIVRANGEREG2_DFLT  0xb5
+
+#define RS880D_FVTHROTPWMFBDIVRANGEREG0_DFLT  0x8d
+#define RS880D_FVTHROTPWMFBDIVRANGEREG1_DFLT  0x8e
+#define RS880D_FVTHROTPWMFBDIVRANGEREG2_DFLT  0xBa
+
+#define RS780_FVTHROTPWMRANGE0_GPIO_DFLT  0x1a
+#define RS780_FVTHROTPWMRANGE1_GPIO_DFLT  0x1a
+#define RS780_FVTHROTPWMRANGE2_GPIO_DFLT  0x0
+#define RS780_FVTHROTPWMRANGE3_GPIO_DFLT  0x0
+
+#define RS780_SLOWCLKFEEDBACKDIV_DFLT 110
+
+#define RS780_CGCLKGATING_DFLT           0x0000E204
+
+#define RS780_DEFAULT_VCLK_FREQ  53300 /* 10 khz */
+#define RS780_DEFAULT_DCLK_FREQ  40000 /* 10 khz */
+
+#endif
diff --git a/drivers/gpu/drm/radeon/rs780d.h b/drivers/gpu/drm/radeon/rs780d.h
new file mode 100644
index 0000000..b1142ed
--- /dev/null
+++ b/drivers/gpu/drm/radeon/rs780d.h
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2011 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef __RS780D_H__
+#define __RS780D_H__
+
+#define CG_SPLL_FUNC_CNTL                                 0x600
+#       define SPLL_RESET                                (1 << 0)
+#       define SPLL_SLEEP                                (1 << 1)
+#       define SPLL_REF_DIV(x)                           ((x) << 2)
+#       define SPLL_REF_DIV_MASK                         (7 << 2)
+#       define SPLL_FB_DIV(x)                            ((x) << 5)
+#       define SPLL_FB_DIV_MASK                          (0xff << 2)
+#       define SPLL_FB_DIV_SHIFT                         2
+#       define SPLL_PULSEEN                              (1 << 13)
+#       define SPLL_PULSENUM(x)                          ((x) << 14)
+#       define SPLL_PULSENUM_MASK                        (3 << 14)
+#       define SPLL_SW_HILEN(x)                          ((x) << 16)
+#       define SPLL_SW_HILEN_MASK                        (0xf << 16)
+#       define SPLL_SW_LOLEN(x)                          ((x) << 20)
+#       define SPLL_SW_LOLEN_MASK                        (0xf << 20)
+#       define SPLL_DIVEN                                (1 << 24)
+#       define SPLL_BYPASS_EN                            (1 << 25)
+#       define SPLL_CHG_STATUS                           (1 << 29)
+#       define SPLL_CTLREQ                               (1 << 30)
+#       define SPLL_CTLACK                               (1 << 31)
+
+/* RS780/RS880 PM */
+#define	FVTHROT_CNTRL_REG				0x3000
+#define		DONT_WAIT_FOR_FBDIV_WRAP		(1 << 0)
+#define		MINIMUM_CIP(x)				((x) << 1)
+#define		MINIMUM_CIP_SHIFT			1
+#define		MINIMUM_CIP_MASK			0x1fffffe
+#define		REFRESH_RATE_DIVISOR(x)			((x) << 25)
+#define		REFRESH_RATE_DIVISOR_SHIFT		25
+#define		REFRESH_RATE_DIVISOR_MASK		(0x3 << 25)
+#define		ENABLE_FV_THROT				(1 << 27)
+#define		ENABLE_FV_UPDATE			(1 << 28)
+#define		TREND_SEL_MODE				(1 << 29)
+#define		FORCE_TREND_SEL				(1 << 30)
+#define		ENABLE_FV_THROT_IO			(1 << 31)
+#define	FVTHROT_TARGET_REG				0x3004
+#define		TARGET_IDLE_COUNT(x)			((x) << 0)
+#define		TARGET_IDLE_COUNT_MASK			0xffffff
+#define		TARGET_IDLE_COUNT_SHIFT			0
+#define	FVTHROT_CB1					0x3008
+#define	FVTHROT_CB2					0x300c
+#define	FVTHROT_CB3					0x3010
+#define	FVTHROT_CB4					0x3014
+#define	FVTHROT_UTC0					0x3018
+#define	FVTHROT_UTC1					0x301c
+#define	FVTHROT_UTC2					0x3020
+#define	FVTHROT_UTC3					0x3024
+#define	FVTHROT_UTC4					0x3028
+#define	FVTHROT_DTC0					0x302c
+#define	FVTHROT_DTC1					0x3030
+#define	FVTHROT_DTC2					0x3034
+#define	FVTHROT_DTC3					0x3038
+#define	FVTHROT_DTC4					0x303c
+#define	FVTHROT_FBDIV_REG0				0x3040
+#define		MIN_FEEDBACK_DIV(x)			((x) << 0)
+#define		MIN_FEEDBACK_DIV_MASK			0xfff
+#define		MIN_FEEDBACK_DIV_SHIFT			0
+#define		MAX_FEEDBACK_DIV(x)			((x) << 12)
+#define		MAX_FEEDBACK_DIV_MASK			(0xfff << 12)
+#define		MAX_FEEDBACK_DIV_SHIFT			12
+#define	FVTHROT_FBDIV_REG1				0x3044
+#define		MAX_FEEDBACK_STEP(x)			((x) << 0)
+#define		MAX_FEEDBACK_STEP_MASK			0xfff
+#define		MAX_FEEDBACK_STEP_SHIFT			0
+#define		STARTING_FEEDBACK_DIV(x)		((x) << 12)
+#define		STARTING_FEEDBACK_DIV_MASK		(0xfff << 12)
+#define		STARTING_FEEDBACK_DIV_SHIFT		12
+#define		FORCE_FEEDBACK_DIV			(1 << 24)
+#define	FVTHROT_FBDIV_REG2				0x3048
+#define		FORCED_FEEDBACK_DIV(x)			((x) << 0)
+#define		FORCED_FEEDBACK_DIV_MASK		0xfff
+#define		FORCED_FEEDBACK_DIV_SHIFT		0
+#define		FB_DIV_TIMER_VAL(x)			((x) << 12)
+#define		FB_DIV_TIMER_VAL_MASK			(0xffff << 12)
+#define		FB_DIV_TIMER_VAL_SHIFT			12
+#define	FVTHROT_FB_US_REG0				0x304c
+#define	FVTHROT_FB_US_REG1				0x3050
+#define	FVTHROT_FB_DS_REG0				0x3054
+#define	FVTHROT_FB_DS_REG1				0x3058
+#define	FVTHROT_PWM_CTRL_REG0				0x305c
+#define		STARTING_PWM_HIGHTIME(x)		((x) << 0)
+#define		STARTING_PWM_HIGHTIME_MASK		0xfff
+#define		STARTING_PWM_HIGHTIME_SHIFT		0
+#define		NUMBER_OF_CYCLES_IN_PERIOD(x)		((x) << 12)
+#define		NUMBER_OF_CYCLES_IN_PERIOD_MASK		(0xfff << 12)
+#define		NUMBER_OF_CYCLES_IN_PERIOD_SHIFT	12
+#define		FORCE_STARTING_PWM_HIGHTIME		(1 << 24)
+#define		INVERT_PWM_WAVEFORM			(1 << 25)
+#define	FVTHROT_PWM_CTRL_REG1				0x3060
+#define		MIN_PWM_HIGHTIME(x)			((x) << 0)
+#define		MIN_PWM_HIGHTIME_MASK			0xfff
+#define		MIN_PWM_HIGHTIME_SHIFT			0
+#define		MAX_PWM_HIGHTIME(x)			((x) << 12)
+#define		MAX_PWM_HIGHTIME_MASK			(0xfff << 12)
+#define		MAX_PWM_HIGHTIME_SHIFT			12
+#define	FVTHROT_PWM_US_REG0				0x3064
+#define	FVTHROT_PWM_US_REG1				0x3068
+#define	FVTHROT_PWM_DS_REG0				0x306c
+#define	FVTHROT_PWM_DS_REG1				0x3070
+#define	FVTHROT_STATUS_REG0				0x3074
+#define		CURRENT_FEEDBACK_DIV_MASK		0xfff
+#define		CURRENT_FEEDBACK_DIV_SHIFT		0
+#define	FVTHROT_STATUS_REG1				0x3078
+#define	FVTHROT_STATUS_REG2				0x307c
+#define	CG_INTGFX_MISC					0x3080
+#define		FVTHROT_VBLANK_SEL			(1 << 9)
+#define	FVTHROT_PWM_FEEDBACK_DIV_REG1			0x308c
+#define		RANGE0_PWM_FEEDBACK_DIV(x)		((x) << 0)
+#define		RANGE0_PWM_FEEDBACK_DIV_MASK		0xfff
+#define		RANGE0_PWM_FEEDBACK_DIV_SHIFT		0
+#define		RANGE_PWM_FEEDBACK_DIV_EN		(1 << 12)
+#define	FVTHROT_PWM_FEEDBACK_DIV_REG2			0x3090
+#define		RANGE1_PWM_FEEDBACK_DIV(x)		((x) << 0)
+#define		RANGE1_PWM_FEEDBACK_DIV_MASK		0xfff
+#define		RANGE1_PWM_FEEDBACK_DIV_SHIFT		0
+#define		RANGE2_PWM_FEEDBACK_DIV(x)		((x) << 12)
+#define		RANGE2_PWM_FEEDBACK_DIV_MASK		(0xfff << 12)
+#define		RANGE2_PWM_FEEDBACK_DIV_SHIFT		12
+#define	FVTHROT_PWM_FEEDBACK_DIV_REG3			0x3094
+#define		RANGE0_PWM(x)				((x) << 0)
+#define		RANGE0_PWM_MASK				0xfff
+#define		RANGE0_PWM_SHIFT			0
+#define		RANGE1_PWM(x)				((x) << 12)
+#define		RANGE1_PWM_MASK				(0xfff << 12)
+#define		RANGE1_PWM_SHIFT			12
+#define	FVTHROT_PWM_FEEDBACK_DIV_REG4			0x3098
+#define		RANGE2_PWM(x)				((x) << 0)
+#define		RANGE2_PWM_MASK				0xfff
+#define		RANGE2_PWM_SHIFT			0
+#define		RANGE3_PWM(x)				((x) << 12)
+#define		RANGE3_PWM_MASK				(0xfff << 12)
+#define		RANGE3_PWM_SHIFT			12
+#define	FVTHROT_SLOW_CLK_FEEDBACK_DIV_REG1		0x30ac
+#define		RANGE0_SLOW_CLK_FEEDBACK_DIV(x)		((x) << 0)
+#define		RANGE0_SLOW_CLK_FEEDBACK_DIV_MASK	0xfff
+#define		RANGE0_SLOW_CLK_FEEDBACK_DIV_SHIFT	0
+#define		RANGE_SLOW_CLK_FEEDBACK_DIV_EN		(1 << 12)
+
+#define	GFX_MACRO_BYPASS_CNTL				0x30c0
+#define		SPLL_BYPASS_CNTL			(1 << 0)
+#define		UPLL_BYPASS_CNTL			(1 << 1)
+
+#endif
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 076/165] drm/radeon/kms: add dpm support for rv6xx
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (75 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 075/165] drm/radeon/kms: add dpm support for rs780/rs880 alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 16:45   ` Christian König
  2013-06-26 13:22 ` [PATCH 077/165] drm/radeon/kms: add dpm support for rv7xx (v2) alexdeucher
                   ` (36 subsequent siblings)
  113 siblings, 1 reply; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

This adds dpm support for rv6xx asics.  This includes:
- clockgating
- dynamic engine clock scaling
- dynamic memory clock scaling
- dynamic voltage scaling
- dynamic pcie gen1/gen2 switching

Set radeon.dpm=1 to enable.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/Makefile          |    2 +-
 drivers/gpu/drm/radeon/r600.c            |   27 +
 drivers/gpu/drm/radeon/r600_dpm.c        |   45 +
 drivers/gpu/drm/radeon/r600_dpm.h        |    8 +
 drivers/gpu/drm/radeon/r600d.h           |   13 +
 drivers/gpu/drm/radeon/radeon.h          |    3 +
 drivers/gpu/drm/radeon/radeon_asic.c     |   12 +
 drivers/gpu/drm/radeon/radeon_asic.h     |   12 +
 drivers/gpu/drm/radeon/radeon_atombios.c |    4 +-
 drivers/gpu/drm/radeon/radeon_irq_kms.c  |    2 +
 drivers/gpu/drm/radeon/radeon_mode.h     |    2 +
 drivers/gpu/drm/radeon/radeon_pm.c       |    9 +
 drivers/gpu/drm/radeon/rs780_dpm.c       |   12 +
 drivers/gpu/drm/radeon/rv6xx_dpm.c       | 1991 ++++++++++++++++++++++++++++++
 drivers/gpu/drm/radeon/rv6xx_dpm.h       |   95 ++
 drivers/gpu/drm/radeon/rv6xxd.h          |  246 ++++
 16 files changed, 2480 insertions(+), 3 deletions(-)
 create mode 100644 drivers/gpu/drm/radeon/rv6xx_dpm.c
 create mode 100644 drivers/gpu/drm/radeon/rv6xx_dpm.h
 create mode 100644 drivers/gpu/drm/radeon/rv6xxd.h

diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile
index e44b046..3aa20dc 100644
--- a/drivers/gpu/drm/radeon/Makefile
+++ b/drivers/gpu/drm/radeon/Makefile
@@ -77,7 +77,7 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \
 	evergreen_hdmi.o radeon_trace_points.o ni.o cayman_blit_shaders.o \
 	atombios_encoders.o radeon_semaphore.o radeon_sa.o atombios_i2c.o si.o \
 	si_blit_shaders.o radeon_prime.o radeon_uvd.o cik.o cik_blit_shaders.o \
-	r600_dpm.o rs780_dpm.o
+	r600_dpm.o rs780_dpm.o rv6xx_dpm.o
 
 radeon-$(CONFIG_COMPAT) += radeon_ioc32.o
 radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index 4678ed1..7ea81c8 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -3998,6 +3998,7 @@ int r600_irq_set(struct radeon_device *rdev)
 	u32 hdmi0, hdmi1;
 	u32 d1grph = 0, d2grph = 0;
 	u32 dma_cntl;
+	u32 thermal_int = 0;
 
 	if (!rdev->irq.installed) {
 		WARN(1, "Can't enable IRQ/MSI because no handler is installed\n");
@@ -4032,8 +4033,18 @@ int r600_irq_set(struct radeon_device *rdev)
 		hdmi0 = RREG32(HDMI0_AUDIO_PACKET_CONTROL) & ~HDMI0_AZ_FORMAT_WTRIG_MASK;
 		hdmi1 = RREG32(HDMI1_AUDIO_PACKET_CONTROL) & ~HDMI0_AZ_FORMAT_WTRIG_MASK;
 	}
+
 	dma_cntl = RREG32(DMA_CNTL) & ~TRAP_ENABLE;
 
+	if ((rdev->family > CHIP_R600) && (rdev->family < CHIP_RV770)) {
+		thermal_int = RREG32(CG_THERMAL_INT) &
+			~(THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW);
+		if (rdev->irq.dpm_thermal) {
+			DRM_DEBUG("dpm thermal\n");
+			thermal_int |= THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW;
+		}
+	}
+
 	if (atomic_read(&rdev->irq.ring_int[RADEON_RING_TYPE_GFX_INDEX])) {
 		DRM_DEBUG("r600_irq_set: sw int\n");
 		cp_int_cntl |= RB_INT_ENABLE;
@@ -4115,6 +4126,9 @@ int r600_irq_set(struct radeon_device *rdev)
 		WREG32(HDMI0_AUDIO_PACKET_CONTROL, hdmi0);
 		WREG32(HDMI1_AUDIO_PACKET_CONTROL, hdmi1);
 	}
+	if ((rdev->family > CHIP_R600) && (rdev->family < CHIP_RV770)) {
+		WREG32(CG_THERMAL_INT, thermal_int);
+	}
 
 	return 0;
 }
@@ -4306,6 +4320,7 @@ int r600_irq_process(struct radeon_device *rdev)
 	u32 ring_index;
 	bool queue_hotplug = false;
 	bool queue_hdmi = false;
+	bool queue_thermal = false;
 
 	if (!rdev->ih.enabled || rdev->shutdown)
 		return IRQ_NONE;
@@ -4473,6 +4488,16 @@ restart_ih:
 			DRM_DEBUG("IH: DMA trap\n");
 			radeon_fence_process(rdev, R600_RING_TYPE_DMA_INDEX);
 			break;
+		case 230: /* thermal low to high */
+			DRM_DEBUG("IH: thermal low to high\n");
+			rdev->pm.dpm.thermal.high_to_low = false;
+			queue_thermal = true;
+			break;
+		case 231: /* thermal high to low */
+			DRM_DEBUG("IH: thermal high to low\n");
+			rdev->pm.dpm.thermal.high_to_low = true;
+			queue_thermal = true;
+			break;
 		case 233: /* GUI IDLE */
 			DRM_DEBUG("IH: GUI idle\n");
 			break;
@@ -4489,6 +4514,8 @@ restart_ih:
 		schedule_work(&rdev->hotplug_work);
 	if (queue_hdmi)
 		schedule_work(&rdev->audio_work);
+	if (queue_thermal)
+		schedule_work(&rdev->pm.dpm.thermal.work);
 	rdev->ih.rptr = rptr;
 	WREG32(IH_RB_RPTR, rdev->ih.rptr);
 	atomic_set(&rdev->ih.lock, 0);
diff --git a/drivers/gpu/drm/radeon/r600_dpm.c b/drivers/gpu/drm/radeon/r600_dpm.c
index 91bc5ab..bf396a0 100644
--- a/drivers/gpu/drm/radeon/r600_dpm.c
+++ b/drivers/gpu/drm/radeon/r600_dpm.c
@@ -676,3 +676,48 @@ bool r600_is_uvd_state(u32 class, u32 class2)
 		return true;
 	return false;
 }
+
+int r600_set_thermal_temperature_range(struct radeon_device *rdev,
+				       int min_temp, int max_temp)
+{
+	int low_temp = 0 * 1000;
+	int high_temp = 255 * 1000;
+
+	if (low_temp < min_temp)
+		low_temp = min_temp;
+	if (high_temp > max_temp)
+		high_temp = max_temp;
+	if (high_temp < low_temp) {
+		DRM_ERROR("invalid thermal range: %d - %d\n", low_temp, high_temp);
+		return -EINVAL;
+	}
+
+	WREG32_P(CG_THERMAL_INT, DIG_THERM_INTH(high_temp / 1000), ~DIG_THERM_INTH_MASK);
+	WREG32_P(CG_THERMAL_INT, DIG_THERM_INTL(low_temp / 1000), ~DIG_THERM_INTL_MASK);
+	WREG32_P(CG_THERMAL_CTRL, DIG_THERM_DPM(high_temp / 1000), ~DIG_THERM_DPM_MASK);
+
+	rdev->pm.dpm.thermal.min_temp = low_temp;
+	rdev->pm.dpm.thermal.max_temp = high_temp;
+
+	return 0;
+}
+
+bool r600_is_internal_thermal_sensor(enum radeon_int_thermal_type sensor)
+{
+	switch (sensor) {
+	case THERMAL_TYPE_RV6XX:
+	case THERMAL_TYPE_RV770:
+	case THERMAL_TYPE_EVERGREEN:
+	case THERMAL_TYPE_SUMO:
+	case THERMAL_TYPE_NI:
+		return true;
+	case THERMAL_TYPE_ADT7473_WITH_INTERNAL:
+	case THERMAL_TYPE_EMC2103_WITH_INTERNAL:
+		return false; /* need special handling */
+	case THERMAL_TYPE_NONE:
+	case THERMAL_TYPE_EXTERNAL:
+	case THERMAL_TYPE_EXTERNAL_GPIO:
+	default:
+		return false;
+	}
+}
diff --git a/drivers/gpu/drm/radeon/r600_dpm.h b/drivers/gpu/drm/radeon/r600_dpm.h
index 240a7ed..bd33aa1 100644
--- a/drivers/gpu/drm/radeon/r600_dpm.h
+++ b/drivers/gpu/drm/radeon/r600_dpm.h
@@ -92,6 +92,10 @@
 #define R600_PM_NUMBER_OF_VOLTAGE_LEVELS 4
 #define R600_PM_NUMBER_OF_ACTIVITY_LEVELS 3
 
+/* XXX are these ok? */
+#define R600_TEMP_RANGE_MIN (90 * 1000)
+#define R600_TEMP_RANGE_MAX (120 * 1000)
+
 enum r600_power_level {
 	R600_POWER_LEVEL_LOW = 0,
 	R600_POWER_LEVEL_MEDIUM = 1,
@@ -207,4 +211,8 @@ void r600_wait_for_power_level(struct radeon_device *rdev,
 void r600_start_dpm(struct radeon_device *rdev);
 void r600_stop_dpm(struct radeon_device *rdev);
 
+int r600_set_thermal_temperature_range(struct radeon_device *rdev,
+				       int min_temp, int max_temp);
+bool r600_is_internal_thermal_sensor(enum radeon_int_thermal_type sensor);
+
 #endif
diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h
index d6d385a..3bca4db 100644
--- a/drivers/gpu/drm/radeon/r600d.h
+++ b/drivers/gpu/drm/radeon/r600d.h
@@ -302,10 +302,23 @@
 #define	GRBM_SOFT_RESET					0x8020
 #define		SOFT_RESET_CP					(1<<0)
 
+#define	CG_THERMAL_CTRL					0x7F0
+#define		DIG_THERM_DPM(x)			((x) << 12)
+#define		DIG_THERM_DPM_MASK			0x000FF000
+#define		DIG_THERM_DPM_SHIFT			12
 #define	CG_THERMAL_STATUS				0x7F4
 #define		ASIC_T(x)			        ((x) << 0)
 #define		ASIC_T_MASK			        0x1FF
 #define		ASIC_T_SHIFT			        0
+#define	CG_THERMAL_INT					0x7F8
+#define		DIG_THERM_INTH(x)			((x) << 8)
+#define		DIG_THERM_INTH_MASK			0x0000FF00
+#define		DIG_THERM_INTH_SHIFT			8
+#define		DIG_THERM_INTL(x)			((x) << 16)
+#define		DIG_THERM_INTL_MASK			0x00FF0000
+#define		DIG_THERM_INTL_SHIFT			16
+#define 	THERM_INT_MASK_HIGH			(1 << 24)
+#define 	THERM_INT_MASK_LOW			(1 << 25)
 
 #define	HDP_HOST_PATH_CNTL				0x2C00
 #define	HDP_NONSURFACE_BASE				0x2C04
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 7adc7a1..ce36130 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -227,6 +227,8 @@ void radeon_atom_set_engine_dram_timings(struct radeon_device *rdev,
 					 u32 eng_clock, u32 mem_clock);
 int radeon_atom_get_voltage_step(struct radeon_device *rdev,
 				 u8 voltage_type, u16 *voltage_step);
+int radeon_atom_get_max_vddc(struct radeon_device *rdev, u8 voltage_type,
+			     u16 voltage_id, u16 *voltage);
 int radeon_atom_round_to_true_voltage(struct radeon_device *rdev,
 				      u8 voltage_type,
 				      u16 nominal_voltage,
@@ -681,6 +683,7 @@ struct radeon_irq {
 	bool				hpd[RADEON_MAX_HPD_PINS];
 	bool				afmt[RADEON_MAX_AFMT_BLOCKS];
 	union radeon_irq_stat_regs	stat_regs;
+	bool				dpm_thermal;
 };
 
 int radeon_irq_kms_init(struct radeon_device *rdev);
diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c
index db3c930..4705b02 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.c
+++ b/drivers/gpu/drm/radeon/radeon_asic.c
@@ -1105,6 +1105,18 @@ static struct radeon_asic rv6xx_asic = {
 		.set_clock_gating = NULL,
 		.get_temperature = &rv6xx_get_temp,
 	},
+	.dpm = {
+		.init = &rv6xx_dpm_init,
+		.setup_asic = &rv6xx_setup_asic,
+		.enable = &rv6xx_dpm_enable,
+		.disable = &rv6xx_dpm_disable,
+		.set_power_state = &rv6xx_dpm_set_power_state,
+		.display_configuration_changed = &rv6xx_dpm_display_configuration_changed,
+		.fini = &rv6xx_dpm_fini,
+		.get_sclk = &rv6xx_dpm_get_sclk,
+		.get_mclk = &rv6xx_dpm_get_mclk,
+		.print_power_state = &rv6xx_dpm_print_power_state,
+	},
 	.pflip = {
 		.pre_page_flip = &rs600_pre_page_flip,
 		.page_flip = &rs600_page_flip,
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index 134bf57..878766624 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -396,6 +396,18 @@ int r600_mc_wait_for_idle(struct radeon_device *rdev);
 u32 r600_get_xclk(struct radeon_device *rdev);
 uint64_t r600_get_gpu_clock_counter(struct radeon_device *rdev);
 int rv6xx_get_temp(struct radeon_device *rdev);
+/* rv6xx dpm */
+int rv6xx_dpm_init(struct radeon_device *rdev);
+int rv6xx_dpm_enable(struct radeon_device *rdev);
+void rv6xx_dpm_disable(struct radeon_device *rdev);
+int rv6xx_dpm_set_power_state(struct radeon_device *rdev);
+void rv6xx_setup_asic(struct radeon_device *rdev);
+void rv6xx_dpm_display_configuration_changed(struct radeon_device *rdev);
+void rv6xx_dpm_fini(struct radeon_device *rdev);
+u32 rv6xx_dpm_get_sclk(struct radeon_device *rdev, bool low);
+u32 rv6xx_dpm_get_mclk(struct radeon_device *rdev, bool low);
+void rv6xx_dpm_print_power_state(struct radeon_device *rdev,
+				 struct radeon_ps *ps);
 /* rs780 dpm */
 int rs780_dpm_init(struct radeon_device *rdev);
 int rs780_dpm_enable(struct radeon_device *rdev);
diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c
index 90401fd..612d9bc 100644
--- a/drivers/gpu/drm/radeon/radeon_atombios.c
+++ b/drivers/gpu/drm/radeon/radeon_atombios.c
@@ -2268,8 +2268,8 @@ static void radeon_atombios_add_pplib_thermal_controller(struct radeon_device *r
 	}
 }
 
-static void radeon_atombios_get_default_voltages(struct radeon_device *rdev,
-						 u16 *vddc, u16 *vddci)
+void radeon_atombios_get_default_voltages(struct radeon_device *rdev,
+					  u16 *vddc, u16 *vddci)
 {
 	struct radeon_mode_info *mode_info = &rdev->mode_info;
 	int index = GetIndexIntoMasterTable(DATA, FirmwareInfo);
diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c
index dbffeca..bcdefd1 100644
--- a/drivers/gpu/drm/radeon/radeon_irq_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c
@@ -116,6 +116,7 @@ void radeon_driver_irq_preinstall_kms(struct drm_device *dev)
 	/* Disable *all* interrupts */
 	for (i = 0; i < RADEON_NUM_RINGS; i++)
 		atomic_set(&rdev->irq.ring_int[i], 0);
+	rdev->irq.dpm_thermal = false;
 	for (i = 0; i < RADEON_MAX_HPD_PINS; i++)
 		rdev->irq.hpd[i] = false;
 	for (i = 0; i < RADEON_MAX_CRTCS; i++) {
@@ -163,6 +164,7 @@ void radeon_driver_irq_uninstall_kms(struct drm_device *dev)
 	/* Disable *all* interrupts */
 	for (i = 0; i < RADEON_NUM_RINGS; i++)
 		atomic_set(&rdev->irq.ring_int[i], 0);
+	rdev->irq.dpm_thermal = false;
 	for (i = 0; i < RADEON_MAX_HPD_PINS; i++)
 		rdev->irq.hpd[i] = false;
 	for (i = 0; i < RADEON_MAX_CRTCS; i++) {
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
index 5a1c69e..02bf4a7 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -580,6 +580,8 @@ extern enum radeon_tv_std
 radeon_combios_get_tv_info(struct radeon_device *rdev);
 extern enum radeon_tv_std
 radeon_atombios_get_tv_info(struct radeon_device *rdev);
+extern void radeon_atombios_get_default_voltages(struct radeon_device *rdev,
+						 u16 *vddc, u16 *vddci);
 
 extern struct drm_connector *
 radeon_get_connector_for_encoder(struct drm_encoder *encoder);
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
index 853a8a2..5cb01f2 100644
--- a/drivers/gpu/drm/radeon/radeon_pm.c
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
@@ -565,6 +565,9 @@ static void radeon_dpm_thermal_work_handler(struct work_struct *work)
 	if (!rdev->pm.dpm_enabled)
 		return;
 
+	if (!rdev->pm.dpm_enabled)
+		return;
+
 	if (rdev->asic->pm.get_temperature) {
 		int temp = radeon_get_temperature(rdev);
 
@@ -1030,6 +1033,11 @@ int radeon_pm_init(struct radeon_device *rdev)
 {
 	/* enable dpm on rv6xx+ */
 	switch (rdev->family) {
+	case CHIP_RV610:
+	case CHIP_RV630:
+	case CHIP_RV620:
+	case CHIP_RV635:
+	case CHIP_RV670:
 	case CHIP_RS780:
 	case CHIP_RS880:
 		if (radeon_dpm == 1)
@@ -1114,6 +1122,7 @@ static void radeon_pm_compute_clocks_old(struct radeon_device *rdev)
 	if (rdev->pm.num_power_states < 2)
 		return;
 
+	INIT_WORK(&rdev->pm.dpm.thermal.work, radeon_dpm_thermal_work_handler);
 	mutex_lock(&rdev->pm.mutex);
 
 	rdev->pm.active_crtcs = 0;
diff --git a/drivers/gpu/drm/radeon/rs780_dpm.c b/drivers/gpu/drm/radeon/rs780_dpm.c
index f594900..a1497a6 100644
--- a/drivers/gpu/drm/radeon/rs780_dpm.c
+++ b/drivers/gpu/drm/radeon/rs780_dpm.c
@@ -560,6 +560,12 @@ int rs780_dpm_enable(struct radeon_device *rdev)
 	if (pi->gfx_clock_gating)
 		r600_gfx_clockgating_enable(rdev, true);
 
+	if (rdev->irq.installed && (rdev->pm.int_thermal_type == THERMAL_TYPE_RV6XX)) {
+		r600_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
+		rdev->irq.dpm_thermal = true;
+		radeon_irq_set(rdev);
+	}
+
 	return 0;
 }
 
@@ -574,6 +580,12 @@ void rs780_dpm_disable(struct radeon_device *rdev)
 
 	if (pi->gfx_clock_gating)
 		r600_gfx_clockgating_enable(rdev, false);
+
+	if (rdev->irq.installed &&
+	    (rdev->pm.int_thermal_type == THERMAL_TYPE_RV6XX)) {
+		rdev->irq.dpm_thermal = false;
+		radeon_irq_set(rdev);
+	}
 }
 
 int rs780_dpm_set_power_state(struct radeon_device *rdev)
diff --git a/drivers/gpu/drm/radeon/rv6xx_dpm.c b/drivers/gpu/drm/radeon/rv6xx_dpm.c
new file mode 100644
index 0000000..fa4beb2
--- /dev/null
+++ b/drivers/gpu/drm/radeon/rv6xx_dpm.c
@@ -0,0 +1,1991 @@
+/*
+ * Copyright 2011 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Alex Deucher
+ */
+
+#include "drmP.h"
+#include "radeon.h"
+#include "rv6xxd.h"
+#include "r600_dpm.h"
+#include "rv6xx_dpm.h"
+#include "atom.h"
+
+static u32 rv6xx_scale_count_given_unit(struct radeon_device *rdev,
+					u32 unscaled_count, u32 unit);
+
+static struct rv6xx_ps *rv6xx_get_ps(struct radeon_ps *rps)
+{
+	struct rv6xx_ps *ps = rps->ps_priv;
+
+	return ps;
+}
+
+static struct rv6xx_power_info *rv6xx_get_pi(struct radeon_device *rdev)
+{
+	struct rv6xx_power_info *pi = rdev->pm.dpm.priv;
+
+	return pi;
+}
+
+static void rv6xx_force_pcie_gen1(struct radeon_device *rdev)
+{
+	u32 tmp;
+	int i;
+
+	tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL);
+	tmp &= LC_GEN2_EN;
+	WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp);
+
+	tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL);
+	tmp |= LC_INITIATE_LINK_SPEED_CHANGE;
+	WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp);
+
+	for (i = 0; i < rdev->usec_timeout; i++) {
+		if (!(RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL) & LC_CURRENT_DATA_RATE))
+			break;
+		udelay(1);
+	}
+
+	tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL);
+	tmp &= ~LC_INITIATE_LINK_SPEED_CHANGE;
+	WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp);
+}
+
+static void rv6xx_enable_pcie_gen2_support(struct radeon_device *rdev)
+{
+	u32 tmp;
+
+	tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL);
+
+	if ((tmp & LC_OTHER_SIDE_EVER_SENT_GEN2) &&
+	    (tmp & LC_OTHER_SIDE_SUPPORTS_GEN2)) {
+		tmp |= LC_GEN2_EN;
+		WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp);
+	}
+}
+
+static void rv6xx_enable_bif_dynamic_pcie_gen2(struct radeon_device *rdev,
+					       bool enable)
+{
+	u32 tmp;
+
+	tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL) & ~LC_HW_VOLTAGE_IF_CONTROL_MASK;
+	if (enable)
+		tmp |= LC_HW_VOLTAGE_IF_CONTROL(1);
+	else
+		tmp |= LC_HW_VOLTAGE_IF_CONTROL(0);
+	WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp);
+}
+
+static void rv6xx_enable_l0s(struct radeon_device *rdev)
+{
+	u32 tmp;
+
+	tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL) & ~LC_L0S_INACTIVITY_MASK;
+	tmp |= LC_L0S_INACTIVITY(3);
+	WREG32_PCIE_PORT(PCIE_LC_CNTL, tmp);
+}
+
+static void rv6xx_enable_l1(struct radeon_device *rdev)
+{
+	u32 tmp;
+
+	tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL);
+	tmp &= ~LC_L1_INACTIVITY_MASK;
+	tmp |= LC_L1_INACTIVITY(4);
+	tmp &= ~LC_PMI_TO_L1_DIS;
+	tmp &= ~LC_ASPM_TO_L1_DIS;
+	WREG32_PCIE_PORT(PCIE_LC_CNTL, tmp);
+}
+
+static void rv6xx_enable_pll_sleep_in_l1(struct radeon_device *rdev)
+{
+	u32 tmp;
+
+	tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL) & ~LC_L1_INACTIVITY_MASK;
+	tmp |= LC_L1_INACTIVITY(8);
+	WREG32_PCIE_PORT(PCIE_LC_CNTL, tmp);
+
+	/* NOTE, this is a PCIE indirect reg, not PCIE PORT */
+	tmp = RREG32_PCIE(PCIE_P_CNTL);
+	tmp |= P_PLL_PWRDN_IN_L1L23;
+	tmp &= ~P_PLL_BUF_PDNB;
+	tmp &= ~P_PLL_PDNB;
+	tmp |= P_ALLOW_PRX_FRONTEND_SHUTOFF;
+	WREG32_PCIE(PCIE_P_CNTL, tmp);
+}
+
+static int rv6xx_convert_clock_to_stepping(struct radeon_device *rdev,
+					   u32 clock, struct rv6xx_sclk_stepping *step)
+{
+	int ret;
+	struct atom_clock_dividers dividers;
+
+	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
+					     clock, false, &dividers);
+	if (ret)
+		return ret;
+
+	if (dividers.enable_post_div)
+		step->post_divider = 2 + (dividers.post_div & 0xF) + (dividers.post_div >> 4);
+	else
+		step->post_divider = 1;
+
+	step->vco_frequency = clock * step->post_divider;
+
+	return 0;
+}
+
+static void rv6xx_output_stepping(struct radeon_device *rdev,
+				  u32 step_index, struct rv6xx_sclk_stepping *step)
+{
+	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+	u32 ref_clk = rdev->clock.spll.reference_freq;
+	u32 fb_divider;
+	u32 spll_step_count = rv6xx_scale_count_given_unit(rdev,
+							   R600_SPLLSTEPTIME_DFLT *
+							   pi->spll_ref_div,
+							   R600_SPLLSTEPUNIT_DFLT);
+
+	r600_engine_clock_entry_enable(rdev, step_index, true);
+	r600_engine_clock_entry_enable_pulse_skipping(rdev, step_index, false);
+
+	if (step->post_divider == 1)
+		r600_engine_clock_entry_enable_post_divider(rdev, step_index, false);
+	else {
+		u32 lo_len = (step->post_divider - 2) / 2;
+		u32 hi_len = step->post_divider - 2 - lo_len;
+
+		r600_engine_clock_entry_enable_post_divider(rdev, step_index, true);
+		r600_engine_clock_entry_set_post_divider(rdev, step_index, (hi_len << 4) | lo_len);
+	}
+
+	fb_divider = ((step->vco_frequency * pi->spll_ref_div) / ref_clk) >>
+		pi->fb_div_scale;
+
+	r600_engine_clock_entry_set_reference_divider(rdev, step_index,
+						      pi->spll_ref_div - 1);
+	r600_engine_clock_entry_set_feedback_divider(rdev, step_index, fb_divider);
+	r600_engine_clock_entry_set_step_time(rdev, step_index, spll_step_count);
+
+}
+
+static struct rv6xx_sclk_stepping rv6xx_next_vco_step(struct radeon_device *rdev,
+						      struct rv6xx_sclk_stepping *cur,
+						      bool increasing_vco, u32 step_size)
+{
+	struct rv6xx_sclk_stepping next;
+
+	next.post_divider = cur->post_divider;
+
+	if (increasing_vco)
+		next.vco_frequency = (cur->vco_frequency * (100 + step_size)) / 100;
+	else
+		next.vco_frequency = (cur->vco_frequency * 100 + 99 + step_size) / (100 + step_size);
+
+	return next;
+}
+
+static bool rv6xx_can_step_post_div(struct radeon_device *rdev,
+				    struct rv6xx_sclk_stepping *cur,
+                                    struct rv6xx_sclk_stepping *target)
+{
+	return (cur->post_divider > target->post_divider) &&
+		((cur->vco_frequency * target->post_divider) <=
+		 (target->vco_frequency * (cur->post_divider - 1)));
+}
+
+static struct rv6xx_sclk_stepping rv6xx_next_post_div_step(struct radeon_device *rdev,
+							   struct rv6xx_sclk_stepping *cur,
+							   struct rv6xx_sclk_stepping *target)
+{
+	struct rv6xx_sclk_stepping next = *cur;
+
+	while (rv6xx_can_step_post_div(rdev, &next, target))
+		next.post_divider--;
+
+	return next;
+}
+
+static bool rv6xx_reached_stepping_target(struct radeon_device *rdev,
+					  struct rv6xx_sclk_stepping *cur,
+					  struct rv6xx_sclk_stepping *target,
+					  bool increasing_vco)
+{
+	return (increasing_vco && (cur->vco_frequency >= target->vco_frequency)) ||
+		(!increasing_vco && (cur->vco_frequency <= target->vco_frequency));
+}
+
+static void rv6xx_generate_steps(struct radeon_device *rdev,
+				 u32 low, u32 high,
+                                 u32 start_index, u8 *end_index)
+{
+	struct rv6xx_sclk_stepping cur;
+	struct rv6xx_sclk_stepping target;
+	bool increasing_vco;
+	u32 step_index = start_index;
+
+	rv6xx_convert_clock_to_stepping(rdev, low, &cur);
+	rv6xx_convert_clock_to_stepping(rdev, high, &target);
+
+	rv6xx_output_stepping(rdev, step_index++, &cur);
+
+	increasing_vco = (target.vco_frequency >= cur.vco_frequency);
+
+	if (target.post_divider > cur.post_divider)
+		cur.post_divider = target.post_divider;
+
+	while (1) {
+		struct rv6xx_sclk_stepping next;
+
+		if (rv6xx_can_step_post_div(rdev, &cur, &target))
+			next = rv6xx_next_post_div_step(rdev, &cur, &target);
+		else
+			next = rv6xx_next_vco_step(rdev, &cur, increasing_vco, R600_VCOSTEPPCT_DFLT);
+
+		if (rv6xx_reached_stepping_target(rdev, &next, &target, increasing_vco)) {
+			struct rv6xx_sclk_stepping tiny =
+				rv6xx_next_vco_step(rdev, &target, !increasing_vco, R600_ENDINGVCOSTEPPCT_DFLT);
+			tiny.post_divider = next.post_divider;
+
+			if (!rv6xx_reached_stepping_target(rdev, &tiny, &cur, !increasing_vco))
+				rv6xx_output_stepping(rdev, step_index++, &tiny);
+
+			if ((next.post_divider != target.post_divider) &&
+			    (next.vco_frequency != target.vco_frequency)) {
+				struct rv6xx_sclk_stepping final_vco;
+
+				final_vco.vco_frequency = target.vco_frequency;
+				final_vco.post_divider = next.post_divider;
+
+				rv6xx_output_stepping(rdev, step_index++, &final_vco);
+			}
+
+			rv6xx_output_stepping(rdev, step_index++, &target);
+			break;
+		} else
+			rv6xx_output_stepping(rdev, step_index++, &next);
+
+		cur = next;
+	}
+
+	*end_index = (u8)step_index - 1;
+
+}
+
+static void rv6xx_generate_single_step(struct radeon_device *rdev,
+				       u32 clock, u32 index)
+{
+	struct rv6xx_sclk_stepping step;
+
+	rv6xx_convert_clock_to_stepping(rdev, clock, &step);
+	rv6xx_output_stepping(rdev, index, &step);
+}
+
+static void rv6xx_invalidate_intermediate_steps_range(struct radeon_device *rdev,
+						      u32 start_index, u32 end_index)
+{
+	u32 step_index;
+
+	for (step_index = start_index + 1; step_index < end_index; step_index++)
+		r600_engine_clock_entry_enable(rdev, step_index, false);
+}
+
+static void rv6xx_set_engine_spread_spectrum_clk_s(struct radeon_device *rdev,
+						   u32 index, u32 clk_s)
+{
+	WREG32_P(CG_SPLL_SPREAD_SPECTRUM_LOW + (index * 4),
+		 CLKS(clk_s), ~CLKS_MASK);
+}
+
+static void rv6xx_set_engine_spread_spectrum_clk_v(struct radeon_device *rdev,
+						   u32 index, u32 clk_v)
+{
+	WREG32_P(CG_SPLL_SPREAD_SPECTRUM_LOW + (index * 4),
+		 CLKV(clk_v), ~CLKV_MASK);
+}
+
+static void rv6xx_enable_engine_spread_spectrum(struct radeon_device *rdev,
+						u32 index, bool enable)
+{
+	if (enable)
+		WREG32_P(CG_SPLL_SPREAD_SPECTRUM_LOW + (index * 4),
+			 SSEN, ~SSEN);
+	else
+		WREG32_P(CG_SPLL_SPREAD_SPECTRUM_LOW + (index * 4),
+			 0, ~SSEN);
+}
+
+static void rv6xx_set_memory_spread_spectrum_clk_s(struct radeon_device *rdev,
+						   u32 clk_s)
+{
+	WREG32_P(CG_MPLL_SPREAD_SPECTRUM, CLKS(clk_s), ~CLKS_MASK);
+}
+
+static void rv6xx_set_memory_spread_spectrum_clk_v(struct radeon_device *rdev,
+						   u32 clk_v)
+{
+	WREG32_P(CG_MPLL_SPREAD_SPECTRUM, CLKV(clk_v), ~CLKV_MASK);
+}
+
+static void rv6xx_enable_memory_spread_spectrum(struct radeon_device *rdev,
+						bool enable)
+{
+	if (enable)
+		WREG32_P(CG_MPLL_SPREAD_SPECTRUM, SSEN, ~SSEN);
+	else
+		WREG32_P(CG_MPLL_SPREAD_SPECTRUM, 0, ~SSEN);
+}
+
+static void rv6xx_enable_dynamic_spread_spectrum(struct radeon_device *rdev,
+						 bool enable)
+{
+	if (enable)
+		WREG32_P(GENERAL_PWRMGT, DYN_SPREAD_SPECTRUM_EN, ~DYN_SPREAD_SPECTRUM_EN);
+	else
+		WREG32_P(GENERAL_PWRMGT, 0, ~DYN_SPREAD_SPECTRUM_EN);
+}
+
+static void rv6xx_memory_clock_entry_enable_post_divider(struct radeon_device *rdev,
+							 u32 index, bool enable)
+{
+	if (enable)
+		WREG32_P(MPLL_FREQ_LEVEL_0 + (index * 4),
+			 LEVEL0_MPLL_DIV_EN, ~LEVEL0_MPLL_DIV_EN);
+	else
+		WREG32_P(MPLL_FREQ_LEVEL_0 + (index * 4), 0, ~LEVEL0_MPLL_DIV_EN);
+}
+
+static void rv6xx_memory_clock_entry_set_post_divider(struct radeon_device *rdev,
+						      u32 index, u32 divider)
+{
+	WREG32_P(MPLL_FREQ_LEVEL_0 + (index * 4),
+		 LEVEL0_MPLL_POST_DIV(divider), ~LEVEL0_MPLL_POST_DIV_MASK);
+}
+
+static void rv6xx_memory_clock_entry_set_feedback_divider(struct radeon_device *rdev,
+							  u32 index, u32 divider)
+{
+	WREG32_P(MPLL_FREQ_LEVEL_0 + (index * 4), LEVEL0_MPLL_FB_DIV(divider),
+		 ~LEVEL0_MPLL_FB_DIV_MASK);
+}
+
+static void rv6xx_memory_clock_entry_set_reference_divider(struct radeon_device *rdev,
+							   u32 index, u32 divider)
+{
+	WREG32_P(MPLL_FREQ_LEVEL_0 + (index * 4),
+		 LEVEL0_MPLL_REF_DIV(divider), ~LEVEL0_MPLL_REF_DIV_MASK);
+}
+
+static void rv6xx_vid_response_set_brt(struct radeon_device *rdev, u32 rt)
+{
+	WREG32_P(VID_RT, BRT(rt), ~BRT_MASK);
+}
+
+static void rv6xx_enable_engine_feedback_and_reference_sync(struct radeon_device *rdev)
+{
+	WREG32_P(SPLL_CNTL_MODE, SPLL_DIV_SYNC, ~SPLL_DIV_SYNC);
+}
+
+static u64 rv6xx_clocks_per_unit(u32 unit)
+{
+	u64 tmp = 1 << (2 * unit);
+
+	return tmp;
+}
+
+static u32 rv6xx_scale_count_given_unit(struct radeon_device *rdev,
+					u32 unscaled_count, u32 unit)
+{
+	u32 count_per_unit = (u32)rv6xx_clocks_per_unit(unit);
+
+	return (unscaled_count + count_per_unit - 1) / count_per_unit;
+}
+
+static u32 rv6xx_compute_count_for_delay(struct radeon_device *rdev,
+					 u32 delay_us, u32 unit)
+{
+	u32 ref_clk = rdev->clock.spll.reference_freq;
+
+	return rv6xx_scale_count_given_unit(rdev, delay_us * (ref_clk / 100), unit);
+}
+
+static void rv6xx_calculate_engine_speed_stepping_parameters(struct radeon_device *rdev,
+							     struct rv6xx_ps *state)
+{
+	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+	pi->hw.sclks[R600_POWER_LEVEL_LOW] =
+		state->low.sclk;
+	pi->hw.sclks[R600_POWER_LEVEL_MEDIUM] =
+		state->medium.sclk;
+	pi->hw.sclks[R600_POWER_LEVEL_HIGH] =
+		state->high.sclk;
+
+	pi->hw.low_sclk_index = R600_POWER_LEVEL_LOW;
+	pi->hw.medium_sclk_index = R600_POWER_LEVEL_MEDIUM;
+	pi->hw.high_sclk_index = R600_POWER_LEVEL_HIGH;
+}
+
+static void rv6xx_calculate_memory_clock_stepping_parameters(struct radeon_device *rdev,
+							     struct rv6xx_ps *state)
+{
+	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+	pi->hw.mclks[R600_POWER_LEVEL_CTXSW] =
+		state->high.mclk;
+	pi->hw.mclks[R600_POWER_LEVEL_HIGH] =
+		state->high.mclk;
+	pi->hw.mclks[R600_POWER_LEVEL_MEDIUM] =
+		state->medium.mclk;
+	pi->hw.mclks[R600_POWER_LEVEL_LOW] =
+		state->low.mclk;
+
+	pi->hw.high_mclk_index = R600_POWER_LEVEL_HIGH;
+
+	if (state->high.mclk == state->medium.mclk)
+		pi->hw.medium_mclk_index =
+			pi->hw.high_mclk_index;
+	else
+		pi->hw.medium_mclk_index = R600_POWER_LEVEL_MEDIUM;
+
+
+	if (state->medium.mclk == state->low.mclk)
+		pi->hw.low_mclk_index =
+			pi->hw.medium_mclk_index;
+	else
+		pi->hw.low_mclk_index = R600_POWER_LEVEL_LOW;
+}
+
+static void rv6xx_calculate_voltage_stepping_parameters(struct radeon_device *rdev,
+							struct rv6xx_ps *state)
+{
+	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+	pi->hw.vddc[R600_POWER_LEVEL_CTXSW] = state->high.vddc;
+	pi->hw.vddc[R600_POWER_LEVEL_HIGH] = state->high.vddc;
+	pi->hw.vddc[R600_POWER_LEVEL_MEDIUM] = state->medium.vddc;
+	pi->hw.vddc[R600_POWER_LEVEL_LOW] = state->low.vddc;
+
+	pi->hw.backbias[R600_POWER_LEVEL_CTXSW] =
+		(state->high.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) ? true : false;
+	pi->hw.backbias[R600_POWER_LEVEL_HIGH] =
+		(state->high.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) ? true : false;
+	pi->hw.backbias[R600_POWER_LEVEL_MEDIUM] =
+		(state->medium.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) ? true : false;
+	pi->hw.backbias[R600_POWER_LEVEL_LOW] =
+		(state->low.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) ? true : false;
+
+	pi->hw.pcie_gen2[R600_POWER_LEVEL_HIGH] =
+		(state->high.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) ? true : false;
+	pi->hw.pcie_gen2[R600_POWER_LEVEL_MEDIUM] =
+		(state->medium.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) ? true : false;
+	pi->hw.pcie_gen2[R600_POWER_LEVEL_LOW] =
+		(state->low.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) ? true : false;
+
+	pi->hw.high_vddc_index = R600_POWER_LEVEL_HIGH;
+
+	if ((state->high.vddc == state->medium.vddc) &&
+	    ((state->high.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) ==
+	     (state->medium.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE)))
+		pi->hw.medium_vddc_index =
+			pi->hw.high_vddc_index;
+	else
+		pi->hw.medium_vddc_index = R600_POWER_LEVEL_MEDIUM;
+
+	if ((state->medium.vddc == state->low.vddc) &&
+	    ((state->medium.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) ==
+	     (state->low.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE)))
+		pi->hw.low_vddc_index =
+			pi->hw.medium_vddc_index;
+	else
+		pi->hw.medium_vddc_index = R600_POWER_LEVEL_LOW;
+}
+
+static inline u32 rv6xx_calculate_vco_frequency(u32 ref_clock,
+						struct atom_clock_dividers *dividers,
+						u32 fb_divider_scale)
+{
+	return ref_clock * ((dividers->fb_div & ~1) << fb_divider_scale) /
+		(dividers->ref_div + 1);
+}
+
+static inline u32 rv6xx_calculate_spread_spectrum_clk_v(u32 vco_freq, u32 ref_freq,
+							u32 ss_rate, u32 ss_percent,
+							u32 fb_divider_scale)
+{
+	u32 fb_divider = vco_freq / ref_freq;
+
+	return (ss_percent * ss_rate * 4 * (fb_divider * fb_divider) /
+		(5375 * ((vco_freq * 10) / (4096 >> fb_divider_scale))));
+}
+
+static inline u32 rv6xx_calculate_spread_spectrum_clk_s(u32 ss_rate, u32 ref_freq)
+{
+	return (((ref_freq * 10) / (ss_rate * 2)) - 1) / 4;
+}
+
+static void rv6xx_program_engine_spread_spectrum(struct radeon_device *rdev,
+						 u32 clock, enum r600_power_level level)
+{
+	u32 ref_clk = rdev->clock.spll.reference_freq;
+	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+	struct atom_clock_dividers dividers;
+	struct radeon_atom_ss ss;
+	u32 vco_freq, clk_v, clk_s;
+
+	rv6xx_enable_engine_spread_spectrum(rdev, level, false);
+
+	if (clock && pi->sclk_ss) {
+		if (radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, clock, false, &dividers) == 0) {
+			vco_freq = rv6xx_calculate_vco_frequency(ref_clk, &dividers,
+								 pi->fb_div_scale);
+
+			if (radeon_atombios_get_asic_ss_info(rdev, &ss,
+							     ASIC_INTERNAL_ENGINE_SS, vco_freq)) {
+				clk_v = rv6xx_calculate_spread_spectrum_clk_v(vco_freq,
+									      (ref_clk / (dividers.ref_div + 1)),
+									      ss.rate,
+									      ss.percentage,
+									      pi->fb_div_scale);
+
+				clk_s = rv6xx_calculate_spread_spectrum_clk_s(ss.rate,
+									      (ref_clk / (dividers.ref_div + 1)));
+
+				rv6xx_set_engine_spread_spectrum_clk_v(rdev, level, clk_v);
+				rv6xx_set_engine_spread_spectrum_clk_s(rdev, level, clk_s);
+				rv6xx_enable_engine_spread_spectrum(rdev, level, true);
+			}
+		}
+	}
+}
+
+static void rv6xx_program_sclk_spread_spectrum_parameters_except_lowest_entry(struct radeon_device *rdev)
+{
+	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+	rv6xx_program_engine_spread_spectrum(rdev,
+					     pi->hw.sclks[R600_POWER_LEVEL_HIGH],
+					     R600_POWER_LEVEL_HIGH);
+
+	rv6xx_program_engine_spread_spectrum(rdev,
+					     pi->hw.sclks[R600_POWER_LEVEL_MEDIUM],
+					     R600_POWER_LEVEL_MEDIUM);
+
+}
+
+static int rv6xx_program_mclk_stepping_entry(struct radeon_device *rdev,
+					     u32 entry, u32 clock)
+{
+	struct atom_clock_dividers dividers;
+
+	if (radeon_atom_get_clock_dividers(rdev, COMPUTE_MEMORY_PLL_PARAM, clock, false, &dividers))
+	    return -EINVAL;
+
+
+	rv6xx_memory_clock_entry_set_reference_divider(rdev, entry, dividers.ref_div);
+	rv6xx_memory_clock_entry_set_feedback_divider(rdev, entry, dividers.fb_div);
+	rv6xx_memory_clock_entry_set_post_divider(rdev, entry, dividers.post_div);
+
+	if (dividers.enable_post_div)
+		rv6xx_memory_clock_entry_enable_post_divider(rdev, entry, true);
+	else
+		rv6xx_memory_clock_entry_enable_post_divider(rdev, entry, false);
+
+	return 0;
+}
+
+static void rv6xx_program_mclk_stepping_parameters_except_lowest_entry(struct radeon_device *rdev)
+{
+	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+	int i;
+
+	for (i = 1; i < R600_PM_NUMBER_OF_MCLKS; i++) {
+		if (pi->hw.mclks[i])
+			rv6xx_program_mclk_stepping_entry(rdev, i,
+							  pi->hw.mclks[i]);
+	}
+}
+
+static void rv6xx_find_memory_clock_with_highest_vco(struct radeon_device *rdev,
+						     u32 requested_memory_clock,
+						     u32 ref_clk,
+						     struct atom_clock_dividers *dividers,
+						     u32 *vco_freq)
+{
+	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+	struct atom_clock_dividers req_dividers;
+	u32 vco_freq_temp;
+
+	if (radeon_atom_get_clock_dividers(rdev, COMPUTE_MEMORY_PLL_PARAM,
+					   requested_memory_clock, false, &req_dividers) == 0) {
+		vco_freq_temp = rv6xx_calculate_vco_frequency(ref_clk, &req_dividers,
+							      pi->fb_div_scale);
+
+		if (vco_freq_temp > *vco_freq) {
+			*dividers = req_dividers;
+			*vco_freq = vco_freq_temp;
+		}
+	}
+}
+
+static void rv6xx_program_mclk_spread_spectrum_parameters(struct radeon_device *rdev)
+{
+	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+	u32 ref_clk = rdev->clock.mpll.reference_freq;
+	struct atom_clock_dividers dividers;
+	struct radeon_atom_ss ss;
+	u32 vco_freq = 0, clk_v, clk_s;
+
+	rv6xx_enable_memory_spread_spectrum(rdev, false);
+
+	if (pi->mclk_ss) {
+		rv6xx_find_memory_clock_with_highest_vco(rdev,
+							 pi->hw.mclks[pi->hw.high_mclk_index],
+							 ref_clk,
+							 &dividers,
+							 &vco_freq);
+
+		rv6xx_find_memory_clock_with_highest_vco(rdev,
+							 pi->hw.mclks[pi->hw.medium_mclk_index],
+							 ref_clk,
+							 &dividers,
+							 &vco_freq);
+
+		rv6xx_find_memory_clock_with_highest_vco(rdev,
+							 pi->hw.mclks[pi->hw.low_mclk_index],
+							 ref_clk,
+							 &dividers,
+							 &vco_freq);
+
+		if (vco_freq) {
+			if (radeon_atombios_get_asic_ss_info(rdev, &ss,
+							     ASIC_INTERNAL_MEMORY_SS, vco_freq)) {
+				clk_v = rv6xx_calculate_spread_spectrum_clk_v(vco_freq,
+									     (ref_clk / (dividers.ref_div + 1)),
+									     ss.rate,
+									     ss.percentage,
+									     pi->fb_div_scale);
+
+				clk_s = rv6xx_calculate_spread_spectrum_clk_s(ss.rate,
+									     (ref_clk / (dividers.ref_div + 1)));
+
+				rv6xx_set_memory_spread_spectrum_clk_v(rdev, clk_v);
+				rv6xx_set_memory_spread_spectrum_clk_s(rdev, clk_s);
+				rv6xx_enable_memory_spread_spectrum(rdev, true);
+			}
+		}
+	}
+}
+
+static int rv6xx_program_voltage_stepping_entry(struct radeon_device *rdev,
+						u32 entry, u16 voltage)
+{
+	u32 mask, set_pins;
+	int ret;
+
+	ret = radeon_atom_get_voltage_gpio_settings(rdev, voltage,
+						    SET_VOLTAGE_TYPE_ASIC_VDDC,
+						    &set_pins, &mask);
+	if (ret)
+		return ret;
+
+	r600_voltage_control_program_voltages(rdev, entry, set_pins);
+
+	return 0;
+}
+
+static void rv6xx_program_voltage_stepping_parameters_except_lowest_entry(struct radeon_device *rdev)
+{
+	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+	int i;
+
+	for (i = 1; i < R600_PM_NUMBER_OF_VOLTAGE_LEVELS; i++)
+		rv6xx_program_voltage_stepping_entry(rdev, i,
+						     pi->hw.vddc[i]);
+
+}
+
+static void rv6xx_program_backbias_stepping_parameters_except_lowest_entry(struct radeon_device *rdev)
+{
+	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+	if (pi->hw.backbias[1])
+		WREG32_P(VID_UPPER_GPIO_CNTL, MEDIUM_BACKBIAS_VALUE, ~MEDIUM_BACKBIAS_VALUE);
+	else
+		WREG32_P(VID_UPPER_GPIO_CNTL, 0, ~MEDIUM_BACKBIAS_VALUE);
+
+	if (pi->hw.backbias[2])
+		WREG32_P(VID_UPPER_GPIO_CNTL, HIGH_BACKBIAS_VALUE, ~HIGH_BACKBIAS_VALUE);
+	else
+		WREG32_P(VID_UPPER_GPIO_CNTL, 0, ~HIGH_BACKBIAS_VALUE);
+}
+
+static void rv6xx_program_sclk_spread_spectrum_parameters_lowest_entry(struct radeon_device *rdev)
+{
+	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+	rv6xx_program_engine_spread_spectrum(rdev,
+					     pi->hw.sclks[R600_POWER_LEVEL_LOW],
+					     R600_POWER_LEVEL_LOW);
+}
+
+static void rv6xx_program_mclk_stepping_parameters_lowest_entry(struct radeon_device *rdev)
+{
+	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+	if (pi->hw.mclks[0])
+		rv6xx_program_mclk_stepping_entry(rdev, 0,
+						  pi->hw.mclks[0]);
+}
+
+static void rv6xx_program_voltage_stepping_parameters_lowest_entry(struct radeon_device *rdev)
+{
+	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+	rv6xx_program_voltage_stepping_entry(rdev, 0,
+					     pi->hw.vddc[0]);
+
+}
+
+static void rv6xx_program_backbias_stepping_parameters_lowest_entry(struct radeon_device *rdev)
+{
+	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+	if (pi->hw.backbias[0])
+		WREG32_P(VID_UPPER_GPIO_CNTL, LOW_BACKBIAS_VALUE, ~LOW_BACKBIAS_VALUE);
+	else
+		WREG32_P(VID_UPPER_GPIO_CNTL, 0, ~LOW_BACKBIAS_VALUE);
+}
+
+static u32 calculate_memory_refresh_rate(struct radeon_device *rdev,
+					 u32 engine_clock)
+{
+	u32 dram_rows, dram_refresh_rate;
+	u32 tmp;
+
+	tmp = (RREG32(RAMCFG) & NOOFROWS_MASK) >> NOOFROWS_SHIFT;
+	dram_rows = 1 << (tmp + 10);
+	dram_refresh_rate = 1 << ((RREG32(MC_SEQ_RESERVE_M) & 0x3) + 3);
+
+	return ((engine_clock * 10) * dram_refresh_rate / dram_rows - 32) / 64;
+}
+
+static void rv6xx_program_memory_timing_parameters(struct radeon_device *rdev)
+{
+	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+	u32 sqm_ratio;
+	u32 arb_refresh_rate;
+	u32 high_clock;
+
+	if (pi->hw.sclks[R600_POWER_LEVEL_HIGH] <
+	    (pi->hw.sclks[R600_POWER_LEVEL_LOW] * 0xFF / 0x40))
+		high_clock = pi->hw.sclks[R600_POWER_LEVEL_HIGH];
+	else
+		high_clock =
+			pi->hw.sclks[R600_POWER_LEVEL_LOW] * 0xFF / 0x40;
+
+	radeon_atom_set_engine_dram_timings(rdev, high_clock, 0);
+
+	sqm_ratio = (STATE0(64 * high_clock / pi->hw.sclks[R600_POWER_LEVEL_LOW]) |
+		     STATE1(64 * high_clock / pi->hw.sclks[R600_POWER_LEVEL_MEDIUM]) |
+		     STATE2(64 * high_clock / pi->hw.sclks[R600_POWER_LEVEL_HIGH]) |
+		     STATE3(64 * high_clock / pi->hw.sclks[R600_POWER_LEVEL_HIGH]));
+	WREG32(SQM_RATIO, sqm_ratio);
+
+	arb_refresh_rate =
+		(POWERMODE0(calculate_memory_refresh_rate(rdev,
+							  pi->hw.sclks[R600_POWER_LEVEL_LOW])) |
+		 POWERMODE1(calculate_memory_refresh_rate(rdev,
+							  pi->hw.sclks[R600_POWER_LEVEL_MEDIUM])) |
+		 POWERMODE2(calculate_memory_refresh_rate(rdev,
+							  pi->hw.sclks[R600_POWER_LEVEL_MEDIUM])) |
+		 POWERMODE3(calculate_memory_refresh_rate(rdev,
+							  pi->hw.sclks[R600_POWER_LEVEL_HIGH])));
+	WREG32(ARB_RFSH_RATE, arb_refresh_rate);
+}
+
+static void rv6xx_program_mpll_timing_parameters(struct radeon_device *rdev)
+{
+	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+	r600_set_mpll_lock_time(rdev, R600_MPLLLOCKTIME_DFLT *
+				pi->mpll_ref_div);
+	r600_set_mpll_reset_time(rdev, R600_MPLLRESETTIME_DFLT);
+}
+
+static void rv6xx_program_bsp(struct radeon_device *rdev)
+{
+	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+	u32 ref_clk = rdev->clock.spll.reference_freq;
+
+	r600_calculate_u_and_p(R600_ASI_DFLT,
+			       ref_clk, 16,
+			       &pi->bsp,
+			       &pi->bsu);
+
+	r600_set_bsp(rdev, pi->bsu, pi->bsp);
+}
+
+static void rv6xx_program_at(struct radeon_device *rdev)
+{
+	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+	r600_set_at(rdev,
+		    (pi->hw.rp[0] * pi->bsp) / 200,
+		    (pi->hw.rp[1] * pi->bsp) / 200,
+		    (pi->hw.lp[2] * pi->bsp) / 200,
+		    (pi->hw.lp[1] * pi->bsp) / 200);
+}
+
+static void rv6xx_program_git(struct radeon_device *rdev)
+{
+	r600_set_git(rdev, R600_GICST_DFLT);
+}
+
+static void rv6xx_program_tp(struct radeon_device *rdev)
+{
+	int i;
+
+	for (i = 0; i < R600_PM_NUMBER_OF_TC; i++)
+		r600_set_tc(rdev, i, r600_utc[i], r600_dtc[i]);
+
+	r600_select_td(rdev, R600_TD_DFLT);
+}
+
+static void rv6xx_program_vc(struct radeon_device *rdev)
+{
+	r600_set_vrc(rdev, R600_VRC_DFLT);
+}
+
+static void rv6xx_clear_vc(struct radeon_device *rdev)
+{
+	r600_set_vrc(rdev, 0);
+}
+
+static void rv6xx_program_tpp(struct radeon_device *rdev)
+{
+	r600_set_tpu(rdev, R600_TPU_DFLT);
+	r600_set_tpc(rdev, R600_TPC_DFLT);
+}
+
+static void rv6xx_program_sstp(struct radeon_device *rdev)
+{
+	r600_set_sstu(rdev, R600_SSTU_DFLT);
+	r600_set_sst(rdev, R600_SST_DFLT);
+}
+
+static void rv6xx_program_fcp(struct radeon_device *rdev)
+{
+	r600_set_fctu(rdev, R600_FCTU_DFLT);
+	r600_set_fct(rdev, R600_FCT_DFLT);
+}
+
+static void rv6xx_program_vddc3d_parameters(struct radeon_device *rdev)
+{
+	r600_set_vddc3d_oorsu(rdev, R600_VDDC3DOORSU_DFLT);
+	r600_set_vddc3d_oorphc(rdev, R600_VDDC3DOORPHC_DFLT);
+	r600_set_vddc3d_oorsdc(rdev, R600_VDDC3DOORSDC_DFLT);
+	r600_set_ctxcgtt3d_rphc(rdev, R600_CTXCGTT3DRPHC_DFLT);
+	r600_set_ctxcgtt3d_rsdc(rdev, R600_CTXCGTT3DRSDC_DFLT);
+}
+
+static void rv6xx_program_voltage_timing_parameters(struct radeon_device *rdev)
+{
+	u32 rt;
+
+	r600_vid_rt_set_vru(rdev, R600_VRU_DFLT);
+
+	r600_vid_rt_set_vrt(rdev,
+			    rv6xx_compute_count_for_delay(rdev,
+							  rdev->pm.dpm.voltage_response_time,
+							  R600_VRU_DFLT));
+
+	rt = rv6xx_compute_count_for_delay(rdev,
+					   rdev->pm.dpm.backbias_response_time,
+					   R600_VRU_DFLT);
+
+	rv6xx_vid_response_set_brt(rdev, (rt + 0x1F) >> 5);
+}
+
+static void rv6xx_program_engine_speed_parameters(struct radeon_device *rdev)
+{
+	r600_vid_rt_set_ssu(rdev, R600_SPLLSTEPUNIT_DFLT);
+	rv6xx_enable_engine_feedback_and_reference_sync(rdev);
+}
+
+static u64 rv6xx_get_master_voltage_mask(struct radeon_device *rdev)
+{
+	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+	u64 master_mask = 0;
+	int i;
+
+	for (i = 0; i < R600_PM_NUMBER_OF_VOLTAGE_LEVELS; i++) {
+		u32 tmp_mask, tmp_set_pins;
+		int ret;
+
+		ret = radeon_atom_get_voltage_gpio_settings(rdev,
+							    pi->hw.vddc[i],
+							    SET_VOLTAGE_TYPE_ASIC_VDDC,
+							    &tmp_set_pins, &tmp_mask);
+
+		if (ret == 0)
+			master_mask |= tmp_mask;
+	}
+
+	return master_mask;
+}
+
+static void rv6xx_program_voltage_gpio_pins(struct radeon_device *rdev)
+{
+	r600_voltage_control_enable_pins(rdev,
+					 rv6xx_get_master_voltage_mask(rdev));
+}
+
+static void rv6xx_enable_static_voltage_control(struct radeon_device *rdev, bool enable)
+{
+	struct rv6xx_ps *new_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps);
+
+	if (enable)
+		radeon_atom_set_voltage(rdev,
+					new_state->low.vddc,
+					SET_VOLTAGE_TYPE_ASIC_VDDC);
+	else
+		r600_voltage_control_deactivate_static_control(rdev,
+							       rv6xx_get_master_voltage_mask(rdev));
+}
+
+static void rv6xx_enable_display_gap(struct radeon_device *rdev, bool enable)
+{
+	if (enable) {
+		u32 tmp = (DISP1_GAP(R600_PM_DISPLAY_GAP_VBLANK_OR_WM) |
+			   DISP2_GAP(R600_PM_DISPLAY_GAP_VBLANK_OR_WM) |
+			   DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE) |
+			   DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE) |
+			   VBI_TIMER_COUNT(0x3FFF) |
+			   VBI_TIMER_UNIT(7));
+		WREG32(CG_DISPLAY_GAP_CNTL, tmp);
+
+		WREG32_P(MCLK_PWRMGT_CNTL, USE_DISPLAY_GAP, ~USE_DISPLAY_GAP);
+	} else
+		WREG32_P(MCLK_PWRMGT_CNTL, 0, ~USE_DISPLAY_GAP);
+}
+
+static void rv6xx_program_power_level_enter_state(struct radeon_device *rdev)
+{
+	r600_power_level_set_enter_index(rdev, R600_POWER_LEVEL_MEDIUM);
+}
+
+static void rv6xx_calculate_t(u32 l_f, u32 h_f, int h,
+			      int d_l, int d_r, u8 *l, u8 *r)
+{
+	int a_n, a_d, h_r, l_r;
+
+	h_r = d_l;
+	l_r = 100 - d_r;
+
+	a_n = (int)h_f * d_l + (int)l_f * (h - d_r);
+	a_d = (int)l_f * l_r + (int)h_f * h_r;
+
+	if (a_d != 0) {
+		*l = d_l - h_r * a_n / a_d;
+		*r = d_r + l_r * a_n / a_d;
+	}
+}
+
+static void rv6xx_calculate_ap(struct radeon_device *rdev,
+			       struct rv6xx_ps *state)
+{
+	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+	pi->hw.lp[0] = 0;
+	pi->hw.rp[R600_PM_NUMBER_OF_ACTIVITY_LEVELS - 1]
+		= 100;
+
+	rv6xx_calculate_t(state->low.sclk,
+			  state->medium.sclk,
+			  R600_AH_DFLT,
+			  R600_LMP_DFLT,
+			  R600_RLP_DFLT,
+			  &pi->hw.lp[1],
+			  &pi->hw.rp[0]);
+
+	rv6xx_calculate_t(state->medium.sclk,
+			  state->high.sclk,
+			  R600_AH_DFLT,
+			  R600_LHP_DFLT,
+			  R600_RMP_DFLT,
+			  &pi->hw.lp[2],
+			  &pi->hw.rp[1]);
+
+}
+
+static void rv6xx_calculate_stepping_parameters(struct radeon_device *rdev)
+{
+	struct rv6xx_ps *new_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps);
+
+	rv6xx_calculate_engine_speed_stepping_parameters(rdev, new_state);
+	rv6xx_calculate_memory_clock_stepping_parameters(rdev, new_state);
+	rv6xx_calculate_voltage_stepping_parameters(rdev, new_state);
+	rv6xx_calculate_ap(rdev, new_state);
+}
+
+static void rv6xx_program_stepping_parameters_except_lowest_entry(struct radeon_device *rdev)
+{
+	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+	rv6xx_program_mclk_stepping_parameters_except_lowest_entry(rdev);
+	if (pi->voltage_control)
+		rv6xx_program_voltage_stepping_parameters_except_lowest_entry(rdev);
+	rv6xx_program_backbias_stepping_parameters_except_lowest_entry(rdev);
+	rv6xx_program_sclk_spread_spectrum_parameters_except_lowest_entry(rdev);
+	rv6xx_program_mclk_spread_spectrum_parameters(rdev);
+	rv6xx_program_memory_timing_parameters(rdev);
+}
+
+static void rv6xx_program_stepping_parameters_lowest_entry(struct radeon_device *rdev)
+{
+	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+	rv6xx_program_mclk_stepping_parameters_lowest_entry(rdev);
+	if (pi->voltage_control)
+		rv6xx_program_voltage_stepping_parameters_lowest_entry(rdev);
+	rv6xx_program_backbias_stepping_parameters_lowest_entry(rdev);
+	rv6xx_program_sclk_spread_spectrum_parameters_lowest_entry(rdev);
+}
+
+static void rv6xx_program_power_level_low(struct radeon_device *rdev)
+{
+	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+	r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_LOW,
+					   pi->hw.low_vddc_index);
+	r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_LOW,
+					     pi->hw.low_mclk_index);
+	r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_LOW,
+					     pi->hw.low_sclk_index);
+	r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_LOW,
+					  R600_DISPLAY_WATERMARK_LOW);
+	r600_power_level_set_pcie_gen2(rdev, R600_POWER_LEVEL_LOW,
+				       pi->hw.pcie_gen2[R600_POWER_LEVEL_LOW]);
+}
+
+static void rv6xx_program_power_level_low_to_lowest_state(struct radeon_device *rdev)
+{
+	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+	r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_LOW, 0);
+	r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_LOW, 0);
+	r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_LOW, 0);
+
+	r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_LOW,
+					  R600_DISPLAY_WATERMARK_LOW);
+
+	r600_power_level_set_pcie_gen2(rdev, R600_POWER_LEVEL_LOW,
+				       pi->hw.pcie_gen2[R600_POWER_LEVEL_LOW]);
+
+}
+
+static void rv6xx_program_power_level_medium(struct radeon_device *rdev)
+{
+	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+	r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_MEDIUM,
+					  pi->hw.medium_vddc_index);
+	r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_MEDIUM,
+					    pi->hw.medium_mclk_index);
+	r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_MEDIUM,
+					    pi->hw.medium_sclk_index);
+	r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_MEDIUM,
+					 R600_DISPLAY_WATERMARK_LOW);
+	r600_power_level_set_pcie_gen2(rdev, R600_POWER_LEVEL_MEDIUM,
+				      pi->hw.pcie_gen2[R600_POWER_LEVEL_MEDIUM]);
+}
+
+static void rv6xx_program_power_level_medium_for_transition(struct radeon_device *rdev)
+{
+	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+	rv6xx_program_mclk_stepping_entry(rdev,
+					  R600_POWER_LEVEL_CTXSW,
+					  pi->hw.mclks[pi->hw.low_mclk_index]);
+
+	r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_MEDIUM, 1);
+
+	r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_MEDIUM,
+					     R600_POWER_LEVEL_CTXSW);
+	r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_MEDIUM,
+					     pi->hw.medium_sclk_index);
+
+	r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_MEDIUM,
+					  R600_DISPLAY_WATERMARK_LOW);
+
+	rv6xx_enable_engine_spread_spectrum(rdev, R600_POWER_LEVEL_MEDIUM, false);
+
+	r600_power_level_set_pcie_gen2(rdev, R600_POWER_LEVEL_MEDIUM,
+				       pi->hw.pcie_gen2[R600_POWER_LEVEL_LOW]);
+}
+
+static void rv6xx_program_power_level_high(struct radeon_device *rdev)
+{
+	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+	r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_HIGH,
+					   pi->hw.high_vddc_index);
+	r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_HIGH,
+					     pi->hw.high_mclk_index);
+	r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_HIGH,
+					     pi->hw.high_sclk_index);
+
+	r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_HIGH,
+					  R600_DISPLAY_WATERMARK_HIGH);
+
+	r600_power_level_set_pcie_gen2(rdev, R600_POWER_LEVEL_HIGH,
+				       pi->hw.pcie_gen2[R600_POWER_LEVEL_HIGH]);
+}
+
+static void rv6xx_enable_backbias(struct radeon_device *rdev, bool enable)
+{
+	if (enable)
+		WREG32_P(GENERAL_PWRMGT, BACKBIAS_PAD_EN | BACKBIAS_DPM_CNTL,
+			 ~(BACKBIAS_PAD_EN | BACKBIAS_DPM_CNTL));
+	else
+		WREG32_P(GENERAL_PWRMGT, 0,
+			 ~(BACKBIAS_VALUE | BACKBIAS_PAD_EN | BACKBIAS_DPM_CNTL));
+}
+
+static void rv6xx_program_display_gap(struct radeon_device *rdev)
+{
+	u32 tmp = RREG32(CG_DISPLAY_GAP_CNTL);
+
+	tmp &= ~(DISP1_GAP_MCHG_MASK | DISP2_GAP_MCHG_MASK);
+	if (RREG32(AVIVO_D1CRTC_CONTROL) & AVIVO_CRTC_EN) {
+		tmp |= DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK);
+		tmp |= DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE);
+	} else if (RREG32(AVIVO_D2CRTC_CONTROL) & AVIVO_CRTC_EN) {
+		tmp |= DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE);
+		tmp |= DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK);
+	} else {
+		tmp |= DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE);
+		tmp |= DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE);
+	}
+	WREG32(CG_DISPLAY_GAP_CNTL, tmp);
+}
+
+static void rv6xx_set_sw_voltage_to_safe(struct radeon_device *rdev)
+{
+	struct rv6xx_ps *new_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps);
+	struct rv6xx_ps *old_state = rv6xx_get_ps(rdev->pm.dpm.current_ps);
+	u16 safe_voltage;
+
+	safe_voltage = (new_state->low.vddc >= old_state->low.vddc) ?
+		new_state->low.vddc : old_state->low.vddc;
+
+	rv6xx_program_voltage_stepping_entry(rdev, R600_POWER_LEVEL_CTXSW,
+					     safe_voltage);
+
+	WREG32_P(GENERAL_PWRMGT, SW_GPIO_INDEX(R600_POWER_LEVEL_CTXSW),
+		 ~SW_GPIO_INDEX_MASK);
+}
+
+static void rv6xx_set_sw_voltage_to_low(struct radeon_device *rdev)
+{
+	struct rv6xx_ps *old_state = rv6xx_get_ps(rdev->pm.dpm.current_ps);
+
+	rv6xx_program_voltage_stepping_entry(rdev, R600_POWER_LEVEL_CTXSW,
+					     old_state->low.vddc);
+
+	WREG32_P(GENERAL_PWRMGT, SW_GPIO_INDEX(R600_POWER_LEVEL_CTXSW),
+		~SW_GPIO_INDEX_MASK);
+}
+
+static void rv6xx_set_safe_backbias(struct radeon_device *rdev)
+{
+	struct rv6xx_ps *new_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps);
+	struct rv6xx_ps *old_state = rv6xx_get_ps(rdev->pm.dpm.current_ps);
+
+	if ((new_state->low.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) &&
+	    (old_state->low.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE))
+		WREG32_P(GENERAL_PWRMGT, BACKBIAS_VALUE, ~BACKBIAS_VALUE);
+	else
+		WREG32_P(GENERAL_PWRMGT, 0, ~BACKBIAS_VALUE);
+}
+
+static void rv6xx_set_safe_pcie_gen2(struct radeon_device *rdev)
+{
+	struct rv6xx_ps *new_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps);
+	struct rv6xx_ps *old_state = rv6xx_get_ps(rdev->pm.dpm.current_ps);
+
+	if ((new_state->low.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) !=
+	    (old_state->low.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2))
+		rv6xx_force_pcie_gen1(rdev);
+}
+
+static void rv6xx_enable_dynamic_voltage_control(struct radeon_device *rdev,
+						 bool enable)
+{
+	if (enable)
+		WREG32_P(GENERAL_PWRMGT, VOLT_PWRMGT_EN, ~VOLT_PWRMGT_EN);
+	else
+		WREG32_P(GENERAL_PWRMGT, 0, ~VOLT_PWRMGT_EN);
+}
+
+static void rv6xx_enable_dynamic_backbias_control(struct radeon_device *rdev,
+						  bool enable)
+{
+	if (enable)
+		WREG32_P(GENERAL_PWRMGT, BACKBIAS_DPM_CNTL, ~BACKBIAS_DPM_CNTL);
+	else
+		WREG32_P(GENERAL_PWRMGT, 0, ~BACKBIAS_DPM_CNTL);
+}
+
+static int rv6xx_step_sw_voltage(struct radeon_device *rdev,
+				 u16 initial_voltage,
+				 u16 target_voltage)
+{
+	u16 current_voltage;
+	u16 true_target_voltage;
+	u16 voltage_step;
+	int signed_voltage_step;
+
+	if ((radeon_atom_get_voltage_step(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC,
+					  &voltage_step)) ||
+	    (radeon_atom_round_to_true_voltage(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC,
+					       initial_voltage, &current_voltage)) ||
+	    (radeon_atom_round_to_true_voltage(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC,
+					       target_voltage, &true_target_voltage)))
+		return -EINVAL;
+
+	if (true_target_voltage < current_voltage)
+		signed_voltage_step = -(int)voltage_step;
+	else
+		signed_voltage_step = voltage_step;
+
+	while (current_voltage != true_target_voltage) {
+		current_voltage += signed_voltage_step;
+		rv6xx_program_voltage_stepping_entry(rdev, R600_POWER_LEVEL_CTXSW,
+						     current_voltage);
+		msleep((rdev->pm.dpm.voltage_response_time + 999) / 1000);
+	}
+
+	return 0;
+}
+
+static int rv6xx_step_voltage_if_increasing(struct radeon_device *rdev)
+{
+	struct rv6xx_ps *new_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps);
+	struct rv6xx_ps *old_state = rv6xx_get_ps(rdev->pm.dpm.current_ps);
+
+	if (new_state->low.vddc > old_state->low.vddc)
+		return rv6xx_step_sw_voltage(rdev,
+					     old_state->low.vddc,
+					     new_state->low.vddc);
+
+	return 0;
+}
+
+static int rv6xx_step_voltage_if_decreasing(struct radeon_device *rdev)
+{
+	struct rv6xx_ps *new_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps);
+	struct rv6xx_ps *old_state = rv6xx_get_ps(rdev->pm.dpm.current_ps);
+
+	if (new_state->low.vddc < old_state->low.vddc)
+		return rv6xx_step_sw_voltage(rdev,
+					     old_state->low.vddc,
+					     new_state->low.vddc);
+	else
+		return 0;
+}
+
+static void rv6xx_enable_high(struct radeon_device *rdev)
+{
+	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+	if ((pi->restricted_levels < 1) ||
+	    (pi->restricted_levels == 3))
+		r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, true);
+}
+
+static void rv6xx_enable_medium(struct radeon_device *rdev)
+{
+	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+	if (pi->restricted_levels < 2)
+		r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, true);
+}
+
+static void rv6xx_set_dpm_event_sources(struct radeon_device *rdev, u32 sources)
+{
+	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+	bool want_thermal_protection;
+	enum radeon_dpm_event_src dpm_event_src;
+
+	switch (sources) {
+        case 0:
+        default:
+		want_thermal_protection = false;
+		break;
+        case (1 << RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL):
+		want_thermal_protection = true;
+		dpm_event_src = RADEON_DPM_EVENT_SRC_DIGITAL;
+		break;
+
+        case (1 << RADEON_DPM_AUTO_THROTTLE_SRC_EXTERNAL):
+		want_thermal_protection = true;
+		dpm_event_src = RADEON_DPM_EVENT_SRC_EXTERNAL;
+		break;
+
+        case ((1 << RADEON_DPM_AUTO_THROTTLE_SRC_EXTERNAL) |
+	      (1 << RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL)):
+		want_thermal_protection = true;
+		dpm_event_src = RADEON_DPM_EVENT_SRC_DIGIAL_OR_EXTERNAL;
+		break;
+	}
+
+	if (want_thermal_protection) {
+		WREG32_P(CG_THERMAL_CTRL, DPM_EVENT_SRC(dpm_event_src), ~DPM_EVENT_SRC_MASK);
+		if (pi->thermal_protection)
+			WREG32_P(GENERAL_PWRMGT, 0, ~THERMAL_PROTECTION_DIS);
+	} else {
+		WREG32_P(GENERAL_PWRMGT, THERMAL_PROTECTION_DIS, ~THERMAL_PROTECTION_DIS);
+	}
+}
+
+static void rv6xx_enable_auto_throttle_source(struct radeon_device *rdev,
+					      enum radeon_dpm_auto_throttle_src source,
+					      bool enable)
+{
+	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+	if (enable) {
+		if (!(pi->active_auto_throttle_sources & (1 << source))) {
+			pi->active_auto_throttle_sources |= 1 << source;
+			rv6xx_set_dpm_event_sources(rdev, pi->active_auto_throttle_sources);
+		}
+	} else {
+		if (pi->active_auto_throttle_sources & (1 << source)) {
+			pi->active_auto_throttle_sources &= ~(1 << source);
+			rv6xx_set_dpm_event_sources(rdev, pi->active_auto_throttle_sources);
+		}
+	}
+}
+
+
+static void rv6xx_enable_thermal_protection(struct radeon_device *rdev,
+					    bool enable)
+{
+	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+	if (pi->active_auto_throttle_sources)
+		r600_enable_thermal_protection(rdev, enable);
+}
+
+static void rv6xx_generate_transition_stepping(struct radeon_device *rdev)
+{
+	struct rv6xx_ps *new_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps);
+	struct rv6xx_ps *old_state = rv6xx_get_ps(rdev->pm.dpm.current_ps);
+	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+	rv6xx_generate_steps(rdev,
+			     old_state->low.sclk,
+			     new_state->low.sclk,
+			     0, &pi->hw.medium_sclk_index);
+}
+
+static void rv6xx_generate_low_step(struct radeon_device *rdev)
+{
+	struct rv6xx_ps *new_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps);
+	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+	pi->hw.low_sclk_index = 0;
+	rv6xx_generate_single_step(rdev,
+				   new_state->low.sclk,
+				   0);
+}
+
+static void rv6xx_invalidate_intermediate_steps(struct radeon_device *rdev)
+{
+	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+	rv6xx_invalidate_intermediate_steps_range(rdev, 0,
+						  pi->hw.medium_sclk_index);
+}
+
+static void rv6xx_generate_stepping_table(struct radeon_device *rdev)
+{
+	struct rv6xx_ps *new_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps);
+	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+	pi->hw.low_sclk_index = 0;
+
+	rv6xx_generate_steps(rdev,
+			     new_state->low.sclk,
+			     new_state->medium.sclk,
+			     0,
+			     &pi->hw.medium_sclk_index);
+	rv6xx_generate_steps(rdev,
+			     new_state->medium.sclk,
+			     new_state->high.sclk,
+			     pi->hw.medium_sclk_index,
+			     &pi->hw.high_sclk_index);
+}
+
+static void rv6xx_enable_spread_spectrum(struct radeon_device *rdev,
+					 bool enable)
+{
+	if (enable)
+		rv6xx_enable_dynamic_spread_spectrum(rdev, true);
+	else {
+		rv6xx_enable_engine_spread_spectrum(rdev, R600_POWER_LEVEL_LOW, false);
+		rv6xx_enable_engine_spread_spectrum(rdev, R600_POWER_LEVEL_MEDIUM, false);
+		rv6xx_enable_engine_spread_spectrum(rdev, R600_POWER_LEVEL_HIGH, false);
+		rv6xx_enable_dynamic_spread_spectrum(rdev, false);
+		rv6xx_enable_memory_spread_spectrum(rdev, false);
+	}
+}
+
+static void rv6xx_reset_lvtm_data_sync(struct radeon_device *rdev)
+{
+	if (ASIC_IS_DCE3(rdev))
+		WREG32_P(DCE3_LVTMA_DATA_SYNCHRONIZATION, LVTMA_PFREQCHG, ~LVTMA_PFREQCHG);
+	else
+		WREG32_P(LVTMA_DATA_SYNCHRONIZATION, LVTMA_PFREQCHG, ~LVTMA_PFREQCHG);
+}
+
+static void rv6xx_enable_dynamic_pcie_gen2(struct radeon_device *rdev,
+					   bool enable)
+{
+	struct rv6xx_ps *new_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps);
+
+	if (enable) {
+		rv6xx_enable_bif_dynamic_pcie_gen2(rdev, true);
+		rv6xx_enable_pcie_gen2_support(rdev);
+		r600_enable_dynamic_pcie_gen2(rdev, true);
+	} else {
+		if (!(new_state->low.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2))
+			rv6xx_force_pcie_gen1(rdev);
+		rv6xx_enable_bif_dynamic_pcie_gen2(rdev, false);
+		r600_enable_dynamic_pcie_gen2(rdev, false);
+	}
+}
+
+int rv6xx_dpm_enable(struct radeon_device *rdev)
+{
+	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+	if (r600_dynamicpm_enabled(rdev))
+		return -EINVAL;
+
+	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS)
+		rv6xx_enable_backbias(rdev, true);
+
+	if (pi->dynamic_ss)
+		rv6xx_enable_spread_spectrum(rdev, true);
+
+	rv6xx_program_mpll_timing_parameters(rdev);
+	rv6xx_program_bsp(rdev);
+	rv6xx_program_git(rdev);
+	rv6xx_program_tp(rdev);
+	rv6xx_program_tpp(rdev);
+	rv6xx_program_sstp(rdev);
+	rv6xx_program_fcp(rdev);
+	rv6xx_program_vddc3d_parameters(rdev);
+	rv6xx_program_voltage_timing_parameters(rdev);
+	rv6xx_program_engine_speed_parameters(rdev);
+
+	rv6xx_enable_display_gap(rdev, true);
+	if (pi->display_gap == false)
+		rv6xx_enable_display_gap(rdev, false);
+
+	rv6xx_program_power_level_enter_state(rdev);
+
+	rv6xx_calculate_stepping_parameters(rdev);
+
+	if (pi->voltage_control)
+		rv6xx_program_voltage_gpio_pins(rdev);
+
+	rv6xx_generate_stepping_table(rdev);
+
+	rv6xx_program_stepping_parameters_except_lowest_entry(rdev);
+	rv6xx_program_stepping_parameters_lowest_entry(rdev);
+
+	rv6xx_program_power_level_low(rdev);
+	rv6xx_program_power_level_medium(rdev);
+	rv6xx_program_power_level_high(rdev);
+	rv6xx_program_vc(rdev);
+	rv6xx_program_at(rdev);
+
+	r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true);
+	r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, true);
+	r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, true);
+
+	if (rdev->irq.installed &&
+	    r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
+		r600_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
+		rdev->irq.dpm_thermal = true;
+		radeon_irq_set(rdev);
+	}
+
+	rv6xx_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true);
+
+	r600_start_dpm(rdev);
+
+	if (pi->voltage_control)
+		rv6xx_enable_static_voltage_control(rdev, false);
+
+	if (pi->dynamic_pcie_gen2)
+		rv6xx_enable_dynamic_pcie_gen2(rdev, true);
+
+	if (pi->gfx_clock_gating)
+		r600_gfx_clockgating_enable(rdev, true);
+
+	return 0;
+}
+
+void rv6xx_dpm_disable(struct radeon_device *rdev)
+{
+	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+	if (!r600_dynamicpm_enabled(rdev))
+		return;
+
+	r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true);
+	r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, true);
+	rv6xx_enable_display_gap(rdev, false);
+	rv6xx_clear_vc(rdev);
+	r600_set_at(rdev, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF);
+
+	if (pi->thermal_protection)
+		r600_enable_thermal_protection(rdev, false);
+
+	r600_wait_for_power_level(rdev, R600_POWER_LEVEL_LOW);
+	r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, false);
+	r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, false);
+
+	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS)
+		rv6xx_enable_backbias(rdev, false);
+
+	rv6xx_enable_spread_spectrum(rdev, false);
+
+	if (pi->voltage_control)
+		rv6xx_enable_static_voltage_control(rdev, true);
+
+	if (pi->dynamic_pcie_gen2)
+		rv6xx_enable_dynamic_pcie_gen2(rdev, false);
+
+	if (rdev->irq.installed &&
+	    r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
+		rdev->irq.dpm_thermal = false;
+		radeon_irq_set(rdev);
+	}
+
+	if (pi->gfx_clock_gating)
+		r600_gfx_clockgating_enable(rdev, false);
+
+	r600_stop_dpm(rdev);
+}
+
+int rv6xx_dpm_set_power_state(struct radeon_device *rdev)
+{
+	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+	rv6xx_clear_vc(rdev);
+	r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true);
+	r600_set_at(rdev, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF);
+
+	if (pi->thermal_protection)
+		r600_enable_thermal_protection(rdev, false);
+
+	r600_wait_for_power_level(rdev, R600_POWER_LEVEL_LOW);
+	r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, false);
+	r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, false);
+
+	rv6xx_generate_transition_stepping(rdev);
+	rv6xx_program_power_level_medium_for_transition(rdev);
+
+	if (pi->voltage_control) {
+		rv6xx_set_sw_voltage_to_safe(rdev);
+		if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC)
+			rv6xx_set_sw_voltage_to_low(rdev);
+	}
+
+	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS)
+		rv6xx_set_safe_backbias(rdev);
+
+	if (pi->dynamic_pcie_gen2)
+		rv6xx_set_safe_pcie_gen2(rdev);
+
+	if (pi->voltage_control)
+		rv6xx_enable_dynamic_voltage_control(rdev, false);
+
+	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS)
+		rv6xx_enable_dynamic_backbias_control(rdev, false);
+
+	if (pi->voltage_control) {
+		if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC)
+			rv6xx_step_voltage_if_increasing(rdev);
+		msleep((rdev->pm.dpm.voltage_response_time + 999) / 1000);
+	}
+
+	r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, true);
+	r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, false);
+	r600_wait_for_power_level_unequal(rdev, R600_POWER_LEVEL_LOW);
+
+	rv6xx_generate_low_step(rdev);
+	rv6xx_invalidate_intermediate_steps(rdev);
+	rv6xx_calculate_stepping_parameters(rdev);
+	rv6xx_program_stepping_parameters_lowest_entry(rdev);
+	rv6xx_program_power_level_low_to_lowest_state(rdev);
+
+	r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true);
+	r600_wait_for_power_level(rdev, R600_POWER_LEVEL_LOW);
+	r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, false);
+
+	if (pi->voltage_control) {
+		if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC)
+			rv6xx_step_voltage_if_decreasing(rdev);
+		rv6xx_enable_dynamic_voltage_control(rdev, true);
+	}
+
+	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS)
+		rv6xx_enable_dynamic_backbias_control(rdev, true);
+
+	if (pi->dynamic_pcie_gen2)
+		rv6xx_enable_dynamic_pcie_gen2(rdev, true);
+
+	rv6xx_reset_lvtm_data_sync(rdev);
+
+	rv6xx_generate_stepping_table(rdev);
+	rv6xx_program_stepping_parameters_except_lowest_entry(rdev);
+	rv6xx_program_power_level_low(rdev);
+	rv6xx_program_power_level_medium(rdev);
+	rv6xx_program_power_level_high(rdev);
+	rv6xx_enable_medium(rdev);
+	rv6xx_enable_high(rdev);
+
+	if (pi->thermal_protection)
+		rv6xx_enable_thermal_protection(rdev, true);
+	rv6xx_program_vc(rdev);
+	rv6xx_program_at(rdev);
+
+	return 0;
+}
+
+void rv6xx_setup_asic(struct radeon_device *rdev)
+{
+	r600_enable_acpi_pm(rdev);
+
+	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L0s)
+		rv6xx_enable_l0s(rdev);
+	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L1)
+		rv6xx_enable_l1(rdev);
+	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_TURNOFFPLL_ASPML1)
+		rv6xx_enable_pll_sleep_in_l1(rdev);
+}
+
+void rv6xx_dpm_display_configuration_changed(struct radeon_device *rdev)
+{
+	rv6xx_program_display_gap(rdev);
+}
+
+union power_info {
+	struct _ATOM_POWERPLAY_INFO info;
+	struct _ATOM_POWERPLAY_INFO_V2 info_2;
+	struct _ATOM_POWERPLAY_INFO_V3 info_3;
+	struct _ATOM_PPLIB_POWERPLAYTABLE pplib;
+	struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2;
+	struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3;
+};
+
+union pplib_clock_info {
+	struct _ATOM_PPLIB_R600_CLOCK_INFO r600;
+	struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780;
+	struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen;
+	struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo;
+};
+
+union pplib_power_state {
+	struct _ATOM_PPLIB_STATE v1;
+	struct _ATOM_PPLIB_STATE_V2 v2;
+};
+
+static void rv6xx_parse_pplib_non_clock_info(struct radeon_device *rdev,
+					     struct radeon_ps *rps,
+					     struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info)
+{
+	rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings);
+	rps->class = le16_to_cpu(non_clock_info->usClassification);
+	rps->class2 = le16_to_cpu(non_clock_info->usClassification2);
+
+	if (r600_is_uvd_state(rps->class, rps->class2)) {
+		rps->vclk = RV6XX_DEFAULT_VCLK_FREQ;
+		rps->dclk = RV6XX_DEFAULT_DCLK_FREQ;
+	} else {
+		rps->vclk = 0;
+		rps->dclk = 0;
+	}
+
+	if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT)
+		rdev->pm.dpm.boot_ps = rps;
+	if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
+		rdev->pm.dpm.uvd_ps = rps;
+}
+
+static void rv6xx_parse_pplib_clock_info(struct radeon_device *rdev,
+					 struct radeon_ps *rps, int index,
+					 union pplib_clock_info *clock_info)
+{
+	struct rv6xx_ps *ps = rv6xx_get_ps(rps);
+	u32 sclk, mclk;
+	u16 vddc;
+	struct rv6xx_pl *pl;
+
+	switch (index) {
+	case 0:
+		pl = &ps->low;
+		break;
+	case 1:
+		pl = &ps->medium;
+		break;
+	case 2:
+	default:
+		pl = &ps->high;
+		break;
+	}
+
+	sclk = le16_to_cpu(clock_info->r600.usEngineClockLow);
+	sclk |= clock_info->r600.ucEngineClockHigh << 16;
+	mclk = le16_to_cpu(clock_info->r600.usMemoryClockLow);
+	mclk |= clock_info->r600.ucMemoryClockHigh << 16;
+
+	pl->mclk = mclk;
+	pl->sclk = sclk;
+	pl->vddc = le16_to_cpu(clock_info->r600.usVDDC);
+	pl->flags = le32_to_cpu(clock_info->r600.ulFlags);
+
+	/* patch up vddc if necessary */
+	if (pl->vddc == 0xff01) {
+		if (radeon_atom_get_max_vddc(rdev, 0, 0, &vddc) == 0)
+			pl->vddc = vddc;
+	}
+
+	/* fix up pcie gen2 */
+	if (pl->flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) {
+		if ((rdev->family == CHIP_RV610) || (rdev->family == CHIP_RV630)) {
+			if (pl->vddc < 1100)
+				pl->flags &= ~ATOM_PPLIB_R600_FLAGS_PCIEGEN2;
+		}
+	}
+
+	/* patch up boot state */
+	if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) {
+		u16 vddc, vddci;
+		radeon_atombios_get_default_voltages(rdev, &vddc, &vddci);
+		pl->mclk = rdev->clock.default_mclk;
+		pl->sclk = rdev->clock.default_sclk;
+		pl->vddc = vddc;
+	}
+}
+
+static int rv6xx_parse_power_table(struct radeon_device *rdev)
+{
+	struct radeon_mode_info *mode_info = &rdev->mode_info;
+	struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
+	union pplib_power_state *power_state;
+	int i, j;
+	union pplib_clock_info *clock_info;
+	union power_info *power_info;
+	int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
+        u16 data_offset;
+	u8 frev, crev;
+	struct rv6xx_ps *ps;
+
+	if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
+				   &frev, &crev, &data_offset))
+		return -EINVAL;
+	power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
+
+	rdev->pm.dpm.ps = kzalloc(sizeof(struct radeon_ps) *
+				  power_info->pplib.ucNumStates, GFP_KERNEL);
+	if (!rdev->pm.dpm.ps)
+		return -ENOMEM;
+	rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps);
+	rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime);
+	rdev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime);
+
+	for (i = 0; i < power_info->pplib.ucNumStates; i++) {
+		power_state = (union pplib_power_state *)
+			(mode_info->atom_context->bios + data_offset +
+			 le16_to_cpu(power_info->pplib.usStateArrayOffset) +
+			 i * power_info->pplib.ucStateEntrySize);
+		non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
+			(mode_info->atom_context->bios + data_offset +
+			 le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset) +
+			 (power_state->v1.ucNonClockStateIndex *
+			  power_info->pplib.ucNonClockSize));
+		if (power_info->pplib.ucStateEntrySize - 1) {
+			ps = kzalloc(sizeof(struct rv6xx_ps), GFP_KERNEL);
+			if (ps == NULL) {
+				kfree(rdev->pm.dpm.ps);
+				return -ENOMEM;
+			}
+			rdev->pm.dpm.ps[i].ps_priv = ps;
+			rv6xx_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i],
+							 non_clock_info);
+			for (j = 0; j < (power_info->pplib.ucStateEntrySize - 1); j++) {
+				clock_info = (union pplib_clock_info *)
+					(mode_info->atom_context->bios + data_offset +
+					 le16_to_cpu(power_info->pplib.usClockInfoArrayOffset) +
+					 (power_state->v1.ucClockStateIndices[j] *
+					  power_info->pplib.ucClockInfoSize));
+				rv6xx_parse_pplib_clock_info(rdev,
+							     &rdev->pm.dpm.ps[i], j,
+							     clock_info);
+			}
+		}
+	}
+	rdev->pm.dpm.num_ps = power_info->pplib.ucNumStates;
+	return 0;
+}
+
+int rv6xx_dpm_init(struct radeon_device *rdev)
+{
+	int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info);
+	uint16_t data_offset, size;
+	uint8_t frev, crev;
+	struct atom_clock_dividers dividers;
+	struct rv6xx_power_info *pi;
+	int ret;
+
+	pi = kzalloc(sizeof(struct rv6xx_power_info), GFP_KERNEL);
+	if (pi == NULL)
+		return -ENOMEM;
+	rdev->pm.dpm.priv = pi;
+
+	ret = rv6xx_parse_power_table(rdev);
+	if (ret)
+		return ret;
+
+	if (rdev->pm.dpm.voltage_response_time == 0)
+		rdev->pm.dpm.voltage_response_time = R600_VOLTAGERESPONSETIME_DFLT;
+	if (rdev->pm.dpm.backbias_response_time == 0)
+		rdev->pm.dpm.backbias_response_time = R600_BACKBIASRESPONSETIME_DFLT;
+
+	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
+					     0, false, &dividers);
+	if (ret)
+		pi->spll_ref_div = dividers.ref_div + 1;
+	else
+		pi->spll_ref_div = R600_REFERENCEDIVIDER_DFLT;
+
+	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_MEMORY_PLL_PARAM,
+					     0, false, &dividers);
+	if (ret)
+		pi->mpll_ref_div = dividers.ref_div + 1;
+	else
+		pi->mpll_ref_div = R600_REFERENCEDIVIDER_DFLT;
+
+	if (rdev->family >= CHIP_RV670)
+		pi->fb_div_scale = 1;
+	else
+		pi->fb_div_scale = 0;
+
+	pi->voltage_control =
+		radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC);
+
+	pi->gfx_clock_gating = true;
+
+	if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
+                                   &frev, &crev, &data_offset)) {
+		pi->sclk_ss = true;
+		pi->mclk_ss = true;
+		pi->dynamic_ss = true;
+	} else {
+		pi->sclk_ss = false;
+		pi->mclk_ss = false;
+		pi->dynamic_ss = false;
+	}
+
+	pi->dynamic_pcie_gen2 = true;
+
+	if (pi->gfx_clock_gating &&
+	    (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE))
+		pi->thermal_protection = true;
+	else
+		pi->thermal_protection = false;
+
+	pi->display_gap = true;
+
+	return 0;
+}
+
+void rv6xx_dpm_print_power_state(struct radeon_device *rdev,
+				 struct radeon_ps *rps)
+{
+	struct rv6xx_ps *ps = rv6xx_get_ps(rps);
+	struct rv6xx_pl *pl;
+
+	r600_dpm_print_class_info(rps->class, rps->class2);
+	r600_dpm_print_cap_info(rps->caps);
+	printk("\tuvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
+	pl = &ps->low;
+	printk("\t\tpower level 0    sclk: %u mclk: %u vddc: %u\n",
+	       pl->sclk, pl->mclk, pl->vddc);
+	pl = &ps->medium;
+	printk("\t\tpower level 1    sclk: %u mclk: %u vddc: %u\n",
+	       pl->sclk, pl->mclk, pl->vddc);
+	pl = &ps->high;
+	printk("\t\tpower level 2    sclk: %u mclk: %u vddc: %u\n",
+	       pl->sclk, pl->mclk, pl->vddc);
+	r600_dpm_print_ps_status(rdev, rps);
+}
+
+void rv6xx_dpm_fini(struct radeon_device *rdev)
+{
+	int i;
+
+	for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
+		kfree(rdev->pm.dpm.ps[i].ps_priv);
+	}
+	kfree(rdev->pm.dpm.ps);
+	kfree(rdev->pm.dpm.priv);
+}
+
+u32 rv6xx_dpm_get_sclk(struct radeon_device *rdev, bool low)
+{
+	struct rv6xx_ps *requested_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps);
+
+	if (low)
+		return requested_state->low.sclk;
+	else
+		return requested_state->high.sclk;
+}
+
+u32 rv6xx_dpm_get_mclk(struct radeon_device *rdev, bool low)
+{
+	struct rv6xx_ps *requested_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps);
+
+	if (low)
+		return requested_state->low.mclk;
+	else
+		return requested_state->high.mclk;
+}
diff --git a/drivers/gpu/drm/radeon/rv6xx_dpm.h b/drivers/gpu/drm/radeon/rv6xx_dpm.h
new file mode 100644
index 0000000..8035d53
--- /dev/null
+++ b/drivers/gpu/drm/radeon/rv6xx_dpm.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2011 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Alex Deucher
+ */
+
+#ifndef __RV6XX_DPM_H__
+#define __RV6XX_DPM_H__
+
+#include "r600_dpm.h"
+
+/* Represents a single SCLK step. */
+struct rv6xx_sclk_stepping
+{
+    u32 vco_frequency;
+    u32 post_divider;
+};
+
+struct rv6xx_pm_hw_state {
+	u32 sclks[R600_PM_NUMBER_OF_ACTIVITY_LEVELS];
+	u32 mclks[R600_PM_NUMBER_OF_MCLKS];
+	u16 vddc[R600_PM_NUMBER_OF_VOLTAGE_LEVELS];
+	bool backbias[R600_PM_NUMBER_OF_VOLTAGE_LEVELS];
+	bool pcie_gen2[R600_PM_NUMBER_OF_ACTIVITY_LEVELS];
+	u8 high_sclk_index;
+	u8 medium_sclk_index;
+	u8 low_sclk_index;
+	u8 high_mclk_index;
+	u8 medium_mclk_index;
+	u8 low_mclk_index;
+	u8 high_vddc_index;
+	u8 medium_vddc_index;
+	u8 low_vddc_index;
+	u8 rp[R600_PM_NUMBER_OF_ACTIVITY_LEVELS];
+	u8 lp[R600_PM_NUMBER_OF_ACTIVITY_LEVELS];
+};
+
+struct rv6xx_power_info {
+	/* flags */
+	bool voltage_control;
+	bool sclk_ss;
+	bool mclk_ss;
+	bool dynamic_ss;
+	bool dynamic_pcie_gen2;
+	bool thermal_protection;
+	bool display_gap;
+	bool gfx_clock_gating;
+	/* clk values */
+	u32 fb_div_scale;
+	u32 spll_ref_div;
+	u32 mpll_ref_div;
+	u32 bsu;
+	u32 bsp;
+	/* */
+	u32 active_auto_throttle_sources;
+	/* current power state */
+	u32 restricted_levels;
+	struct rv6xx_pm_hw_state hw;
+};
+
+struct rv6xx_pl {
+	u32 sclk;
+	u32 mclk;
+	u16 vddc;
+	u32 flags;
+};
+
+struct rv6xx_ps {
+	struct rv6xx_pl high;
+	struct rv6xx_pl medium;
+	struct rv6xx_pl low;
+};
+
+#define RV6XX_DEFAULT_VCLK_FREQ  40000 /* 10 khz */
+#define RV6XX_DEFAULT_DCLK_FREQ  30000 /* 10 khz */
+
+#endif
diff --git a/drivers/gpu/drm/radeon/rv6xxd.h b/drivers/gpu/drm/radeon/rv6xxd.h
new file mode 100644
index 0000000..34e86f9
--- /dev/null
+++ b/drivers/gpu/drm/radeon/rv6xxd.h
@@ -0,0 +1,246 @@
+/*
+ * Copyright 2011 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef RV6XXD_H
+#define RV6XXD_H
+
+/* RV6xx power management */
+#define SPLL_CNTL_MODE                                    0x60c
+#       define SPLL_DIV_SYNC                              (1 << 5)
+
+#define GENERAL_PWRMGT                                    0x618
+#       define GLOBAL_PWRMGT_EN                           (1 << 0)
+#       define STATIC_PM_EN                               (1 << 1)
+#       define MOBILE_SU                                  (1 << 2)
+#       define THERMAL_PROTECTION_DIS                     (1 << 3)
+#       define THERMAL_PROTECTION_TYPE                    (1 << 4)
+#       define ENABLE_GEN2PCIE                            (1 << 5)
+#       define SW_GPIO_INDEX(x)                           ((x) << 6)
+#       define SW_GPIO_INDEX_MASK                         (3 << 6)
+#       define LOW_VOLT_D2_ACPI                           (1 << 8)
+#       define LOW_VOLT_D3_ACPI                           (1 << 9)
+#       define VOLT_PWRMGT_EN                             (1 << 10)
+#       define BACKBIAS_PAD_EN                            (1 << 16)
+#       define BACKBIAS_VALUE                             (1 << 17)
+#       define BACKBIAS_DPM_CNTL                          (1 << 18)
+#       define DYN_SPREAD_SPECTRUM_EN                     (1 << 21)
+
+#define MCLK_PWRMGT_CNTL                                  0x624
+#       define MPLL_PWRMGT_OFF                            (1 << 0)
+#       define YCLK_TURNOFF                               (1 << 1)
+#       define MPLL_TURNOFF                               (1 << 2)
+#       define SU_MCLK_USE_BCLK                           (1 << 3)
+#       define DLL_READY                                  (1 << 4)
+#       define MC_BUSY                                    (1 << 5)
+#       define MC_INT_CNTL                                (1 << 7)
+#       define MRDCKA_SLEEP                               (1 << 8)
+#       define MRDCKB_SLEEP                               (1 << 9)
+#       define MRDCKC_SLEEP                               (1 << 10)
+#       define MRDCKD_SLEEP                               (1 << 11)
+#       define MRDCKE_SLEEP                               (1 << 12)
+#       define MRDCKF_SLEEP                               (1 << 13)
+#       define MRDCKG_SLEEP                               (1 << 14)
+#       define MRDCKH_SLEEP                               (1 << 15)
+#       define MRDCKA_RESET                               (1 << 16)
+#       define MRDCKB_RESET                               (1 << 17)
+#       define MRDCKC_RESET                               (1 << 18)
+#       define MRDCKD_RESET                               (1 << 19)
+#       define MRDCKE_RESET                               (1 << 20)
+#       define MRDCKF_RESET                               (1 << 21)
+#       define MRDCKG_RESET                               (1 << 22)
+#       define MRDCKH_RESET                               (1 << 23)
+#       define DLL_READY_READ                             (1 << 24)
+#       define USE_DISPLAY_GAP                            (1 << 25)
+#       define USE_DISPLAY_URGENT_NORMAL                  (1 << 26)
+#       define USE_DISPLAY_GAP_CTXSW                      (1 << 27)
+#       define MPLL_TURNOFF_D2                            (1 << 28)
+#       define USE_DISPLAY_URGENT_CTXSW                   (1 << 29)
+
+#define MPLL_FREQ_LEVEL_0                                 0x6e8
+#       define LEVEL0_MPLL_POST_DIV(x)                    ((x) << 0)
+#       define LEVEL0_MPLL_POST_DIV_MASK                  (0xff << 0)
+#       define LEVEL0_MPLL_FB_DIV(x)                      ((x) << 8)
+#       define LEVEL0_MPLL_FB_DIV_MASK                    (0xfff << 8)
+#       define LEVEL0_MPLL_REF_DIV(x)                     ((x) << 20)
+#       define LEVEL0_MPLL_REF_DIV_MASK                   (0x3f << 20)
+#       define LEVEL0_MPLL_DIV_EN                         (1 << 28)
+#       define LEVEL0_DLL_BYPASS                          (1 << 29)
+#       define LEVEL0_DLL_RESET                           (1 << 30)
+
+#define VID_RT                                            0x6f8
+#       define VID_CRT(x)                                 ((x) << 0)
+#       define VID_CRT_MASK                               (0x1fff << 0)
+#       define VID_CRTU(x)                                ((x) << 13)
+#       define VID_CRTU_MASK                              (7 << 13)
+#       define SSTU(x)                                    ((x) << 16)
+#       define SSTU_MASK                                  (7 << 16)
+#       define VID_SWT(x)                                 ((x) << 19)
+#       define VID_SWT_MASK                               (0x1f << 19)
+#       define BRT(x)                                     ((x) << 24)
+#       define BRT_MASK                                   (0xff << 24)
+
+#define TARGET_AND_CURRENT_PROFILE_INDEX                  0x70c
+#       define TARGET_PROFILE_INDEX_MASK                  (3 << 0)
+#       define TARGET_PROFILE_INDEX_SHIFT                 0
+#       define CURRENT_PROFILE_INDEX_MASK                 (3 << 2)
+#       define CURRENT_PROFILE_INDEX_SHIFT                2
+#       define DYN_PWR_ENTER_INDEX(x)                     ((x) << 4)
+#       define DYN_PWR_ENTER_INDEX_MASK                   (3 << 4)
+#       define DYN_PWR_ENTER_INDEX_SHIFT                  4
+#       define CURR_MCLK_INDEX_MASK                       (3 << 6)
+#       define CURR_MCLK_INDEX_SHIFT                      6
+#       define CURR_SCLK_INDEX_MASK                       (0x1f << 8)
+#       define CURR_SCLK_INDEX_SHIFT                      8
+#       define CURR_VID_INDEX_MASK                        (3 << 13)
+#       define CURR_VID_INDEX_SHIFT                       13
+
+#define VID_UPPER_GPIO_CNTL                               0x740
+#       define CTXSW_UPPER_GPIO_VALUES(x)                 ((x) << 0)
+#       define CTXSW_UPPER_GPIO_VALUES_MASK               (7 << 0)
+#       define HIGH_UPPER_GPIO_VALUES(x)                  ((x) << 3)
+#       define HIGH_UPPER_GPIO_VALUES_MASK                (7 << 3)
+#       define MEDIUM_UPPER_GPIO_VALUES(x)                ((x) << 6)
+#       define MEDIUM_UPPER_GPIO_VALUES_MASK              (7 << 6)
+#       define LOW_UPPER_GPIO_VALUES(x)                   ((x) << 9)
+#       define LOW_UPPER_GPIO_VALUES_MASK                 (7 << 9)
+#       define CTXSW_BACKBIAS_VALUE                       (1 << 12)
+#       define HIGH_BACKBIAS_VALUE                        (1 << 13)
+#       define MEDIUM_BACKBIAS_VALUE                      (1 << 14)
+#       define LOW_BACKBIAS_VALUE                         (1 << 15)
+
+#define CG_DISPLAY_GAP_CNTL                               0x7dc
+#       define DISP1_GAP(x)                               ((x) << 0)
+#       define DISP1_GAP_MASK                             (3 << 0)
+#       define DISP2_GAP(x)                               ((x) << 2)
+#       define DISP2_GAP_MASK                             (3 << 2)
+#       define VBI_TIMER_COUNT(x)                         ((x) << 4)
+#       define VBI_TIMER_COUNT_MASK                       (0x3fff << 4)
+#       define VBI_TIMER_UNIT(x)                          ((x) << 20)
+#       define VBI_TIMER_UNIT_MASK                        (7 << 20)
+#       define DISP1_GAP_MCHG(x)                          ((x) << 24)
+#       define DISP1_GAP_MCHG_MASK                        (3 << 24)
+#       define DISP2_GAP_MCHG(x)                          ((x) << 26)
+#       define DISP2_GAP_MCHG_MASK                        (3 << 26)
+
+#define CG_THERMAL_CTRL                                   0x7f0
+#       define DPM_EVENT_SRC(x)                           ((x) << 0)
+#       define DPM_EVENT_SRC_MASK                         (7 << 0)
+#       define THERM_INC_CLK                              (1 << 3)
+#       define TOFFSET(x)                                 ((x) << 4)
+#       define TOFFSET_MASK                               (0xff << 4)
+#       define DIG_THERM_DPM(x)                           ((x) << 12)
+#       define DIG_THERM_DPM_MASK                         (0xff << 12)
+#       define CTF_SEL(x)                                 ((x) << 20)
+#       define CTF_SEL_MASK                               (7 << 20)
+#       define CTF_PAD_POLARITY                           (1 << 23)
+#       define CTF_PAD_EN                                 (1 << 24)
+
+#define CG_SPLL_SPREAD_SPECTRUM_LOW                       0x820
+#       define SSEN                                       (1 << 0)
+#       define CLKS(x)                                    ((x) << 3)
+#       define CLKS_MASK                                  (0xff << 3)
+#       define CLKS_SHIFT                                 3
+#       define CLKV(x)                                    ((x) << 11)
+#       define CLKV_MASK                                  (0x7ff << 11)
+#       define CLKV_SHIFT                                 11
+#define CG_MPLL_SPREAD_SPECTRUM                           0x830
+
+#define CITF_CNTL					0x200c
+#       define BLACKOUT_RD                              (1 << 0)
+#       define BLACKOUT_WR                              (1 << 1)
+
+#define RAMCFG						0x2408
+#define		NOOFBANK_SHIFT					0
+#define		NOOFBANK_MASK					0x00000001
+#define		NOOFRANK_SHIFT					1
+#define		NOOFRANK_MASK					0x00000002
+#define		NOOFROWS_SHIFT					2
+#define		NOOFROWS_MASK					0x0000001C
+#define		NOOFCOLS_SHIFT					5
+#define		NOOFCOLS_MASK					0x00000060
+#define		CHANSIZE_SHIFT					7
+#define		CHANSIZE_MASK					0x00000080
+#define		BURSTLENGTH_SHIFT				8
+#define		BURSTLENGTH_MASK				0x00000100
+#define		CHANSIZE_OVERRIDE				(1 << 10)
+
+#define SQM_RATIO					0x2424
+#       define STATE0(x)                                ((x) << 0)
+#       define STATE0_MASK                              (0xff << 0)
+#       define STATE1(x)                                ((x) << 8)
+#       define STATE1_MASK                              (0xff << 8)
+#       define STATE2(x)                                ((x) << 16)
+#       define STATE2_MASK                              (0xff << 16)
+#       define STATE3(x)                                ((x) << 24)
+#       define STATE3_MASK                              (0xff << 24)
+
+#define ARB_RFSH_CNTL					0x2460
+#       define ENABLE                                   (1 << 0)
+#define ARB_RFSH_RATE					0x2464
+#       define POWERMODE0(x)                            ((x) << 0)
+#       define POWERMODE0_MASK                          (0xff << 0)
+#       define POWERMODE1(x)                            ((x) << 8)
+#       define POWERMODE1_MASK                          (0xff << 8)
+#       define POWERMODE2(x)                            ((x) << 16)
+#       define POWERMODE2_MASK                          (0xff << 16)
+#       define POWERMODE3(x)                            ((x) << 24)
+#       define POWERMODE3_MASK                          (0xff << 24)
+
+#define MC_SEQ_DRAM					0x2608
+#       define CKE_DYN                                  (1 << 12)
+
+#define MC_SEQ_CMD					0x26c4
+
+#define MC_SEQ_RESERVE_S				0x2890
+#define MC_SEQ_RESERVE_M				0x2894
+
+#define LVTMA_DATA_SYNCHRONIZATION                      0x7adc
+#       define LVTMA_PFREQCHG                           (1 << 8)
+#define DCE3_LVTMA_DATA_SYNCHRONIZATION                 0x7f98
+
+/* PCIE indirect regs */
+#define PCIE_P_CNTL                                       0x40
+#       define P_PLL_PWRDN_IN_L1L23                       (1 << 3)
+#       define P_PLL_BUF_PDNB                             (1 << 4)
+#       define P_PLL_PDNB                                 (1 << 9)
+#       define P_ALLOW_PRX_FRONTEND_SHUTOFF               (1 << 12)
+/* PCIE PORT indirect regs */
+#define PCIE_LC_CNTL                                      0xa0
+#       define LC_L0S_INACTIVITY(x)                       ((x) << 8)
+#       define LC_L0S_INACTIVITY_MASK                     (0xf << 8)
+#       define LC_L0S_INACTIVITY_SHIFT                    8
+#       define LC_L1_INACTIVITY(x)                        ((x) << 12)
+#       define LC_L1_INACTIVITY_MASK                      (0xf << 12)
+#       define LC_L1_INACTIVITY_SHIFT                     12
+#       define LC_PMI_TO_L1_DIS                           (1 << 16)
+#       define LC_ASPM_TO_L1_DIS                          (1 << 24)
+#define PCIE_LC_SPEED_CNTL                                0xa4
+#       define LC_GEN2_EN                                 (1 << 0)
+#       define LC_INITIATE_LINK_SPEED_CHANGE              (1 << 7)
+#       define LC_CURRENT_DATA_RATE                       (1 << 11)
+#       define LC_HW_VOLTAGE_IF_CONTROL(x)                ((x) << 12)
+#       define LC_HW_VOLTAGE_IF_CONTROL_MASK              (3 << 12)
+#       define LC_HW_VOLTAGE_IF_CONTROL_SHIFT             12
+#       define LC_OTHER_SIDE_EVER_SENT_GEN2               (1 << 23)
+#       define LC_OTHER_SIDE_SUPPORTS_GEN2                (1 << 24)
+
+#endif
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 077/165] drm/radeon/kms: add dpm support for rv7xx (v2)
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (76 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 076/165] drm/radeon/kms: add dpm support for rv6xx alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 078/165] drm/radeon/kms: add dpm support for evergreen (v2) alexdeucher
                   ` (35 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

This adds dpm support for rv7xx asics.  This includes:
- clockgating
- dynamic engine clock scaling
- dynamic memory clock scaling
- dynamic voltage scaling
- dynamic pcie gen1/gen2 switching

Set radeon.dpm=1 to enable.

v2: reduce stack usage

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/Makefile       |    3 +-
 drivers/gpu/drm/radeon/ppsmc.h        |   76 ++
 drivers/gpu/drm/radeon/r600.c         |   48 +-
 drivers/gpu/drm/radeon/r600d.h        |    2 +
 drivers/gpu/drm/radeon/radeon.h       |    1 +
 drivers/gpu/drm/radeon/radeon_asic.c  |   12 +
 drivers/gpu/drm/radeon/radeon_asic.h  |   12 +
 drivers/gpu/drm/radeon/radeon_pm.c    |    4 +
 drivers/gpu/drm/radeon/radeon_ucode.h |   21 +
 drivers/gpu/drm/radeon/rv730_dpm.c    |  508 +++++++
 drivers/gpu/drm/radeon/rv730d.h       |  165 +++
 drivers/gpu/drm/radeon/rv740_dpm.c    |  417 ++++++
 drivers/gpu/drm/radeon/rv740d.h       |  117 ++
 drivers/gpu/drm/radeon/rv770_dpm.c    | 2325 +++++++++++++++++++++++++++++++++
 drivers/gpu/drm/radeon/rv770_dpm.h    |  272 ++++
 drivers/gpu/drm/radeon/rv770_smc.c    |  404 ++++++
 drivers/gpu/drm/radeon/rv770_smc.h    |  208 +++
 drivers/gpu/drm/radeon/rv770d.h       |  279 ++++-
 18 files changed, 4861 insertions(+), 13 deletions(-)
 create mode 100644 drivers/gpu/drm/radeon/ppsmc.h
 create mode 100644 drivers/gpu/drm/radeon/rv730_dpm.c
 create mode 100644 drivers/gpu/drm/radeon/rv730d.h
 create mode 100644 drivers/gpu/drm/radeon/rv740_dpm.c
 create mode 100644 drivers/gpu/drm/radeon/rv740d.h
 create mode 100644 drivers/gpu/drm/radeon/rv770_dpm.c
 create mode 100644 drivers/gpu/drm/radeon/rv770_dpm.h
 create mode 100644 drivers/gpu/drm/radeon/rv770_smc.c
 create mode 100644 drivers/gpu/drm/radeon/rv770_smc.h

diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile
index 3aa20dc..c97753d 100644
--- a/drivers/gpu/drm/radeon/Makefile
+++ b/drivers/gpu/drm/radeon/Makefile
@@ -77,7 +77,8 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \
 	evergreen_hdmi.o radeon_trace_points.o ni.o cayman_blit_shaders.o \
 	atombios_encoders.o radeon_semaphore.o radeon_sa.o atombios_i2c.o si.o \
 	si_blit_shaders.o radeon_prime.o radeon_uvd.o cik.o cik_blit_shaders.o \
-	r600_dpm.o rs780_dpm.o rv6xx_dpm.o
+	r600_dpm.o rs780_dpm.o rv6xx_dpm.o rv770_dpm.o rv730_dpm.o rv740_dpm.o \
+	rv770_smc.o
 
 radeon-$(CONFIG_COMPAT) += radeon_ioc32.o
 radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o
diff --git a/drivers/gpu/drm/radeon/ppsmc.h b/drivers/gpu/drm/radeon/ppsmc.h
new file mode 100644
index 0000000..638de17
--- /dev/null
+++ b/drivers/gpu/drm/radeon/ppsmc.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2011 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef PP_SMC_H
+#define PP_SMC_H
+
+#pragma pack(push, 1)
+
+#define PPSMC_SWSTATE_FLAG_DC                           0x01
+
+#define PPSMC_THERMAL_PROTECT_TYPE_INTERNAL             0x00
+#define PPSMC_THERMAL_PROTECT_TYPE_EXTERNAL             0x01
+#define PPSMC_THERMAL_PROTECT_TYPE_NONE                 0xff
+
+#define PPSMC_SYSTEMFLAG_GPIO_DC                        0x01
+#define PPSMC_SYSTEMFLAG_STEPVDDC                       0x02
+#define PPSMC_SYSTEMFLAG_GDDR5                          0x04
+#define PPSMC_SYSTEMFLAG_DISABLE_BABYSTEP               0x08
+#define PPSMC_SYSTEMFLAG_REGULATOR_HOT                  0x10
+
+#define PPSMC_EXTRAFLAGS_AC2DC_ACTION_MASK              0x07
+#define PPSMC_EXTRAFLAGS_AC2DC_DONT_WAIT_FOR_VBLANK     0x08
+#define PPSMC_EXTRAFLAGS_AC2DC_ACTION_GOTODPMLOWSTATE   0x00
+#define PPSMC_EXTRAFLAGS_AC2DC_ACTION_GOTOINITIALSTATE  0x01
+
+#define PPSMC_DISPLAY_WATERMARK_LOW                     0
+#define PPSMC_DISPLAY_WATERMARK_HIGH                    1
+
+#define PPSMC_STATEFLAG_AUTO_PULSE_SKIP    0x01
+
+#define PPSMC_Result_OK             ((uint8_t)0x01)
+#define PPSMC_Result_Failed         ((uint8_t)0xFF)
+
+typedef uint8_t PPSMC_Result;
+
+#define PPSMC_MSG_Halt                      ((uint8_t)0x10)
+#define PPSMC_MSG_Resume                    ((uint8_t)0x11)
+#define PPSMC_MSG_TwoLevelsDisabled         ((uint8_t)0x15)
+#define PPSMC_MSG_EnableThermalInterrupt    ((uint8_t)0x16)
+#define PPSMC_MSG_SwitchToSwState           ((uint8_t)0x20)
+#define PPSMC_MSG_SwitchToInitialState      ((uint8_t)0x40)
+#define PPSMC_MSG_NoForcedLevel             ((uint8_t)0x41)
+#define PPSMC_MSG_SwitchToMinimumPower      ((uint8_t)0x51)
+#define PPSMC_MSG_ResumeFromMinimumPower    ((uint8_t)0x52)
+#define PPSMC_MSG_NoDisplay                 ((uint8_t)0x5D)
+#define PPSMC_MSG_HasDisplay                ((uint8_t)0x5E)
+#define PPSMC_MSG_EnableULV                 ((uint8_t)0x62)
+#define PPSMC_MSG_DisableULV                ((uint8_t)0x63)
+#define PPSMC_MSG_EnterULV                  ((uint8_t)0x64)
+#define PPSMC_MSG_ExitULV                   ((uint8_t)0x65)
+#define PPSMC_MSG_ResetToDefaults           ((uint8_t)0x84)
+
+typedef uint8_t PPSMC_Msg;
+
+#pragma pack(pop)
+
+#endif
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index 7ea81c8..0688016 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -57,10 +57,14 @@ MODULE_FIRMWARE("radeon/RS780_pfp.bin");
 MODULE_FIRMWARE("radeon/RS780_me.bin");
 MODULE_FIRMWARE("radeon/RV770_pfp.bin");
 MODULE_FIRMWARE("radeon/RV770_me.bin");
+MODULE_FIRMWARE("radeon/RV770_smc.bin");
 MODULE_FIRMWARE("radeon/RV730_pfp.bin");
 MODULE_FIRMWARE("radeon/RV730_me.bin");
+MODULE_FIRMWARE("radeon/RV730_smc.bin");
+MODULE_FIRMWARE("radeon/RV740_smc.bin");
 MODULE_FIRMWARE("radeon/RV710_pfp.bin");
 MODULE_FIRMWARE("radeon/RV710_me.bin");
+MODULE_FIRMWARE("radeon/RV710_smc.bin");
 MODULE_FIRMWARE("radeon/R600_rlc.bin");
 MODULE_FIRMWARE("radeon/R700_rlc.bin");
 MODULE_FIRMWARE("radeon/CEDAR_pfp.bin");
@@ -2139,7 +2143,8 @@ int r600_init_microcode(struct radeon_device *rdev)
 	struct platform_device *pdev;
 	const char *chip_name;
 	const char *rlc_chip_name;
-	size_t pfp_req_size, me_req_size, rlc_req_size;
+	const char *smc_chip_name = "RV770";
+	size_t pfp_req_size, me_req_size, rlc_req_size, smc_req_size = 0;
 	char fw_name[30];
 	int err;
 
@@ -2185,15 +2190,26 @@ int r600_init_microcode(struct radeon_device *rdev)
 	case CHIP_RV770:
 		chip_name = "RV770";
 		rlc_chip_name = "R700";
+		smc_chip_name = "RV770";
+		smc_req_size = ALIGN(RV770_SMC_UCODE_SIZE, 4);
 		break;
 	case CHIP_RV730:
-	case CHIP_RV740:
 		chip_name = "RV730";
 		rlc_chip_name = "R700";
+		smc_chip_name = "RV730";
+		smc_req_size = ALIGN(RV730_SMC_UCODE_SIZE, 4);
 		break;
 	case CHIP_RV710:
 		chip_name = "RV710";
 		rlc_chip_name = "R700";
+		smc_chip_name = "RV710";
+		smc_req_size = ALIGN(RV710_SMC_UCODE_SIZE, 4);
+		break;
+	case CHIP_RV740:
+		chip_name = "RV730";
+		rlc_chip_name = "R700";
+		smc_chip_name = "RV740";
+		smc_req_size = ALIGN(RV740_SMC_UCODE_SIZE, 4);
 		break;
 	case CHIP_CEDAR:
 		chip_name = "CEDAR";
@@ -2277,6 +2293,19 @@ int r600_init_microcode(struct radeon_device *rdev)
 		err = -EINVAL;
 	}
 
+	if ((rdev->family >= CHIP_RV770) && (rdev->family <= CHIP_RV740)) {
+		snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", smc_chip_name);
+		err = request_firmware(&rdev->smc_fw, fw_name, &pdev->dev);
+		if (err)
+			goto out;
+		if (rdev->smc_fw->size != smc_req_size) {
+			printk(KERN_ERR
+			       "smc: Bogus length %zu in firmware \"%s\"\n",
+			       rdev->smc_fw->size, fw_name);
+			err = -EINVAL;
+		}
+	}
+
 out:
 	platform_device_unregister(pdev);
 
@@ -2291,6 +2320,8 @@ out:
 		rdev->me_fw = NULL;
 		release_firmware(rdev->rlc_fw);
 		rdev->rlc_fw = NULL;
+		release_firmware(rdev->smc_fw);
+		rdev->smc_fw = NULL;
 	}
 	return err;
 }
@@ -4039,10 +4070,13 @@ int r600_irq_set(struct radeon_device *rdev)
 	if ((rdev->family > CHIP_R600) && (rdev->family < CHIP_RV770)) {
 		thermal_int = RREG32(CG_THERMAL_INT) &
 			~(THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW);
-		if (rdev->irq.dpm_thermal) {
-			DRM_DEBUG("dpm thermal\n");
-			thermal_int |= THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW;
-		}
+	} else if (rdev->family >= CHIP_RV770) {
+		thermal_int = RREG32(RV770_CG_THERMAL_INT) &
+			~(THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW);
+	}
+	if (rdev->irq.dpm_thermal) {
+		DRM_DEBUG("dpm thermal\n");
+		thermal_int |= THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW;
 	}
 
 	if (atomic_read(&rdev->irq.ring_int[RADEON_RING_TYPE_GFX_INDEX])) {
@@ -4128,6 +4162,8 @@ int r600_irq_set(struct radeon_device *rdev)
 	}
 	if ((rdev->family > CHIP_R600) && (rdev->family < CHIP_RV770)) {
 		WREG32(CG_THERMAL_INT, thermal_int);
+	} else if (rdev->family >= CHIP_RV770) {
+		WREG32(RV770_CG_THERMAL_INT, thermal_int);
 	}
 
 	return 0;
diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h
index 3bca4db..f1b3084 100644
--- a/drivers/gpu/drm/radeon/r600d.h
+++ b/drivers/gpu/drm/radeon/r600d.h
@@ -320,6 +320,8 @@
 #define 	THERM_INT_MASK_HIGH			(1 << 24)
 #define 	THERM_INT_MASK_LOW			(1 << 25)
 
+#define	RV770_CG_THERMAL_INT				0x734
+
 #define	HDP_HOST_PATH_CNTL				0x2C00
 #define	HDP_NONSURFACE_BASE				0x2C04
 #define	HDP_NONSURFACE_INFO				0x2C08
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index ce36130..3e94920 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -1914,6 +1914,7 @@ struct radeon_device {
 	const struct firmware *uvd_fw;	/* UVD firmware */
 	const struct firmware *mec_fw;	/* CIK MEC firmware */
 	const struct firmware *sdma_fw;	/* CIK SDMA firmware */
+	const struct firmware *smc_fw;	/* SMC firmware */
 	struct r600_blit r600_blit;
 	struct r600_vram_scratch vram_scratch;
 	int msi_enabled; /* msi enabled */
diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c
index 4705b02..dbbcf33 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.c
+++ b/drivers/gpu/drm/radeon/radeon_asic.c
@@ -1317,6 +1317,18 @@ static struct radeon_asic rv770_asic = {
 		.set_uvd_clocks = &rv770_set_uvd_clocks,
 		.get_temperature = &rv770_get_temp,
 	},
+	.dpm = {
+		.init = &rv770_dpm_init,
+		.setup_asic = &rv770_dpm_setup_asic,
+		.enable = &rv770_dpm_enable,
+		.disable = &rv770_dpm_disable,
+		.set_power_state = &rv770_dpm_set_power_state,
+		.display_configuration_changed = &rv770_dpm_display_configuration_changed,
+		.fini = &rv770_dpm_fini,
+		.get_sclk = &rv770_dpm_get_sclk,
+		.get_mclk = &rv770_dpm_get_mclk,
+		.print_power_state = &rv770_dpm_print_power_state,
+	},
 	.pflip = {
 		.pre_page_flip = &rs600_pre_page_flip,
 		.page_flip = &rv770_page_flip,
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index 878766624..f7041a7 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -454,6 +454,18 @@ u32 rv770_get_xclk(struct radeon_device *rdev);
 int rv770_uvd_resume(struct radeon_device *rdev);
 int rv770_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk);
 int rv770_get_temp(struct radeon_device *rdev);
+/* rv7xx pm */
+int rv770_dpm_init(struct radeon_device *rdev);
+int rv770_dpm_enable(struct radeon_device *rdev);
+void rv770_dpm_disable(struct radeon_device *rdev);
+int rv770_dpm_set_power_state(struct radeon_device *rdev);
+void rv770_dpm_setup_asic(struct radeon_device *rdev);
+void rv770_dpm_display_configuration_changed(struct radeon_device *rdev);
+void rv770_dpm_fini(struct radeon_device *rdev);
+u32 rv770_dpm_get_sclk(struct radeon_device *rdev, bool low);
+u32 rv770_dpm_get_mclk(struct radeon_device *rdev, bool low);
+void rv770_dpm_print_power_state(struct radeon_device *rdev,
+				 struct radeon_ps *ps);
 
 /*
  * evergreen
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
index 5cb01f2..595607c 100644
--- a/drivers/gpu/drm/radeon/radeon_pm.c
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
@@ -1040,6 +1040,10 @@ int radeon_pm_init(struct radeon_device *rdev)
 	case CHIP_RV670:
 	case CHIP_RS780:
 	case CHIP_RS880:
+	case CHIP_RV770:
+	case CHIP_RV730:
+	case CHIP_RV710:
+	case CHIP_RV740:
 		if (radeon_dpm == 1)
 			rdev->pm.pm_method = PM_METHOD_DPM;
 		else
diff --git a/drivers/gpu/drm/radeon/radeon_ucode.h b/drivers/gpu/drm/radeon/radeon_ucode.h
index d2642b0..1910545 100644
--- a/drivers/gpu/drm/radeon/radeon_ucode.h
+++ b/drivers/gpu/drm/radeon/radeon_ucode.h
@@ -44,4 +44,25 @@
 #define BTC_MC_UCODE_SIZE            6024
 #define CAYMAN_MC_UCODE_SIZE         6037
 
+/* SMC */
+#define RV770_SMC_UCODE_START        0x0100
+#define RV770_SMC_UCODE_SIZE         0x410d
+#define RV770_SMC_INT_VECTOR_START   0xffc0
+#define RV770_SMC_INT_VECTOR_SIZE    0x0040
+
+#define RV730_SMC_UCODE_START        0x0100
+#define RV730_SMC_UCODE_SIZE         0x412c
+#define RV730_SMC_INT_VECTOR_START   0xffc0
+#define RV730_SMC_INT_VECTOR_SIZE    0x0040
+
+#define RV710_SMC_UCODE_START        0x0100
+#define RV710_SMC_UCODE_SIZE         0x3f1f
+#define RV710_SMC_INT_VECTOR_START   0xffc0
+#define RV710_SMC_INT_VECTOR_SIZE    0x0040
+
+#define RV740_SMC_UCODE_START        0x0100
+#define RV740_SMC_UCODE_SIZE         0x41c5
+#define RV740_SMC_INT_VECTOR_START   0xffc0
+#define RV740_SMC_INT_VECTOR_SIZE    0x0040
+
 #endif
diff --git a/drivers/gpu/drm/radeon/rv730_dpm.c b/drivers/gpu/drm/radeon/rv730_dpm.c
new file mode 100644
index 0000000..b23be71
--- /dev/null
+++ b/drivers/gpu/drm/radeon/rv730_dpm.c
@@ -0,0 +1,508 @@
+/*
+ * Copyright 2011 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Alex Deucher
+ */
+
+#include "drmP.h"
+#include "radeon.h"
+#include "rv730d.h"
+#include "r600_dpm.h"
+#include "rv770_dpm.h"
+#include "atom.h"
+
+#define MC_CG_ARB_FREQ_F0           0x0a
+#define MC_CG_ARB_FREQ_F1           0x0b
+#define MC_CG_ARB_FREQ_F2           0x0c
+#define MC_CG_ARB_FREQ_F3           0x0d
+
+struct rv7xx_ps *rv770_get_ps(struct radeon_ps *rps);
+struct rv7xx_power_info *rv770_get_pi(struct radeon_device *rdev);
+
+int rv730_populate_sclk_value(struct radeon_device *rdev,
+			      u32 engine_clock,
+			      RV770_SMC_SCLK_VALUE *sclk)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	struct atom_clock_dividers dividers;
+	u32 spll_func_cntl = pi->clk_regs.rv730.cg_spll_func_cntl;
+	u32 spll_func_cntl_2 = pi->clk_regs.rv730.cg_spll_func_cntl_2;
+	u32 spll_func_cntl_3 = pi->clk_regs.rv730.cg_spll_func_cntl_3;
+	u32 cg_spll_spread_spectrum = pi->clk_regs.rv730.cg_spll_spread_spectrum;
+	u32 cg_spll_spread_spectrum_2 = pi->clk_regs.rv730.cg_spll_spread_spectrum_2;
+	u64 tmp;
+	u32 reference_clock = rdev->clock.spll.reference_freq;
+	u32 reference_divider, post_divider;
+	u32 fbdiv;
+	int ret;
+
+	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
+					     engine_clock, false, &dividers);
+	if (ret)
+		return ret;
+
+	reference_divider = 1 + dividers.ref_div;
+
+	if (dividers.enable_post_div)
+		post_divider = ((dividers.post_div >> 4) & 0xf) +
+			(dividers.post_div & 0xf) + 2;
+	else
+		post_divider = 1;
+
+	tmp = (u64) engine_clock * reference_divider * post_divider;
+
+	fbdiv = (u32) ((16384 * tmp) / reference_clock);
+
+	/* set up registers */
+	if (dividers.enable_post_div)
+		spll_func_cntl |= SPLL_DIVEN;
+	else
+		spll_func_cntl &= ~SPLL_DIVEN;
+	spll_func_cntl &= ~(SPLL_HILEN_MASK | SPLL_LOLEN_MASK | SPLL_REF_DIV_MASK);
+	spll_func_cntl |= SPLL_REF_DIV(dividers.ref_div);
+	spll_func_cntl |= SPLL_HILEN((dividers.post_div >> 4) & 0xf);
+	spll_func_cntl |= SPLL_LOLEN(dividers.post_div & 0xf);
+
+	spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK;
+	spll_func_cntl_2 |= SCLK_MUX_SEL(2);
+
+	spll_func_cntl_3 &= ~SPLL_FB_DIV_MASK;
+	spll_func_cntl_3 |= SPLL_FB_DIV(fbdiv);
+	spll_func_cntl_3 |= SPLL_DITHEN;
+
+	if (pi->sclk_ss) {
+		struct radeon_atom_ss ss;
+		u32 vco_freq = engine_clock * post_divider;
+
+		if (radeon_atombios_get_asic_ss_info(rdev, &ss,
+						     ASIC_INTERNAL_ENGINE_SS, vco_freq)) {
+			u32 clk_s = reference_clock * 5 / (reference_divider * ss.rate);
+			u32 clk_v = ss.percentage * fbdiv / (clk_s * 10000);
+
+			cg_spll_spread_spectrum &= ~CLK_S_MASK;
+			cg_spll_spread_spectrum |= CLK_S(clk_s);
+			cg_spll_spread_spectrum |= SSEN;
+
+			cg_spll_spread_spectrum_2 &= ~CLK_V_MASK;
+			cg_spll_spread_spectrum_2 |= CLK_V(clk_v);
+		}
+	}
+
+	sclk->sclk_value = cpu_to_be32(engine_clock);
+	sclk->vCG_SPLL_FUNC_CNTL = cpu_to_be32(spll_func_cntl);
+	sclk->vCG_SPLL_FUNC_CNTL_2 = cpu_to_be32(spll_func_cntl_2);
+	sclk->vCG_SPLL_FUNC_CNTL_3 = cpu_to_be32(spll_func_cntl_3);
+	sclk->vCG_SPLL_SPREAD_SPECTRUM = cpu_to_be32(cg_spll_spread_spectrum);
+	sclk->vCG_SPLL_SPREAD_SPECTRUM_2 = cpu_to_be32(cg_spll_spread_spectrum_2);
+
+	return 0;
+}
+
+int rv730_populate_mclk_value(struct radeon_device *rdev,
+			      u32 engine_clock, u32 memory_clock,
+			      LPRV7XX_SMC_MCLK_VALUE mclk)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	u32 mclk_pwrmgt_cntl = pi->clk_regs.rv730.mclk_pwrmgt_cntl;
+	u32 dll_cntl = pi->clk_regs.rv730.dll_cntl;
+	u32 mpll_func_cntl = pi->clk_regs.rv730.mpll_func_cntl;
+	u32 mpll_func_cntl_2 = pi->clk_regs.rv730.mpll_func_cntl2;
+	u32 mpll_func_cntl_3 = pi->clk_regs.rv730.mpll_func_cntl3;
+	u32 mpll_ss = pi->clk_regs.rv730.mpll_ss;
+	u32 mpll_ss2 = pi->clk_regs.rv730.mpll_ss2;
+	struct atom_clock_dividers dividers;
+	u32 post_divider, reference_divider;
+	int ret;
+
+	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_MEMORY_PLL_PARAM,
+					     memory_clock, false, &dividers);
+	if (ret)
+		return ret;
+
+	reference_divider = dividers.ref_div + 1;
+
+	if (dividers.enable_post_div)
+		post_divider = ((dividers.post_div >> 4) & 0xf) +
+			(dividers.post_div & 0xf) + 2;
+	else
+		post_divider = 1;
+
+	/* setup the registers */
+	if (dividers.enable_post_div)
+		mpll_func_cntl |= MPLL_DIVEN;
+	else
+		mpll_func_cntl &= ~MPLL_DIVEN;
+
+	mpll_func_cntl &= ~(MPLL_REF_DIV_MASK | MPLL_HILEN_MASK | MPLL_LOLEN_MASK);
+	mpll_func_cntl |= MPLL_REF_DIV(dividers.ref_div);
+	mpll_func_cntl |= MPLL_HILEN((dividers.post_div >> 4) & 0xf);
+	mpll_func_cntl |= MPLL_LOLEN(dividers.post_div & 0xf);
+
+	mpll_func_cntl_3 &= ~MPLL_FB_DIV_MASK;
+	mpll_func_cntl_3 |= MPLL_FB_DIV(dividers.fb_div);
+	if (dividers.enable_dithen)
+		mpll_func_cntl_3 |= MPLL_DITHEN;
+	else
+		mpll_func_cntl_3 &= ~MPLL_DITHEN;
+
+	if (pi->mclk_ss) {
+		struct radeon_atom_ss ss;
+		u32 vco_freq = memory_clock * post_divider;
+
+		if (radeon_atombios_get_asic_ss_info(rdev, &ss,
+						     ASIC_INTERNAL_MEMORY_SS, vco_freq)) {
+			u32 reference_clock = rdev->clock.mpll.reference_freq;
+			u32 clk_s = reference_clock * 5 / (reference_divider * ss.rate);
+			u32 clk_v = ss.percentage * dividers.fb_div / (clk_s * 10000);
+
+			mpll_ss &= ~CLK_S_MASK;
+			mpll_ss |= CLK_S(clk_s);
+			mpll_ss |= SSEN;
+
+			mpll_ss2 &= ~CLK_V_MASK;
+			mpll_ss |= CLK_V(clk_v);
+		}
+	}
+
+
+	mclk->mclk730.vMCLK_PWRMGT_CNTL = cpu_to_be32(mclk_pwrmgt_cntl);
+	mclk->mclk730.vDLL_CNTL = cpu_to_be32(dll_cntl);
+	mclk->mclk730.mclk_value = cpu_to_be32(memory_clock);
+	mclk->mclk730.vMPLL_FUNC_CNTL = cpu_to_be32(mpll_func_cntl);
+	mclk->mclk730.vMPLL_FUNC_CNTL2 = cpu_to_be32(mpll_func_cntl_2);
+	mclk->mclk730.vMPLL_FUNC_CNTL3 = cpu_to_be32(mpll_func_cntl_3);
+	mclk->mclk730.vMPLL_SS = cpu_to_be32(mpll_ss);
+	mclk->mclk730.vMPLL_SS2 = cpu_to_be32(mpll_ss2);
+
+	return 0;
+}
+
+void rv730_read_clock_registers(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+	pi->clk_regs.rv730.cg_spll_func_cntl =
+		RREG32(CG_SPLL_FUNC_CNTL);
+	pi->clk_regs.rv730.cg_spll_func_cntl_2 =
+		RREG32(CG_SPLL_FUNC_CNTL_2);
+	pi->clk_regs.rv730.cg_spll_func_cntl_3 =
+		RREG32(CG_SPLL_FUNC_CNTL_3);
+	pi->clk_regs.rv730.cg_spll_spread_spectrum =
+		RREG32(CG_SPLL_SPREAD_SPECTRUM);
+	pi->clk_regs.rv730.cg_spll_spread_spectrum_2 =
+		RREG32(CG_SPLL_SPREAD_SPECTRUM_2);
+
+	pi->clk_regs.rv730.mclk_pwrmgt_cntl =
+		RREG32(TCI_MCLK_PWRMGT_CNTL);
+	pi->clk_regs.rv730.dll_cntl =
+		RREG32(TCI_DLL_CNTL);
+	pi->clk_regs.rv730.mpll_func_cntl =
+		RREG32(CG_MPLL_FUNC_CNTL);
+	pi->clk_regs.rv730.mpll_func_cntl2 =
+		RREG32(CG_MPLL_FUNC_CNTL_2);
+	pi->clk_regs.rv730.mpll_func_cntl3 =
+		RREG32(CG_MPLL_FUNC_CNTL_3);
+	pi->clk_regs.rv730.mpll_ss =
+		RREG32(CG_TCI_MPLL_SPREAD_SPECTRUM);
+	pi->clk_regs.rv730.mpll_ss2 =
+		RREG32(CG_TCI_MPLL_SPREAD_SPECTRUM_2);
+}
+
+int rv730_populate_smc_acpi_state(struct radeon_device *rdev,
+				  RV770_SMC_STATETABLE *table)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	u32 mpll_func_cntl = 0;
+	u32 mpll_func_cntl_2 = 0 ;
+	u32 mpll_func_cntl_3 = 0;
+	u32 mclk_pwrmgt_cntl;
+	u32 dll_cntl;
+	u32 spll_func_cntl;
+	u32 spll_func_cntl_2;
+	u32 spll_func_cntl_3;
+
+	table->ACPIState = table->initialState;
+	table->ACPIState.flags &= ~PPSMC_SWSTATE_FLAG_DC;
+
+	if (pi->acpi_vddc) {
+		rv770_populate_vddc_value(rdev, pi->acpi_vddc,
+					  &table->ACPIState.levels[0].vddc);
+		table->ACPIState.levels[0].gen2PCIE = pi->pcie_gen2 ?
+			pi->acpi_pcie_gen2 : 0;
+		table->ACPIState.levels[0].gen2XSP =
+			pi->acpi_pcie_gen2;
+	} else {
+		rv770_populate_vddc_value(rdev, pi->min_vddc_in_table,
+					  &table->ACPIState.levels[0].vddc);
+		table->ACPIState.levels[0].gen2PCIE = 0;
+	}
+
+	mpll_func_cntl = pi->clk_regs.rv730.mpll_func_cntl;
+	mpll_func_cntl_2 = pi->clk_regs.rv730.mpll_func_cntl2;
+	mpll_func_cntl_3 = pi->clk_regs.rv730.mpll_func_cntl3;
+
+	mpll_func_cntl |= MPLL_RESET | MPLL_BYPASS_EN;
+	mpll_func_cntl &= ~MPLL_SLEEP;
+
+	mpll_func_cntl_2 &= ~MCLK_MUX_SEL_MASK;
+	mpll_func_cntl_2 |= MCLK_MUX_SEL(1);
+
+	mclk_pwrmgt_cntl = (MRDCKA_RESET |
+			    MRDCKB_RESET |
+			    MRDCKC_RESET |
+			    MRDCKD_RESET |
+			    MRDCKE_RESET |
+			    MRDCKF_RESET |
+			    MRDCKG_RESET |
+			    MRDCKH_RESET |
+			    MRDCKA_SLEEP |
+			    MRDCKB_SLEEP |
+			    MRDCKC_SLEEP |
+			    MRDCKD_SLEEP |
+			    MRDCKE_SLEEP |
+			    MRDCKF_SLEEP |
+			    MRDCKG_SLEEP |
+			    MRDCKH_SLEEP);
+
+	dll_cntl = 0xff000000;
+
+	spll_func_cntl = pi->clk_regs.rv730.cg_spll_func_cntl;
+	spll_func_cntl_2 = pi->clk_regs.rv730.cg_spll_func_cntl_2;
+	spll_func_cntl_3 = pi->clk_regs.rv730.cg_spll_func_cntl_3;
+
+	spll_func_cntl |= SPLL_RESET | SPLL_BYPASS_EN;
+	spll_func_cntl &= ~SPLL_SLEEP;
+
+	spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK;
+	spll_func_cntl_2 |= SCLK_MUX_SEL(4);
+
+	table->ACPIState.levels[0].mclk.mclk730.vMPLL_FUNC_CNTL = cpu_to_be32(mpll_func_cntl);
+	table->ACPIState.levels[0].mclk.mclk730.vMPLL_FUNC_CNTL2 = cpu_to_be32(mpll_func_cntl_2);
+	table->ACPIState.levels[0].mclk.mclk730.vMPLL_FUNC_CNTL3 = cpu_to_be32(mpll_func_cntl_3);
+	table->ACPIState.levels[0].mclk.mclk730.vMCLK_PWRMGT_CNTL = cpu_to_be32(mclk_pwrmgt_cntl);
+	table->ACPIState.levels[0].mclk.mclk730.vDLL_CNTL = cpu_to_be32(dll_cntl);
+
+	table->ACPIState.levels[0].mclk.mclk730.mclk_value = 0;
+
+	table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL = cpu_to_be32(spll_func_cntl);
+	table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_2 = cpu_to_be32(spll_func_cntl_2);
+	table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_3 = cpu_to_be32(spll_func_cntl_3);
+
+	table->ACPIState.levels[0].sclk.sclk_value = 0;
+
+	rv770_populate_mvdd_value(rdev, 0, &table->ACPIState.levels[0].mvdd);
+
+	table->ACPIState.levels[1] = table->ACPIState.levels[0];
+	table->ACPIState.levels[2] = table->ACPIState.levels[0];
+
+	return 0;
+}
+
+int rv730_populate_smc_initial_state(struct radeon_device *rdev,
+				     struct radeon_ps *radeon_state,
+				     RV770_SMC_STATETABLE *table)
+{
+	struct rv7xx_ps *initial_state = rv770_get_ps(radeon_state);
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	u32 a_t;
+
+	table->initialState.levels[0].mclk.mclk730.vMPLL_FUNC_CNTL =
+		cpu_to_be32(pi->clk_regs.rv730.mpll_func_cntl);
+	table->initialState.levels[0].mclk.mclk730.vMPLL_FUNC_CNTL2 =
+		cpu_to_be32(pi->clk_regs.rv730.mpll_func_cntl2);
+	table->initialState.levels[0].mclk.mclk730.vMPLL_FUNC_CNTL3 =
+		cpu_to_be32(pi->clk_regs.rv730.mpll_func_cntl3);
+	table->initialState.levels[0].mclk.mclk730.vMCLK_PWRMGT_CNTL =
+		cpu_to_be32(pi->clk_regs.rv730.mclk_pwrmgt_cntl);
+	table->initialState.levels[0].mclk.mclk730.vDLL_CNTL =
+		cpu_to_be32(pi->clk_regs.rv730.dll_cntl);
+	table->initialState.levels[0].mclk.mclk730.vMPLL_SS =
+		cpu_to_be32(pi->clk_regs.rv730.mpll_ss);
+	table->initialState.levels[0].mclk.mclk730.vMPLL_SS2 =
+		cpu_to_be32(pi->clk_regs.rv730.mpll_ss2);
+
+	table->initialState.levels[0].mclk.mclk730.mclk_value =
+		cpu_to_be32(initial_state->low.mclk);
+
+	table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL =
+		cpu_to_be32(pi->clk_regs.rv730.cg_spll_func_cntl);
+	table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_2 =
+		cpu_to_be32(pi->clk_regs.rv730.cg_spll_func_cntl_2);
+	table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_3 =
+		cpu_to_be32(pi->clk_regs.rv730.cg_spll_func_cntl_3);
+	table->initialState.levels[0].sclk.vCG_SPLL_SPREAD_SPECTRUM =
+		cpu_to_be32(pi->clk_regs.rv730.cg_spll_spread_spectrum);
+	table->initialState.levels[0].sclk.vCG_SPLL_SPREAD_SPECTRUM_2 =
+		cpu_to_be32(pi->clk_regs.rv730.cg_spll_spread_spectrum_2);
+
+	table->initialState.levels[0].sclk.sclk_value =
+		cpu_to_be32(initial_state->low.sclk);
+
+	table->initialState.levels[0].arbValue = MC_CG_ARB_FREQ_F0;
+
+	table->initialState.levels[0].seqValue =
+		rv770_get_seq_value(rdev, &initial_state->low);
+
+	rv770_populate_vddc_value(rdev,
+				  initial_state->low.vddc,
+				  &table->initialState.levels[0].vddc);
+	rv770_populate_initial_mvdd_value(rdev,
+					  &table->initialState.levels[0].mvdd);
+
+	a_t = CG_R(0xffff) | CG_L(0);
+
+	table->initialState.levels[0].aT = cpu_to_be32(a_t);
+
+	table->initialState.levels[0].bSP = cpu_to_be32(pi->dsp);
+
+	if (pi->boot_in_gen2)
+		table->initialState.levels[0].gen2PCIE = 1;
+	else
+		table->initialState.levels[0].gen2PCIE = 0;
+	if (initial_state->low.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2)
+		table->initialState.levels[0].gen2XSP = 1;
+	else
+		table->initialState.levels[0].gen2XSP = 0;
+
+	table->initialState.levels[1] = table->initialState.levels[0];
+	table->initialState.levels[2] = table->initialState.levels[0];
+
+	table->initialState.flags |= PPSMC_SWSTATE_FLAG_DC;
+
+	return 0;
+}
+
+void rv730_program_memory_timing_parameters(struct radeon_device *rdev,
+					    struct radeon_ps *radeon_state)
+{
+	struct rv7xx_ps *state = rv770_get_ps(radeon_state);
+	u32 arb_refresh_rate = 0;
+	u32 dram_timing = 0;
+	u32 dram_timing2 = 0;
+	u32 old_dram_timing = 0;
+	u32 old_dram_timing2 = 0;
+
+	arb_refresh_rate = RREG32(MC_ARB_RFSH_RATE) &
+		~(POWERMODE1_MASK | POWERMODE2_MASK | POWERMODE3_MASK);
+	arb_refresh_rate |=
+		(POWERMODE1(rv770_calculate_memory_refresh_rate(rdev, state->low.sclk)) |
+		 POWERMODE2(rv770_calculate_memory_refresh_rate(rdev, state->medium.sclk)) |
+		 POWERMODE3(rv770_calculate_memory_refresh_rate(rdev, state->high.sclk)));
+	WREG32(MC_ARB_RFSH_RATE, arb_refresh_rate);
+
+	/* save the boot dram timings */
+	old_dram_timing = RREG32(MC_ARB_DRAM_TIMING);
+	old_dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2);
+
+	radeon_atom_set_engine_dram_timings(rdev,
+					    state->high.sclk,
+					    state->high.mclk);
+
+	dram_timing = RREG32(MC_ARB_DRAM_TIMING);
+	dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2);
+
+	WREG32(MC_ARB_DRAM_TIMING_3, dram_timing);
+	WREG32(MC_ARB_DRAM_TIMING2_3, dram_timing2);
+
+	radeon_atom_set_engine_dram_timings(rdev,
+					    state->medium.sclk,
+					    state->medium.mclk);
+
+	dram_timing = RREG32(MC_ARB_DRAM_TIMING);
+	dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2);
+
+	WREG32(MC_ARB_DRAM_TIMING_2, dram_timing);
+	WREG32(MC_ARB_DRAM_TIMING2_2, dram_timing2);
+
+	radeon_atom_set_engine_dram_timings(rdev,
+					    state->low.sclk,
+					    state->low.mclk);
+
+	dram_timing = RREG32(MC_ARB_DRAM_TIMING);
+	dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2);
+
+	WREG32(MC_ARB_DRAM_TIMING_1, dram_timing);
+	WREG32(MC_ARB_DRAM_TIMING2_1, dram_timing2);
+
+	/* restore the boot dram timings */
+	WREG32(MC_ARB_DRAM_TIMING, old_dram_timing);
+	WREG32(MC_ARB_DRAM_TIMING2, old_dram_timing2);
+
+}
+
+void rv730_start_dpm(struct radeon_device *rdev)
+{
+	WREG32_P(SCLK_PWRMGT_CNTL, 0, ~SCLK_PWRMGT_OFF);
+
+	WREG32_P(TCI_MCLK_PWRMGT_CNTL, 0, ~MPLL_PWRMGT_OFF);
+
+	WREG32_P(GENERAL_PWRMGT, GLOBAL_PWRMGT_EN, ~GLOBAL_PWRMGT_EN);
+}
+
+void rv730_stop_dpm(struct radeon_device *rdev)
+{
+	PPSMC_Result result;
+
+	result = rv770_send_msg_to_smc(rdev, PPSMC_MSG_TwoLevelsDisabled);
+
+	if (result != PPSMC_Result_OK)
+		DRM_ERROR("Could not force DPM to low\n");
+
+	WREG32_P(GENERAL_PWRMGT, 0, ~GLOBAL_PWRMGT_EN);
+
+	WREG32_P(SCLK_PWRMGT_CNTL, SCLK_PWRMGT_OFF, ~SCLK_PWRMGT_OFF);
+
+	WREG32_P(TCI_MCLK_PWRMGT_CNTL, MPLL_PWRMGT_OFF, ~MPLL_PWRMGT_OFF);
+}
+
+void rv730_program_dcodt(struct radeon_device *rdev, bool use_dcodt)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	u32 i = use_dcodt ? 0 : 1;
+	u32 mc4_io_pad_cntl;
+
+	mc4_io_pad_cntl = RREG32(MC4_IO_DQ_PAD_CNTL_D0_I0);
+	mc4_io_pad_cntl &= 0xFFFFFF00;
+	mc4_io_pad_cntl |= pi->odt_value_0[i];
+	WREG32(MC4_IO_DQ_PAD_CNTL_D0_I0, mc4_io_pad_cntl);
+	WREG32(MC4_IO_DQ_PAD_CNTL_D0_I1, mc4_io_pad_cntl);
+
+	mc4_io_pad_cntl = RREG32(MC4_IO_QS_PAD_CNTL_D0_I0);
+	mc4_io_pad_cntl &= 0xFFFFFF00;
+	mc4_io_pad_cntl |= pi->odt_value_1[i];
+	WREG32(MC4_IO_QS_PAD_CNTL_D0_I0, mc4_io_pad_cntl);
+	WREG32(MC4_IO_QS_PAD_CNTL_D0_I1, mc4_io_pad_cntl);
+}
+
+void rv730_get_odt_values(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	u32 mc4_io_pad_cntl;
+
+	pi->odt_value_0[0] = (u8)0;
+	pi->odt_value_1[0] = (u8)0x80;
+
+	mc4_io_pad_cntl = RREG32(MC4_IO_DQ_PAD_CNTL_D0_I0);
+	pi->odt_value_0[1] = (u8)(mc4_io_pad_cntl & 0xff);
+
+	mc4_io_pad_cntl = RREG32(MC4_IO_QS_PAD_CNTL_D0_I0);
+	pi->odt_value_1[1] = (u8)(mc4_io_pad_cntl & 0xff);
+}
diff --git a/drivers/gpu/drm/radeon/rv730d.h b/drivers/gpu/drm/radeon/rv730d.h
new file mode 100644
index 0000000..f0a7954
--- /dev/null
+++ b/drivers/gpu/drm/radeon/rv730d.h
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2011 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef RV730_H
+#define RV730_H
+
+#define	CG_SPLL_FUNC_CNTL				0x600
+#define		SPLL_RESET				(1 << 0)
+#define		SPLL_SLEEP				(1 << 1)
+#define		SPLL_DIVEN				(1 << 2)
+#define		SPLL_BYPASS_EN				(1 << 3)
+#define		SPLL_REF_DIV(x)				((x) << 4)
+#define		SPLL_REF_DIV_MASK			(0x3f << 4)
+#define		SPLL_HILEN(x)				((x) << 12)
+#define		SPLL_HILEN_MASK				(0xf << 12)
+#define		SPLL_LOLEN(x)				((x) << 16)
+#define		SPLL_LOLEN_MASK				(0xf << 16)
+#define	CG_SPLL_FUNC_CNTL_2				0x604
+#define		SCLK_MUX_SEL(x)				((x) << 0)
+#define		SCLK_MUX_SEL_MASK			(0x1ff << 0)
+#define	CG_SPLL_FUNC_CNTL_3				0x608
+#define		SPLL_FB_DIV(x)				((x) << 0)
+#define		SPLL_FB_DIV_MASK			(0x3ffffff << 0)
+#define		SPLL_DITHEN				(1 << 28)
+
+#define	CG_MPLL_FUNC_CNTL				0x624
+#define		MPLL_RESET				(1 << 0)
+#define		MPLL_SLEEP				(1 << 1)
+#define		MPLL_DIVEN				(1 << 2)
+#define		MPLL_BYPASS_EN				(1 << 3)
+#define		MPLL_REF_DIV(x)				((x) << 4)
+#define		MPLL_REF_DIV_MASK			(0x3f << 4)
+#define		MPLL_HILEN(x)				((x) << 12)
+#define		MPLL_HILEN_MASK				(0xf << 12)
+#define		MPLL_LOLEN(x)				((x) << 16)
+#define		MPLL_LOLEN_MASK				(0xf << 16)
+#define	CG_MPLL_FUNC_CNTL_2				0x628
+#define		MCLK_MUX_SEL(x)				((x) << 0)
+#define		MCLK_MUX_SEL_MASK			(0x1ff << 0)
+#define	CG_MPLL_FUNC_CNTL_3				0x62c
+#define		MPLL_FB_DIV(x)				((x) << 0)
+#define		MPLL_FB_DIV_MASK			(0x3ffffff << 0)
+#define		MPLL_DITHEN				(1 << 28)
+
+#define	CG_TCI_MPLL_SPREAD_SPECTRUM			0x634
+#define	CG_TCI_MPLL_SPREAD_SPECTRUM_2			0x638
+#define GENERAL_PWRMGT                                  0x63c
+#       define GLOBAL_PWRMGT_EN                         (1 << 0)
+#       define STATIC_PM_EN                             (1 << 1)
+#       define THERMAL_PROTECTION_DIS                   (1 << 2)
+#       define THERMAL_PROTECTION_TYPE                  (1 << 3)
+#       define ENABLE_GEN2PCIE                          (1 << 4)
+#       define ENABLE_GEN2XSP                           (1 << 5)
+#       define SW_SMIO_INDEX(x)                         ((x) << 6)
+#       define SW_SMIO_INDEX_MASK                       (3 << 6)
+#       define LOW_VOLT_D2_ACPI                         (1 << 8)
+#       define LOW_VOLT_D3_ACPI                         (1 << 9)
+#       define VOLT_PWRMGT_EN                           (1 << 10)
+#       define BACKBIAS_PAD_EN                          (1 << 18)
+#       define BACKBIAS_VALUE                           (1 << 19)
+#       define DYN_SPREAD_SPECTRUM_EN                   (1 << 23)
+#       define AC_DC_SW                                 (1 << 24)
+
+#define SCLK_PWRMGT_CNTL                                  0x644
+#       define SCLK_PWRMGT_OFF                            (1 << 0)
+#       define SCLK_LOW_D1                                (1 << 1)
+#       define FIR_RESET                                  (1 << 4)
+#       define FIR_FORCE_TREND_SEL                        (1 << 5)
+#       define FIR_TREND_MODE                             (1 << 6)
+#       define DYN_GFX_CLK_OFF_EN                         (1 << 7)
+#       define GFX_CLK_FORCE_ON                           (1 << 8)
+#       define GFX_CLK_REQUEST_OFF                        (1 << 9)
+#       define GFX_CLK_FORCE_OFF                          (1 << 10)
+#       define GFX_CLK_OFF_ACPI_D1                        (1 << 11)
+#       define GFX_CLK_OFF_ACPI_D2                        (1 << 12)
+#       define GFX_CLK_OFF_ACPI_D3                        (1 << 13)
+
+#define	TCI_MCLK_PWRMGT_CNTL				0x648
+#       define MPLL_PWRMGT_OFF                          (1 << 5)
+#       define DLL_READY                                (1 << 6)
+#       define MC_INT_CNTL                              (1 << 7)
+#       define MRDCKA_SLEEP                             (1 << 8)
+#       define MRDCKB_SLEEP                             (1 << 9)
+#       define MRDCKC_SLEEP                             (1 << 10)
+#       define MRDCKD_SLEEP                             (1 << 11)
+#       define MRDCKE_SLEEP                             (1 << 12)
+#       define MRDCKF_SLEEP                             (1 << 13)
+#       define MRDCKG_SLEEP                             (1 << 14)
+#       define MRDCKH_SLEEP                             (1 << 15)
+#       define MRDCKA_RESET                             (1 << 16)
+#       define MRDCKB_RESET                             (1 << 17)
+#       define MRDCKC_RESET                             (1 << 18)
+#       define MRDCKD_RESET                             (1 << 19)
+#       define MRDCKE_RESET                             (1 << 20)
+#       define MRDCKF_RESET                             (1 << 21)
+#       define MRDCKG_RESET                             (1 << 22)
+#       define MRDCKH_RESET                             (1 << 23)
+#       define DLL_READY_READ                           (1 << 24)
+#       define USE_DISPLAY_GAP                          (1 << 25)
+#       define USE_DISPLAY_URGENT_NORMAL                (1 << 26)
+#       define MPLL_TURNOFF_D2                          (1 << 28)
+#define	TCI_DLL_CNTL					0x64c
+
+#define	CG_PG_CNTL					0x858
+#       define PWRGATE_ENABLE                           (1 << 0)
+
+#define	CG_AT				                0x6d4
+#define		CG_R(x)					((x) << 0)
+#define		CG_R_MASK				(0xffff << 0)
+#define		CG_L(x)					((x) << 16)
+#define		CG_L_MASK				(0xffff << 16)
+
+#define	CG_SPLL_SPREAD_SPECTRUM				0x790
+#define		SSEN					(1 << 0)
+#define		CLK_S(x)				((x) << 4)
+#define		CLK_S_MASK				(0xfff << 4)
+#define	CG_SPLL_SPREAD_SPECTRUM_2			0x794
+#define		CLK_V(x)				((x) << 0)
+#define		CLK_V_MASK				(0x3ffffff << 0)
+
+#define	MC_ARB_DRAM_TIMING				0x2774
+#define	MC_ARB_DRAM_TIMING2				0x2778
+
+#define	MC_ARB_RFSH_RATE				0x27b0
+#define		POWERMODE0(x)				((x) << 0)
+#define		POWERMODE0_MASK				(0xff << 0)
+#define		POWERMODE1(x)				((x) << 8)
+#define		POWERMODE1_MASK				(0xff << 8)
+#define		POWERMODE2(x)				((x) << 16)
+#define		POWERMODE2_MASK				(0xff << 16)
+#define		POWERMODE3(x)				((x) << 24)
+#define		POWERMODE3_MASK				(0xff << 24)
+
+#define	MC_ARB_DRAM_TIMING_1				0x27f0
+#define	MC_ARB_DRAM_TIMING_2				0x27f4
+#define	MC_ARB_DRAM_TIMING_3				0x27f8
+#define	MC_ARB_DRAM_TIMING2_1				0x27fc
+#define	MC_ARB_DRAM_TIMING2_2				0x2800
+#define	MC_ARB_DRAM_TIMING2_3				0x2804
+
+#define	MC4_IO_DQ_PAD_CNTL_D0_I0			0x2978
+#define	MC4_IO_DQ_PAD_CNTL_D0_I1			0x297c
+#define	MC4_IO_QS_PAD_CNTL_D0_I0			0x2980
+#define	MC4_IO_QS_PAD_CNTL_D0_I1			0x2984
+
+#endif
diff --git a/drivers/gpu/drm/radeon/rv740_dpm.c b/drivers/gpu/drm/radeon/rv740_dpm.c
new file mode 100644
index 0000000..d0d750e
--- /dev/null
+++ b/drivers/gpu/drm/radeon/rv740_dpm.c
@@ -0,0 +1,417 @@
+/*
+ * Copyright 2011 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Alex Deucher
+ */
+
+#include "drmP.h"
+#include "radeon.h"
+#include "rv740d.h"
+#include "r600_dpm.h"
+#include "rv770_dpm.h"
+#include "atom.h"
+
+struct rv7xx_ps *rv770_get_ps(struct radeon_ps *rps);
+struct rv7xx_power_info *rv770_get_pi(struct radeon_device *rdev);
+
+u32 rv740_get_decoded_reference_divider(u32 encoded_ref)
+{
+	u32 ref = 0;
+
+	switch (encoded_ref) {
+        case 0:
+		ref = 1;
+		break;
+        case 16:
+		ref = 2;
+		break;
+        case 17:
+		ref = 3;
+		break;
+        case 18:
+		ref = 2;
+		break;
+        case 19:
+		ref = 3;
+		break;
+        case 20:
+		ref = 4;
+		break;
+        case 21:
+		ref = 5;
+		break;
+        default:
+		DRM_ERROR("Invalid encoded Reference Divider\n");
+		ref = 0;
+		break;
+	}
+
+	return ref;
+}
+
+struct dll_speed_setting {
+	u16 min;
+	u16 max;
+	u32 dll_speed;
+};
+
+static struct dll_speed_setting dll_speed_table[16] =
+{
+	{ 270, 320, 0x0f },
+	{ 240, 270, 0x0e },
+	{ 200, 240, 0x0d },
+	{ 180, 200, 0x0c },
+	{ 160, 180, 0x0b },
+	{ 140, 160, 0x0a },
+	{ 120, 140, 0x09 },
+	{ 110, 120, 0x08 },
+	{  95, 110, 0x07 },
+	{  85,  95, 0x06 },
+	{  78,  85, 0x05 },
+	{  70,  78, 0x04 },
+	{  65,  70, 0x03 },
+	{  60,  65, 0x02 },
+	{  42,  60, 0x01 },
+	{  00,  42, 0x00 }
+};
+
+u32 rv740_get_dll_speed(bool is_gddr5, u32 memory_clock)
+{
+	int i;
+	u32 factor;
+	u16 data_rate;
+
+	if (is_gddr5)
+		factor = 4;
+	else
+		factor = 2;
+
+	data_rate = (u16)(memory_clock * factor / 1000);
+
+	if (data_rate < dll_speed_table[0].max) {
+		for (i = 0; i < 16; i++) {
+			if (data_rate > dll_speed_table[i].min &&
+			    data_rate <= dll_speed_table[i].max)
+				return dll_speed_table[i].dll_speed;
+		}
+	}
+
+	DRM_DEBUG_KMS("Target MCLK greater than largest MCLK in DLL speed table\n");
+
+	return 0x0f;
+}
+
+int rv740_populate_sclk_value(struct radeon_device *rdev, u32 engine_clock,
+			      RV770_SMC_SCLK_VALUE *sclk)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	struct atom_clock_dividers dividers;
+	u32 spll_func_cntl = pi->clk_regs.rv770.cg_spll_func_cntl;
+	u32 spll_func_cntl_2 = pi->clk_regs.rv770.cg_spll_func_cntl_2;
+	u32 spll_func_cntl_3 = pi->clk_regs.rv770.cg_spll_func_cntl_3;
+	u32 cg_spll_spread_spectrum = pi->clk_regs.rv770.cg_spll_spread_spectrum;
+	u32 cg_spll_spread_spectrum_2 = pi->clk_regs.rv770.cg_spll_spread_spectrum_2;
+	u64 tmp;
+	u32 reference_clock = rdev->clock.spll.reference_freq;
+	u32 reference_divider;
+	u32 fbdiv;
+	int ret;
+
+	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
+					     engine_clock, false, &dividers);
+	if (ret)
+		return ret;
+
+	reference_divider = 1 + dividers.ref_div;
+
+	tmp = (u64) engine_clock * reference_divider * dividers.post_div;
+
+	fbdiv = (u32) ((16384 * tmp) / reference_clock);
+
+	spll_func_cntl &= ~(SPLL_PDIV_A_MASK | SPLL_REF_DIV_MASK);
+	spll_func_cntl |= SPLL_REF_DIV(dividers.ref_div);
+	spll_func_cntl |= SPLL_PDIV_A(dividers.post_div);
+
+	spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK;
+	spll_func_cntl_2 |= SCLK_MUX_SEL(2);
+
+	spll_func_cntl_3 &= ~SPLL_FB_DIV_MASK;
+	spll_func_cntl_3 |= SPLL_FB_DIV(fbdiv);
+	spll_func_cntl_3 |= SPLL_DITHEN;
+
+	if (pi->sclk_ss) {
+		struct radeon_atom_ss ss;
+		u32 vco_freq = engine_clock * dividers.post_div;
+
+		if (radeon_atombios_get_asic_ss_info(rdev, &ss,
+						     ASIC_INTERNAL_ENGINE_SS, vco_freq)) {
+			u32 clk_s = reference_clock * 5 / (reference_divider * ss.rate);
+			u32 clk_v = 4 * ss.percentage * fbdiv / (clk_s * 10000);
+
+			cg_spll_spread_spectrum &= ~CLK_S_MASK;
+			cg_spll_spread_spectrum |= CLK_S(clk_s);
+			cg_spll_spread_spectrum |= SSEN;
+
+			cg_spll_spread_spectrum_2 &= ~CLK_V_MASK;
+			cg_spll_spread_spectrum_2 |= CLK_V(clk_v);
+		}
+	}
+
+	sclk->sclk_value = cpu_to_be32(engine_clock);
+	sclk->vCG_SPLL_FUNC_CNTL = cpu_to_be32(spll_func_cntl);
+	sclk->vCG_SPLL_FUNC_CNTL_2 = cpu_to_be32(spll_func_cntl_2);
+	sclk->vCG_SPLL_FUNC_CNTL_3 = cpu_to_be32(spll_func_cntl_3);
+	sclk->vCG_SPLL_SPREAD_SPECTRUM = cpu_to_be32(cg_spll_spread_spectrum);
+	sclk->vCG_SPLL_SPREAD_SPECTRUM_2 = cpu_to_be32(cg_spll_spread_spectrum_2);
+
+	return 0;
+}
+
+int rv740_populate_mclk_value(struct radeon_device *rdev,
+			      u32 engine_clock, u32 memory_clock,
+			      RV7XX_SMC_MCLK_VALUE *mclk)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	u32 mpll_ad_func_cntl = pi->clk_regs.rv770.mpll_ad_func_cntl;
+	u32 mpll_ad_func_cntl_2 = pi->clk_regs.rv770.mpll_ad_func_cntl_2;
+	u32 mpll_dq_func_cntl = pi->clk_regs.rv770.mpll_dq_func_cntl;
+	u32 mpll_dq_func_cntl_2 = pi->clk_regs.rv770.mpll_dq_func_cntl_2;
+	u32 mclk_pwrmgt_cntl = pi->clk_regs.rv770.mclk_pwrmgt_cntl;
+	u32 dll_cntl = pi->clk_regs.rv770.dll_cntl;
+	u32 mpll_ss1 = pi->clk_regs.rv770.mpll_ss1;
+	u32 mpll_ss2 = pi->clk_regs.rv770.mpll_ss2;
+	struct atom_clock_dividers dividers;
+	u32 ibias;
+	u32 dll_speed;
+	int ret;
+
+	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_MEMORY_PLL_PARAM,
+					     memory_clock, false, &dividers);
+	if (ret)
+		return ret;
+
+	ibias = rv770_map_clkf_to_ibias(rdev, dividers.whole_fb_div);
+
+	mpll_ad_func_cntl &= ~(CLKR_MASK |
+			       YCLK_POST_DIV_MASK |
+			       CLKF_MASK |
+			       CLKFRAC_MASK |
+			       IBIAS_MASK);
+	mpll_ad_func_cntl |= CLKR(dividers.ref_div);
+	mpll_ad_func_cntl |= YCLK_POST_DIV(dividers.post_div);
+	mpll_ad_func_cntl |= CLKF(dividers.whole_fb_div);
+	mpll_ad_func_cntl |= CLKFRAC(dividers.frac_fb_div);
+	mpll_ad_func_cntl |= IBIAS(ibias);
+
+	if (dividers.vco_mode)
+		mpll_ad_func_cntl_2 |= VCO_MODE;
+	else
+		mpll_ad_func_cntl_2 &= ~VCO_MODE;
+
+	if (pi->mem_gddr5) {
+		mpll_dq_func_cntl &= ~(CLKR_MASK |
+				       YCLK_POST_DIV_MASK |
+				       CLKF_MASK |
+				       CLKFRAC_MASK |
+				       IBIAS_MASK);
+		mpll_dq_func_cntl |= CLKR(dividers.ref_div);
+		mpll_dq_func_cntl |= YCLK_POST_DIV(dividers.post_div);
+		mpll_dq_func_cntl |= CLKF(dividers.whole_fb_div);
+		mpll_dq_func_cntl |= CLKFRAC(dividers.frac_fb_div);
+		mpll_dq_func_cntl |= IBIAS(ibias);
+
+		if (dividers.vco_mode)
+			mpll_dq_func_cntl_2 |= VCO_MODE;
+		else
+			mpll_dq_func_cntl_2 &= ~VCO_MODE;
+	}
+
+	if (pi->mclk_ss) {
+		struct radeon_atom_ss ss;
+		u32 vco_freq = memory_clock * dividers.post_div;
+
+		if (radeon_atombios_get_asic_ss_info(rdev, &ss,
+						     ASIC_INTERNAL_MEMORY_SS, vco_freq)) {
+			u32 reference_clock = rdev->clock.mpll.reference_freq;
+			u32 decoded_ref = rv740_get_decoded_reference_divider(dividers.ref_div);
+			u32 clk_s = reference_clock * 5 / (decoded_ref * ss.rate);
+			u32 clk_v = 0x40000 * ss.percentage *
+				(dividers.whole_fb_div + (dividers.frac_fb_div / 8)) / (clk_s * 10000);
+
+			mpll_ss1 &= ~CLKV_MASK;
+			mpll_ss1 |= CLKV(clk_v);
+
+			mpll_ss2 &= ~CLKS_MASK;
+			mpll_ss2 |= CLKS(clk_s);
+		}
+	}
+
+	dll_speed = rv740_get_dll_speed(pi->mem_gddr5,
+					memory_clock);
+
+	mclk_pwrmgt_cntl &= ~DLL_SPEED_MASK;
+	mclk_pwrmgt_cntl |= DLL_SPEED(dll_speed);
+
+	mclk->mclk770.mclk_value = cpu_to_be32(memory_clock);
+	mclk->mclk770.vMPLL_AD_FUNC_CNTL = cpu_to_be32(mpll_ad_func_cntl);
+	mclk->mclk770.vMPLL_AD_FUNC_CNTL_2 = cpu_to_be32(mpll_ad_func_cntl_2);
+	mclk->mclk770.vMPLL_DQ_FUNC_CNTL = cpu_to_be32(mpll_dq_func_cntl);
+	mclk->mclk770.vMPLL_DQ_FUNC_CNTL_2 = cpu_to_be32(mpll_dq_func_cntl_2);
+	mclk->mclk770.vMCLK_PWRMGT_CNTL = cpu_to_be32(mclk_pwrmgt_cntl);
+	mclk->mclk770.vDLL_CNTL = cpu_to_be32(dll_cntl);
+	mclk->mclk770.vMPLL_SS = cpu_to_be32(mpll_ss1);
+	mclk->mclk770.vMPLL_SS2 = cpu_to_be32(mpll_ss2);
+
+	return 0;
+}
+
+void rv740_read_clock_registers(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+	pi->clk_regs.rv770.cg_spll_func_cntl =
+		RREG32(CG_SPLL_FUNC_CNTL);
+	pi->clk_regs.rv770.cg_spll_func_cntl_2 =
+		RREG32(CG_SPLL_FUNC_CNTL_2);
+	pi->clk_regs.rv770.cg_spll_func_cntl_3 =
+		RREG32(CG_SPLL_FUNC_CNTL_3);
+	pi->clk_regs.rv770.cg_spll_spread_spectrum =
+		RREG32(CG_SPLL_SPREAD_SPECTRUM);
+	pi->clk_regs.rv770.cg_spll_spread_spectrum_2 =
+		RREG32(CG_SPLL_SPREAD_SPECTRUM_2);
+
+	pi->clk_regs.rv770.mpll_ad_func_cntl =
+		RREG32(MPLL_AD_FUNC_CNTL);
+	pi->clk_regs.rv770.mpll_ad_func_cntl_2 =
+		RREG32(MPLL_AD_FUNC_CNTL_2);
+	pi->clk_regs.rv770.mpll_dq_func_cntl =
+		RREG32(MPLL_DQ_FUNC_CNTL);
+	pi->clk_regs.rv770.mpll_dq_func_cntl_2 =
+		RREG32(MPLL_DQ_FUNC_CNTL_2);
+	pi->clk_regs.rv770.mclk_pwrmgt_cntl =
+		RREG32(MCLK_PWRMGT_CNTL);
+	pi->clk_regs.rv770.dll_cntl = RREG32(DLL_CNTL);
+	pi->clk_regs.rv770.mpll_ss1 = RREG32(MPLL_SS1);
+	pi->clk_regs.rv770.mpll_ss2 = RREG32(MPLL_SS2);
+}
+
+int rv740_populate_smc_acpi_state(struct radeon_device *rdev,
+				  RV770_SMC_STATETABLE *table)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	u32 mpll_ad_func_cntl = pi->clk_regs.rv770.mpll_ad_func_cntl;
+	u32 mpll_ad_func_cntl_2 = pi->clk_regs.rv770.mpll_ad_func_cntl_2;
+	u32 mpll_dq_func_cntl = pi->clk_regs.rv770.mpll_dq_func_cntl;
+	u32 mpll_dq_func_cntl_2 = pi->clk_regs.rv770.mpll_dq_func_cntl_2;
+	u32 spll_func_cntl = pi->clk_regs.rv770.cg_spll_func_cntl;
+	u32 spll_func_cntl_2 = pi->clk_regs.rv770.cg_spll_func_cntl_2;
+	u32 spll_func_cntl_3 = pi->clk_regs.rv770.cg_spll_func_cntl_3;
+	u32 mclk_pwrmgt_cntl = pi->clk_regs.rv770.mclk_pwrmgt_cntl;
+	u32 dll_cntl = pi->clk_regs.rv770.dll_cntl;
+
+	table->ACPIState = table->initialState;
+
+	table->ACPIState.flags &= ~PPSMC_SWSTATE_FLAG_DC;
+
+	if (pi->acpi_vddc) {
+		rv770_populate_vddc_value(rdev, pi->acpi_vddc,
+					  &table->ACPIState.levels[0].vddc);
+		table->ACPIState.levels[0].gen2PCIE =
+			pi->pcie_gen2 ?
+			pi->acpi_pcie_gen2 : 0;
+		table->ACPIState.levels[0].gen2XSP =
+			pi->acpi_pcie_gen2;
+	} else {
+		rv770_populate_vddc_value(rdev, pi->min_vddc_in_table,
+					  &table->ACPIState.levels[0].vddc);
+		table->ACPIState.levels[0].gen2PCIE = 0;
+	}
+
+	mpll_ad_func_cntl_2 |= BIAS_GEN_PDNB | RESET_EN;
+
+	mpll_dq_func_cntl_2 |= BYPASS | BIAS_GEN_PDNB | RESET_EN;
+
+	mclk_pwrmgt_cntl |= (MRDCKA0_RESET |
+			     MRDCKA1_RESET |
+			     MRDCKB0_RESET |
+			     MRDCKB1_RESET |
+			     MRDCKC0_RESET |
+			     MRDCKC1_RESET |
+			     MRDCKD0_RESET |
+			     MRDCKD1_RESET);
+
+	dll_cntl |= (MRDCKA0_BYPASS |
+		     MRDCKA1_BYPASS |
+		     MRDCKB0_BYPASS |
+		     MRDCKB1_BYPASS |
+		     MRDCKC0_BYPASS |
+		     MRDCKC1_BYPASS |
+		     MRDCKD0_BYPASS |
+		     MRDCKD1_BYPASS);
+
+	spll_func_cntl |= SPLL_RESET | SPLL_SLEEP | SPLL_BYPASS_EN;
+
+	spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK;
+	spll_func_cntl_2 |= SCLK_MUX_SEL(4);
+
+	table->ACPIState.levels[0].mclk.mclk770.vMPLL_AD_FUNC_CNTL = cpu_to_be32(mpll_ad_func_cntl);
+	table->ACPIState.levels[0].mclk.mclk770.vMPLL_AD_FUNC_CNTL_2 = cpu_to_be32(mpll_ad_func_cntl_2);
+	table->ACPIState.levels[0].mclk.mclk770.vMPLL_DQ_FUNC_CNTL = cpu_to_be32(mpll_dq_func_cntl);
+	table->ACPIState.levels[0].mclk.mclk770.vMPLL_DQ_FUNC_CNTL_2 = cpu_to_be32(mpll_dq_func_cntl_2);
+	table->ACPIState.levels[0].mclk.mclk770.vMCLK_PWRMGT_CNTL = cpu_to_be32(mclk_pwrmgt_cntl);
+	table->ACPIState.levels[0].mclk.mclk770.vDLL_CNTL = cpu_to_be32(dll_cntl);
+
+	table->ACPIState.levels[0].mclk.mclk770.mclk_value = 0;
+
+	table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL = cpu_to_be32(spll_func_cntl);
+	table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_2 = cpu_to_be32(spll_func_cntl_2);
+	table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_3 = cpu_to_be32(spll_func_cntl_3);
+
+	table->ACPIState.levels[0].sclk.sclk_value = 0;
+
+	table->ACPIState.levels[1] = table->ACPIState.levels[0];
+	table->ACPIState.levels[2] = table->ACPIState.levels[0];
+
+	rv770_populate_mvdd_value(rdev, 0, &table->ACPIState.levels[0].mvdd);
+
+	return 0;
+}
+
+void rv740_enable_mclk_spread_spectrum(struct radeon_device *rdev,
+				       bool enable)
+{
+	if (enable)
+		WREG32_P(MPLL_CNTL_MODE, SS_SSEN, ~SS_SSEN);
+	else
+		WREG32_P(MPLL_CNTL_MODE, 0, ~SS_SSEN);
+}
+
+u8 rv740_get_mclk_frequency_ratio(u32 memory_clock)
+{
+	u8 mc_para_index;
+
+	if ((memory_clock < 10000) || (memory_clock > 47500))
+		mc_para_index = 0x00;
+	else
+		mc_para_index = (u8)((memory_clock - 10000) / 2500);
+
+	return mc_para_index;
+}
diff --git a/drivers/gpu/drm/radeon/rv740d.h b/drivers/gpu/drm/radeon/rv740d.h
new file mode 100644
index 0000000..fe5ab07
--- /dev/null
+++ b/drivers/gpu/drm/radeon/rv740d.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2011 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef RV740_H
+#define RV740_H
+
+#define	CG_SPLL_FUNC_CNTL				0x600
+#define		SPLL_RESET				(1 << 0)
+#define		SPLL_SLEEP				(1 << 1)
+#define		SPLL_BYPASS_EN				(1 << 3)
+#define		SPLL_REF_DIV(x)				((x) << 4)
+#define		SPLL_REF_DIV_MASK			(0x3f << 4)
+#define		SPLL_PDIV_A(x)				((x) << 20)
+#define		SPLL_PDIV_A_MASK			(0x7f << 20)
+#define	CG_SPLL_FUNC_CNTL_2				0x604
+#define		SCLK_MUX_SEL(x)				((x) << 0)
+#define		SCLK_MUX_SEL_MASK			(0x1ff << 0)
+#define	CG_SPLL_FUNC_CNTL_3				0x608
+#define		SPLL_FB_DIV(x)				((x) << 0)
+#define		SPLL_FB_DIV_MASK			(0x3ffffff << 0)
+#define		SPLL_DITHEN				(1 << 28)
+
+#define	MPLL_CNTL_MODE					0x61c
+#define		SS_SSEN					(1 << 24)
+
+#define	MPLL_AD_FUNC_CNTL				0x624
+#define		CLKF(x)					((x) << 0)
+#define		CLKF_MASK				(0x7f << 0)
+#define		CLKR(x)					((x) << 7)
+#define		CLKR_MASK				(0x1f << 7)
+#define		CLKFRAC(x)				((x) << 12)
+#define		CLKFRAC_MASK				(0x1f << 12)
+#define		YCLK_POST_DIV(x)			((x) << 17)
+#define		YCLK_POST_DIV_MASK			(3 << 17)
+#define		IBIAS(x)				((x) << 20)
+#define		IBIAS_MASK				(0x3ff << 20)
+#define		RESET					(1 << 30)
+#define		PDNB					(1 << 31)
+#define	MPLL_AD_FUNC_CNTL_2				0x628
+#define		BYPASS					(1 << 19)
+#define		BIAS_GEN_PDNB				(1 << 24)
+#define		RESET_EN				(1 << 25)
+#define		VCO_MODE				(1 << 29)
+#define	MPLL_DQ_FUNC_CNTL				0x62c
+#define	MPLL_DQ_FUNC_CNTL_2				0x630
+
+#define	MCLK_PWRMGT_CNTL				0x648
+#define		DLL_SPEED(x)				((x) << 0)
+#define		DLL_SPEED_MASK				(0x1f << 0)
+#       define MPLL_PWRMGT_OFF                          (1 << 5)
+#       define DLL_READY                                (1 << 6)
+#       define MC_INT_CNTL                              (1 << 7)
+#       define MRDCKA0_SLEEP                            (1 << 8)
+#       define MRDCKA1_SLEEP                            (1 << 9)
+#       define MRDCKB0_SLEEP                            (1 << 10)
+#       define MRDCKB1_SLEEP                            (1 << 11)
+#       define MRDCKC0_SLEEP                            (1 << 12)
+#       define MRDCKC1_SLEEP                            (1 << 13)
+#       define MRDCKD0_SLEEP                            (1 << 14)
+#       define MRDCKD1_SLEEP                            (1 << 15)
+#       define MRDCKA0_RESET                            (1 << 16)
+#       define MRDCKA1_RESET                            (1 << 17)
+#       define MRDCKB0_RESET                            (1 << 18)
+#       define MRDCKB1_RESET                            (1 << 19)
+#       define MRDCKC0_RESET                            (1 << 20)
+#       define MRDCKC1_RESET                            (1 << 21)
+#       define MRDCKD0_RESET                            (1 << 22)
+#       define MRDCKD1_RESET                            (1 << 23)
+#       define DLL_READY_READ                           (1 << 24)
+#       define USE_DISPLAY_GAP                          (1 << 25)
+#       define USE_DISPLAY_URGENT_NORMAL                (1 << 26)
+#       define MPLL_TURNOFF_D2                          (1 << 28)
+#define	DLL_CNTL					0x64c
+#       define MRDCKA0_BYPASS                           (1 << 24)
+#       define MRDCKA1_BYPASS                           (1 << 25)
+#       define MRDCKB0_BYPASS                           (1 << 26)
+#       define MRDCKB1_BYPASS                           (1 << 27)
+#       define MRDCKC0_BYPASS                           (1 << 28)
+#       define MRDCKC1_BYPASS                           (1 << 29)
+#       define MRDCKD0_BYPASS                           (1 << 30)
+#       define MRDCKD1_BYPASS                           (1 << 31)
+
+#define	CG_SPLL_SPREAD_SPECTRUM				0x790
+#define		SSEN					(1 << 0)
+#define		CLK_S(x)				((x) << 4)
+#define		CLK_S_MASK				(0xfff << 4)
+#define	CG_SPLL_SPREAD_SPECTRUM_2			0x794
+#define		CLK_V(x)				((x) << 0)
+#define		CLK_V_MASK				(0x3ffffff << 0)
+
+#define	MPLL_SS1					0x85c
+#define		CLKV(x)					((x) << 0)
+#define		CLKV_MASK				(0x3ffffff << 0)
+#define	MPLL_SS2					0x860
+#define		CLKS(x)					((x) << 0)
+#define		CLKS_MASK				(0xfff << 0)
+
+#endif
diff --git a/drivers/gpu/drm/radeon/rv770_dpm.c b/drivers/gpu/drm/radeon/rv770_dpm.c
new file mode 100644
index 0000000..81660a6
--- /dev/null
+++ b/drivers/gpu/drm/radeon/rv770_dpm.c
@@ -0,0 +1,2325 @@
+/*
+ * Copyright 2011 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Alex Deucher
+ */
+
+#include "drmP.h"
+#include "radeon.h"
+#include "rv770d.h"
+#include "r600_dpm.h"
+#include "rv770_dpm.h"
+#include "atom.h"
+
+#define MC_CG_ARB_FREQ_F0           0x0a
+#define MC_CG_ARB_FREQ_F1           0x0b
+#define MC_CG_ARB_FREQ_F2           0x0c
+#define MC_CG_ARB_FREQ_F3           0x0d
+
+#define MC_CG_SEQ_DRAMCONF_S0       0x05
+#define MC_CG_SEQ_DRAMCONF_S1       0x06
+
+#define PCIE_BUS_CLK                10000
+#define TCLK                        (PCIE_BUS_CLK / 10)
+
+#define SMC_RAM_END 0xC000
+
+struct rv7xx_ps *rv770_get_ps(struct radeon_ps *rps)
+{
+	struct rv7xx_ps *ps = rps->ps_priv;
+
+	return ps;
+}
+
+struct rv7xx_power_info *rv770_get_pi(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rdev->pm.dpm.priv;
+
+	return pi;
+}
+
+static void rv770_enable_bif_dynamic_pcie_gen2(struct radeon_device *rdev,
+					       bool enable)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	u32 tmp;
+
+	tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL);
+	if (enable) {
+		tmp &= ~LC_HW_VOLTAGE_IF_CONTROL_MASK;
+		tmp |= LC_HW_VOLTAGE_IF_CONTROL(1);
+		tmp |= LC_GEN2_EN_STRAP;
+	} else {
+		if (!pi->boot_in_gen2) {
+			tmp &= ~LC_HW_VOLTAGE_IF_CONTROL_MASK;
+			tmp &= ~LC_GEN2_EN_STRAP;
+		}
+	}
+	if ((tmp & LC_OTHER_SIDE_EVER_SENT_GEN2) ||
+	    (tmp & LC_OTHER_SIDE_SUPPORTS_GEN2))
+		WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp);
+
+}
+
+static void rv770_enable_l0s(struct radeon_device *rdev)
+{
+	u32 tmp;
+
+	tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL) & ~LC_L0S_INACTIVITY_MASK;
+	tmp |= LC_L0S_INACTIVITY(3);
+	WREG32_PCIE_PORT(PCIE_LC_CNTL, tmp);
+}
+
+static void rv770_enable_l1(struct radeon_device *rdev)
+{
+	u32 tmp;
+
+	tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL);
+	tmp &= ~LC_L1_INACTIVITY_MASK;
+	tmp |= LC_L1_INACTIVITY(4);
+	tmp &= ~LC_PMI_TO_L1_DIS;
+	tmp &= ~LC_ASPM_TO_L1_DIS;
+	WREG32_PCIE_PORT(PCIE_LC_CNTL, tmp);
+}
+
+static void rv770_enable_pll_sleep_in_l1(struct radeon_device *rdev)
+{
+	u32 tmp;
+
+	tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL) & ~LC_L1_INACTIVITY_MASK;
+	tmp |= LC_L1_INACTIVITY(8);
+	WREG32_PCIE_PORT(PCIE_LC_CNTL, tmp);
+
+	/* NOTE, this is a PCIE indirect reg, not PCIE PORT */
+	tmp = RREG32_PCIE(PCIE_P_CNTL);
+	tmp |= P_PLL_PWRDN_IN_L1L23;
+	tmp &= ~P_PLL_BUF_PDNB;
+	tmp &= ~P_PLL_PDNB;
+	tmp |= P_ALLOW_PRX_FRONTEND_SHUTOFF;
+	WREG32_PCIE(PCIE_P_CNTL, tmp);
+}
+
+static void rv770_gfx_clock_gating_enable(struct radeon_device *rdev,
+					  bool enable)
+{
+	if (enable)
+		WREG32_P(SCLK_PWRMGT_CNTL, DYN_GFX_CLK_OFF_EN, ~DYN_GFX_CLK_OFF_EN);
+	else {
+		WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_GFX_CLK_OFF_EN);
+		WREG32_P(SCLK_PWRMGT_CNTL, GFX_CLK_FORCE_ON, ~GFX_CLK_FORCE_ON);
+		WREG32_P(SCLK_PWRMGT_CNTL, 0, ~GFX_CLK_FORCE_ON);
+		RREG32(GB_TILING_CONFIG);
+	}
+}
+
+static void rv770_mg_clock_gating_enable(struct radeon_device *rdev,
+					 bool enable)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+	if (enable) {
+		u32 mgcg_cgtt_local0;
+
+		if (rdev->family == CHIP_RV770)
+			mgcg_cgtt_local0 = RV770_MGCGTTLOCAL0_DFLT;
+		else
+			mgcg_cgtt_local0 = RV7XX_MGCGTTLOCAL0_DFLT;
+
+		WREG32(CG_CGTT_LOCAL_0, mgcg_cgtt_local0);
+		WREG32(CG_CGTT_LOCAL_1, (RV770_MGCGTTLOCAL1_DFLT & 0xFFFFCFFF));
+
+		if (pi->mgcgtssm)
+			WREG32(CGTS_SM_CTRL_REG, RV770_MGCGCGTSSMCTRL_DFLT);
+	} else {
+		WREG32(CG_CGTT_LOCAL_0, 0xFFFFFFFF);
+		WREG32(CG_CGTT_LOCAL_1, 0xFFFFCFFF);
+	}
+}
+
+void rv770_restore_cgcg(struct radeon_device *rdev)
+{
+	bool dpm_en = false, cg_en = false;
+
+	if (RREG32(GENERAL_PWRMGT) & GLOBAL_PWRMGT_EN)
+		dpm_en = true;
+	if (RREG32(SCLK_PWRMGT_CNTL) & DYN_GFX_CLK_OFF_EN)
+		cg_en = true;
+
+	if (dpm_en && !cg_en)
+		WREG32_P(SCLK_PWRMGT_CNTL, DYN_GFX_CLK_OFF_EN, ~DYN_GFX_CLK_OFF_EN);
+}
+
+static void rv770_start_dpm(struct radeon_device *rdev)
+{
+	WREG32_P(SCLK_PWRMGT_CNTL, 0, ~SCLK_PWRMGT_OFF);
+
+	WREG32_P(MCLK_PWRMGT_CNTL, 0, ~MPLL_PWRMGT_OFF);
+
+	WREG32_P(GENERAL_PWRMGT, GLOBAL_PWRMGT_EN, ~GLOBAL_PWRMGT_EN);
+}
+
+void rv770_stop_dpm(struct radeon_device *rdev)
+{
+	PPSMC_Result result;
+
+	result = rv770_send_msg_to_smc(rdev, PPSMC_MSG_TwoLevelsDisabled);
+
+	if (result != PPSMC_Result_OK)
+		DRM_ERROR("Could not force DPM to low.\n");
+
+	WREG32_P(GENERAL_PWRMGT, 0, ~GLOBAL_PWRMGT_EN);
+
+	WREG32_P(SCLK_PWRMGT_CNTL, SCLK_PWRMGT_OFF, ~SCLK_PWRMGT_OFF);
+
+	WREG32_P(MCLK_PWRMGT_CNTL, MPLL_PWRMGT_OFF, ~MPLL_PWRMGT_OFF);
+}
+
+bool rv770_dpm_enabled(struct radeon_device *rdev)
+{
+	if (RREG32(GENERAL_PWRMGT) & GLOBAL_PWRMGT_EN)
+		return true;
+	else
+		return false;
+}
+
+void rv770_enable_thermal_protection(struct radeon_device *rdev,
+				     bool enable)
+{
+	if (enable)
+		WREG32_P(GENERAL_PWRMGT, 0, ~THERMAL_PROTECTION_DIS);
+	else
+		WREG32_P(GENERAL_PWRMGT, THERMAL_PROTECTION_DIS, ~THERMAL_PROTECTION_DIS);
+}
+
+void rv770_enable_acpi_pm(struct radeon_device *rdev)
+{
+	WREG32_P(GENERAL_PWRMGT, STATIC_PM_EN, ~STATIC_PM_EN);
+}
+
+u8 rv770_get_seq_value(struct radeon_device *rdev,
+		       struct rv7xx_pl *pl)
+{
+	return (pl->flags & ATOM_PPLIB_R600_FLAGS_LOWPOWER) ?
+		MC_CG_SEQ_DRAMCONF_S0 : MC_CG_SEQ_DRAMCONF_S1;
+}
+
+int rv770_read_smc_soft_register(struct radeon_device *rdev,
+				 u16 reg_offset, u32 *value)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+	return rv770_read_smc_sram_dword(rdev,
+					 pi->soft_regs_start + reg_offset,
+					 value, pi->sram_end);
+}
+
+int rv770_write_smc_soft_register(struct radeon_device *rdev,
+				  u16 reg_offset, u32 value)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+	return rv770_write_smc_sram_dword(rdev,
+					  pi->soft_regs_start + reg_offset,
+					  value, pi->sram_end);
+}
+
+int rv770_populate_smc_t(struct radeon_device *rdev,
+			 struct radeon_ps *radeon_state,
+			 RV770_SMC_SWSTATE *smc_state)
+{
+	struct rv7xx_ps *state = rv770_get_ps(radeon_state);
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	int i;
+	int a_n;
+	int a_d;
+	u8 l[RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE];
+	u8 r[RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE];
+	u32 a_t;
+
+	l[0] = 0;
+	r[2] = 100;
+
+	a_n = (int)state->medium.sclk * RV770_LMP_DFLT +
+		(int)state->low.sclk * (R600_AH_DFLT - RV770_RLP_DFLT);
+	a_d = (int)state->low.sclk * (100 - (int)RV770_RLP_DFLT) +
+		(int)state->medium.sclk * RV770_LMP_DFLT;
+
+	l[1] = (u8)(RV770_LMP_DFLT - (int)RV770_LMP_DFLT * a_n / a_d);
+	r[0] = (u8)(RV770_RLP_DFLT + (100 - (int)RV770_RLP_DFLT) * a_n / a_d);
+
+	a_n = (int)state->high.sclk * RV770_LHP_DFLT +
+		(int)state->medium.sclk *
+		(R600_AH_DFLT - RV770_RMP_DFLT);
+	a_d = (int)state->medium.sclk * (100 - (int)RV770_RMP_DFLT) +
+		(int)state->high.sclk * RV770_LHP_DFLT;
+
+	l[2] = (u8)(RV770_LHP_DFLT - (int)RV770_LHP_DFLT * a_n / a_d);
+	r[1] = (u8)(RV770_RMP_DFLT + (100 - (int)RV770_RMP_DFLT) * a_n / a_d);
+
+	for (i = 0; i < (RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE - 1); i++) {
+		a_t = CG_R(r[i] * pi->bsp / 200) | CG_L(l[i] * pi->bsp / 200);
+		smc_state->levels[i].aT = cpu_to_be32(a_t);
+	}
+
+	a_t = CG_R(r[RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE - 1] * pi->pbsp / 200) |
+		CG_L(l[RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE - 1] * pi->pbsp / 200);
+
+	smc_state->levels[RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE - 1].aT =
+		cpu_to_be32(a_t);
+
+	return 0;
+}
+
+int rv770_populate_smc_sp(struct radeon_device *rdev,
+			  struct radeon_ps *radeon_state,
+			  RV770_SMC_SWSTATE *smc_state)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	int i;
+
+	for (i = 0; i < (RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE - 1); i++)
+		smc_state->levels[i].bSP = cpu_to_be32(pi->dsp);
+
+	smc_state->levels[RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE - 1].bSP =
+		cpu_to_be32(pi->psp);
+
+	return 0;
+}
+
+static void rv770_calculate_fractional_mpll_feedback_divider(u32 memory_clock,
+							     u32 reference_clock,
+							     bool gddr5,
+							     struct atom_clock_dividers *dividers,
+							     u32 *clkf,
+							     u32 *clkfrac)
+{
+	u32 post_divider, reference_divider, feedback_divider8;
+	u32 fyclk;
+
+	if (gddr5)
+		fyclk = (memory_clock * 8) / 2;
+	else
+		fyclk = (memory_clock * 4) / 2;
+
+	post_divider = dividers->post_div;
+	reference_divider = dividers->ref_div;
+
+	feedback_divider8 =
+		(8 * fyclk * reference_divider * post_divider) / reference_clock;
+
+	*clkf = feedback_divider8 / 8;
+	*clkfrac = feedback_divider8 % 8;
+}
+
+static int rv770_encode_yclk_post_div(u32 postdiv, u32 *encoded_postdiv)
+{
+	int ret = 0;
+
+	switch (postdiv) {
+        case 1:
+		*encoded_postdiv = 0;
+		break;
+        case 2:
+		*encoded_postdiv = 1;
+		break;
+        case 4:
+		*encoded_postdiv = 2;
+		break;
+        case 8:
+		*encoded_postdiv = 3;
+		break;
+        case 16:
+		*encoded_postdiv = 4;
+		break;
+        default:
+		ret = -EINVAL;
+		break;
+	}
+
+    return ret;
+}
+
+u32 rv770_map_clkf_to_ibias(struct radeon_device *rdev, u32 clkf)
+{
+	if (clkf <= 0x10)
+		return 0x4B;
+	if (clkf <= 0x19)
+		return 0x5B;
+	if (clkf <= 0x21)
+		return 0x2B;
+	if (clkf <= 0x27)
+		return 0x6C;
+	if (clkf <= 0x31)
+		return 0x9D;
+	return 0xC6;
+}
+
+static int rv770_populate_mclk_value(struct radeon_device *rdev,
+				     u32 engine_clock, u32 memory_clock,
+				     RV7XX_SMC_MCLK_VALUE *mclk)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	u8 encoded_reference_dividers[] = { 0, 16, 17, 20, 21 };
+	u32 mpll_ad_func_cntl =
+		pi->clk_regs.rv770.mpll_ad_func_cntl;
+	u32 mpll_ad_func_cntl_2 =
+		pi->clk_regs.rv770.mpll_ad_func_cntl_2;
+	u32 mpll_dq_func_cntl =
+		pi->clk_regs.rv770.mpll_dq_func_cntl;
+	u32 mpll_dq_func_cntl_2 =
+		pi->clk_regs.rv770.mpll_dq_func_cntl_2;
+	u32 mclk_pwrmgt_cntl =
+		pi->clk_regs.rv770.mclk_pwrmgt_cntl;
+	u32 dll_cntl = pi->clk_regs.rv770.dll_cntl;
+	struct atom_clock_dividers dividers;
+	u32 reference_clock = rdev->clock.mpll.reference_freq;
+	u32 clkf, clkfrac;
+	u32 postdiv_yclk;
+	u32 ibias;
+	int ret;
+
+	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_MEMORY_PLL_PARAM,
+					     memory_clock, false, &dividers);
+	if (ret)
+		return ret;
+
+	if ((dividers.ref_div < 1) || (dividers.ref_div > 5))
+		return -EINVAL;
+
+	rv770_calculate_fractional_mpll_feedback_divider(memory_clock, reference_clock,
+							 pi->mem_gddr5,
+							 &dividers, &clkf, &clkfrac);
+
+	ret = rv770_encode_yclk_post_div(dividers.post_div, &postdiv_yclk);
+	if (ret)
+		return ret;
+
+	ibias = rv770_map_clkf_to_ibias(rdev, clkf);
+
+	mpll_ad_func_cntl &= ~(CLKR_MASK |
+			       YCLK_POST_DIV_MASK |
+			       CLKF_MASK |
+			       CLKFRAC_MASK |
+			       IBIAS_MASK);
+	mpll_ad_func_cntl |= CLKR(encoded_reference_dividers[dividers.ref_div - 1]);
+	mpll_ad_func_cntl |= YCLK_POST_DIV(postdiv_yclk);
+	mpll_ad_func_cntl |= CLKF(clkf);
+	mpll_ad_func_cntl |= CLKFRAC(clkfrac);
+	mpll_ad_func_cntl |= IBIAS(ibias);
+
+	if (dividers.vco_mode)
+		mpll_ad_func_cntl_2 |= VCO_MODE;
+	else
+		mpll_ad_func_cntl_2 &= ~VCO_MODE;
+
+	if (pi->mem_gddr5) {
+		rv770_calculate_fractional_mpll_feedback_divider(memory_clock,
+								 reference_clock,
+								 pi->mem_gddr5,
+								 &dividers, &clkf, &clkfrac);
+
+		ibias = rv770_map_clkf_to_ibias(rdev, clkf);
+
+		ret = rv770_encode_yclk_post_div(dividers.post_div, &postdiv_yclk);
+		if (ret)
+			return ret;
+
+		mpll_dq_func_cntl &= ~(CLKR_MASK |
+				       YCLK_POST_DIV_MASK |
+				       CLKF_MASK |
+				       CLKFRAC_MASK |
+				       IBIAS_MASK);
+		mpll_dq_func_cntl |= CLKR(encoded_reference_dividers[dividers.ref_div - 1]);
+		mpll_dq_func_cntl |= YCLK_POST_DIV(postdiv_yclk);
+		mpll_dq_func_cntl |= CLKF(clkf);
+		mpll_dq_func_cntl |= CLKFRAC(clkfrac);
+		mpll_dq_func_cntl |= IBIAS(ibias);
+
+		if (dividers.vco_mode)
+			mpll_dq_func_cntl_2 |= VCO_MODE;
+		else
+			mpll_dq_func_cntl_2 &= ~VCO_MODE;
+	}
+
+	mclk->mclk770.mclk_value = cpu_to_be32(memory_clock);
+	mclk->mclk770.vMPLL_AD_FUNC_CNTL = cpu_to_be32(mpll_ad_func_cntl);
+	mclk->mclk770.vMPLL_AD_FUNC_CNTL_2 = cpu_to_be32(mpll_ad_func_cntl_2);
+	mclk->mclk770.vMPLL_DQ_FUNC_CNTL = cpu_to_be32(mpll_dq_func_cntl);
+	mclk->mclk770.vMPLL_DQ_FUNC_CNTL_2 = cpu_to_be32(mpll_dq_func_cntl_2);
+	mclk->mclk770.vMCLK_PWRMGT_CNTL = cpu_to_be32(mclk_pwrmgt_cntl);
+	mclk->mclk770.vDLL_CNTL = cpu_to_be32(dll_cntl);
+
+	return 0;
+}
+
+static int rv770_populate_sclk_value(struct radeon_device *rdev,
+				     u32 engine_clock,
+				     RV770_SMC_SCLK_VALUE *sclk)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	struct atom_clock_dividers dividers;
+	u32 spll_func_cntl =
+		pi->clk_regs.rv770.cg_spll_func_cntl;
+	u32 spll_func_cntl_2 =
+		pi->clk_regs.rv770.cg_spll_func_cntl_2;
+	u32 spll_func_cntl_3 =
+		pi->clk_regs.rv770.cg_spll_func_cntl_3;
+	u32 cg_spll_spread_spectrum =
+		pi->clk_regs.rv770.cg_spll_spread_spectrum;
+	u32 cg_spll_spread_spectrum_2 =
+		pi->clk_regs.rv770.cg_spll_spread_spectrum_2;
+	u64 tmp;
+	u32 reference_clock = rdev->clock.spll.reference_freq;
+	u32 reference_divider, post_divider;
+	u32 fbdiv;
+	int ret;
+
+	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
+					     engine_clock, false, &dividers);
+	if (ret)
+		return ret;
+
+	reference_divider = 1 + dividers.ref_div;
+
+	if (dividers.enable_post_div)
+		post_divider = (0x0f & (dividers.post_div >> 4)) + (0x0f & dividers.post_div) + 2;
+	else
+		post_divider = 1;
+
+	tmp = (u64) engine_clock * reference_divider * post_divider;
+
+	fbdiv = (u32) ((16384 * tmp) / reference_clock);
+
+	if (dividers.enable_post_div)
+		spll_func_cntl |= SPLL_DIVEN;
+	else
+		spll_func_cntl &= ~SPLL_DIVEN;
+	spll_func_cntl &= ~(SPLL_HILEN_MASK | SPLL_LOLEN_MASK | SPLL_REF_DIV_MASK);
+	spll_func_cntl |= SPLL_REF_DIV(dividers.ref_div);
+	spll_func_cntl |= SPLL_HILEN((dividers.post_div >> 4) & 0xf);
+	spll_func_cntl |= SPLL_LOLEN(dividers.post_div & 0xf);
+
+	spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK;
+	spll_func_cntl_2 |= SCLK_MUX_SEL(2);
+
+	spll_func_cntl_3 &= ~SPLL_FB_DIV_MASK;
+	spll_func_cntl_3 |= SPLL_FB_DIV(fbdiv);
+	spll_func_cntl_3 |= SPLL_DITHEN;
+
+	if (pi->sclk_ss) {
+		struct radeon_atom_ss ss;
+		u32 vco_freq = engine_clock * post_divider;
+
+		if (radeon_atombios_get_asic_ss_info(rdev, &ss,
+						     ASIC_INTERNAL_ENGINE_SS, vco_freq)) {
+			u32 clk_s = reference_clock * 5 / (reference_divider * ss.rate);
+			u32 clk_v = ss.percentage * fbdiv / (clk_s * 10000);
+
+			cg_spll_spread_spectrum &= ~CLKS_MASK;
+			cg_spll_spread_spectrum |= CLKS(clk_s);
+			cg_spll_spread_spectrum |= SSEN;
+
+			cg_spll_spread_spectrum_2 &= ~CLKV_MASK;
+			cg_spll_spread_spectrum_2 |= CLKV(clk_v);
+		}
+	}
+
+	sclk->sclk_value = cpu_to_be32(engine_clock);
+	sclk->vCG_SPLL_FUNC_CNTL = cpu_to_be32(spll_func_cntl);
+	sclk->vCG_SPLL_FUNC_CNTL_2 = cpu_to_be32(spll_func_cntl_2);
+	sclk->vCG_SPLL_FUNC_CNTL_3 = cpu_to_be32(spll_func_cntl_3);
+	sclk->vCG_SPLL_SPREAD_SPECTRUM = cpu_to_be32(cg_spll_spread_spectrum);
+	sclk->vCG_SPLL_SPREAD_SPECTRUM_2 = cpu_to_be32(cg_spll_spread_spectrum_2);
+
+	return 0;
+}
+
+int rv770_populate_vddc_value(struct radeon_device *rdev, u16 vddc,
+			      RV770_SMC_VOLTAGE_VALUE *voltage)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	int i;
+
+	if (!pi->voltage_control) {
+		voltage->index = 0;
+		voltage->value = 0;
+		return 0;
+	}
+
+	for (i = 0; i < pi->valid_vddc_entries; i++) {
+		if (vddc <= pi->vddc_table[i].vddc) {
+			voltage->index = pi->vddc_table[i].vddc_index;
+			voltage->value = cpu_to_be16(vddc);
+			break;
+		}
+	}
+
+	if (i == pi->valid_vddc_entries)
+		return -EINVAL;
+
+	return 0;
+}
+
+int rv770_populate_mvdd_value(struct radeon_device *rdev, u32 mclk,
+			      RV770_SMC_VOLTAGE_VALUE *voltage)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+	if (!pi->mvdd_control) {
+		voltage->index = MVDD_HIGH_INDEX;
+		voltage->value = cpu_to_be16(MVDD_HIGH_VALUE);
+		return 0;
+	}
+
+	if (mclk <= pi->mvdd_split_frequency) {
+		voltage->index = MVDD_LOW_INDEX;
+		voltage->value = cpu_to_be16(MVDD_LOW_VALUE);
+	} else {
+		voltage->index = MVDD_HIGH_INDEX;
+		voltage->value = cpu_to_be16(MVDD_HIGH_VALUE);
+	}
+
+	return 0;
+}
+
+static int rv770_convert_power_level_to_smc(struct radeon_device *rdev,
+					    struct rv7xx_pl *pl,
+					    RV770_SMC_HW_PERFORMANCE_LEVEL *level,
+					    u8 watermark_level)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	int ret;
+
+	level->gen2PCIE = pi->pcie_gen2 ?
+		((pl->flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) ? 1 : 0) : 0;
+	level->gen2XSP  = (pl->flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) ? 1 : 0;
+	level->backbias = (pl->flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) ? 1 : 0;
+	level->displayWatermark = watermark_level;
+
+	if (rdev->family == CHIP_RV740)
+		ret = rv740_populate_sclk_value(rdev, pl->sclk,
+						&level->sclk);
+	else if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710))
+		ret = rv730_populate_sclk_value(rdev, pl->sclk,
+						&level->sclk);
+	else
+		ret = rv770_populate_sclk_value(rdev, pl->sclk,
+						&level->sclk);
+	if (ret)
+		return ret;
+
+	if (rdev->family == CHIP_RV740) {
+		if (pi->mem_gddr5) {
+			if (pl->mclk <= pi->mclk_strobe_mode_threshold)
+				level->strobeMode =
+					rv740_get_mclk_frequency_ratio(pl->mclk) | 0x10;
+			else
+				level->strobeMode = 0;
+
+			if (pl->mclk > pi->mclk_edc_enable_threshold)
+				level->mcFlags = SMC_MC_EDC_RD_FLAG | SMC_MC_EDC_WR_FLAG;
+			else
+				level->mcFlags =  0;
+		}
+		ret = rv740_populate_mclk_value(rdev, pl->sclk,
+						pl->mclk, &level->mclk);
+	} else if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710))
+		ret = rv730_populate_mclk_value(rdev, pl->sclk,
+						pl->mclk, &level->mclk);
+	else
+		ret = rv770_populate_mclk_value(rdev, pl->sclk,
+						pl->mclk, &level->mclk);
+	if (ret)
+		return ret;
+
+	ret = rv770_populate_vddc_value(rdev, pl->vddc,
+					&level->vddc);
+	if (ret)
+		return ret;
+
+	ret = rv770_populate_mvdd_value(rdev, pl->mclk, &level->mvdd);
+
+	return ret;
+}
+
+static int rv770_convert_power_state_to_smc(struct radeon_device *rdev,
+					    struct radeon_ps *radeon_state,
+					    RV770_SMC_SWSTATE *smc_state)
+{
+	struct rv7xx_ps *state = rv770_get_ps(radeon_state);
+	int ret;
+
+	if (!(radeon_state->caps & ATOM_PPLIB_DISALLOW_ON_DC))
+		smc_state->flags |= PPSMC_SWSTATE_FLAG_DC;
+
+	ret = rv770_convert_power_level_to_smc(rdev,
+					       &state->low,
+					       &smc_state->levels[0],
+					       PPSMC_DISPLAY_WATERMARK_LOW);
+	if (ret)
+		return ret;
+
+	ret = rv770_convert_power_level_to_smc(rdev,
+					       &state->medium,
+					       &smc_state->levels[1],
+					       PPSMC_DISPLAY_WATERMARK_LOW);
+	if (ret)
+		return ret;
+
+	ret = rv770_convert_power_level_to_smc(rdev,
+					       &state->high,
+					       &smc_state->levels[2],
+					       PPSMC_DISPLAY_WATERMARK_HIGH);
+	if (ret)
+		return ret;
+
+	smc_state->levels[0].arbValue = MC_CG_ARB_FREQ_F1;
+	smc_state->levels[1].arbValue = MC_CG_ARB_FREQ_F2;
+	smc_state->levels[2].arbValue = MC_CG_ARB_FREQ_F3;
+
+	smc_state->levels[0].seqValue = rv770_get_seq_value(rdev,
+							    &state->low);
+	smc_state->levels[1].seqValue = rv770_get_seq_value(rdev,
+							    &state->medium);
+	smc_state->levels[2].seqValue = rv770_get_seq_value(rdev,
+							    &state->high);
+
+	rv770_populate_smc_sp(rdev, radeon_state, smc_state);
+
+	return rv770_populate_smc_t(rdev, radeon_state, smc_state);
+
+}
+
+u32 rv770_calculate_memory_refresh_rate(struct radeon_device *rdev,
+					u32 engine_clock)
+{
+	u32 dram_rows;
+	u32 dram_refresh_rate;
+	u32 mc_arb_rfsh_rate;
+	u32 tmp;
+
+	tmp = (RREG32(MC_ARB_RAMCFG) & NOOFROWS_MASK) >> NOOFROWS_SHIFT;
+	dram_rows = 1 << (tmp + 10);
+	tmp = RREG32(MC_SEQ_MISC0) & 3;
+	dram_refresh_rate = 1 << (tmp + 3);
+	mc_arb_rfsh_rate = ((engine_clock * 10) * dram_refresh_rate / dram_rows - 32) / 64;
+
+	return mc_arb_rfsh_rate;
+}
+
+static void rv770_program_memory_timing_parameters(struct radeon_device *rdev,
+						   struct radeon_ps *radeon_state)
+{
+	struct rv7xx_ps *state = rv770_get_ps(radeon_state);
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	u32 sqm_ratio;
+	u32 arb_refresh_rate;
+	u32 high_clock;
+
+	if (state->high.sclk < (state->low.sclk * 0xFF / 0x40))
+		high_clock = state->high.sclk;
+	else
+		high_clock = (state->low.sclk * 0xFF / 0x40);
+
+	radeon_atom_set_engine_dram_timings(rdev, high_clock,
+					    state->high.mclk);
+
+	sqm_ratio =
+		STATE0(64 * high_clock / pi->boot_sclk) |
+		STATE1(64 * high_clock / state->low.sclk) |
+		STATE2(64 * high_clock / state->medium.sclk) |
+		STATE3(64 * high_clock / state->high.sclk);
+	WREG32(MC_ARB_SQM_RATIO, sqm_ratio);
+
+	arb_refresh_rate =
+		POWERMODE0(rv770_calculate_memory_refresh_rate(rdev, pi->boot_sclk)) |
+		POWERMODE1(rv770_calculate_memory_refresh_rate(rdev, state->low.sclk)) |
+		POWERMODE2(rv770_calculate_memory_refresh_rate(rdev, state->medium.sclk)) |
+		POWERMODE3(rv770_calculate_memory_refresh_rate(rdev, state->high.sclk));
+	WREG32(MC_ARB_RFSH_RATE, arb_refresh_rate);
+}
+
+void rv770_enable_backbias(struct radeon_device *rdev,
+			   bool enable)
+{
+	if (enable)
+		WREG32_P(GENERAL_PWRMGT, BACKBIAS_PAD_EN, ~BACKBIAS_PAD_EN);
+	else
+		WREG32_P(GENERAL_PWRMGT, 0, ~(BACKBIAS_VALUE | BACKBIAS_PAD_EN));
+}
+
+static void rv770_enable_spread_spectrum(struct radeon_device *rdev,
+					 bool enable)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+	if (enable) {
+		if (pi->sclk_ss)
+			WREG32_P(GENERAL_PWRMGT, DYN_SPREAD_SPECTRUM_EN, ~DYN_SPREAD_SPECTRUM_EN);
+
+		if (pi->mclk_ss) {
+			if (rdev->family == CHIP_RV740)
+				rv740_enable_mclk_spread_spectrum(rdev, true);
+		}
+	} else {
+		WREG32_P(CG_SPLL_SPREAD_SPECTRUM, 0, ~SSEN);
+
+		WREG32_P(GENERAL_PWRMGT, 0, ~DYN_SPREAD_SPECTRUM_EN);
+
+		WREG32_P(CG_MPLL_SPREAD_SPECTRUM, 0, ~SSEN);
+
+		if (rdev->family == CHIP_RV740)
+			rv740_enable_mclk_spread_spectrum(rdev, false);
+	}
+}
+
+static void rv770_program_mpll_timing_parameters(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+	if ((rdev->family == CHIP_RV770) && !pi->mem_gddr5) {
+		WREG32(MPLL_TIME,
+		       (MPLL_LOCK_TIME(R600_MPLLLOCKTIME_DFLT * pi->ref_div) |
+			MPLL_RESET_TIME(R600_MPLLRESETTIME_DFLT)));
+	}
+}
+
+void rv770_setup_bsp(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	u32 xclk = radeon_get_xclk(rdev);
+
+	r600_calculate_u_and_p(pi->asi,
+			       xclk,
+			       16,
+			       &pi->bsp,
+			       &pi->bsu);
+
+	r600_calculate_u_and_p(pi->pasi,
+			       xclk,
+			       16,
+			       &pi->pbsp,
+			       &pi->pbsu);
+
+	pi->dsp = BSP(pi->bsp) | BSU(pi->bsu);
+	pi->psp = BSP(pi->pbsp) | BSU(pi->pbsu);
+
+	WREG32(CG_BSP, pi->dsp);
+
+}
+
+void rv770_program_git(struct radeon_device *rdev)
+{
+	WREG32_P(CG_GIT, CG_GICST(R600_GICST_DFLT), ~CG_GICST_MASK);
+}
+
+void rv770_program_tp(struct radeon_device *rdev)
+{
+	int i;
+	enum r600_td td = R600_TD_DFLT;
+
+	for (i = 0; i < R600_PM_NUMBER_OF_TC; i++)
+		WREG32(CG_FFCT_0 + (i * 4), (UTC_0(r600_utc[i]) | DTC_0(r600_dtc[i])));
+
+	if (td == R600_TD_AUTO)
+		WREG32_P(SCLK_PWRMGT_CNTL, 0, ~FIR_FORCE_TREND_SEL);
+	else
+		WREG32_P(SCLK_PWRMGT_CNTL, FIR_FORCE_TREND_SEL, ~FIR_FORCE_TREND_SEL);
+	if (td == R600_TD_UP)
+		WREG32_P(SCLK_PWRMGT_CNTL, 0, ~FIR_TREND_MODE);
+	if (td == R600_TD_DOWN)
+		WREG32_P(SCLK_PWRMGT_CNTL, FIR_TREND_MODE, ~FIR_TREND_MODE);
+}
+
+void rv770_program_tpp(struct radeon_device *rdev)
+{
+	WREG32(CG_TPC, R600_TPC_DFLT);
+}
+
+void rv770_program_sstp(struct radeon_device *rdev)
+{
+	WREG32(CG_SSP, (SSTU(R600_SSTU_DFLT) | SST(R600_SST_DFLT)));
+}
+
+void rv770_program_engine_speed_parameters(struct radeon_device *rdev)
+{
+	WREG32_P(SPLL_CNTL_MODE, SPLL_DIV_SYNC, ~SPLL_DIV_SYNC);
+}
+
+static void rv770_enable_display_gap(struct radeon_device *rdev)
+{
+	u32 tmp = RREG32(CG_DISPLAY_GAP_CNTL);
+
+	tmp &= ~(DISP1_GAP_MCHG_MASK | DISP2_GAP_MCHG_MASK);
+	tmp |= (DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE) |
+		DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE));
+	WREG32(CG_DISPLAY_GAP_CNTL, tmp);
+}
+
+void rv770_program_vc(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+	WREG32(CG_FTV, pi->vrc);
+}
+
+void rv770_clear_vc(struct radeon_device *rdev)
+{
+	WREG32(CG_FTV, 0);
+}
+
+int rv770_upload_firmware(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	int ret;
+
+	rv770_reset_smc(rdev);
+	rv770_stop_smc_clock(rdev);
+
+	ret = rv770_load_smc_ucode(rdev, pi->sram_end);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int rv770_populate_smc_acpi_state(struct radeon_device *rdev,
+					 RV770_SMC_STATETABLE *table)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+	u32 mpll_ad_func_cntl =
+		pi->clk_regs.rv770.mpll_ad_func_cntl;
+	u32 mpll_ad_func_cntl_2 =
+		pi->clk_regs.rv770.mpll_ad_func_cntl_2;
+	u32 mpll_dq_func_cntl =
+		pi->clk_regs.rv770.mpll_dq_func_cntl;
+	u32 mpll_dq_func_cntl_2 =
+		pi->clk_regs.rv770.mpll_dq_func_cntl_2;
+	u32 spll_func_cntl =
+		pi->clk_regs.rv770.cg_spll_func_cntl;
+	u32 spll_func_cntl_2 =
+		pi->clk_regs.rv770.cg_spll_func_cntl_2;
+	u32 spll_func_cntl_3 =
+		pi->clk_regs.rv770.cg_spll_func_cntl_3;
+	u32 mclk_pwrmgt_cntl;
+	u32 dll_cntl;
+
+	table->ACPIState = table->initialState;
+
+	table->ACPIState.flags &= ~PPSMC_SWSTATE_FLAG_DC;
+
+	if (pi->acpi_vddc) {
+		rv770_populate_vddc_value(rdev, pi->acpi_vddc,
+					  &table->ACPIState.levels[0].vddc);
+		if (pi->pcie_gen2) {
+			if (pi->acpi_pcie_gen2)
+				table->ACPIState.levels[0].gen2PCIE = 1;
+			else
+				table->ACPIState.levels[0].gen2PCIE = 0;
+		} else
+			table->ACPIState.levels[0].gen2PCIE = 0;
+		if (pi->acpi_pcie_gen2)
+			table->ACPIState.levels[0].gen2XSP = 1;
+		else
+			table->ACPIState.levels[0].gen2XSP = 0;
+	} else {
+		rv770_populate_vddc_value(rdev, pi->min_vddc_in_table,
+					  &table->ACPIState.levels[0].vddc);
+		table->ACPIState.levels[0].gen2PCIE = 0;
+	}
+
+
+	mpll_ad_func_cntl_2 |= BIAS_GEN_PDNB | RESET_EN;
+
+	mpll_dq_func_cntl_2 |= BIAS_GEN_PDNB | RESET_EN;
+
+	mclk_pwrmgt_cntl = (MRDCKA0_RESET |
+			    MRDCKA1_RESET |
+			    MRDCKB0_RESET |
+			    MRDCKB1_RESET |
+			    MRDCKC0_RESET |
+			    MRDCKC1_RESET |
+			    MRDCKD0_RESET |
+			    MRDCKD1_RESET);
+
+	dll_cntl = 0xff000000;
+
+	spll_func_cntl |= SPLL_RESET | SPLL_SLEEP | SPLL_BYPASS_EN;
+
+	spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK;
+	spll_func_cntl_2 |= SCLK_MUX_SEL(4);
+
+	table->ACPIState.levels[0].mclk.mclk770.vMPLL_AD_FUNC_CNTL = cpu_to_be32(mpll_ad_func_cntl);
+	table->ACPIState.levels[0].mclk.mclk770.vMPLL_AD_FUNC_CNTL_2 = cpu_to_be32(mpll_ad_func_cntl_2);
+	table->ACPIState.levels[0].mclk.mclk770.vMPLL_DQ_FUNC_CNTL = cpu_to_be32(mpll_dq_func_cntl);
+	table->ACPIState.levels[0].mclk.mclk770.vMPLL_DQ_FUNC_CNTL_2 = cpu_to_be32(mpll_dq_func_cntl_2);
+
+	table->ACPIState.levels[0].mclk.mclk770.vMCLK_PWRMGT_CNTL = cpu_to_be32(mclk_pwrmgt_cntl);
+	table->ACPIState.levels[0].mclk.mclk770.vDLL_CNTL = cpu_to_be32(dll_cntl);
+
+	table->ACPIState.levels[0].mclk.mclk770.mclk_value = 0;
+
+	table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL = cpu_to_be32(spll_func_cntl);
+	table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_2 = cpu_to_be32(spll_func_cntl_2);
+	table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_3 = cpu_to_be32(spll_func_cntl_3);
+
+	table->ACPIState.levels[0].sclk.sclk_value = 0;
+
+	rv770_populate_mvdd_value(rdev, 0, &table->ACPIState.levels[0].mvdd);
+
+	table->ACPIState.levels[1] = table->ACPIState.levels[0];
+	table->ACPIState.levels[2] = table->ACPIState.levels[0];
+
+	return 0;
+}
+
+int rv770_populate_initial_mvdd_value(struct radeon_device *rdev,
+				      RV770_SMC_VOLTAGE_VALUE *voltage)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+	if ((pi->s0_vid_lower_smio_cntl & pi->mvdd_mask_low) ==
+	     (pi->mvdd_low_smio[MVDD_LOW_INDEX] & pi->mvdd_mask_low) ) {
+		voltage->index = MVDD_LOW_INDEX;
+		voltage->value = cpu_to_be16(MVDD_LOW_VALUE);
+	} else {
+		voltage->index = MVDD_HIGH_INDEX;
+		voltage->value = cpu_to_be16(MVDD_HIGH_VALUE);
+	}
+
+	return 0;
+}
+
+static int rv770_populate_smc_initial_state(struct radeon_device *rdev,
+					    struct radeon_ps *radeon_state,
+					    RV770_SMC_STATETABLE *table)
+{
+	struct rv7xx_ps *initial_state = rv770_get_ps(radeon_state);
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	u32 a_t;
+
+	table->initialState.levels[0].mclk.mclk770.vMPLL_AD_FUNC_CNTL =
+		cpu_to_be32(pi->clk_regs.rv770.mpll_ad_func_cntl);
+	table->initialState.levels[0].mclk.mclk770.vMPLL_AD_FUNC_CNTL_2 =
+		cpu_to_be32(pi->clk_regs.rv770.mpll_ad_func_cntl_2);
+	table->initialState.levels[0].mclk.mclk770.vMPLL_DQ_FUNC_CNTL =
+		cpu_to_be32(pi->clk_regs.rv770.mpll_dq_func_cntl);
+	table->initialState.levels[0].mclk.mclk770.vMPLL_DQ_FUNC_CNTL_2 =
+		cpu_to_be32(pi->clk_regs.rv770.mpll_dq_func_cntl_2);
+	table->initialState.levels[0].mclk.mclk770.vMCLK_PWRMGT_CNTL =
+		cpu_to_be32(pi->clk_regs.rv770.mclk_pwrmgt_cntl);
+	table->initialState.levels[0].mclk.mclk770.vDLL_CNTL =
+		cpu_to_be32(pi->clk_regs.rv770.dll_cntl);
+
+	table->initialState.levels[0].mclk.mclk770.vMPLL_SS =
+		cpu_to_be32(pi->clk_regs.rv770.mpll_ss1);
+	table->initialState.levels[0].mclk.mclk770.vMPLL_SS2 =
+		cpu_to_be32(pi->clk_regs.rv770.mpll_ss2);
+
+	table->initialState.levels[0].mclk.mclk770.mclk_value =
+		cpu_to_be32(initial_state->low.mclk);
+
+	table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL =
+		cpu_to_be32(pi->clk_regs.rv770.cg_spll_func_cntl);
+	table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_2 =
+		cpu_to_be32(pi->clk_regs.rv770.cg_spll_func_cntl_2);
+	table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_3 =
+		cpu_to_be32(pi->clk_regs.rv770.cg_spll_func_cntl_3);
+	table->initialState.levels[0].sclk.vCG_SPLL_SPREAD_SPECTRUM =
+		cpu_to_be32(pi->clk_regs.rv770.cg_spll_spread_spectrum);
+	table->initialState.levels[0].sclk.vCG_SPLL_SPREAD_SPECTRUM_2 =
+		cpu_to_be32(pi->clk_regs.rv770.cg_spll_spread_spectrum_2);
+
+	table->initialState.levels[0].sclk.sclk_value =
+		cpu_to_be32(initial_state->low.sclk);
+
+	table->initialState.levels[0].arbValue = MC_CG_ARB_FREQ_F0;
+
+	table->initialState.levels[0].seqValue =
+		rv770_get_seq_value(rdev, &initial_state->low);
+
+	rv770_populate_vddc_value(rdev,
+				  initial_state->low.vddc,
+				  &table->initialState.levels[0].vddc);
+	rv770_populate_initial_mvdd_value(rdev,
+					  &table->initialState.levels[0].mvdd);
+
+	a_t = CG_R(0xffff) | CG_L(0);
+	table->initialState.levels[0].aT = cpu_to_be32(a_t);
+
+	table->initialState.levels[0].bSP = cpu_to_be32(pi->dsp);
+
+	if (pi->boot_in_gen2)
+		table->initialState.levels[0].gen2PCIE = 1;
+	else
+		table->initialState.levels[0].gen2PCIE = 0;
+	if (initial_state->low.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2)
+		table->initialState.levels[0].gen2XSP = 1;
+	else
+		table->initialState.levels[0].gen2XSP = 0;
+
+	if (rdev->family == CHIP_RV740) {
+		if (pi->mem_gddr5) {
+			if (initial_state->low.mclk <= pi->mclk_strobe_mode_threshold)
+				table->initialState.levels[0].strobeMode =
+					rv740_get_mclk_frequency_ratio(initial_state->low.mclk) | 0x10;
+			else
+				table->initialState.levels[0].strobeMode = 0;
+
+			if (initial_state->low.mclk >= pi->mclk_edc_enable_threshold)
+				table->initialState.levels[0].mcFlags = SMC_MC_EDC_RD_FLAG | SMC_MC_EDC_WR_FLAG;
+			else
+				table->initialState.levels[0].mcFlags =  0;
+		}
+	}
+
+	table->initialState.levels[1] = table->initialState.levels[0];
+	table->initialState.levels[2] = table->initialState.levels[0];
+
+	table->initialState.flags |= PPSMC_SWSTATE_FLAG_DC;
+
+	return 0;
+}
+
+static int rv770_populate_smc_vddc_table(struct radeon_device *rdev,
+					 RV770_SMC_STATETABLE *table)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	int i;
+
+	for (i = 0; i < pi->valid_vddc_entries; i++) {
+		table->highSMIO[pi->vddc_table[i].vddc_index] =
+			pi->vddc_table[i].high_smio;
+		table->lowSMIO[pi->vddc_table[i].vddc_index] =
+			cpu_to_be32(pi->vddc_table[i].low_smio);
+	}
+
+	table->voltageMaskTable.highMask[RV770_SMC_VOLTAGEMASK_VDDC] = 0;
+	table->voltageMaskTable.lowMask[RV770_SMC_VOLTAGEMASK_VDDC] =
+		cpu_to_be32(pi->vddc_mask_low);
+
+	for (i = 0;
+	     ((i < pi->valid_vddc_entries) &&
+	      (pi->max_vddc_in_table >
+	       pi->vddc_table[i].vddc));
+	     i++);
+
+	table->maxVDDCIndexInPPTable =
+		pi->vddc_table[i].vddc_index;
+
+	return 0;
+}
+
+static int rv770_populate_smc_mvdd_table(struct radeon_device *rdev,
+					 RV770_SMC_STATETABLE *table)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+	if (pi->mvdd_control) {
+		table->lowSMIO[MVDD_HIGH_INDEX] |=
+			cpu_to_be32(pi->mvdd_low_smio[MVDD_HIGH_INDEX]);
+		table->lowSMIO[MVDD_LOW_INDEX] |=
+			cpu_to_be32(pi->mvdd_low_smio[MVDD_LOW_INDEX]);
+
+		table->voltageMaskTable.highMask[RV770_SMC_VOLTAGEMASK_MVDD] = 0;
+		table->voltageMaskTable.lowMask[RV770_SMC_VOLTAGEMASK_MVDD] =
+			cpu_to_be32(pi->mvdd_mask_low);
+	}
+
+	return 0;
+}
+
+static int rv770_init_smc_table(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	struct radeon_ps *radeon_boot_state = rdev->pm.dpm.boot_ps;
+	struct rv7xx_ps *boot_state = rv770_get_ps(radeon_boot_state);
+	RV770_SMC_STATETABLE *table = &pi->smc_statetable;
+	int ret;
+
+	memset(table, 0, sizeof(RV770_SMC_STATETABLE));
+
+	pi->boot_sclk = boot_state->low.sclk;
+
+	rv770_populate_smc_vddc_table(rdev, table);
+	rv770_populate_smc_mvdd_table(rdev, table);
+
+	switch (rdev->pm.int_thermal_type) {
+        case THERMAL_TYPE_RV770:
+        case THERMAL_TYPE_ADT7473_WITH_INTERNAL:
+		table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_INTERNAL;
+		break;
+        case THERMAL_TYPE_NONE:
+		table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_NONE;
+		break;
+        case THERMAL_TYPE_EXTERNAL_GPIO:
+        default:
+		table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_EXTERNAL;
+		break;
+	}
+
+	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_HARDWAREDC) {
+		table->systemFlags |= PPSMC_SYSTEMFLAG_GPIO_DC;
+
+		if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_DONT_WAIT_FOR_VBLANK_ON_ALERT)
+			table->extraFlags |= PPSMC_EXTRAFLAGS_AC2DC_DONT_WAIT_FOR_VBLANK;
+
+		if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_GOTO_BOOT_ON_ALERT)
+			table->extraFlags |= PPSMC_EXTRAFLAGS_AC2DC_ACTION_GOTOINITIALSTATE;
+	}
+
+	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC)
+		table->systemFlags |= PPSMC_SYSTEMFLAG_STEPVDDC;
+
+	if (pi->mem_gddr5)
+		table->systemFlags |= PPSMC_SYSTEMFLAG_GDDR5;
+
+	if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710))
+		ret = rv730_populate_smc_initial_state(rdev, radeon_boot_state, table);
+	else
+		ret = rv770_populate_smc_initial_state(rdev, radeon_boot_state, table);
+	if (ret)
+		return ret;
+
+	if (rdev->family == CHIP_RV740)
+		ret = rv740_populate_smc_acpi_state(rdev, table);
+	else if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710))
+		ret = rv730_populate_smc_acpi_state(rdev, table);
+	else
+		ret = rv770_populate_smc_acpi_state(rdev, table);
+	if (ret)
+		return ret;
+
+	table->driverState = table->initialState;
+
+	return rv770_copy_bytes_to_smc(rdev,
+				       pi->state_table_start,
+				       (const u8 *)table,
+				       sizeof(RV770_SMC_STATETABLE),
+				       pi->sram_end);
+}
+
+static int rv770_construct_vddc_table(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	u16 min, max, step;
+	u32 steps = 0;
+	u8 vddc_index = 0;
+	u32 i;
+
+	radeon_atom_get_min_voltage(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, &min);
+	radeon_atom_get_max_voltage(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, &max);
+	radeon_atom_get_voltage_step(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, &step);
+
+	steps = (max - min) / step + 1;
+
+	if (steps > MAX_NO_VREG_STEPS)
+		return -EINVAL;
+
+	for (i = 0; i < steps; i++) {
+		u32 gpio_pins, gpio_mask;
+
+		pi->vddc_table[i].vddc = (u16)(min + i * step);
+		radeon_atom_get_voltage_gpio_settings(rdev,
+						      pi->vddc_table[i].vddc,
+						      SET_VOLTAGE_TYPE_ASIC_VDDC,
+						      &gpio_pins, &gpio_mask);
+		pi->vddc_table[i].low_smio = gpio_pins & gpio_mask;
+		pi->vddc_table[i].high_smio = 0;
+		pi->vddc_mask_low = gpio_mask;
+		if (i > 0) {
+			if ((pi->vddc_table[i].low_smio !=
+			     pi->vddc_table[i - 1].low_smio ) ||
+			     (pi->vddc_table[i].high_smio !=
+			      pi->vddc_table[i - 1].high_smio))
+				vddc_index++;
+		}
+		pi->vddc_table[i].vddc_index = vddc_index;
+	}
+
+	pi->valid_vddc_entries = (u8)steps;
+
+	return 0;
+}
+
+static u32 rv770_get_mclk_split_point(struct atom_memory_info *memory_info)
+{
+	if (memory_info->mem_type == MEM_TYPE_GDDR3)
+		return 30000;
+
+	return 0;
+}
+
+static int rv770_get_mvdd_pin_configuration(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	u32 gpio_pins, gpio_mask;
+
+	radeon_atom_get_voltage_gpio_settings(rdev,
+					      MVDD_HIGH_VALUE, SET_VOLTAGE_TYPE_ASIC_MVDDC,
+					      &gpio_pins, &gpio_mask);
+	pi->mvdd_mask_low = gpio_mask;
+	pi->mvdd_low_smio[MVDD_HIGH_INDEX] =
+		gpio_pins & gpio_mask;
+
+	radeon_atom_get_voltage_gpio_settings(rdev,
+					      MVDD_LOW_VALUE, SET_VOLTAGE_TYPE_ASIC_MVDDC,
+					      &gpio_pins, &gpio_mask);
+	pi->mvdd_low_smio[MVDD_LOW_INDEX] =
+		gpio_pins & gpio_mask;
+
+	return 0;
+}
+
+u8 rv770_get_memory_module_index(struct radeon_device *rdev)
+{
+	return (u8) ((RREG32(BIOS_SCRATCH_4) >> 16) & 0xff);
+}
+
+static int rv770_get_mvdd_configuration(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	u8 memory_module_index;
+	struct atom_memory_info memory_info;
+
+	memory_module_index = rv770_get_memory_module_index(rdev);
+
+	if (radeon_atom_get_memory_info(rdev, memory_module_index, &memory_info)) {
+		pi->mvdd_control = false;
+		return 0;
+	}
+
+	pi->mvdd_split_frequency =
+		rv770_get_mclk_split_point(&memory_info);
+
+	if (pi->mvdd_split_frequency == 0) {
+		pi->mvdd_control = false;
+		return 0;
+	}
+
+	return rv770_get_mvdd_pin_configuration(rdev);
+}
+
+void rv770_enable_voltage_control(struct radeon_device *rdev,
+				  bool enable)
+{
+	if (enable)
+		WREG32_P(GENERAL_PWRMGT, VOLT_PWRMGT_EN, ~VOLT_PWRMGT_EN);
+	else
+		WREG32_P(GENERAL_PWRMGT, 0, ~VOLT_PWRMGT_EN);
+}
+
+static void rv770_program_display_gap(struct radeon_device *rdev)
+{
+	u32 tmp = RREG32(CG_DISPLAY_GAP_CNTL);
+
+	tmp &= ~(DISP1_GAP_MCHG_MASK | DISP2_GAP_MCHG_MASK);
+	if (RREG32(AVIVO_D1CRTC_CONTROL) & AVIVO_CRTC_EN) {
+		tmp |= DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK);
+		tmp |= DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE);
+	} else if (RREG32(AVIVO_D2CRTC_CONTROL) & AVIVO_CRTC_EN) {
+		tmp |= DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE);
+		tmp |= DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK);
+	} else {
+		tmp |= DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE);
+		tmp |= DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE);
+	}
+	WREG32(CG_DISPLAY_GAP_CNTL, tmp);
+}
+
+static void rv770_enable_dynamic_pcie_gen2(struct radeon_device *rdev,
+					   bool enable)
+{
+	rv770_enable_bif_dynamic_pcie_gen2(rdev, enable);
+
+	if (enable)
+		WREG32_P(GENERAL_PWRMGT, ENABLE_GEN2PCIE, ~ENABLE_GEN2PCIE);
+	else
+		WREG32_P(GENERAL_PWRMGT, 0, ~ENABLE_GEN2PCIE);
+}
+
+static void r7xx_program_memory_timing_parameters(struct radeon_device *rdev)
+{
+	struct radeon_ps *radeon_new_state = rdev->pm.dpm.requested_ps;
+
+	if ((rdev->family == CHIP_RV730) ||
+	    (rdev->family == CHIP_RV710) ||
+	    (rdev->family == CHIP_RV740))
+		rv730_program_memory_timing_parameters(rdev, radeon_new_state);
+	else
+		rv770_program_memory_timing_parameters(rdev, radeon_new_state);
+}
+
+static int rv770_upload_sw_state(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	struct radeon_ps *radeon_new_state = rdev->pm.dpm.requested_ps;
+	u16 address = pi->state_table_start +
+		offsetof(RV770_SMC_STATETABLE, driverState);
+	RV770_SMC_SWSTATE state = { 0 };
+	int ret;
+
+	ret = rv770_convert_power_state_to_smc(rdev, radeon_new_state, &state);
+	if (ret)
+		return ret;
+
+	return rv770_copy_bytes_to_smc(rdev, address, (const u8 *)&state,
+				       sizeof(RV770_SMC_SWSTATE),
+				       pi->sram_end);
+}
+
+int rv770_halt_smc(struct radeon_device *rdev)
+{
+	if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_Halt) != PPSMC_Result_OK)
+		return -EINVAL;
+
+	if (rv770_wait_for_smc_inactive(rdev) != PPSMC_Result_OK)
+		return -EINVAL;
+
+	return 0;
+}
+
+int rv770_resume_smc(struct radeon_device *rdev)
+{
+	if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_Resume) != PPSMC_Result_OK)
+		return -EINVAL;
+	return 0;
+}
+
+int rv770_set_sw_state(struct radeon_device *rdev)
+{
+	if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_SwitchToSwState) != PPSMC_Result_OK)
+		return -EINVAL;
+	return 0;
+}
+
+int rv770_set_boot_state(struct radeon_device *rdev)
+{
+	if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_SwitchToInitialState) != PPSMC_Result_OK)
+		return -EINVAL;
+	return 0;
+}
+
+int rv770_restrict_performance_levels_before_switch(struct radeon_device *rdev)
+{
+	if (rv770_send_msg_to_smc(rdev, (PPSMC_Msg)(PPSMC_MSG_NoForcedLevel)) != PPSMC_Result_OK)
+		return -EINVAL;
+
+	if (rv770_send_msg_to_smc(rdev, (PPSMC_Msg)(PPSMC_MSG_TwoLevelsDisabled)) != PPSMC_Result_OK)
+		return -EINVAL;
+
+	return 0;
+}
+
+void r7xx_start_smc(struct radeon_device *rdev)
+{
+	rv770_start_smc(rdev);
+	rv770_start_smc_clock(rdev);
+}
+
+
+void r7xx_stop_smc(struct radeon_device *rdev)
+{
+	rv770_reset_smc(rdev);
+	rv770_stop_smc_clock(rdev);
+}
+
+static void rv770_read_clock_registers(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+	pi->clk_regs.rv770.cg_spll_func_cntl =
+		RREG32(CG_SPLL_FUNC_CNTL);
+	pi->clk_regs.rv770.cg_spll_func_cntl_2 =
+		RREG32(CG_SPLL_FUNC_CNTL_2);
+	pi->clk_regs.rv770.cg_spll_func_cntl_3 =
+		RREG32(CG_SPLL_FUNC_CNTL_3);
+	pi->clk_regs.rv770.cg_spll_spread_spectrum =
+		RREG32(CG_SPLL_SPREAD_SPECTRUM);
+	pi->clk_regs.rv770.cg_spll_spread_spectrum_2 =
+		RREG32(CG_SPLL_SPREAD_SPECTRUM_2);
+	pi->clk_regs.rv770.mpll_ad_func_cntl =
+		RREG32(MPLL_AD_FUNC_CNTL);
+	pi->clk_regs.rv770.mpll_ad_func_cntl_2 =
+		RREG32(MPLL_AD_FUNC_CNTL_2);
+	pi->clk_regs.rv770.mpll_dq_func_cntl =
+		RREG32(MPLL_DQ_FUNC_CNTL);
+	pi->clk_regs.rv770.mpll_dq_func_cntl_2 =
+		RREG32(MPLL_DQ_FUNC_CNTL_2);
+	pi->clk_regs.rv770.mclk_pwrmgt_cntl =
+		RREG32(MCLK_PWRMGT_CNTL);
+	pi->clk_regs.rv770.dll_cntl = RREG32(DLL_CNTL);
+}
+
+static void r7xx_read_clock_registers(struct radeon_device *rdev)
+{
+	if (rdev->family == CHIP_RV740)
+		rv740_read_clock_registers(rdev);
+	else if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710))
+		rv730_read_clock_registers(rdev);
+	else
+		rv770_read_clock_registers(rdev);
+}
+
+void rv770_read_voltage_smio_registers(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+	pi->s0_vid_lower_smio_cntl =
+		RREG32(S0_VID_LOWER_SMIO_CNTL);
+}
+
+void rv770_reset_smio_status(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	u32 sw_smio_index, vid_smio_cntl;
+
+	sw_smio_index =
+		(RREG32(GENERAL_PWRMGT) & SW_SMIO_INDEX_MASK) >> SW_SMIO_INDEX_SHIFT;
+	switch (sw_smio_index) {
+        case 3:
+		vid_smio_cntl = RREG32(S3_VID_LOWER_SMIO_CNTL);
+		break;
+        case 2:
+		vid_smio_cntl = RREG32(S2_VID_LOWER_SMIO_CNTL);
+		break;
+        case 1:
+		vid_smio_cntl = RREG32(S1_VID_LOWER_SMIO_CNTL);
+		break;
+        case 0:
+		return;
+        default:
+		vid_smio_cntl = pi->s0_vid_lower_smio_cntl;
+		break;
+	}
+
+	WREG32(S0_VID_LOWER_SMIO_CNTL, vid_smio_cntl);
+	WREG32_P(GENERAL_PWRMGT, SW_SMIO_INDEX(0), ~SW_SMIO_INDEX_MASK);
+}
+
+void rv770_get_memory_type(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	u32 tmp;
+
+	tmp = RREG32(MC_SEQ_MISC0);
+
+	if (((tmp & MC_SEQ_MISC0_GDDR5_MASK) >> MC_SEQ_MISC0_GDDR5_SHIFT) ==
+	    MC_SEQ_MISC0_GDDR5_VALUE)
+		pi->mem_gddr5 = true;
+	else
+		pi->mem_gddr5 = false;
+
+}
+
+void rv770_get_pcie_gen2_status(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	u32 tmp;
+
+	tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL);
+
+	if ((tmp & LC_OTHER_SIDE_EVER_SENT_GEN2) &&
+	    (tmp & LC_OTHER_SIDE_SUPPORTS_GEN2))
+		pi->pcie_gen2 = true;
+	else
+		pi->pcie_gen2 = false;
+
+	if (pi->pcie_gen2) {
+		if (tmp & LC_CURRENT_DATA_RATE)
+			pi->boot_in_gen2 = true;
+		else
+			pi->boot_in_gen2 = false;
+	} else
+		pi->boot_in_gen2 = false;
+}
+
+#if 0
+static int rv770_enter_ulp_state(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+	if (pi->gfx_clock_gating) {
+		WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_GFX_CLK_OFF_EN);
+		WREG32_P(SCLK_PWRMGT_CNTL, GFX_CLK_FORCE_ON, ~GFX_CLK_FORCE_ON);
+		WREG32_P(SCLK_PWRMGT_CNTL, 0, ~GFX_CLK_FORCE_ON);
+		RREG32(GB_TILING_CONFIG);
+	}
+
+	WREG32_P(SMC_MSG, HOST_SMC_MSG(PPSMC_MSG_SwitchToMinimumPower),
+		 ~HOST_SMC_MSG_MASK);
+
+	udelay(7000);
+
+	return 0;
+}
+
+static int rv770_exit_ulp_state(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	int i;
+
+	WREG32_P(SMC_MSG, HOST_SMC_MSG(PPSMC_MSG_ResumeFromMinimumPower),
+		 ~HOST_SMC_MSG_MASK);
+
+	udelay(7000);
+
+	for (i = 0; i < rdev->usec_timeout; i++) {
+		if (((RREG32(SMC_MSG) & HOST_SMC_RESP_MASK) >> HOST_SMC_RESP_SHIFT) == 1)
+			break;
+		udelay(1000);
+	}
+
+	if (pi->gfx_clock_gating)
+		WREG32_P(SCLK_PWRMGT_CNTL, DYN_GFX_CLK_OFF_EN, ~DYN_GFX_CLK_OFF_EN);
+
+	return 0;
+}
+#endif
+
+static void rv770_get_mclk_odt_threshold(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	u8 memory_module_index;
+	struct atom_memory_info memory_info;
+
+	pi->mclk_odt_threshold = 0;
+
+	if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710)) {
+		memory_module_index = rv770_get_memory_module_index(rdev);
+
+		if (radeon_atom_get_memory_info(rdev, memory_module_index, &memory_info))
+			return;
+
+		if (memory_info.mem_type == MEM_TYPE_DDR2 ||
+		    memory_info.mem_type == MEM_TYPE_DDR3)
+			pi->mclk_odt_threshold = 30000;
+	}
+}
+
+void rv770_get_max_vddc(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	u16 vddc;
+
+	if (radeon_atom_get_max_vddc(rdev, 0, 0, &vddc))
+		pi->max_vddc = 0;
+	else
+		pi->max_vddc = vddc;
+}
+
+void rv770_program_response_times(struct radeon_device *rdev)
+{
+	u32 voltage_response_time, backbias_response_time;
+	u32 acpi_delay_time, vbi_time_out;
+	u32 vddc_dly, bb_dly, acpi_dly, vbi_dly;
+	u32 reference_clock;
+
+	voltage_response_time = (u32)rdev->pm.dpm.voltage_response_time;
+	backbias_response_time = (u32)rdev->pm.dpm.backbias_response_time;
+
+	if (voltage_response_time == 0)
+		voltage_response_time = 1000;
+
+	if (backbias_response_time == 0)
+		backbias_response_time = 1000;
+
+	acpi_delay_time = 15000;
+	vbi_time_out = 100000;
+
+	reference_clock = radeon_get_xclk(rdev);
+
+	vddc_dly = (voltage_response_time  * reference_clock) / 1600;
+	bb_dly = (backbias_response_time * reference_clock) / 1600;
+	acpi_dly = (acpi_delay_time * reference_clock) / 1600;
+	vbi_dly = (vbi_time_out * reference_clock) / 1600;
+
+	rv770_write_smc_soft_register(rdev,
+				      RV770_SMC_SOFT_REGISTER_delay_vreg, vddc_dly);
+	rv770_write_smc_soft_register(rdev,
+				      RV770_SMC_SOFT_REGISTER_delay_bbias, bb_dly);
+	rv770_write_smc_soft_register(rdev,
+				      RV770_SMC_SOFT_REGISTER_delay_acpi, acpi_dly);
+	rv770_write_smc_soft_register(rdev,
+				      RV770_SMC_SOFT_REGISTER_mclk_chg_timeout, vbi_dly);
+#if 0
+	/* XXX look up hw revision */
+	if (WEKIVA_A21)
+		rv770_write_smc_soft_register(rdev,
+					      RV770_SMC_SOFT_REGISTER_baby_step_timer,
+					      0x10);
+#endif
+}
+
+static void rv770_program_dcodt_before_state_switch(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	struct radeon_ps *radeon_new_state = rdev->pm.dpm.requested_ps;
+	struct radeon_ps *radeon_current_state = rdev->pm.dpm.current_ps;
+	struct rv7xx_ps *new_state = rv770_get_ps(radeon_new_state);
+	struct rv7xx_ps *current_state = rv770_get_ps(radeon_current_state);
+	bool current_use_dc = false;
+	bool new_use_dc = false;
+
+	if (pi->mclk_odt_threshold == 0)
+		return;
+
+	if (current_state->high.mclk <= pi->mclk_odt_threshold)
+		current_use_dc = true;
+
+	if (new_state->high.mclk <= pi->mclk_odt_threshold)
+		new_use_dc = true;
+
+	if (current_use_dc == new_use_dc)
+		return;
+
+	if (!current_use_dc && new_use_dc)
+		return;
+
+	if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710))
+		rv730_program_dcodt(rdev, new_use_dc);
+}
+
+static void rv770_program_dcodt_after_state_switch(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	struct radeon_ps *radeon_new_state = rdev->pm.dpm.requested_ps;
+	struct radeon_ps *radeon_current_state = rdev->pm.dpm.current_ps;
+	struct rv7xx_ps *new_state = rv770_get_ps(radeon_new_state);
+	struct rv7xx_ps *current_state = rv770_get_ps(radeon_current_state);
+	bool current_use_dc = false;
+	bool new_use_dc = false;
+
+	if (pi->mclk_odt_threshold == 0)
+		return;
+
+	if (current_state->high.mclk <= pi->mclk_odt_threshold)
+		current_use_dc = true;
+
+	if (new_state->high.mclk <= pi->mclk_odt_threshold)
+		new_use_dc = true;
+
+	if (current_use_dc == new_use_dc)
+		return;
+
+	if (current_use_dc && !new_use_dc)
+		return;
+
+	if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710))
+		rv730_program_dcodt(rdev, new_use_dc);
+}
+
+static void rv770_retrieve_odt_values(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+	if (pi->mclk_odt_threshold == 0)
+		return;
+
+	if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710))
+		rv730_get_odt_values(rdev);
+}
+
+static void rv770_set_dpm_event_sources(struct radeon_device *rdev, u32 sources)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	bool want_thermal_protection;
+	enum radeon_dpm_event_src dpm_event_src;
+
+	switch (sources) {
+        case 0:
+        default:
+		want_thermal_protection = false;
+		break;
+        case (1 << RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL):
+		want_thermal_protection = true;
+		dpm_event_src = RADEON_DPM_EVENT_SRC_DIGITAL;
+		break;
+
+        case (1 << RADEON_DPM_AUTO_THROTTLE_SRC_EXTERNAL):
+		want_thermal_protection = true;
+		dpm_event_src = RADEON_DPM_EVENT_SRC_EXTERNAL;
+		break;
+
+        case ((1 << RADEON_DPM_AUTO_THROTTLE_SRC_EXTERNAL) |
+	      (1 << RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL)):
+		want_thermal_protection = true;
+		dpm_event_src = RADEON_DPM_EVENT_SRC_DIGIAL_OR_EXTERNAL;
+		break;
+	}
+
+	if (want_thermal_protection) {
+		WREG32_P(CG_THERMAL_CTRL, DPM_EVENT_SRC(dpm_event_src), ~DPM_EVENT_SRC_MASK);
+		if (pi->thermal_protection)
+			WREG32_P(GENERAL_PWRMGT, 0, ~THERMAL_PROTECTION_DIS);
+	} else {
+		WREG32_P(GENERAL_PWRMGT, THERMAL_PROTECTION_DIS, ~THERMAL_PROTECTION_DIS);
+	}
+}
+
+void rv770_enable_auto_throttle_source(struct radeon_device *rdev,
+				       enum radeon_dpm_auto_throttle_src source,
+				       bool enable)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+	if (enable) {
+		if (!(pi->active_auto_throttle_sources & (1 << source))) {
+			pi->active_auto_throttle_sources |= 1 << source;
+			rv770_set_dpm_event_sources(rdev, pi->active_auto_throttle_sources);
+		}
+	} else {
+		if (pi->active_auto_throttle_sources & (1 << source)) {
+			pi->active_auto_throttle_sources &= ~(1 << source);
+			rv770_set_dpm_event_sources(rdev, pi->active_auto_throttle_sources);
+		}
+	}
+}
+
+static int rv770_set_thermal_temperature_range(struct radeon_device *rdev,
+					       int min_temp, int max_temp)
+{
+	int low_temp = 0 * 1000;
+	int high_temp = 255 * 1000;
+
+	if (low_temp < min_temp)
+		low_temp = min_temp;
+	if (high_temp > max_temp)
+		high_temp = max_temp;
+	if (high_temp < low_temp) {
+		DRM_ERROR("invalid thermal range: %d - %d\n", low_temp, high_temp);
+		return -EINVAL;
+	}
+
+	WREG32_P(CG_THERMAL_INT, DIG_THERM_INTH(high_temp / 1000), ~DIG_THERM_INTH_MASK);
+	WREG32_P(CG_THERMAL_INT, DIG_THERM_INTL(low_temp / 1000), ~DIG_THERM_INTL_MASK);
+	WREG32_P(CG_THERMAL_CTRL, DIG_THERM_DPM(high_temp / 1000), ~DIG_THERM_DPM_MASK);
+
+	rdev->pm.dpm.thermal.min_temp = low_temp;
+	rdev->pm.dpm.thermal.max_temp = high_temp;
+
+	return 0;
+}
+
+int rv770_dpm_enable(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+	if (pi->gfx_clock_gating)
+		rv770_restore_cgcg(rdev);
+
+	if (rv770_dpm_enabled(rdev))
+		return -EINVAL;
+
+	if (pi->voltage_control) {
+		rv770_enable_voltage_control(rdev, true);
+		rv770_construct_vddc_table(rdev);
+	}
+
+	if (pi->dcodt)
+		rv770_retrieve_odt_values(rdev);
+
+	if (pi->mvdd_control)
+		rv770_get_mvdd_configuration(rdev);
+
+	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS)
+		rv770_enable_backbias(rdev, true);
+
+	rv770_enable_spread_spectrum(rdev, true);
+
+	if (pi->thermal_protection)
+		rv770_enable_thermal_protection(rdev, true);
+
+	rv770_program_mpll_timing_parameters(rdev);
+	rv770_setup_bsp(rdev);
+	rv770_program_git(rdev);
+	rv770_program_tp(rdev);
+	rv770_program_tpp(rdev);
+	rv770_program_sstp(rdev);
+	rv770_program_engine_speed_parameters(rdev);
+	rv770_enable_display_gap(rdev);
+	rv770_program_vc(rdev);
+
+	if (pi->dynamic_pcie_gen2)
+		rv770_enable_dynamic_pcie_gen2(rdev, true);
+
+	if (rv770_upload_firmware(rdev))
+		return -EINVAL;
+	/* get ucode version ?  */
+	if (rv770_init_smc_table(rdev))
+		return -EINVAL;
+	rv770_program_response_times(rdev);
+	r7xx_start_smc(rdev);
+
+	if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710))
+		rv730_start_dpm(rdev);
+	else
+		rv770_start_dpm(rdev);
+
+	if (pi->gfx_clock_gating)
+		rv770_gfx_clock_gating_enable(rdev, true);
+
+	if (pi->mg_clock_gating)
+		rv770_mg_clock_gating_enable(rdev, true);
+
+	if (rdev->irq.installed &&
+	    r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
+		PPSMC_Result result;
+
+		rv770_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
+		rdev->irq.dpm_thermal = true;
+		radeon_irq_set(rdev);
+		result = rv770_send_msg_to_smc(rdev, PPSMC_MSG_EnableThermalInterrupt);
+
+		if (result != PPSMC_Result_OK)
+			DRM_DEBUG_KMS("Could not enable thermal interrupts.\n");
+	}
+
+	rv770_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true);
+
+	return 0;
+}
+
+void rv770_dpm_disable(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+	if (!rv770_dpm_enabled(rdev))
+		return;
+
+	rv770_clear_vc(rdev);
+
+	if (pi->thermal_protection)
+		rv770_enable_thermal_protection(rdev, false);
+
+	rv770_enable_spread_spectrum(rdev, false);
+
+	if (pi->dynamic_pcie_gen2)
+		rv770_enable_dynamic_pcie_gen2(rdev, false);
+
+	if (rdev->irq.installed &&
+	    r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
+		rdev->irq.dpm_thermal = false;
+		radeon_irq_set(rdev);
+	}
+
+	if (pi->gfx_clock_gating)
+		rv770_gfx_clock_gating_enable(rdev, false);
+
+	if (pi->mg_clock_gating)
+		rv770_mg_clock_gating_enable(rdev, false);
+
+	if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710))
+		rv730_stop_dpm(rdev);
+	else
+		rv770_stop_dpm(rdev);
+
+	r7xx_stop_smc(rdev);
+	rv770_reset_smio_status(rdev);
+}
+
+int rv770_dpm_set_power_state(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+	rv770_restrict_performance_levels_before_switch(rdev);
+	rv770_halt_smc(rdev);
+	rv770_upload_sw_state(rdev);
+	r7xx_program_memory_timing_parameters(rdev);
+	if (pi->dcodt)
+		rv770_program_dcodt_before_state_switch(rdev);
+	rv770_resume_smc(rdev);
+	rv770_set_sw_state(rdev);
+	if (pi->dcodt)
+		rv770_program_dcodt_after_state_switch(rdev);
+
+	return 0;
+}
+
+void rv770_dpm_reset_asic(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+	rv770_restrict_performance_levels_before_switch(rdev);
+	if (pi->dcodt)
+		rv770_program_dcodt_before_state_switch(rdev);
+	rv770_set_boot_state(rdev);
+	if (pi->dcodt)
+		rv770_program_dcodt_after_state_switch(rdev);
+}
+
+void rv770_dpm_setup_asic(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+	r7xx_read_clock_registers(rdev);
+	rv770_read_voltage_smio_registers(rdev);
+	rv770_get_memory_type(rdev);
+	if (pi->dcodt)
+		rv770_get_mclk_odt_threshold(rdev);
+	rv770_get_pcie_gen2_status(rdev);
+
+	rv770_enable_acpi_pm(rdev);
+
+	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L0s)
+		rv770_enable_l0s(rdev);
+	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L1)
+		rv770_enable_l1(rdev);
+	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_TURNOFFPLL_ASPML1)
+		rv770_enable_pll_sleep_in_l1(rdev);
+}
+
+void rv770_dpm_display_configuration_changed(struct radeon_device *rdev)
+{
+	rv770_program_display_gap(rdev);
+}
+
+union power_info {
+	struct _ATOM_POWERPLAY_INFO info;
+	struct _ATOM_POWERPLAY_INFO_V2 info_2;
+	struct _ATOM_POWERPLAY_INFO_V3 info_3;
+	struct _ATOM_PPLIB_POWERPLAYTABLE pplib;
+	struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2;
+	struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3;
+};
+
+union pplib_clock_info {
+	struct _ATOM_PPLIB_R600_CLOCK_INFO r600;
+	struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780;
+	struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen;
+	struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo;
+};
+
+union pplib_power_state {
+	struct _ATOM_PPLIB_STATE v1;
+	struct _ATOM_PPLIB_STATE_V2 v2;
+};
+
+static void rv7xx_parse_pplib_non_clock_info(struct radeon_device *rdev,
+					     struct radeon_ps *rps,
+					     struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info,
+					     u8 table_rev)
+{
+	rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings);
+	rps->class = le16_to_cpu(non_clock_info->usClassification);
+	rps->class2 = le16_to_cpu(non_clock_info->usClassification2);
+
+	if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) {
+		rps->vclk = le32_to_cpu(non_clock_info->ulVCLK);
+		rps->dclk = le32_to_cpu(non_clock_info->ulDCLK);
+	} else if (r600_is_uvd_state(rps->class, rps->class2)) {
+		rps->vclk = RV770_DEFAULT_VCLK_FREQ;
+		rps->dclk = RV770_DEFAULT_DCLK_FREQ;
+	} else {
+		rps->vclk = 0;
+		rps->dclk = 0;
+	}
+
+	if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT)
+		rdev->pm.dpm.boot_ps = rps;
+	if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
+		rdev->pm.dpm.uvd_ps = rps;
+}
+
+static void rv7xx_parse_pplib_clock_info(struct radeon_device *rdev,
+					 struct radeon_ps *rps, int index,
+					 union pplib_clock_info *clock_info)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	struct rv7xx_ps *ps = rv770_get_ps(rps);
+	u32 sclk, mclk;
+	u16 vddc;
+	struct rv7xx_pl *pl;
+
+	switch (index) {
+	case 0:
+		pl = &ps->low;
+		break;
+	case 1:
+		pl = &ps->medium;
+		break;
+	case 2:
+	default:
+		pl = &ps->high;
+		break;
+	}
+
+	sclk = le16_to_cpu(clock_info->r600.usEngineClockLow);
+	sclk |= clock_info->r600.ucEngineClockHigh << 16;
+	mclk = le16_to_cpu(clock_info->r600.usMemoryClockLow);
+	mclk |= clock_info->r600.ucMemoryClockHigh << 16;
+
+	pl->vddc = le16_to_cpu(clock_info->r600.usVDDC);
+	pl->flags = le32_to_cpu(clock_info->r600.ulFlags);
+
+	pl->mclk = mclk;
+	pl->sclk = sclk;
+
+	/* patch up vddc if necessary */
+	if (pl->vddc == 0xff01) {
+		if (radeon_atom_get_max_vddc(rdev, 0, 0, &vddc) == 0)
+			pl->vddc = vddc;
+	}
+
+	if (rps->class & ATOM_PPLIB_CLASSIFICATION_ACPI) {
+		pi->acpi_vddc = pl->vddc;
+		if (ps->low.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2)
+			pi->acpi_pcie_gen2 = true;
+		else
+			pi->acpi_pcie_gen2 = false;
+	}
+
+	if (pi->min_vddc_in_table > pl->vddc)
+		pi->min_vddc_in_table = pl->vddc;
+
+	if (pi->max_vddc_in_table < pl->vddc)
+		pi->max_vddc_in_table = pl->vddc;
+
+	/* patch up boot state */
+	if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) {
+		u16 vddc, vddci;
+		radeon_atombios_get_default_voltages(rdev, &vddc, &vddci);
+		pl->mclk = rdev->clock.default_mclk;
+		pl->sclk = rdev->clock.default_sclk;
+		pl->vddc = vddc;
+		pl->vddci = vddci;
+	}
+}
+
+int rv7xx_parse_power_table(struct radeon_device *rdev)
+{
+	struct radeon_mode_info *mode_info = &rdev->mode_info;
+	struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
+	union pplib_power_state *power_state;
+	int i, j;
+	union pplib_clock_info *clock_info;
+	union power_info *power_info;
+	int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
+        u16 data_offset;
+	u8 frev, crev;
+	struct rv7xx_ps *ps;
+
+	if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
+				   &frev, &crev, &data_offset))
+		return -EINVAL;
+	power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
+
+	rdev->pm.dpm.ps = kzalloc(sizeof(struct radeon_ps) *
+				  power_info->pplib.ucNumStates, GFP_KERNEL);
+	if (!rdev->pm.dpm.ps)
+		return -ENOMEM;
+	rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps);
+	rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime);
+	rdev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime);
+
+	for (i = 0; i < power_info->pplib.ucNumStates; i++) {
+		power_state = (union pplib_power_state *)
+			(mode_info->atom_context->bios + data_offset +
+			 le16_to_cpu(power_info->pplib.usStateArrayOffset) +
+			 i * power_info->pplib.ucStateEntrySize);
+		non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
+			(mode_info->atom_context->bios + data_offset +
+			 le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset) +
+			 (power_state->v1.ucNonClockStateIndex *
+			  power_info->pplib.ucNonClockSize));
+		if (power_info->pplib.ucStateEntrySize - 1) {
+			ps = kzalloc(sizeof(struct rv7xx_ps), GFP_KERNEL);
+			if (ps == NULL) {
+				kfree(rdev->pm.dpm.ps);
+				return -ENOMEM;
+			}
+			rdev->pm.dpm.ps[i].ps_priv = ps;
+			rv7xx_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i],
+							 non_clock_info,
+							 power_info->pplib.ucNonClockSize);
+			for (j = 0; j < (power_info->pplib.ucStateEntrySize - 1); j++) {
+				clock_info = (union pplib_clock_info *)
+					(mode_info->atom_context->bios + data_offset +
+					 le16_to_cpu(power_info->pplib.usClockInfoArrayOffset) +
+					 (power_state->v1.ucClockStateIndices[j] *
+					  power_info->pplib.ucClockInfoSize));
+				rv7xx_parse_pplib_clock_info(rdev,
+							     &rdev->pm.dpm.ps[i], j,
+							     clock_info);
+			}
+		}
+	}
+	rdev->pm.dpm.num_ps = power_info->pplib.ucNumStates;
+	return 0;
+}
+
+int rv770_dpm_init(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi;
+	int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info);
+	uint16_t data_offset, size;
+	uint8_t frev, crev;
+	struct atom_clock_dividers dividers;
+	int ret;
+
+	pi = kzalloc(sizeof(struct rv7xx_power_info), GFP_KERNEL);
+	if (pi == NULL)
+		return -ENOMEM;
+	rdev->pm.dpm.priv = pi;
+
+	rv770_get_max_vddc(rdev);
+
+	pi->acpi_vddc = 0;
+	pi->min_vddc_in_table = 0;
+	pi->max_vddc_in_table = 0;
+
+	ret = rv7xx_parse_power_table(rdev);
+	if (ret)
+		return ret;
+
+	if (rdev->pm.dpm.voltage_response_time == 0)
+		rdev->pm.dpm.voltage_response_time = R600_VOLTAGERESPONSETIME_DFLT;
+	if (rdev->pm.dpm.backbias_response_time == 0)
+		rdev->pm.dpm.backbias_response_time = R600_BACKBIASRESPONSETIME_DFLT;
+
+	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
+					     0, false, &dividers);
+	if (ret)
+		pi->ref_div = dividers.ref_div + 1;
+	else
+		pi->ref_div = R600_REFERENCEDIVIDER_DFLT;
+
+	pi->mclk_strobe_mode_threshold = 30000;
+	pi->mclk_edc_enable_threshold = 30000;
+
+	pi->voltage_control =
+		radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC);
+
+	pi->mvdd_control =
+		radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_MVDDC);
+
+	if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
+                                   &frev, &crev, &data_offset)) {
+		pi->sclk_ss = true;
+		pi->mclk_ss = true;
+		pi->dynamic_ss = true;
+	} else {
+		pi->sclk_ss = false;
+		pi->mclk_ss = false;
+		pi->dynamic_ss = false;
+	}
+
+	pi->asi = RV770_ASI_DFLT;
+	pi->pasi = RV770_HASI_DFLT;
+	pi->vrc = RV770_VRC_DFLT;
+
+	pi->power_gating = false;
+
+	pi->gfx_clock_gating = true;
+
+	pi->mg_clock_gating = true;
+	pi->mgcgtssm = true;
+
+	pi->dynamic_pcie_gen2 = true;
+
+	if (pi->gfx_clock_gating &&
+	    (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE))
+		pi->thermal_protection = true;
+	else
+		pi->thermal_protection = false;
+
+	pi->display_gap = true;
+
+	if (rdev->flags & RADEON_IS_MOBILITY)
+		pi->dcodt = true;
+	else
+		pi->dcodt = false;
+
+	pi->ulps = true;
+
+	pi->mclk_stutter_mode_threshold = 0;
+
+	pi->sram_end = SMC_RAM_END;
+	pi->state_table_start = RV770_SMC_TABLE_ADDRESS;
+	pi->soft_regs_start = RV770_SMC_SOFT_REGISTERS_START;
+
+	return 0;
+}
+
+void rv770_dpm_print_power_state(struct radeon_device *rdev,
+				 struct radeon_ps *rps)
+{
+	struct rv7xx_ps *ps = rv770_get_ps(rps);
+	struct rv7xx_pl *pl;
+
+	r600_dpm_print_class_info(rps->class, rps->class2);
+	r600_dpm_print_cap_info(rps->caps);
+	printk("\tuvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
+	if (rdev->family >= CHIP_CEDAR) {
+		pl = &ps->low;
+		printk("\t\tpower level 0    sclk: %u mclk: %u vddc: %u vddci: %u\n",
+		       pl->sclk, pl->mclk, pl->vddc, pl->vddci);
+		pl = &ps->medium;
+		printk("\t\tpower level 1    sclk: %u mclk: %u vddc: %u vddci: %u\n",
+		       pl->sclk, pl->mclk, pl->vddc, pl->vddci);
+		pl = &ps->high;
+		printk("\t\tpower level 2    sclk: %u mclk: %u vddc: %u vddci: %u\n",
+		       pl->sclk, pl->mclk, pl->vddc, pl->vddci);
+	} else {
+		pl = &ps->low;
+		printk("\t\tpower level 0    sclk: %u mclk: %u vddc: %u\n",
+		       pl->sclk, pl->mclk, pl->vddc);
+		pl = &ps->medium;
+		printk("\t\tpower level 1    sclk: %u mclk: %u vddc: %u\n",
+		       pl->sclk, pl->mclk, pl->vddc);
+		pl = &ps->high;
+		printk("\t\tpower level 2    sclk: %u mclk: %u vddc: %u\n",
+		       pl->sclk, pl->mclk, pl->vddc);
+	}
+	r600_dpm_print_ps_status(rdev, rps);
+}
+
+void rv770_dpm_fini(struct radeon_device *rdev)
+{
+	int i;
+
+	for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
+		kfree(rdev->pm.dpm.ps[i].ps_priv);
+	}
+	kfree(rdev->pm.dpm.ps);
+	kfree(rdev->pm.dpm.priv);
+}
+
+u32 rv770_dpm_get_sclk(struct radeon_device *rdev, bool low)
+{
+	struct rv7xx_ps *requested_state = rv770_get_ps(rdev->pm.dpm.requested_ps);
+
+	if (low)
+		return requested_state->low.sclk;
+	else
+		return requested_state->high.sclk;
+}
+
+u32 rv770_dpm_get_mclk(struct radeon_device *rdev, bool low)
+{
+	struct rv7xx_ps *requested_state = rv770_get_ps(rdev->pm.dpm.requested_ps);
+
+	if (low)
+		return requested_state->low.mclk;
+	else
+		return requested_state->high.mclk;
+}
diff --git a/drivers/gpu/drm/radeon/rv770_dpm.h b/drivers/gpu/drm/radeon/rv770_dpm.h
new file mode 100644
index 0000000..df9aae5
--- /dev/null
+++ b/drivers/gpu/drm/radeon/rv770_dpm.h
@@ -0,0 +1,272 @@
+/*
+ * Copyright 2011 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef __RV770_DPM_H__
+#define __RV770_DPM_H__
+
+#include "rv770_smc.h"
+
+struct rv770_clock_registers {
+	u32 cg_spll_func_cntl;
+	u32 cg_spll_func_cntl_2;
+	u32 cg_spll_func_cntl_3;
+	u32 cg_spll_spread_spectrum;
+	u32 cg_spll_spread_spectrum_2;
+	u32 mpll_ad_func_cntl;
+	u32 mpll_ad_func_cntl_2;
+	u32 mpll_dq_func_cntl;
+	u32 mpll_dq_func_cntl_2;
+	u32 mclk_pwrmgt_cntl;
+	u32 dll_cntl;
+	u32 mpll_ss1;
+	u32 mpll_ss2;
+};
+
+struct rv730_clock_registers {
+	u32 cg_spll_func_cntl;
+	u32 cg_spll_func_cntl_2;
+	u32 cg_spll_func_cntl_3;
+	u32 cg_spll_spread_spectrum;
+	u32 cg_spll_spread_spectrum_2;
+	u32 mclk_pwrmgt_cntl;
+	u32 dll_cntl;
+	u32 mpll_func_cntl;
+	u32 mpll_func_cntl2;
+	u32 mpll_func_cntl3;
+	u32 mpll_ss;
+	u32 mpll_ss2;
+};
+
+union r7xx_clock_registers {
+	struct rv770_clock_registers rv770;
+	struct rv730_clock_registers rv730;
+};
+
+struct vddc_table_entry {
+	u16 vddc;
+	u8 vddc_index;
+	u8 high_smio;
+	u32 low_smio;
+};
+
+#define MAX_NO_OF_MVDD_VALUES 2
+#define MAX_NO_VREG_STEPS 32
+
+struct rv7xx_power_info {
+	/* flags */
+	bool mem_gddr5;
+	bool pcie_gen2;
+	bool dynamic_pcie_gen2;
+	bool acpi_pcie_gen2;
+	bool boot_in_gen2;
+	bool voltage_control; /* vddc */
+	bool mvdd_control;
+	bool sclk_ss;
+	bool mclk_ss;
+	bool dynamic_ss;
+	bool gfx_clock_gating;
+	bool mg_clock_gating;
+	bool mgcgtssm;
+	bool power_gating;
+	bool thermal_protection;
+	bool display_gap;
+	bool dcodt;
+	bool ulps;
+	/* registers */
+	union r7xx_clock_registers clk_regs;
+	u32 s0_vid_lower_smio_cntl;
+	/* voltage */
+	u32 vddc_mask_low;
+	u32 mvdd_mask_low;
+	u32 mvdd_split_frequency;
+	u32 mvdd_low_smio[MAX_NO_OF_MVDD_VALUES];
+	u16 max_vddc;
+	u16 max_vddc_in_table;
+	u16 min_vddc_in_table;
+	struct vddc_table_entry vddc_table[MAX_NO_VREG_STEPS];
+	u8 valid_vddc_entries;
+	/* dc odt */
+	u32 mclk_odt_threshold;
+	u8 odt_value_0[2];
+	u8 odt_value_1[2];
+	/* stored values */
+	u32 boot_sclk;
+	u16 acpi_vddc;
+	u32 ref_div;
+	u32 active_auto_throttle_sources;
+	u32 mclk_stutter_mode_threshold;
+	u32 mclk_strobe_mode_threshold;
+	u32 mclk_edc_enable_threshold;
+	u32 bsp;
+	u32 bsu;
+	u32 pbsp;
+	u32 pbsu;
+	u32 dsp;
+	u32 psp;
+	u32 asi;
+	u32 pasi;
+	u32 vrc;
+	u32 restricted_levels;
+	/* smc offsets */
+	u16 state_table_start;
+	u16 soft_regs_start;
+	u16 sram_end;
+	/* scratch structs */
+	RV770_SMC_STATETABLE smc_statetable;
+};
+
+struct rv7xx_pl {
+	u32 sclk;
+	u32 mclk;
+	u16 vddc;
+	u16 vddci; /* eg+ only */
+	u32 flags;
+};
+
+struct rv7xx_ps {
+	struct rv7xx_pl high;
+	struct rv7xx_pl medium;
+	struct rv7xx_pl low;
+	bool dc_compatible;
+};
+
+#define RV770_RLP_DFLT                                10
+#define RV770_RMP_DFLT                                25
+#define RV770_LHP_DFLT                                25
+#define RV770_LMP_DFLT                                10
+#define RV770_VRC_DFLT                                0x003f
+#define RV770_ASI_DFLT                                1000
+#define RV770_HASI_DFLT                               200000
+#define RV770_MGCGTTLOCAL0_DFLT                       0x00100000
+#define RV7XX_MGCGTTLOCAL0_DFLT                       0
+#define RV770_MGCGTTLOCAL1_DFLT                       0xFFFF0000
+#define RV770_MGCGCGTSSMCTRL_DFLT                     0x55940000
+
+#define MVDD_LOW_INDEX  0
+#define MVDD_HIGH_INDEX 1
+
+#define MVDD_LOW_VALUE  0
+#define MVDD_HIGH_VALUE 0xffff
+
+#define RV770_DEFAULT_VCLK_FREQ  53300 /* 10 khz */
+#define RV770_DEFAULT_DCLK_FREQ  40000 /* 10 khz */
+
+/* rv730/rv710 */
+int rv730_populate_sclk_value(struct radeon_device *rdev,
+			      u32 engine_clock,
+			      RV770_SMC_SCLK_VALUE *sclk);
+int rv730_populate_mclk_value(struct radeon_device *rdev,
+			      u32 engine_clock, u32 memory_clock,
+			      LPRV7XX_SMC_MCLK_VALUE mclk);
+void rv730_read_clock_registers(struct radeon_device *rdev);
+int rv730_populate_smc_acpi_state(struct radeon_device *rdev,
+				  RV770_SMC_STATETABLE *table);
+int rv730_populate_smc_initial_state(struct radeon_device *rdev,
+				     struct radeon_ps *radeon_initial_state,
+				     RV770_SMC_STATETABLE *table);
+void rv730_program_memory_timing_parameters(struct radeon_device *rdev,
+					    struct radeon_ps *radeon_state);
+void rv730_power_gating_enable(struct radeon_device *rdev,
+			       bool enable);
+void rv730_start_dpm(struct radeon_device *rdev);
+void rv730_stop_dpm(struct radeon_device *rdev);
+void rv730_program_dcodt(struct radeon_device *rdev, bool use_dcodt);
+void rv730_get_odt_values(struct radeon_device *rdev);
+
+/* rv740 */
+int rv740_populate_sclk_value(struct radeon_device *rdev, u32 engine_clock,
+			      RV770_SMC_SCLK_VALUE *sclk);
+int rv740_populate_mclk_value(struct radeon_device *rdev,
+			      u32 engine_clock, u32 memory_clock,
+			      RV7XX_SMC_MCLK_VALUE *mclk);
+void rv740_read_clock_registers(struct radeon_device *rdev);
+int rv740_populate_smc_acpi_state(struct radeon_device *rdev,
+				  RV770_SMC_STATETABLE *table);
+void rv740_enable_mclk_spread_spectrum(struct radeon_device *rdev,
+				       bool enable);
+u8 rv740_get_mclk_frequency_ratio(u32 memory_clock);
+u32 rv740_get_dll_speed(bool is_gddr5, u32 memory_clock);
+u32 rv740_get_decoded_reference_divider(u32 encoded_ref);
+
+/* rv770 */
+u32 rv770_map_clkf_to_ibias(struct radeon_device *rdev, u32 clkf);
+int rv770_populate_vddc_value(struct radeon_device *rdev, u16 vddc,
+			      RV770_SMC_VOLTAGE_VALUE *voltage);
+int rv770_populate_mvdd_value(struct radeon_device *rdev, u32 mclk,
+			      RV770_SMC_VOLTAGE_VALUE *voltage);
+u8 rv770_get_seq_value(struct radeon_device *rdev,
+		       struct rv7xx_pl *pl);
+int rv770_populate_initial_mvdd_value(struct radeon_device *rdev,
+				      RV770_SMC_VOLTAGE_VALUE *voltage);
+u32 rv770_calculate_memory_refresh_rate(struct radeon_device *rdev,
+					u32 engine_clock);
+void rv770_program_response_times(struct radeon_device *rdev);
+int rv770_populate_smc_sp(struct radeon_device *rdev,
+			  struct radeon_ps *radeon_state,
+			  RV770_SMC_SWSTATE *smc_state);
+int rv770_populate_smc_t(struct radeon_device *rdev,
+			 struct radeon_ps *radeon_state,
+			 RV770_SMC_SWSTATE *smc_state);
+void rv770_read_voltage_smio_registers(struct radeon_device *rdev);
+void rv770_get_memory_type(struct radeon_device *rdev);
+void r7xx_start_smc(struct radeon_device *rdev);
+u8 rv770_get_memory_module_index(struct radeon_device *rdev);
+void rv770_get_max_vddc(struct radeon_device *rdev);
+void rv770_get_pcie_gen2_status(struct radeon_device *rdev);
+void rv770_enable_acpi_pm(struct radeon_device *rdev);
+void rv770_restore_cgcg(struct radeon_device *rdev);
+bool rv770_dpm_enabled(struct radeon_device *rdev);
+void rv770_enable_voltage_control(struct radeon_device *rdev,
+				  bool enable);
+void rv770_enable_backbias(struct radeon_device *rdev,
+			   bool enable);
+void rv770_enable_thermal_protection(struct radeon_device *rdev,
+				     bool enable);
+void rv770_enable_auto_throttle_source(struct radeon_device *rdev,
+				       enum radeon_dpm_auto_throttle_src source,
+				       bool enable);
+void rv770_setup_bsp(struct radeon_device *rdev);
+void rv770_program_git(struct radeon_device *rdev);
+void rv770_program_tp(struct radeon_device *rdev);
+void rv770_program_tpp(struct radeon_device *rdev);
+void rv770_program_sstp(struct radeon_device *rdev);
+void rv770_program_engine_speed_parameters(struct radeon_device *rdev);
+void rv770_program_vc(struct radeon_device *rdev);
+void rv770_clear_vc(struct radeon_device *rdev);
+int rv770_upload_firmware(struct radeon_device *rdev);
+void rv770_stop_dpm(struct radeon_device *rdev);
+void r7xx_stop_smc(struct radeon_device *rdev);
+void rv770_reset_smio_status(struct radeon_device *rdev);
+int rv770_restrict_performance_levels_before_switch(struct radeon_device *rdev);
+int rv770_halt_smc(struct radeon_device *rdev);
+int rv770_resume_smc(struct radeon_device *rdev);
+int rv770_set_sw_state(struct radeon_device *rdev);
+int rv770_set_boot_state(struct radeon_device *rdev);
+int rv7xx_parse_power_table(struct radeon_device *rdev);
+
+/* smc */
+int rv770_read_smc_soft_register(struct radeon_device *rdev,
+				 u16 reg_offset, u32 *value);
+int rv770_write_smc_soft_register(struct radeon_device *rdev,
+				  u16 reg_offset, u32 value);
+
+#endif
diff --git a/drivers/gpu/drm/radeon/rv770_smc.c b/drivers/gpu/drm/radeon/rv770_smc.c
new file mode 100644
index 0000000..8e07153
--- /dev/null
+++ b/drivers/gpu/drm/radeon/rv770_smc.c
@@ -0,0 +1,404 @@
+/*
+ * Copyright 2011 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Alex Deucher
+ */
+
+#include <linux/firmware.h>
+#include "drmP.h"
+#include "radeon.h"
+#include "rv770d.h"
+#include "rv770_dpm.h"
+#include "rv770_smc.h"
+#include "atom.h"
+#include "radeon_ucode.h"
+
+#define FIRST_SMC_INT_VECT_REG 0xFFD8
+#define FIRST_INT_VECT_S19     0xFFC0
+
+static const u8 rv770_smc_int_vectors[] =
+{
+	0x08, 0x10, 0x08, 0x10,
+	0x08, 0x10, 0x08, 0x10,
+	0x08, 0x10, 0x08, 0x10,
+	0x08, 0x10, 0x08, 0x10,
+	0x08, 0x10, 0x08, 0x10,
+	0x08, 0x10, 0x08, 0x10,
+	0x08, 0x10, 0x08, 0x10,
+	0x08, 0x10, 0x08, 0x10,
+	0x08, 0x10, 0x08, 0x10,
+	0x08, 0x10, 0x08, 0x10,
+	0x08, 0x10, 0x08, 0x10,
+	0x08, 0x10, 0x08, 0x10,
+	0x08, 0x10, 0x0C, 0xD7,
+	0x08, 0x2B, 0x08, 0x10,
+	0x03, 0x51, 0x03, 0x51,
+	0x03, 0x51, 0x03, 0x51
+};
+
+static const u8 rv730_smc_int_vectors[] =
+{
+	0x08, 0x15, 0x08, 0x15,
+	0x08, 0x15, 0x08, 0x15,
+	0x08, 0x15, 0x08, 0x15,
+	0x08, 0x15, 0x08, 0x15,
+	0x08, 0x15, 0x08, 0x15,
+	0x08, 0x15, 0x08, 0x15,
+	0x08, 0x15, 0x08, 0x15,
+	0x08, 0x15, 0x08, 0x15,
+	0x08, 0x15, 0x08, 0x15,
+	0x08, 0x15, 0x08, 0x15,
+	0x08, 0x15, 0x08, 0x15,
+	0x08, 0x15, 0x08, 0x15,
+	0x08, 0x15, 0x0C, 0xBB,
+	0x08, 0x30, 0x08, 0x15,
+	0x03, 0x56, 0x03, 0x56,
+	0x03, 0x56, 0x03, 0x56
+};
+
+static const u8 rv710_smc_int_vectors[] =
+{
+	0x08, 0x04, 0x08, 0x04,
+	0x08, 0x04, 0x08, 0x04,
+	0x08, 0x04, 0x08, 0x04,
+	0x08, 0x04, 0x08, 0x04,
+	0x08, 0x04, 0x08, 0x04,
+	0x08, 0x04, 0x08, 0x04,
+	0x08, 0x04, 0x08, 0x04,
+	0x08, 0x04, 0x08, 0x04,
+	0x08, 0x04, 0x08, 0x04,
+	0x08, 0x04, 0x08, 0x04,
+	0x08, 0x04, 0x08, 0x04,
+	0x08, 0x04, 0x08, 0x04,
+	0x08, 0x04, 0x0C, 0xCB,
+	0x08, 0x1F, 0x08, 0x04,
+	0x03, 0x51, 0x03, 0x51,
+	0x03, 0x51, 0x03, 0x51
+};
+
+static const u8 rv740_smc_int_vectors[] =
+{
+	0x08, 0x10, 0x08, 0x10,
+	0x08, 0x10, 0x08, 0x10,
+	0x08, 0x10, 0x08, 0x10,
+	0x08, 0x10, 0x08, 0x10,
+	0x08, 0x10, 0x08, 0x10,
+	0x08, 0x10, 0x08, 0x10,
+	0x08, 0x10, 0x08, 0x10,
+	0x08, 0x10, 0x08, 0x10,
+	0x08, 0x10, 0x08, 0x10,
+	0x08, 0x10, 0x08, 0x10,
+	0x08, 0x10, 0x08, 0x10,
+	0x08, 0x10, 0x08, 0x10,
+	0x08, 0x10, 0x0C, 0xD7,
+	0x08, 0x2B, 0x08, 0x10,
+	0x03, 0x51, 0x03, 0x51,
+	0x03, 0x51, 0x03, 0x51
+};
+
+int rv770_set_smc_sram_address(struct radeon_device *rdev,
+			       u16 smc_address, u16 limit)
+{
+	u32 addr;
+
+	if (smc_address & 3)
+		return -EINVAL;
+	if ((smc_address + 3) > limit)
+		return -EINVAL;
+
+	addr = smc_address;
+	addr |= SMC_SRAM_AUTO_INC_DIS;
+
+	WREG32(SMC_SRAM_ADDR, addr);
+
+	return 0;
+}
+
+int rv770_copy_bytes_to_smc(struct radeon_device *rdev,
+			    u16 smc_start_address, const u8 *src,
+			    u16 byte_count, u16 limit)
+{
+	u32 data, original_data, extra_shift;
+	u16 addr;
+	int ret;
+
+	if (smc_start_address & 3)
+		return -EINVAL;
+	if ((smc_start_address + byte_count) > limit)
+		return -EINVAL;
+
+	addr = smc_start_address;
+
+	while (byte_count >= 4) {
+		/* SMC address space is BE */
+		data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
+
+		ret = rv770_set_smc_sram_address(rdev, addr, limit);
+		if (ret)
+			return ret;
+
+		WREG32(SMC_SRAM_DATA, data);
+
+		src += 4;
+		byte_count -= 4;
+		addr += 4;
+	}
+
+	/* RMW for final bytes */
+	if (byte_count > 0) {
+		data = 0;
+
+		ret = rv770_set_smc_sram_address(rdev, addr, limit);
+		if (ret)
+			return ret;
+
+		original_data = RREG32(SMC_SRAM_DATA);
+
+		extra_shift = 8 * (4 - byte_count);
+
+		while (byte_count > 0) {
+			/* SMC address space is BE */
+			data = (data << 8) + *src++;
+			byte_count--;
+		}
+
+		data <<= extra_shift;
+
+		data |= (original_data & ~((~0UL) << extra_shift));
+
+		ret = rv770_set_smc_sram_address(rdev, addr, limit);
+		if (ret)
+			return ret;
+
+		WREG32(SMC_SRAM_DATA, data);
+	}
+
+	return 0;
+}
+
+static int rv770_program_interrupt_vectors(struct radeon_device *rdev,
+					   u32 smc_first_vector, const u8 *src,
+					   u32 byte_count)
+{
+	u32 tmp, i;
+
+	if (byte_count % 4)
+		return -EINVAL;
+
+	if (smc_first_vector < FIRST_SMC_INT_VECT_REG) {
+		tmp = FIRST_SMC_INT_VECT_REG - smc_first_vector;
+
+		if (tmp > byte_count)
+			return 0;
+
+		byte_count -= tmp;
+		src += tmp;
+		smc_first_vector = FIRST_SMC_INT_VECT_REG;
+	}
+
+	for (i = 0; i < byte_count; i += 4) {
+		/* SMC address space is BE */
+		tmp = (src[i] << 24) | (src[i + 1] << 16) | (src[i + 2] << 8) | src[i + 3];
+
+		WREG32(SMC_ISR_FFD8_FFDB + i, tmp);
+	}
+
+	return 0;
+}
+
+void rv770_start_smc(struct radeon_device *rdev)
+{
+	WREG32_P(SMC_IO, SMC_RST_N, ~SMC_RST_N);
+}
+
+void rv770_reset_smc(struct radeon_device *rdev)
+{
+	WREG32_P(SMC_IO, 0, ~SMC_RST_N);
+}
+
+void rv770_stop_smc_clock(struct radeon_device *rdev)
+{
+	WREG32_P(SMC_IO, 0, ~SMC_CLK_EN);
+}
+
+void rv770_start_smc_clock(struct radeon_device *rdev)
+{
+	WREG32_P(SMC_IO, SMC_CLK_EN, ~SMC_CLK_EN);
+}
+
+bool rv770_is_smc_running(struct radeon_device *rdev)
+{
+	u32 tmp;
+
+	tmp = RREG32(SMC_IO);
+
+	if ((tmp & SMC_RST_N) && (tmp & SMC_CLK_EN))
+		return true;
+	else
+		return false;
+}
+
+PPSMC_Result rv770_send_msg_to_smc(struct radeon_device *rdev, PPSMC_Msg msg)
+{
+	u32 tmp;
+	int i;
+	PPSMC_Result result;
+
+	if (!rv770_is_smc_running(rdev))
+		return PPSMC_Result_Failed;
+
+	WREG32_P(SMC_MSG, HOST_SMC_MSG(msg), ~HOST_SMC_MSG_MASK);
+
+	for (i = 0; i < rdev->usec_timeout; i++) {
+		tmp = RREG32(SMC_MSG) & HOST_SMC_RESP_MASK;
+		tmp >>= HOST_SMC_RESP_SHIFT;
+		if (tmp != 0)
+			break;
+		udelay(1);
+	}
+
+	tmp = RREG32(SMC_MSG) & HOST_SMC_RESP_MASK;
+	tmp >>= HOST_SMC_RESP_SHIFT;
+
+	result = (PPSMC_Result)tmp;
+	return result;
+}
+
+PPSMC_Result rv770_wait_for_smc_inactive(struct radeon_device *rdev)
+{
+	int i;
+	PPSMC_Result result = PPSMC_Result_OK;
+
+	if (!rv770_is_smc_running(rdev))
+		return result;
+
+	for (i = 0; i < rdev->usec_timeout; i++) {
+		if (RREG32(SMC_IO) & SMC_STOP_MODE)
+			break;
+		udelay(1);
+	}
+
+	return result;
+}
+
+static void rv770_clear_smc_sram(struct radeon_device *rdev, u16 limit)
+{
+	u16 i;
+
+	for (i = 0;  i < limit; i += 4) {
+		rv770_set_smc_sram_address(rdev, i, limit);
+		WREG32(SMC_SRAM_DATA, 0);
+	}
+}
+
+int rv770_load_smc_ucode(struct radeon_device *rdev,
+			 u16 limit)
+{
+	int ret;
+	const u8 *int_vect;
+	u16 int_vect_start_address;
+	u16 int_vect_size;
+	const u8 *ucode_data;
+	u16 ucode_start_address;
+	u16 ucode_size;
+
+	if (!rdev->smc_fw)
+		return -EINVAL;
+
+	rv770_clear_smc_sram(rdev, limit);
+
+	switch (rdev->family) {
+	case CHIP_RV770:
+		ucode_start_address = RV770_SMC_UCODE_START;
+		ucode_size = RV770_SMC_UCODE_SIZE;
+		int_vect = (const u8 *)&rv770_smc_int_vectors;
+		int_vect_start_address = RV770_SMC_INT_VECTOR_START;
+		int_vect_size = RV770_SMC_INT_VECTOR_SIZE;
+		break;
+	case CHIP_RV730:
+		ucode_start_address = RV730_SMC_UCODE_START;
+		ucode_size = RV730_SMC_UCODE_SIZE;
+		int_vect = (const u8 *)&rv730_smc_int_vectors;
+		int_vect_start_address = RV730_SMC_INT_VECTOR_START;
+		int_vect_size = RV730_SMC_INT_VECTOR_SIZE;
+		break;
+	case CHIP_RV710:
+		ucode_start_address = RV710_SMC_UCODE_START;
+		ucode_size = RV710_SMC_UCODE_SIZE;
+		int_vect = (const u8 *)&rv710_smc_int_vectors;
+		int_vect_start_address = RV710_SMC_INT_VECTOR_START;
+		int_vect_size = RV710_SMC_INT_VECTOR_SIZE;
+		break;
+	case CHIP_RV740:
+		ucode_start_address = RV740_SMC_UCODE_START;
+		ucode_size = RV740_SMC_UCODE_SIZE;
+		int_vect = (const u8 *)&rv740_smc_int_vectors;
+		int_vect_start_address = RV740_SMC_INT_VECTOR_START;
+		int_vect_size = RV740_SMC_INT_VECTOR_SIZE;
+		break;
+	default:
+		DRM_ERROR("unknown asic in smc ucode loader\n");
+		BUG();
+	}
+
+	/* load the ucode */
+	ucode_data = (const u8 *)rdev->smc_fw->data;
+	ret = rv770_copy_bytes_to_smc(rdev, ucode_start_address,
+				      ucode_data, ucode_size, limit);
+	if (ret)
+		return ret;
+
+	/* set up the int vectors */
+	ret = rv770_program_interrupt_vectors(rdev, int_vect_start_address,
+					      int_vect, int_vect_size);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+int rv770_read_smc_sram_dword(struct radeon_device *rdev,
+			      u16 smc_address, u32 *value, u16 limit)
+{
+	int ret;
+
+	ret = rv770_set_smc_sram_address(rdev, smc_address, limit);
+	if (ret)
+		return ret;
+
+	*value = RREG32(SMC_SRAM_DATA);
+
+	return 0;
+}
+
+int rv770_write_smc_sram_dword(struct radeon_device *rdev,
+			       u16 smc_address, u32 value, u16 limit)
+{
+	int ret;
+
+	ret = rv770_set_smc_sram_address(rdev, smc_address, limit);
+	if (ret)
+		return ret;
+
+	WREG32(SMC_SRAM_DATA, value);
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/radeon/rv770_smc.h b/drivers/gpu/drm/radeon/rv770_smc.h
new file mode 100644
index 0000000..bdb652c
--- /dev/null
+++ b/drivers/gpu/drm/radeon/rv770_smc.h
@@ -0,0 +1,208 @@
+/*
+ * Copyright 2011 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef __RV770_SMC_H__
+#define __RV770_SMC_H__
+
+#include "ppsmc.h"
+
+#pragma pack(push, 1)
+
+#define RV770_SMC_TABLE_ADDRESS 0xB000
+
+#define RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE    3
+
+struct RV770_SMC_SCLK_VALUE
+{
+    uint32_t        vCG_SPLL_FUNC_CNTL;
+    uint32_t        vCG_SPLL_FUNC_CNTL_2;
+    uint32_t        vCG_SPLL_FUNC_CNTL_3;
+    uint32_t        vCG_SPLL_SPREAD_SPECTRUM;
+    uint32_t        vCG_SPLL_SPREAD_SPECTRUM_2;
+    uint32_t        sclk_value;
+};
+
+typedef struct RV770_SMC_SCLK_VALUE RV770_SMC_SCLK_VALUE;
+
+struct RV770_SMC_MCLK_VALUE
+{
+    uint32_t        vMPLL_AD_FUNC_CNTL;
+    uint32_t        vMPLL_AD_FUNC_CNTL_2;
+    uint32_t        vMPLL_DQ_FUNC_CNTL;
+    uint32_t        vMPLL_DQ_FUNC_CNTL_2;
+    uint32_t        vMCLK_PWRMGT_CNTL;
+    uint32_t        vDLL_CNTL;
+    uint32_t        vMPLL_SS;
+    uint32_t        vMPLL_SS2;
+    uint32_t        mclk_value;
+};
+
+typedef struct RV770_SMC_MCLK_VALUE RV770_SMC_MCLK_VALUE;
+
+
+struct RV730_SMC_MCLK_VALUE
+{
+    uint32_t        vMCLK_PWRMGT_CNTL;
+    uint32_t        vDLL_CNTL;
+    uint32_t        vMPLL_FUNC_CNTL;
+    uint32_t        vMPLL_FUNC_CNTL2;
+    uint32_t        vMPLL_FUNC_CNTL3;
+    uint32_t        vMPLL_SS;
+    uint32_t        vMPLL_SS2;
+    uint32_t        mclk_value;
+};
+
+typedef struct RV730_SMC_MCLK_VALUE RV730_SMC_MCLK_VALUE;
+
+struct RV770_SMC_VOLTAGE_VALUE
+{
+    uint16_t             value;
+    uint8_t              index;
+    uint8_t              padding;
+};
+
+typedef struct RV770_SMC_VOLTAGE_VALUE RV770_SMC_VOLTAGE_VALUE;
+
+union RV7XX_SMC_MCLK_VALUE
+{
+    RV770_SMC_MCLK_VALUE    mclk770;
+    RV730_SMC_MCLK_VALUE    mclk730;
+};
+
+typedef union RV7XX_SMC_MCLK_VALUE RV7XX_SMC_MCLK_VALUE, *LPRV7XX_SMC_MCLK_VALUE;
+
+struct RV770_SMC_HW_PERFORMANCE_LEVEL
+{
+    uint8_t                 arbValue;
+    union{
+        uint8_t             seqValue;
+        uint8_t             ACIndex;
+    };
+    uint8_t                 displayWatermark;
+    uint8_t                 gen2PCIE;
+    uint8_t                 gen2XSP;
+    uint8_t                 backbias;
+    uint8_t                 strobeMode;
+    uint8_t                 mcFlags;
+    uint32_t                aT;
+    uint32_t                bSP;
+    RV770_SMC_SCLK_VALUE    sclk;
+    RV7XX_SMC_MCLK_VALUE    mclk;
+    RV770_SMC_VOLTAGE_VALUE vddc;
+    RV770_SMC_VOLTAGE_VALUE mvdd;
+    RV770_SMC_VOLTAGE_VALUE vddci;
+    uint8_t                 reserved1;
+    uint8_t                 reserved2;
+    uint8_t                 stateFlags;
+    uint8_t                 padding;
+};
+
+#define SMC_STROBE_RATIO    0x0F
+#define SMC_STROBE_ENABLE   0x10
+
+#define SMC_MC_EDC_RD_FLAG  0x01
+#define SMC_MC_EDC_WR_FLAG  0x02
+#define SMC_MC_RTT_ENABLE   0x04
+#define SMC_MC_STUTTER_EN   0x08
+
+typedef struct RV770_SMC_HW_PERFORMANCE_LEVEL RV770_SMC_HW_PERFORMANCE_LEVEL;
+
+struct RV770_SMC_SWSTATE
+{
+    uint8_t           flags;
+    uint8_t           padding1;
+    uint8_t           padding2;
+    uint8_t           padding3;
+    RV770_SMC_HW_PERFORMANCE_LEVEL levels[RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE];
+};
+
+typedef struct RV770_SMC_SWSTATE RV770_SMC_SWSTATE;
+
+#define RV770_SMC_VOLTAGEMASK_VDDC 0
+#define RV770_SMC_VOLTAGEMASK_MVDD 1
+#define RV770_SMC_VOLTAGEMASK_VDDCI 2
+#define RV770_SMC_VOLTAGEMASK_MAX  4
+
+struct RV770_SMC_VOLTAGEMASKTABLE
+{
+    uint8_t  highMask[RV770_SMC_VOLTAGEMASK_MAX];
+    uint32_t lowMask[RV770_SMC_VOLTAGEMASK_MAX];
+};
+
+typedef struct RV770_SMC_VOLTAGEMASKTABLE RV770_SMC_VOLTAGEMASKTABLE;
+
+#define MAX_NO_VREG_STEPS 32
+
+struct RV770_SMC_STATETABLE
+{
+    uint8_t             thermalProtectType;
+    uint8_t             systemFlags;
+    uint8_t             maxVDDCIndexInPPTable;
+    uint8_t             extraFlags;
+    uint8_t             highSMIO[MAX_NO_VREG_STEPS];
+    uint32_t            lowSMIO[MAX_NO_VREG_STEPS];
+    RV770_SMC_VOLTAGEMASKTABLE voltageMaskTable;
+    RV770_SMC_SWSTATE   initialState;
+    RV770_SMC_SWSTATE   ACPIState;
+    RV770_SMC_SWSTATE   driverState;
+    RV770_SMC_SWSTATE   ULVState;
+};
+
+typedef struct RV770_SMC_STATETABLE RV770_SMC_STATETABLE;
+
+#define PPSMC_STATEFLAG_AUTO_PULSE_SKIP 0x01
+
+#pragma pack(pop)
+
+#define RV770_SMC_SOFT_REGISTERS_START        0x104
+
+#define RV770_SMC_SOFT_REGISTER_mclk_chg_timeout        0x0
+#define RV770_SMC_SOFT_REGISTER_baby_step_timer         0x8
+#define RV770_SMC_SOFT_REGISTER_delay_bbias             0xC
+#define RV770_SMC_SOFT_REGISTER_delay_vreg              0x10
+#define RV770_SMC_SOFT_REGISTER_delay_acpi              0x2C
+#define RV770_SMC_SOFT_REGISTER_seq_index               0x64
+#define RV770_SMC_SOFT_REGISTER_mvdd_chg_time           0x68
+#define RV770_SMC_SOFT_REGISTER_mclk_switch_lim         0x78
+#define RV770_SMC_SOFT_REGISTER_mc_block_delay          0x90
+#define RV770_SMC_SOFT_REGISTER_is_asic_lombok          0xA0
+
+int rv770_set_smc_sram_address(struct radeon_device *rdev,
+			       u16 smc_address, u16 limit);
+int rv770_copy_bytes_to_smc(struct radeon_device *rdev,
+			    u16 smc_start_address, const u8 *src,
+			    u16 byte_count, u16 limit);
+void rv770_start_smc(struct radeon_device *rdev);
+void rv770_reset_smc(struct radeon_device *rdev);
+void rv770_stop_smc_clock(struct radeon_device *rdev);
+void rv770_start_smc_clock(struct radeon_device *rdev);
+bool rv770_is_smc_running(struct radeon_device *rdev);
+PPSMC_Result rv770_send_msg_to_smc(struct radeon_device *rdev, PPSMC_Msg msg);
+PPSMC_Result rv770_wait_for_smc_inactive(struct radeon_device *rdev);
+int rv770_read_smc_sram_dword(struct radeon_device *rdev,
+			      u16 smc_address, u32 *value, u16 limit);
+int rv770_write_smc_sram_dword(struct radeon_device *rdev,
+			       u16 smc_address, u32 value, u16 limit);
+int rv770_load_smc_ucode(struct radeon_device *rdev,
+			 u16 limit);
+
+#endif
diff --git a/drivers/gpu/drm/radeon/rv770d.h b/drivers/gpu/drm/radeon/rv770d.h
index 85b1626..784eeaf 100644
--- a/drivers/gpu/drm/radeon/rv770d.h
+++ b/drivers/gpu/drm/radeon/rv770d.h
@@ -62,6 +62,242 @@
 #	define UPLL_FB_DIV(x)				((x) << 0)
 #	define UPLL_FB_DIV_MASK				0x01FFFFFF
 
+/* pm registers */
+#define	SMC_SRAM_ADDR					0x200
+#define		SMC_SRAM_AUTO_INC_DIS				(1 << 16)
+#define	SMC_SRAM_DATA					0x204
+#define	SMC_IO						0x208
+#define		SMC_RST_N					(1 << 0)
+#define		SMC_STOP_MODE					(1 << 2)
+#define		SMC_CLK_EN					(1 << 11)
+#define	SMC_MSG						0x20c
+#define		HOST_SMC_MSG(x)					((x) << 0)
+#define		HOST_SMC_MSG_MASK				(0xff << 0)
+#define		HOST_SMC_MSG_SHIFT				0
+#define		HOST_SMC_RESP(x)				((x) << 8)
+#define		HOST_SMC_RESP_MASK				(0xff << 8)
+#define		HOST_SMC_RESP_SHIFT				8
+#define		SMC_HOST_MSG(x)					((x) << 16)
+#define		SMC_HOST_MSG_MASK				(0xff << 16)
+#define		SMC_HOST_MSG_SHIFT				16
+#define		SMC_HOST_RESP(x)				((x) << 24)
+#define		SMC_HOST_RESP_MASK				(0xff << 24)
+#define		SMC_HOST_RESP_SHIFT				24
+
+#define	SMC_ISR_FFD8_FFDB				0x218
+
+#define	CG_SPLL_FUNC_CNTL				0x600
+#define		SPLL_RESET				(1 << 0)
+#define		SPLL_SLEEP				(1 << 1)
+#define		SPLL_DIVEN				(1 << 2)
+#define		SPLL_BYPASS_EN				(1 << 3)
+#define		SPLL_REF_DIV(x)				((x) << 4)
+#define		SPLL_REF_DIV_MASK			(0x3f << 4)
+#define		SPLL_HILEN(x)				((x) << 12)
+#define		SPLL_HILEN_MASK				(0xf << 12)
+#define		SPLL_LOLEN(x)				((x) << 16)
+#define		SPLL_LOLEN_MASK				(0xf << 16)
+#define	CG_SPLL_FUNC_CNTL_2				0x604
+#define		SCLK_MUX_SEL(x)				((x) << 0)
+#define		SCLK_MUX_SEL_MASK			(0x1ff << 0)
+#define	CG_SPLL_FUNC_CNTL_3				0x608
+#define		SPLL_FB_DIV(x)				((x) << 0)
+#define		SPLL_FB_DIV_MASK			(0x3ffffff << 0)
+#define		SPLL_DITHEN				(1 << 28)
+
+#define	SPLL_CNTL_MODE					0x610
+#define		SPLL_DIV_SYNC				(1 << 5)
+
+#define	MPLL_AD_FUNC_CNTL				0x624
+#define		CLKF(x)					((x) << 0)
+#define		CLKF_MASK				(0x7f << 0)
+#define		CLKR(x)					((x) << 7)
+#define		CLKR_MASK				(0x1f << 7)
+#define		CLKFRAC(x)				((x) << 12)
+#define		CLKFRAC_MASK				(0x1f << 12)
+#define		YCLK_POST_DIV(x)			((x) << 17)
+#define		YCLK_POST_DIV_MASK			(3 << 17)
+#define		IBIAS(x)				((x) << 20)
+#define		IBIAS_MASK				(0x3ff << 20)
+#define		RESET					(1 << 30)
+#define		PDNB					(1 << 31)
+#define	MPLL_AD_FUNC_CNTL_2				0x628
+#define		BYPASS					(1 << 19)
+#define		BIAS_GEN_PDNB				(1 << 24)
+#define		RESET_EN				(1 << 25)
+#define		VCO_MODE				(1 << 29)
+#define	MPLL_DQ_FUNC_CNTL				0x62c
+#define	MPLL_DQ_FUNC_CNTL_2				0x630
+
+#define GENERAL_PWRMGT                                  0x63c
+#       define GLOBAL_PWRMGT_EN                         (1 << 0)
+#       define STATIC_PM_EN                             (1 << 1)
+#       define THERMAL_PROTECTION_DIS                   (1 << 2)
+#       define THERMAL_PROTECTION_TYPE                  (1 << 3)
+#       define ENABLE_GEN2PCIE                          (1 << 4)
+#       define ENABLE_GEN2XSP                           (1 << 5)
+#       define SW_SMIO_INDEX(x)                         ((x) << 6)
+#       define SW_SMIO_INDEX_MASK                       (3 << 6)
+#       define SW_SMIO_INDEX_SHIFT                      6
+#       define LOW_VOLT_D2_ACPI                         (1 << 8)
+#       define LOW_VOLT_D3_ACPI                         (1 << 9)
+#       define VOLT_PWRMGT_EN                           (1 << 10)
+#       define BACKBIAS_PAD_EN                          (1 << 18)
+#       define BACKBIAS_VALUE                           (1 << 19)
+#       define DYN_SPREAD_SPECTRUM_EN                   (1 << 23)
+#       define AC_DC_SW                                 (1 << 24)
+
+#define CG_TPC                                            0x640
+#define SCLK_PWRMGT_CNTL                                  0x644
+#       define SCLK_PWRMGT_OFF                            (1 << 0)
+#       define SCLK_LOW_D1                                (1 << 1)
+#       define FIR_RESET                                  (1 << 4)
+#       define FIR_FORCE_TREND_SEL                        (1 << 5)
+#       define FIR_TREND_MODE                             (1 << 6)
+#       define DYN_GFX_CLK_OFF_EN                         (1 << 7)
+#       define GFX_CLK_FORCE_ON                           (1 << 8)
+#       define GFX_CLK_REQUEST_OFF                        (1 << 9)
+#       define GFX_CLK_FORCE_OFF                          (1 << 10)
+#       define GFX_CLK_OFF_ACPI_D1                        (1 << 11)
+#       define GFX_CLK_OFF_ACPI_D2                        (1 << 12)
+#       define GFX_CLK_OFF_ACPI_D3                        (1 << 13)
+#define	MCLK_PWRMGT_CNTL				0x648
+#       define DLL_SPEED(x)				((x) << 0)
+#       define DLL_SPEED_MASK				(0x1f << 0)
+#       define MPLL_PWRMGT_OFF                          (1 << 5)
+#       define DLL_READY                                (1 << 6)
+#       define MC_INT_CNTL                              (1 << 7)
+#       define MRDCKA0_SLEEP                            (1 << 8)
+#       define MRDCKA1_SLEEP                            (1 << 9)
+#       define MRDCKB0_SLEEP                            (1 << 10)
+#       define MRDCKB1_SLEEP                            (1 << 11)
+#       define MRDCKC0_SLEEP                            (1 << 12)
+#       define MRDCKC1_SLEEP                            (1 << 13)
+#       define MRDCKD0_SLEEP                            (1 << 14)
+#       define MRDCKD1_SLEEP                            (1 << 15)
+#       define MRDCKA0_RESET                            (1 << 16)
+#       define MRDCKA1_RESET                            (1 << 17)
+#       define MRDCKB0_RESET                            (1 << 18)
+#       define MRDCKB1_RESET                            (1 << 19)
+#       define MRDCKC0_RESET                            (1 << 20)
+#       define MRDCKC1_RESET                            (1 << 21)
+#       define MRDCKD0_RESET                            (1 << 22)
+#       define MRDCKD1_RESET                            (1 << 23)
+#       define DLL_READY_READ                           (1 << 24)
+#       define USE_DISPLAY_GAP                          (1 << 25)
+#       define USE_DISPLAY_URGENT_NORMAL                (1 << 26)
+#       define MPLL_TURNOFF_D2                          (1 << 28)
+#define	DLL_CNTL					0x64c
+#       define MRDCKA0_BYPASS                           (1 << 24)
+#       define MRDCKA1_BYPASS                           (1 << 25)
+#       define MRDCKB0_BYPASS                           (1 << 26)
+#       define MRDCKB1_BYPASS                           (1 << 27)
+#       define MRDCKC0_BYPASS                           (1 << 28)
+#       define MRDCKC1_BYPASS                           (1 << 29)
+#       define MRDCKD0_BYPASS                           (1 << 30)
+#       define MRDCKD1_BYPASS                           (1 << 31)
+
+#define MPLL_TIME                                         0x654
+#       define MPLL_LOCK_TIME(x)			((x) << 0)
+#       define MPLL_LOCK_TIME_MASK			(0xffff << 0)
+#       define MPLL_RESET_TIME(x)			((x) << 16)
+#       define MPLL_RESET_TIME_MASK			(0xffff << 16)
+
+#define CG_CLKPIN_CNTL                                    0x660
+#       define MUX_TCLK_TO_XCLK                           (1 << 8)
+#       define XTALIN_DIVIDE                              (1 << 9)
+
+#define S0_VID_LOWER_SMIO_CNTL                            0x678
+#define S1_VID_LOWER_SMIO_CNTL                            0x67c
+#define S2_VID_LOWER_SMIO_CNTL                            0x680
+#define S3_VID_LOWER_SMIO_CNTL                            0x684
+
+#define CG_FTV                                            0x690
+#define CG_FFCT_0                                         0x694
+#       define UTC_0(x)                                   ((x) << 0)
+#       define UTC_0_MASK                                 (0x3ff << 0)
+#       define DTC_0(x)                                   ((x) << 10)
+#       define DTC_0_MASK                                 (0x3ff << 10)
+
+#define CG_BSP                                          0x6d0
+#       define BSP(x)					((x) << 0)
+#       define BSP_MASK					(0xffff << 0)
+#       define BSU(x)					((x) << 16)
+#       define BSU_MASK					(0xf << 16)
+#define CG_AT                                           0x6d4
+#       define CG_R(x)					((x) << 0)
+#       define CG_R_MASK				(0xffff << 0)
+#       define CG_L(x)					((x) << 16)
+#       define CG_L_MASK				(0xffff << 16)
+#define CG_GIT                                          0x6d8
+#       define CG_GICST(x)                              ((x) << 0)
+#       define CG_GICST_MASK                            (0xffff << 0)
+#       define CG_GIPOT(x)                              ((x) << 16)
+#       define CG_GIPOT_MASK                            (0xffff << 16)
+
+#define CG_SSP                                            0x6e8
+#       define SST(x)                                     ((x) << 0)
+#       define SST_MASK                                   (0xffff << 0)
+#       define SSTU(x)                                    ((x) << 16)
+#       define SSTU_MASK                                  (0xf << 16)
+
+#define CG_DISPLAY_GAP_CNTL                               0x714
+#       define DISP1_GAP(x)                               ((x) << 0)
+#       define DISP1_GAP_MASK                             (3 << 0)
+#       define DISP2_GAP(x)                               ((x) << 2)
+#       define DISP2_GAP_MASK                             (3 << 2)
+#       define VBI_TIMER_COUNT(x)                         ((x) << 4)
+#       define VBI_TIMER_COUNT_MASK                       (0x3fff << 4)
+#       define VBI_TIMER_UNIT(x)                          ((x) << 20)
+#       define VBI_TIMER_UNIT_MASK                        (7 << 20)
+#       define DISP1_GAP_MCHG(x)                          ((x) << 24)
+#       define DISP1_GAP_MCHG_MASK                        (3 << 24)
+#       define DISP2_GAP_MCHG(x)                          ((x) << 26)
+#       define DISP2_GAP_MCHG_MASK                        (3 << 26)
+
+#define	CG_SPLL_SPREAD_SPECTRUM				0x790
+#define		SSEN					(1 << 0)
+#define		CLKS(x)					((x) << 4)
+#define		CLKS_MASK				(0xfff << 4)
+#define	CG_SPLL_SPREAD_SPECTRUM_2			0x794
+#define		CLKV(x)					((x) << 0)
+#define		CLKV_MASK				(0x3ffffff << 0)
+#define	CG_MPLL_SPREAD_SPECTRUM				0x798
+#define CG_UPLL_SPREAD_SPECTRUM				0x79c
+#	define SSEN_MASK				0x00000001
+
+#define CG_CGTT_LOCAL_0                                   0x7d0
+#define CG_CGTT_LOCAL_1                                   0x7d4
+
+#define BIOS_SCRATCH_4                                    0x1734
+
+#define MC_SEQ_MISC0                                      0x2a00
+#define         MC_SEQ_MISC0_GDDR5_SHIFT                  28
+#define         MC_SEQ_MISC0_GDDR5_MASK                   0xf0000000
+#define         MC_SEQ_MISC0_GDDR5_VALUE                  5
+
+#define MC_ARB_SQM_RATIO                                  0x2770
+#define		STATE0(x)				((x) << 0)
+#define		STATE0_MASK				(0xff << 0)
+#define		STATE1(x)				((x) << 8)
+#define		STATE1_MASK				(0xff << 8)
+#define		STATE2(x)				((x) << 16)
+#define		STATE2_MASK				(0xff << 16)
+#define		STATE3(x)				((x) << 24)
+#define		STATE3_MASK				(0xff << 24)
+
+#define	MC_ARB_RFSH_RATE				0x27b0
+#define		POWERMODE0(x)				((x) << 0)
+#define		POWERMODE0_MASK				(0xff << 0)
+#define		POWERMODE1(x)				((x) << 8)
+#define		POWERMODE1_MASK				(0xff << 8)
+#define		POWERMODE2(x)				((x) << 16)
+#define		POWERMODE2_MASK				(0xff << 16)
+#define		POWERMODE3(x)				((x) << 24)
+#define		POWERMODE3_MASK				(0xff << 24)
+
+#define CGTS_SM_CTRL_REG                                  0x9150
+
 /* Registers */
 #define	CB_COLOR0_BASE					0x28040
 #define	CB_COLOR1_BASE					0x28044
@@ -86,8 +322,8 @@
 #define	CONFIG_MEMSIZE					0x5428
 
 #define	CP_ME_CNTL					0x86D8
-#define		CP_ME_HALT					(1<<28)
-#define		CP_PFP_HALT					(1<<26)
+#define		CP_ME_HALT					(1 << 28)
+#define		CP_PFP_HALT					(1 << 26)
 #define	CP_ME_RAM_DATA					0xC160
 #define	CP_ME_RAM_RADDR					0xC158
 #define	CP_ME_RAM_WADDR					0xC15C
@@ -157,9 +393,22 @@
 #define		GUI_ACTIVE					(1<<31)
 #define	GRBM_STATUS2					0x8014
 
-#define CG_CLKPIN_CNTL                                    0x660
-#       define MUX_TCLK_TO_XCLK                           (1 << 8)
-#       define XTALIN_DIVIDE                              (1 << 9)
+#define	CG_THERMAL_CTRL					0x72C
+#define 	DPM_EVENT_SRC(x)			((x) << 0)
+#define 	DPM_EVENT_SRC_MASK			(7 << 0)
+#define		DIG_THERM_DPM(x)			((x) << 14)
+#define		DIG_THERM_DPM_MASK			0x003FC000
+#define		DIG_THERM_DPM_SHIFT			14
+
+#define	CG_THERMAL_INT					0x734
+#define		DIG_THERM_INTH(x)			((x) << 8)
+#define		DIG_THERM_INTH_MASK			0x0000FF00
+#define		DIG_THERM_INTH_SHIFT			8
+#define		DIG_THERM_INTL(x)			((x) << 16)
+#define		DIG_THERM_INTL_MASK			0x00FF0000
+#define		DIG_THERM_INTL_SHIFT			16
+#define 	THERM_INT_MASK_HIGH			(1 << 24)
+#define 	THERM_INT_MASK_LOW			(1 << 25)
 
 #define	CG_MULT_THERMAL_STATUS				0x740
 #define		ASIC_T(x)			        ((x) << 16)
@@ -662,7 +911,22 @@
 #define D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH             0x691c
 #define D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH             0x611c
 
-/* PCIE link stuff */
+/* PCIE indirect regs */
+#define PCIE_P_CNTL                                       0x40
+#       define P_PLL_PWRDN_IN_L1L23                       (1 << 3)
+#       define P_PLL_BUF_PDNB                             (1 << 4)
+#       define P_PLL_PDNB                                 (1 << 9)
+#       define P_ALLOW_PRX_FRONTEND_SHUTOFF               (1 << 12)
+/* PCIE PORT regs */
+#define PCIE_LC_CNTL                                      0xa0
+#       define LC_L0S_INACTIVITY(x)                       ((x) << 8)
+#       define LC_L0S_INACTIVITY_MASK                     (0xf << 8)
+#       define LC_L0S_INACTIVITY_SHIFT                    8
+#       define LC_L1_INACTIVITY(x)                        ((x) << 12)
+#       define LC_L1_INACTIVITY_MASK                      (0xf << 12)
+#       define LC_L1_INACTIVITY_SHIFT                     12
+#       define LC_PMI_TO_L1_DIS                           (1 << 16)
+#       define LC_ASPM_TO_L1_DIS                          (1 << 24)
 #define PCIE_LC_TRAINING_CNTL                             0xa1 /* PCIE_P */
 #define PCIE_LC_LINK_WIDTH_CNTL                           0xa2 /* PCIE_P */
 #       define LC_LINK_WIDTH_SHIFT                        0
@@ -690,6 +954,9 @@
 #       define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_MASK      (0x3 << 8)
 #       define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_SHIFT     3
 #       define LC_CURRENT_DATA_RATE                       (1 << 11)
+#       define LC_HW_VOLTAGE_IF_CONTROL(x)                ((x) << 12)
+#       define LC_HW_VOLTAGE_IF_CONTROL_MASK              (3 << 12)
+#       define LC_HW_VOLTAGE_IF_CONTROL_SHIFT             12
 #       define LC_VOLTAGE_TIMER_SEL_MASK                  (0xf << 14)
 #       define LC_CLR_FAILED_SPD_CHANGE_CNT               (1 << 21)
 #       define LC_OTHER_SIDE_EVER_SENT_GEN2               (1 << 23)
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 078/165] drm/radeon/kms: add dpm support for evergreen (v2)
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (77 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 077/165] drm/radeon/kms: add dpm support for rv7xx (v2) alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 079/165] drm/radeon/kms: add dpm support for btc (v2) alexdeucher
                   ` (34 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

This adds dpm support for evergreen asics.  This includes:
- clockgating
- dynamic engine clock scaling
- dynamic memory clock scaling
- dynamic voltage scaling
- dynamic pcie gen1/gen2 switching (requires additional acpi support)

Set radeon.dpm=1 to enable.

v2: reduce stack usage, rename ulv struct

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/Makefile        |    2 +-
 drivers/gpu/drm/radeon/cypress_dpm.c   | 2103 ++++++++++++++++++++++++++++++++
 drivers/gpu/drm/radeon/cypress_dpm.h   |  134 ++
 drivers/gpu/drm/radeon/evergreen.c     |   22 +
 drivers/gpu/drm/radeon/evergreen_smc.h |   67 +
 drivers/gpu/drm/radeon/evergreend.h    |  305 +++++
 drivers/gpu/drm/radeon/r600.c          |   14 +-
 drivers/gpu/drm/radeon/radeon.h        |   13 +
 drivers/gpu/drm/radeon/radeon_acpi.c   |   23 +
 drivers/gpu/drm/radeon/radeon_asic.c   |   12 +
 drivers/gpu/drm/radeon/radeon_asic.h   |    7 +
 drivers/gpu/drm/radeon/radeon_pm.c     |    5 +
 drivers/gpu/drm/radeon/radeon_ucode.h  |   20 +
 drivers/gpu/drm/radeon/rv770_dpm.c     |   45 +-
 drivers/gpu/drm/radeon/rv770_dpm.h     |    4 +
 drivers/gpu/drm/radeon/rv770_smc.c     |  109 ++
 16 files changed, 2875 insertions(+), 10 deletions(-)
 create mode 100644 drivers/gpu/drm/radeon/cypress_dpm.c
 create mode 100644 drivers/gpu/drm/radeon/cypress_dpm.h
 create mode 100644 drivers/gpu/drm/radeon/evergreen_smc.h

diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile
index c97753d..7092c96 100644
--- a/drivers/gpu/drm/radeon/Makefile
+++ b/drivers/gpu/drm/radeon/Makefile
@@ -78,7 +78,7 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \
 	atombios_encoders.o radeon_semaphore.o radeon_sa.o atombios_i2c.o si.o \
 	si_blit_shaders.o radeon_prime.o radeon_uvd.o cik.o cik_blit_shaders.o \
 	r600_dpm.o rs780_dpm.o rv6xx_dpm.o rv770_dpm.o rv730_dpm.o rv740_dpm.o \
-	rv770_smc.o
+	rv770_smc.o cypress_dpm.o
 
 radeon-$(CONFIG_COMPAT) += radeon_ioc32.o
 radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o
diff --git a/drivers/gpu/drm/radeon/cypress_dpm.c b/drivers/gpu/drm/radeon/cypress_dpm.c
new file mode 100644
index 0000000..2345c81
--- /dev/null
+++ b/drivers/gpu/drm/radeon/cypress_dpm.c
@@ -0,0 +1,2103 @@
+/*
+ * Copyright 2011 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Alex Deucher
+ */
+
+#include "drmP.h"
+#include "radeon.h"
+#include "evergreend.h"
+#include "r600_dpm.h"
+#include "cypress_dpm.h"
+#include "atom.h"
+
+#define SMC_RAM_END 0x8000
+
+#define MC_CG_ARB_FREQ_F0           0x0a
+#define MC_CG_ARB_FREQ_F1           0x0b
+#define MC_CG_ARB_FREQ_F2           0x0c
+#define MC_CG_ARB_FREQ_F3           0x0d
+
+#define MC_CG_SEQ_DRAMCONF_S0       0x05
+#define MC_CG_SEQ_DRAMCONF_S1       0x06
+#define MC_CG_SEQ_YCLK_SUSPEND      0x04
+#define MC_CG_SEQ_YCLK_RESUME       0x0a
+
+struct rv7xx_ps *rv770_get_ps(struct radeon_ps *rps);
+struct rv7xx_power_info *rv770_get_pi(struct radeon_device *rdev);
+struct evergreen_power_info *evergreen_get_pi(struct radeon_device *rdev);
+
+static u8 cypress_get_mclk_frequency_ratio(struct radeon_device *rdev,
+					   u32 memory_clock, bool strobe_mode);
+
+static void cypress_enable_bif_dynamic_pcie_gen2(struct radeon_device *rdev,
+						 bool enable)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	u32 tmp, bif;
+
+	tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL);
+	if (enable) {
+		if ((tmp & LC_OTHER_SIDE_EVER_SENT_GEN2) &&
+		    (tmp & LC_OTHER_SIDE_SUPPORTS_GEN2)) {
+			if (!pi->boot_in_gen2) {
+				bif = RREG32(CG_BIF_REQ_AND_RSP) & ~CG_CLIENT_REQ_MASK;
+				bif |= CG_CLIENT_REQ(0xd);
+				WREG32(CG_BIF_REQ_AND_RSP, bif);
+
+				tmp &= ~LC_HW_VOLTAGE_IF_CONTROL_MASK;
+				tmp |= LC_HW_VOLTAGE_IF_CONTROL(1);
+				tmp |= LC_GEN2_EN_STRAP;
+
+				tmp |= LC_CLR_FAILED_SPD_CHANGE_CNT;
+				WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp);
+				udelay(10);
+				tmp &= ~LC_CLR_FAILED_SPD_CHANGE_CNT;
+				WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp);
+			}
+		}
+	} else {
+		if (!pi->boot_in_gen2) {
+			tmp &= ~LC_HW_VOLTAGE_IF_CONTROL_MASK;
+			tmp &= ~LC_GEN2_EN_STRAP;
+		}
+		if ((tmp & LC_OTHER_SIDE_EVER_SENT_GEN2) ||
+		    (tmp & LC_OTHER_SIDE_SUPPORTS_GEN2))
+			WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp);
+	}
+}
+
+static void cypress_enable_dynamic_pcie_gen2(struct radeon_device *rdev,
+					     bool enable)
+{
+	cypress_enable_bif_dynamic_pcie_gen2(rdev, enable);
+
+	if (enable)
+		WREG32_P(GENERAL_PWRMGT, ENABLE_GEN2PCIE, ~ENABLE_GEN2PCIE);
+	else
+		WREG32_P(GENERAL_PWRMGT, 0, ~ENABLE_GEN2PCIE);
+}
+
+#if 0
+static int cypress_enter_ulp_state(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+	if (pi->gfx_clock_gating) {
+		WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_GFX_CLK_OFF_EN);
+		WREG32_P(SCLK_PWRMGT_CNTL, GFX_CLK_FORCE_ON, ~GFX_CLK_FORCE_ON);
+		WREG32_P(SCLK_PWRMGT_CNTL, 0, ~GFX_CLK_FORCE_ON);
+
+		RREG32(GB_ADDR_CONFIG);
+	}
+
+	WREG32_P(SMC_MSG, HOST_SMC_MSG(PPSMC_MSG_SwitchToMinimumPower),
+		 ~HOST_SMC_MSG_MASK);
+
+	udelay(7000);
+
+	return 0;
+}
+#endif
+
+static void cypress_gfx_clock_gating_enable(struct radeon_device *rdev,
+					    bool enable)
+{
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+
+	if (enable) {
+		if (eg_pi->light_sleep) {
+			WREG32(GRBM_GFX_INDEX, 0xC0000000);
+
+			WREG32_CG(CG_CGLS_TILE_0, 0xFFFFFFFF);
+			WREG32_CG(CG_CGLS_TILE_1, 0xFFFFFFFF);
+			WREG32_CG(CG_CGLS_TILE_2, 0xFFFFFFFF);
+			WREG32_CG(CG_CGLS_TILE_3, 0xFFFFFFFF);
+			WREG32_CG(CG_CGLS_TILE_4, 0xFFFFFFFF);
+			WREG32_CG(CG_CGLS_TILE_5, 0xFFFFFFFF);
+			WREG32_CG(CG_CGLS_TILE_6, 0xFFFFFFFF);
+			WREG32_CG(CG_CGLS_TILE_7, 0xFFFFFFFF);
+			WREG32_CG(CG_CGLS_TILE_8, 0xFFFFFFFF);
+			WREG32_CG(CG_CGLS_TILE_9, 0xFFFFFFFF);
+			WREG32_CG(CG_CGLS_TILE_10, 0xFFFFFFFF);
+			WREG32_CG(CG_CGLS_TILE_11, 0xFFFFFFFF);
+
+			WREG32_P(SCLK_PWRMGT_CNTL, DYN_LIGHT_SLEEP_EN, ~DYN_LIGHT_SLEEP_EN);
+		}
+		WREG32_P(SCLK_PWRMGT_CNTL, DYN_GFX_CLK_OFF_EN, ~DYN_GFX_CLK_OFF_EN);
+	} else {
+		WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_GFX_CLK_OFF_EN);
+		WREG32_P(SCLK_PWRMGT_CNTL, GFX_CLK_FORCE_ON, ~GFX_CLK_FORCE_ON);
+		WREG32_P(SCLK_PWRMGT_CNTL, 0, ~GFX_CLK_FORCE_ON);
+		RREG32(GB_ADDR_CONFIG);
+
+		if (eg_pi->light_sleep) {
+			WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_LIGHT_SLEEP_EN);
+
+			WREG32(GRBM_GFX_INDEX, 0xC0000000);
+
+			WREG32_CG(CG_CGLS_TILE_0, 0);
+			WREG32_CG(CG_CGLS_TILE_1, 0);
+			WREG32_CG(CG_CGLS_TILE_2, 0);
+			WREG32_CG(CG_CGLS_TILE_3, 0);
+			WREG32_CG(CG_CGLS_TILE_4, 0);
+			WREG32_CG(CG_CGLS_TILE_5, 0);
+			WREG32_CG(CG_CGLS_TILE_6, 0);
+			WREG32_CG(CG_CGLS_TILE_7, 0);
+			WREG32_CG(CG_CGLS_TILE_8, 0);
+			WREG32_CG(CG_CGLS_TILE_9, 0);
+			WREG32_CG(CG_CGLS_TILE_10, 0);
+			WREG32_CG(CG_CGLS_TILE_11, 0);
+		}
+	}
+}
+
+static void cypress_mg_clock_gating_enable(struct radeon_device *rdev,
+					   bool enable)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+
+	if (enable) {
+		u32 cgts_sm_ctrl_reg;
+
+		if (rdev->family == CHIP_CEDAR)
+			cgts_sm_ctrl_reg = CEDAR_MGCGCGTSSMCTRL_DFLT;
+		else if (rdev->family == CHIP_REDWOOD)
+			cgts_sm_ctrl_reg = REDWOOD_MGCGCGTSSMCTRL_DFLT;
+		else
+			cgts_sm_ctrl_reg = CYPRESS_MGCGCGTSSMCTRL_DFLT;
+
+		WREG32(GRBM_GFX_INDEX, 0xC0000000);
+
+		WREG32_CG(CG_CGTT_LOCAL_0, CYPRESS_MGCGTTLOCAL0_DFLT);
+		WREG32_CG(CG_CGTT_LOCAL_1, CYPRESS_MGCGTTLOCAL1_DFLT & 0xFFFFCFFF);
+		WREG32_CG(CG_CGTT_LOCAL_2, CYPRESS_MGCGTTLOCAL2_DFLT);
+		WREG32_CG(CG_CGTT_LOCAL_3, CYPRESS_MGCGTTLOCAL3_DFLT);
+
+		if (pi->mgcgtssm)
+			WREG32(CGTS_SM_CTRL_REG, cgts_sm_ctrl_reg);
+
+		if (eg_pi->mcls) {
+			WREG32_P(MC_CITF_MISC_RD_CG, MEM_LS_ENABLE, ~MEM_LS_ENABLE);
+			WREG32_P(MC_CITF_MISC_WR_CG, MEM_LS_ENABLE, ~MEM_LS_ENABLE);
+			WREG32_P(MC_CITF_MISC_VM_CG, MEM_LS_ENABLE, ~MEM_LS_ENABLE);
+			WREG32_P(MC_HUB_MISC_HUB_CG, MEM_LS_ENABLE, ~MEM_LS_ENABLE);
+			WREG32_P(MC_HUB_MISC_VM_CG, MEM_LS_ENABLE, ~MEM_LS_ENABLE);
+			WREG32_P(MC_HUB_MISC_SIP_CG, MEM_LS_ENABLE, ~MEM_LS_ENABLE);
+			WREG32_P(MC_XPB_CLK_GAT, MEM_LS_ENABLE, ~MEM_LS_ENABLE);
+			WREG32_P(VM_L2_CG, MEM_LS_ENABLE, ~MEM_LS_ENABLE);
+		}
+	} else {
+		WREG32(GRBM_GFX_INDEX, 0xC0000000);
+
+		WREG32_CG(CG_CGTT_LOCAL_0, 0xFFFFFFFF);
+		WREG32_CG(CG_CGTT_LOCAL_1, 0xFFFFFFFF);
+		WREG32_CG(CG_CGTT_LOCAL_2, 0xFFFFFFFF);
+		WREG32_CG(CG_CGTT_LOCAL_3, 0xFFFFFFFF);
+
+		if (pi->mgcgtssm)
+			WREG32(CGTS_SM_CTRL_REG, 0x81f44bc0);
+	}
+}
+
+void cypress_enable_spread_spectrum(struct radeon_device *rdev,
+				    bool enable)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+	if (enable) {
+		if (pi->sclk_ss)
+			WREG32_P(GENERAL_PWRMGT, DYN_SPREAD_SPECTRUM_EN, ~DYN_SPREAD_SPECTRUM_EN);
+
+		if (pi->mclk_ss)
+			WREG32_P(MPLL_CNTL_MODE, SS_SSEN, ~SS_SSEN);
+	} else {
+		WREG32_P(CG_SPLL_SPREAD_SPECTRUM, 0, ~SSEN);
+		WREG32_P(GENERAL_PWRMGT, 0, ~DYN_SPREAD_SPECTRUM_EN);
+		WREG32_P(MPLL_CNTL_MODE, 0, ~SS_SSEN);
+		WREG32_P(MPLL_CNTL_MODE, 0, ~SS_DSMODE_EN);
+	}
+}
+
+void cypress_start_dpm(struct radeon_device *rdev)
+{
+	WREG32_P(GENERAL_PWRMGT, GLOBAL_PWRMGT_EN, ~GLOBAL_PWRMGT_EN);
+}
+
+void cypress_enable_sclk_control(struct radeon_device *rdev,
+				 bool enable)
+{
+	if (enable)
+		WREG32_P(SCLK_PWRMGT_CNTL, 0, ~SCLK_PWRMGT_OFF);
+	else
+		WREG32_P(SCLK_PWRMGT_CNTL, SCLK_PWRMGT_OFF, ~SCLK_PWRMGT_OFF);
+}
+
+void cypress_enable_mclk_control(struct radeon_device *rdev,
+				 bool enable)
+{
+	if (enable)
+		WREG32_P(MCLK_PWRMGT_CNTL, 0, ~MPLL_PWRMGT_OFF);
+	else
+		WREG32_P(MCLK_PWRMGT_CNTL, MPLL_PWRMGT_OFF, ~MPLL_PWRMGT_OFF);
+}
+
+int cypress_notify_smc_display_change(struct radeon_device *rdev,
+				      bool has_display)
+{
+	PPSMC_Msg msg = has_display ?
+		(PPSMC_Msg)PPSMC_MSG_HasDisplay : (PPSMC_Msg)PPSMC_MSG_NoDisplay;
+
+	if (rv770_send_msg_to_smc(rdev, msg) != PPSMC_Result_OK)
+		return -EINVAL;
+
+	return 0;
+}
+
+void cypress_program_response_times(struct radeon_device *rdev)
+{
+	u32 reference_clock;
+	u32 mclk_switch_limit;
+
+	reference_clock = radeon_get_xclk(rdev);
+	mclk_switch_limit = (460 * reference_clock) / 100;
+
+	rv770_write_smc_soft_register(rdev,
+				      RV770_SMC_SOFT_REGISTER_mclk_switch_lim,
+				      mclk_switch_limit);
+
+	rv770_write_smc_soft_register(rdev,
+				      RV770_SMC_SOFT_REGISTER_mvdd_chg_time, 1);
+
+	rv770_write_smc_soft_register(rdev,
+				      RV770_SMC_SOFT_REGISTER_mc_block_delay, 0xAA);
+
+	rv770_program_response_times(rdev);
+
+	if (ASIC_IS_LOMBOK(rdev))
+		rv770_write_smc_soft_register(rdev,
+					      RV770_SMC_SOFT_REGISTER_is_asic_lombok, 1);
+
+}
+
+static int cypress_pcie_performance_request(struct radeon_device *rdev,
+					    u8 perf_req, bool advertise)
+{
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	u32 tmp;
+
+	udelay(10);
+	tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL);
+	if ((perf_req == PCIE_PERF_REQ_PECI_GEN1) && (tmp & LC_CURRENT_DATA_RATE))
+		return 0;
+
+#if defined(CONFIG_ACPI)
+	if ((perf_req == PCIE_PERF_REQ_PECI_GEN1) ||
+	    (perf_req == PCIE_PERF_REQ_PECI_GEN2)) {
+		eg_pi->pcie_performance_request_registered = true;
+		return radeon_acpi_pcie_performance_request(rdev, perf_req, advertise);
+	} else if ((perf_req == PCIE_PERF_REQ_REMOVE_REGISTRY) &&
+		   eg_pi->pcie_performance_request_registered) {
+		eg_pi->pcie_performance_request_registered = false;
+		return radeon_acpi_pcie_performance_request(rdev, perf_req, advertise);
+	}
+#endif
+
+	return 0;
+}
+
+void cypress_advertise_gen2_capability(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	u32 tmp;
+
+#if defined(CONFIG_ACPI)
+	radeon_acpi_pcie_notify_device_ready(rdev);
+#endif
+
+	tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL);
+
+	if ((tmp & LC_OTHER_SIDE_EVER_SENT_GEN2) &&
+	    (tmp & LC_OTHER_SIDE_SUPPORTS_GEN2))
+		pi->pcie_gen2 = true;
+	else
+		pi->pcie_gen2 = false;
+
+	if (!pi->pcie_gen2)
+		cypress_pcie_performance_request(rdev, PCIE_PERF_REQ_PECI_GEN2, true);
+
+}
+
+static u32 cypress_get_maximum_link_speed(struct radeon_ps *radeon_state)
+{
+	struct rv7xx_ps *state = rv770_get_ps(radeon_state);
+
+	if (state->high.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2)
+		return 1;
+	return 0;
+}
+
+void cypress_notify_link_speed_change_after_state_change(struct radeon_device *rdev)
+{
+	struct radeon_ps *radeon_new_state = rdev->pm.dpm.requested_ps;
+	struct radeon_ps *radeon_current_state = rdev->pm.dpm.current_ps;
+	u32 pcie_link_speed_target =  cypress_get_maximum_link_speed(radeon_new_state);
+	u32 pcie_link_speed_current = cypress_get_maximum_link_speed(radeon_current_state);
+	u8 request;
+
+	if (pcie_link_speed_target < pcie_link_speed_current) {
+		if (pcie_link_speed_target == 0)
+			request = PCIE_PERF_REQ_PECI_GEN1;
+		else if (pcie_link_speed_target == 1)
+			request = PCIE_PERF_REQ_PECI_GEN2;
+		else
+			request = PCIE_PERF_REQ_PECI_GEN3;
+
+		cypress_pcie_performance_request(rdev, request, false);
+	}
+}
+
+void cypress_notify_link_speed_change_before_state_change(struct radeon_device *rdev)
+{
+	struct radeon_ps *radeon_new_state = rdev->pm.dpm.requested_ps;
+	struct radeon_ps *radeon_current_state = rdev->pm.dpm.current_ps;
+	u32 pcie_link_speed_target =  cypress_get_maximum_link_speed(radeon_new_state);
+	u32 pcie_link_speed_current = cypress_get_maximum_link_speed(radeon_current_state);
+	u8 request;
+
+	if (pcie_link_speed_target > pcie_link_speed_current) {
+		if (pcie_link_speed_target == 0)
+			request = PCIE_PERF_REQ_PECI_GEN1;
+		else if (pcie_link_speed_target == 1)
+			request = PCIE_PERF_REQ_PECI_GEN2;
+		else
+			request = PCIE_PERF_REQ_PECI_GEN3;
+
+		cypress_pcie_performance_request(rdev, request, false);
+	}
+}
+
+static int cypress_populate_voltage_value(struct radeon_device *rdev,
+					  struct atom_voltage_table *table,
+					  u16 value, RV770_SMC_VOLTAGE_VALUE *voltage)
+{
+	unsigned int i;
+
+	for (i = 0; i < table->count; i++) {
+		if (value <= table->entries[i].value) {
+			voltage->index = (u8)i;
+			voltage->value = cpu_to_be16(table->entries[i].value);
+			break;
+		}
+	}
+
+	if (i == table->count)
+		return -EINVAL;
+
+	return 0;
+}
+
+static u8 cypress_get_strobe_mode_settings(struct radeon_device *rdev, u32 mclk)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	u8 result = 0;
+	bool strobe_mode = false;
+
+	if (pi->mem_gddr5) {
+		if (mclk <= pi->mclk_strobe_mode_threshold)
+			strobe_mode = true;
+		result = cypress_get_mclk_frequency_ratio(rdev, mclk, strobe_mode);
+
+		if (strobe_mode)
+			result |= SMC_STROBE_ENABLE;
+	}
+
+	return result;
+}
+
+static u32 cypress_map_clkf_to_ibias(struct radeon_device *rdev, u32 clkf)
+{
+	u32 ref_clk = rdev->clock.mpll.reference_freq;
+	u32 vco = clkf * ref_clk;
+
+	/* 100 Mhz ref clk */
+	if (ref_clk == 10000) {
+		if (vco > 500000)
+			return 0xC6;
+		if (vco > 400000)
+			return 0x9D;
+		if (vco > 330000)
+			return 0x6C;
+		if (vco > 250000)
+			return 0x2B;
+		if (vco >  160000)
+			return 0x5B;
+		if (vco > 120000)
+			return 0x0A;
+		return 0x4B;
+	}
+
+	/* 27 Mhz ref clk */
+	if (vco > 250000)
+		return 0x8B;
+	if (vco > 200000)
+		return 0xCC;
+	if (vco > 150000)
+		return 0x9B;
+	return 0x6B;
+}
+
+static int cypress_populate_mclk_value(struct radeon_device *rdev,
+				       u32 engine_clock, u32 memory_clock,
+				       RV7XX_SMC_MCLK_VALUE *mclk,
+				       bool strobe_mode, bool dll_state_on)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+	u32 mpll_ad_func_cntl =
+		pi->clk_regs.rv770.mpll_ad_func_cntl;
+	u32 mpll_ad_func_cntl_2 =
+		pi->clk_regs.rv770.mpll_ad_func_cntl_2;
+	u32 mpll_dq_func_cntl =
+		pi->clk_regs.rv770.mpll_dq_func_cntl;
+	u32 mpll_dq_func_cntl_2 =
+		pi->clk_regs.rv770.mpll_dq_func_cntl_2;
+	u32 mclk_pwrmgt_cntl =
+		pi->clk_regs.rv770.mclk_pwrmgt_cntl;
+	u32 dll_cntl =
+		pi->clk_regs.rv770.dll_cntl;
+	u32 mpll_ss1 = pi->clk_regs.rv770.mpll_ss1;
+	u32 mpll_ss2 = pi->clk_regs.rv770.mpll_ss2;
+	struct atom_clock_dividers dividers;
+	u32 ibias;
+	u32 dll_speed;
+	int ret;
+	u32 mc_seq_misc7;
+
+	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_MEMORY_PLL_PARAM,
+					     memory_clock, strobe_mode, &dividers);
+	if (ret)
+		return ret;
+
+	if (!strobe_mode) {
+		mc_seq_misc7 = RREG32(MC_SEQ_MISC7);
+
+		if(mc_seq_misc7 & 0x8000000)
+			dividers.post_div = 1;
+	}
+
+	ibias = cypress_map_clkf_to_ibias(rdev, dividers.whole_fb_div);
+
+	mpll_ad_func_cntl &= ~(CLKR_MASK |
+			       YCLK_POST_DIV_MASK |
+			       CLKF_MASK |
+			       CLKFRAC_MASK |
+			       IBIAS_MASK);
+	mpll_ad_func_cntl |= CLKR(dividers.ref_div);
+	mpll_ad_func_cntl |= YCLK_POST_DIV(dividers.post_div);
+	mpll_ad_func_cntl |= CLKF(dividers.whole_fb_div);
+	mpll_ad_func_cntl |= CLKFRAC(dividers.frac_fb_div);
+	mpll_ad_func_cntl |= IBIAS(ibias);
+
+	if (dividers.vco_mode)
+		mpll_ad_func_cntl_2 |= VCO_MODE;
+	else
+		mpll_ad_func_cntl_2 &= ~VCO_MODE;
+
+	if (pi->mem_gddr5) {
+		mpll_dq_func_cntl &= ~(CLKR_MASK |
+				       YCLK_POST_DIV_MASK |
+				       CLKF_MASK |
+				       CLKFRAC_MASK |
+				       IBIAS_MASK);
+		mpll_dq_func_cntl |= CLKR(dividers.ref_div);
+		mpll_dq_func_cntl |= YCLK_POST_DIV(dividers.post_div);
+		mpll_dq_func_cntl |= CLKF(dividers.whole_fb_div);
+		mpll_dq_func_cntl |= CLKFRAC(dividers.frac_fb_div);
+		mpll_dq_func_cntl |= IBIAS(ibias);
+
+		if (strobe_mode)
+			mpll_dq_func_cntl &= ~PDNB;
+		else
+			mpll_dq_func_cntl |= PDNB;
+
+		if (dividers.vco_mode)
+			mpll_dq_func_cntl_2 |= VCO_MODE;
+		else
+			mpll_dq_func_cntl_2 &= ~VCO_MODE;
+	}
+
+	if (pi->mclk_ss) {
+		struct radeon_atom_ss ss;
+		u32 vco_freq = memory_clock * dividers.post_div;
+
+		if (radeon_atombios_get_asic_ss_info(rdev, &ss,
+						     ASIC_INTERNAL_MEMORY_SS, vco_freq)) {
+			u32 reference_clock = rdev->clock.mpll.reference_freq;
+			u32 decoded_ref = rv740_get_decoded_reference_divider(dividers.ref_div);
+			u32 clk_s = reference_clock * 5 / (decoded_ref * ss.rate);
+			u32 clk_v = ss.percentage *
+				(0x4000 * dividers.whole_fb_div + 0x800 * dividers.frac_fb_div) / (clk_s * 625);
+
+			mpll_ss1 &= ~CLKV_MASK;
+			mpll_ss1 |= CLKV(clk_v);
+
+			mpll_ss2 &= ~CLKS_MASK;
+			mpll_ss2 |= CLKS(clk_s);
+		}
+	}
+
+	dll_speed = rv740_get_dll_speed(pi->mem_gddr5,
+					memory_clock);
+
+	mclk_pwrmgt_cntl &= ~DLL_SPEED_MASK;
+	mclk_pwrmgt_cntl |= DLL_SPEED(dll_speed);
+	if (dll_state_on)
+		mclk_pwrmgt_cntl |= (MRDCKA0_PDNB |
+				     MRDCKA1_PDNB |
+				     MRDCKB0_PDNB |
+				     MRDCKB1_PDNB |
+				     MRDCKC0_PDNB |
+				     MRDCKC1_PDNB |
+				     MRDCKD0_PDNB |
+				     MRDCKD1_PDNB);
+	else
+		mclk_pwrmgt_cntl &= ~(MRDCKA0_PDNB |
+				      MRDCKA1_PDNB |
+				      MRDCKB0_PDNB |
+				      MRDCKB1_PDNB |
+				      MRDCKC0_PDNB |
+				      MRDCKC1_PDNB |
+				      MRDCKD0_PDNB |
+				      MRDCKD1_PDNB);
+
+	mclk->mclk770.mclk_value = cpu_to_be32(memory_clock);
+	mclk->mclk770.vMPLL_AD_FUNC_CNTL = cpu_to_be32(mpll_ad_func_cntl);
+	mclk->mclk770.vMPLL_AD_FUNC_CNTL_2 = cpu_to_be32(mpll_ad_func_cntl_2);
+	mclk->mclk770.vMPLL_DQ_FUNC_CNTL = cpu_to_be32(mpll_dq_func_cntl);
+	mclk->mclk770.vMPLL_DQ_FUNC_CNTL_2 = cpu_to_be32(mpll_dq_func_cntl_2);
+	mclk->mclk770.vMCLK_PWRMGT_CNTL = cpu_to_be32(mclk_pwrmgt_cntl);
+	mclk->mclk770.vDLL_CNTL = cpu_to_be32(dll_cntl);
+	mclk->mclk770.vMPLL_SS = cpu_to_be32(mpll_ss1);
+	mclk->mclk770.vMPLL_SS2 = cpu_to_be32(mpll_ss2);
+
+	return 0;
+}
+
+static u8 cypress_get_mclk_frequency_ratio(struct radeon_device *rdev,
+					   u32 memory_clock, bool strobe_mode)
+{
+	u8 mc_para_index;
+
+	if (rdev->family >= CHIP_BARTS) {
+		if (strobe_mode) {
+			if (memory_clock < 10000)
+				mc_para_index = 0x00;
+			else if (memory_clock > 47500)
+				mc_para_index = 0x0f;
+			else
+				mc_para_index = (u8)((memory_clock - 10000) / 2500);
+		} else {
+			if (memory_clock < 65000)
+				mc_para_index = 0x00;
+			else if (memory_clock > 135000)
+				mc_para_index = 0x0f;
+			else
+				mc_para_index = (u8)((memory_clock - 60000) / 5000);
+		}
+	} else {
+		if (strobe_mode) {
+			if (memory_clock < 10000)
+				mc_para_index = 0x00;
+			else if (memory_clock > 47500)
+				mc_para_index = 0x0f;
+			else
+				mc_para_index = (u8)((memory_clock - 10000) / 2500);
+		} else {
+			if (memory_clock < 40000)
+				mc_para_index = 0x00;
+			else if (memory_clock > 115000)
+				mc_para_index = 0x0f;
+			else
+				mc_para_index = (u8)((memory_clock - 40000) / 5000);
+		}
+	}
+	return mc_para_index;
+}
+
+static int cypress_populate_mvdd_value(struct radeon_device *rdev,
+				       u32 mclk,
+				       RV770_SMC_VOLTAGE_VALUE *voltage)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+
+	if (!pi->mvdd_control) {
+		voltage->index = eg_pi->mvdd_high_index;
+		voltage->value = cpu_to_be16(MVDD_HIGH_VALUE);
+		return 0;
+	}
+
+	if (mclk <= pi->mvdd_split_frequency) {
+		voltage->index = eg_pi->mvdd_low_index;
+		voltage->value = cpu_to_be16(MVDD_LOW_VALUE);
+	} else {
+		voltage->index = eg_pi->mvdd_high_index;
+		voltage->value = cpu_to_be16(MVDD_HIGH_VALUE);
+	}
+
+	return 0;
+}
+
+int cypress_convert_power_level_to_smc(struct radeon_device *rdev,
+				       struct rv7xx_pl *pl,
+				       RV770_SMC_HW_PERFORMANCE_LEVEL *level,
+				       u8 watermark_level)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	int ret;
+	bool dll_state_on;
+
+	level->gen2PCIE = pi->pcie_gen2 ?
+		((pl->flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) ? 1 : 0) : 0;
+	level->gen2XSP  = (pl->flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) ? 1 : 0;
+	level->backbias = (pl->flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) ? 1 : 0;
+	level->displayWatermark = watermark_level;
+
+	ret = rv740_populate_sclk_value(rdev, pl->sclk, &level->sclk);
+	if (ret)
+		return ret;
+
+	level->mcFlags =  0;
+	if (pi->mclk_stutter_mode_threshold &&
+	    (pl->mclk <= pi->mclk_stutter_mode_threshold)) {
+		level->mcFlags |= SMC_MC_STUTTER_EN;
+		if (eg_pi->sclk_deep_sleep)
+			level->stateFlags |= PPSMC_STATEFLAG_AUTO_PULSE_SKIP;
+		else
+			level->stateFlags &= ~PPSMC_STATEFLAG_AUTO_PULSE_SKIP;
+	}
+
+	if (pi->mem_gddr5) {
+		if (pl->mclk > pi->mclk_edc_enable_threshold)
+			level->mcFlags |= SMC_MC_EDC_RD_FLAG;
+
+		if (pl->mclk > eg_pi->mclk_edc_wr_enable_threshold)
+			level->mcFlags |= SMC_MC_EDC_WR_FLAG;
+
+		level->strobeMode = cypress_get_strobe_mode_settings(rdev, pl->mclk);
+
+		if (level->strobeMode & SMC_STROBE_ENABLE) {
+			if (cypress_get_mclk_frequency_ratio(rdev, pl->mclk, true) >=
+			    ((RREG32(MC_SEQ_MISC7) >> 16) & 0xf))
+				dll_state_on = ((RREG32(MC_SEQ_MISC5) >> 1) & 0x1) ? true : false;
+			else
+				dll_state_on = ((RREG32(MC_SEQ_MISC6) >> 1) & 0x1) ? true : false;
+		} else
+			dll_state_on = eg_pi->dll_default_on;
+
+		ret = cypress_populate_mclk_value(rdev,
+						  pl->sclk,
+						  pl->mclk,
+						  &level->mclk,
+						  (level->strobeMode & SMC_STROBE_ENABLE) != 0,
+						  dll_state_on);
+	} else {
+		ret = cypress_populate_mclk_value(rdev,
+						  pl->sclk,
+						  pl->mclk,
+						  &level->mclk,
+						  true,
+						  true);
+	}
+	if (ret)
+		return ret;
+
+	ret = cypress_populate_voltage_value(rdev,
+					     &eg_pi->vddc_voltage_table,
+					     pl->vddc,
+					     &level->vddc);
+	if (ret)
+		return ret;
+
+	if (eg_pi->vddci_control) {
+		ret = cypress_populate_voltage_value(rdev,
+						     &eg_pi->vddci_voltage_table,
+						     pl->vddci,
+						     &level->vddci);
+		if (ret)
+			return ret;
+	}
+
+	ret = cypress_populate_mvdd_value(rdev, pl->mclk, &level->mvdd);
+
+	return ret;
+}
+
+static int cypress_convert_power_state_to_smc(struct radeon_device *rdev,
+					      struct radeon_ps *radeon_state,
+					      RV770_SMC_SWSTATE *smc_state)
+{
+	struct rv7xx_ps *state = rv770_get_ps(radeon_state);
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	int ret;
+
+	if (!(radeon_state->caps & ATOM_PPLIB_DISALLOW_ON_DC))
+		smc_state->flags |= PPSMC_SWSTATE_FLAG_DC;
+
+	ret = cypress_convert_power_level_to_smc(rdev,
+						 &state->low,
+						 &smc_state->levels[0],
+						 PPSMC_DISPLAY_WATERMARK_LOW);
+	if (ret)
+		return ret;
+
+	ret = cypress_convert_power_level_to_smc(rdev,
+						 &state->medium,
+						 &smc_state->levels[1],
+						 PPSMC_DISPLAY_WATERMARK_LOW);
+	if (ret)
+		return ret;
+
+	ret = cypress_convert_power_level_to_smc(rdev,
+						 &state->high,
+						 &smc_state->levels[2],
+						 PPSMC_DISPLAY_WATERMARK_HIGH);
+	if (ret)
+		return ret;
+
+	smc_state->levels[0].arbValue = MC_CG_ARB_FREQ_F1;
+	smc_state->levels[1].arbValue = MC_CG_ARB_FREQ_F2;
+	smc_state->levels[2].arbValue = MC_CG_ARB_FREQ_F3;
+
+	if (eg_pi->dynamic_ac_timing) {
+		smc_state->levels[0].ACIndex = 2;
+		smc_state->levels[1].ACIndex = 3;
+		smc_state->levels[2].ACIndex = 4;
+	} else {
+		smc_state->levels[0].ACIndex = 0;
+		smc_state->levels[1].ACIndex = 0;
+		smc_state->levels[2].ACIndex = 0;
+	}
+
+	rv770_populate_smc_sp(rdev, radeon_state, smc_state);
+
+	return rv770_populate_smc_t(rdev, radeon_state, smc_state);
+}
+
+static void cypress_convert_mc_registers(struct evergreen_mc_reg_entry *entry,
+					 SMC_Evergreen_MCRegisterSet *data,
+					 u32 num_entries, u32 valid_flag)
+{
+	u32 i, j;
+
+	for (i = 0, j = 0; j < num_entries; j++) {
+		if (valid_flag & (1 << j)) {
+			data->value[i] = cpu_to_be32(entry->mc_data[j]);
+			i++;
+		}
+	}
+}
+
+static void cypress_convert_mc_reg_table_entry_to_smc(struct radeon_device *rdev,
+						      struct rv7xx_pl *pl,
+						      SMC_Evergreen_MCRegisterSet *mc_reg_table_data)
+{
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	u32 i = 0;
+
+	for (i = 0; i < eg_pi->mc_reg_table.num_entries; i++) {
+		if (pl->mclk <=
+		    eg_pi->mc_reg_table.mc_reg_table_entry[i].mclk_max)
+			break;
+	}
+
+	if ((i == eg_pi->mc_reg_table.num_entries) && (i > 0))
+		--i;
+
+	cypress_convert_mc_registers(&eg_pi->mc_reg_table.mc_reg_table_entry[i],
+				     mc_reg_table_data,
+				     eg_pi->mc_reg_table.last,
+				     eg_pi->mc_reg_table.valid_flag);
+}
+
+static void cypress_convert_mc_reg_table_to_smc(struct radeon_device *rdev,
+						struct radeon_ps *radeon_state,
+						SMC_Evergreen_MCRegisters *mc_reg_table)
+{
+	struct rv7xx_ps *state = rv770_get_ps(radeon_state);
+
+	cypress_convert_mc_reg_table_entry_to_smc(rdev,
+						  &state->low,
+						  &mc_reg_table->data[2]);
+	cypress_convert_mc_reg_table_entry_to_smc(rdev,
+						  &state->medium,
+						  &mc_reg_table->data[3]);
+	cypress_convert_mc_reg_table_entry_to_smc(rdev,
+						  &state->high,
+						  &mc_reg_table->data[4]);
+}
+
+int cypress_upload_sw_state(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	struct radeon_ps *radeon_new_state = rdev->pm.dpm.requested_ps;
+	u16 address = pi->state_table_start +
+		offsetof(RV770_SMC_STATETABLE, driverState);
+	RV770_SMC_SWSTATE state = { 0 };
+	int ret;
+
+	ret = cypress_convert_power_state_to_smc(rdev, radeon_new_state, &state);
+	if (ret)
+		return ret;
+
+	return rv770_copy_bytes_to_smc(rdev, address, (u8 *)&state,
+				    sizeof(RV770_SMC_SWSTATE),
+				    pi->sram_end);
+}
+
+int cypress_upload_mc_reg_table(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	struct radeon_ps *radeon_new_state = rdev->pm.dpm.requested_ps;
+	SMC_Evergreen_MCRegisters mc_reg_table = { 0 };
+	u16 address;
+
+	cypress_convert_mc_reg_table_to_smc(rdev, radeon_new_state, &mc_reg_table);
+
+	address = eg_pi->mc_reg_table_start +
+		(u16)offsetof(SMC_Evergreen_MCRegisters, data[2]);
+
+	return rv770_copy_bytes_to_smc(rdev, address,
+				       (u8 *)&mc_reg_table.data[2],
+				       sizeof(SMC_Evergreen_MCRegisterSet) * 3,
+				       pi->sram_end);
+}
+
+u32 cypress_calculate_burst_time(struct radeon_device *rdev,
+				 u32 engine_clock, u32 memory_clock)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	u32 multiplier = pi->mem_gddr5 ? 1 : 2;
+	u32 result = (4 * multiplier * engine_clock) / (memory_clock / 2);
+	u32 burst_time;
+
+	if (result <= 4)
+		burst_time = 0;
+	else if (result < 8)
+		burst_time = result - 4;
+	else {
+		burst_time = result / 2 ;
+		if (burst_time > 18)
+			burst_time = 18;
+	}
+
+	return burst_time;
+}
+
+void cypress_program_memory_timing_parameters(struct radeon_device *rdev)
+{
+	struct radeon_ps *radeon_new_state = rdev->pm.dpm.requested_ps;
+	struct rv7xx_ps *new_state = rv770_get_ps(radeon_new_state);
+	u32 mc_arb_burst_time = RREG32(MC_ARB_BURST_TIME);
+
+	mc_arb_burst_time &= ~(STATE1_MASK | STATE2_MASK | STATE3_MASK);
+
+	mc_arb_burst_time |= STATE1(cypress_calculate_burst_time(rdev,
+								 new_state->low.sclk,
+								 new_state->low.mclk));
+	mc_arb_burst_time |= STATE2(cypress_calculate_burst_time(rdev,
+								 new_state->medium.sclk,
+								 new_state->medium.mclk));
+	mc_arb_burst_time |= STATE3(cypress_calculate_burst_time(rdev,
+								 new_state->high.sclk,
+								 new_state->high.mclk));
+
+	rv730_program_memory_timing_parameters(rdev, radeon_new_state);
+
+	WREG32(MC_ARB_BURST_TIME, mc_arb_burst_time);
+}
+
+static void cypress_populate_mc_reg_addresses(struct radeon_device *rdev,
+					      SMC_Evergreen_MCRegisters *mc_reg_table)
+{
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	u32 i, j;
+
+	for (i = 0, j = 0; j < eg_pi->mc_reg_table.last; j++) {
+		if (eg_pi->mc_reg_table.valid_flag & (1 << j)) {
+			mc_reg_table->address[i].s0 =
+				cpu_to_be16(eg_pi->mc_reg_table.mc_reg_address[j].s0);
+			mc_reg_table->address[i].s1 =
+				cpu_to_be16(eg_pi->mc_reg_table.mc_reg_address[j].s1);
+			i++;
+		}
+	}
+
+	mc_reg_table->last = (u8)i;
+}
+
+static void cypress_set_mc_reg_address_table(struct radeon_device *rdev)
+{
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	u32 i = 0;
+
+	eg_pi->mc_reg_table.mc_reg_address[i].s0 = MC_SEQ_RAS_TIMING_LP >> 2;
+	eg_pi->mc_reg_table.mc_reg_address[i].s1 = MC_SEQ_RAS_TIMING >> 2;
+	i++;
+
+	eg_pi->mc_reg_table.mc_reg_address[i].s0 = MC_SEQ_CAS_TIMING_LP >> 2;
+	eg_pi->mc_reg_table.mc_reg_address[i].s1 = MC_SEQ_CAS_TIMING >> 2;
+	i++;
+
+	eg_pi->mc_reg_table.mc_reg_address[i].s0 = MC_SEQ_MISC_TIMING_LP >> 2;
+	eg_pi->mc_reg_table.mc_reg_address[i].s1 = MC_SEQ_MISC_TIMING >> 2;
+	i++;
+
+	eg_pi->mc_reg_table.mc_reg_address[i].s0 = MC_SEQ_MISC_TIMING2_LP >> 2;
+	eg_pi->mc_reg_table.mc_reg_address[i].s1 = MC_SEQ_MISC_TIMING2 >> 2;
+	i++;
+
+	eg_pi->mc_reg_table.mc_reg_address[i].s0 = MC_SEQ_RD_CTL_D0_LP >> 2;
+	eg_pi->mc_reg_table.mc_reg_address[i].s1 = MC_SEQ_RD_CTL_D0 >> 2;
+	i++;
+
+	eg_pi->mc_reg_table.mc_reg_address[i].s0 = MC_SEQ_RD_CTL_D1_LP >> 2;
+	eg_pi->mc_reg_table.mc_reg_address[i].s1 = MC_SEQ_RD_CTL_D1 >> 2;
+	i++;
+
+	eg_pi->mc_reg_table.mc_reg_address[i].s0 = MC_SEQ_WR_CTL_D0_LP >> 2;
+	eg_pi->mc_reg_table.mc_reg_address[i].s1 = MC_SEQ_WR_CTL_D0 >> 2;
+	i++;
+
+	eg_pi->mc_reg_table.mc_reg_address[i].s0 = MC_SEQ_WR_CTL_D1_LP >> 2;
+	eg_pi->mc_reg_table.mc_reg_address[i].s1 = MC_SEQ_WR_CTL_D1 >> 2;
+	i++;
+
+	eg_pi->mc_reg_table.mc_reg_address[i].s0 = MC_SEQ_PMG_CMD_EMRS_LP >> 2;
+	eg_pi->mc_reg_table.mc_reg_address[i].s1 = MC_PMG_CMD_EMRS >> 2;
+	i++;
+
+	eg_pi->mc_reg_table.mc_reg_address[i].s0 = MC_SEQ_PMG_CMD_MRS_LP >> 2;
+	eg_pi->mc_reg_table.mc_reg_address[i].s1 = MC_PMG_CMD_MRS >> 2;
+	i++;
+
+	eg_pi->mc_reg_table.mc_reg_address[i].s0 = MC_SEQ_PMG_CMD_MRS1_LP >> 2;
+	eg_pi->mc_reg_table.mc_reg_address[i].s1 = MC_PMG_CMD_MRS1 >> 2;
+	i++;
+
+	eg_pi->mc_reg_table.mc_reg_address[i].s0 = MC_SEQ_MISC1 >> 2;
+	eg_pi->mc_reg_table.mc_reg_address[i].s1 = MC_SEQ_MISC1 >> 2;
+	i++;
+
+	eg_pi->mc_reg_table.mc_reg_address[i].s0 = MC_SEQ_RESERVE_M >> 2;
+	eg_pi->mc_reg_table.mc_reg_address[i].s1 = MC_SEQ_RESERVE_M >> 2;
+	i++;
+
+	eg_pi->mc_reg_table.mc_reg_address[i].s0 = MC_SEQ_MISC3 >> 2;
+	eg_pi->mc_reg_table.mc_reg_address[i].s1 = MC_SEQ_MISC3 >> 2;
+	i++;
+
+	eg_pi->mc_reg_table.last = (u8)i;
+}
+
+static void cypress_retrieve_ac_timing_for_one_entry(struct radeon_device *rdev,
+						     struct evergreen_mc_reg_entry *entry)
+{
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	u32 i;
+
+	for (i = 0; i < eg_pi->mc_reg_table.last; i++)
+		entry->mc_data[i] =
+			RREG32(eg_pi->mc_reg_table.mc_reg_address[i].s1 << 2);
+
+}
+
+static void cypress_retrieve_ac_timing_for_all_ranges(struct radeon_device *rdev,
+						      struct atom_memory_clock_range_table *range_table)
+{
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	u32 i, j;
+
+	for (i = 0; i < range_table->num_entries; i++) {
+		eg_pi->mc_reg_table.mc_reg_table_entry[i].mclk_max =
+			range_table->mclk[i];
+		radeon_atom_set_ac_timing(rdev, range_table->mclk[i]);
+		cypress_retrieve_ac_timing_for_one_entry(rdev,
+							 &eg_pi->mc_reg_table.mc_reg_table_entry[i]);
+	}
+
+	eg_pi->mc_reg_table.num_entries = range_table->num_entries;
+	eg_pi->mc_reg_table.valid_flag = 0;
+
+	for (i = 0; i < eg_pi->mc_reg_table.last; i++) {
+		for (j = 1; j < range_table->num_entries; j++) {
+			if (eg_pi->mc_reg_table.mc_reg_table_entry[j-1].mc_data[i] !=
+			    eg_pi->mc_reg_table.mc_reg_table_entry[j].mc_data[i]) {
+				eg_pi->mc_reg_table.valid_flag |= (1 << i);
+				break;
+			}
+		}
+	}
+}
+
+static int cypress_initialize_mc_reg_table(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	u8 module_index = rv770_get_memory_module_index(rdev);
+	struct atom_memory_clock_range_table range_table = { 0 };
+	int ret;
+
+	ret = radeon_atom_get_mclk_range_table(rdev,
+					       pi->mem_gddr5,
+					       module_index, &range_table);
+	if (ret)
+		return ret;
+
+	cypress_retrieve_ac_timing_for_all_ranges(rdev, &range_table);
+
+	return 0;
+}
+
+static void cypress_wait_for_mc_sequencer(struct radeon_device *rdev, u8 value)
+{
+	u32 i, j;
+	u32 channels = 2;
+
+	if ((rdev->family == CHIP_CYPRESS) ||
+	    (rdev->family == CHIP_HEMLOCK))
+		channels = 4;
+	else if (rdev->family == CHIP_CEDAR)
+		channels = 1;
+
+	for (i = 0; i < channels; i++) {
+		if ((rdev->family == CHIP_CYPRESS) ||
+		    (rdev->family == CHIP_HEMLOCK)) {
+			WREG32_P(MC_CONFIG_MCD, MC_RD_ENABLE_MCD(i), ~MC_RD_ENABLE_MCD_MASK);
+			WREG32_P(MC_CG_CONFIG_MCD, MC_RD_ENABLE_MCD(i), ~MC_RD_ENABLE_MCD_MASK);
+		} else {
+			WREG32_P(MC_CONFIG, MC_RD_ENABLE(i), ~MC_RD_ENABLE_MASK);
+			WREG32_P(MC_CG_CONFIG, MC_RD_ENABLE(i), ~MC_RD_ENABLE_MASK);
+		}
+		for (j = 0; j < rdev->usec_timeout; j++) {
+			if (((RREG32(MC_SEQ_CG) & CG_SEQ_RESP_MASK) >> CG_SEQ_RESP_SHIFT) == value)
+				break;
+			udelay(1);
+		}
+	}
+}
+
+static void cypress_force_mc_use_s1(struct radeon_device *rdev)
+{
+	struct radeon_ps *radeon_boot_state = rdev->pm.dpm.boot_ps;
+	struct rv7xx_ps *boot_state = rv770_get_ps(radeon_boot_state);
+	u32 strobe_mode;
+	u32 mc_seq_cg;
+	int i;
+
+	if (RREG32(MC_SEQ_STATUS_M) & PMG_PWRSTATE)
+		return;
+
+	radeon_atom_set_ac_timing(rdev, boot_state->low.mclk);
+	radeon_mc_wait_for_idle(rdev);
+
+	if ((rdev->family == CHIP_CYPRESS) ||
+	    (rdev->family == CHIP_HEMLOCK)) {
+		WREG32(MC_CONFIG_MCD, 0xf);
+		WREG32(MC_CG_CONFIG_MCD, 0xf);
+	} else {
+		WREG32(MC_CONFIG, 0xf);
+		WREG32(MC_CG_CONFIG, 0xf);
+	}
+
+	for (i = 0; i < rdev->num_crtc; i++)
+		radeon_wait_for_vblank(rdev, i);
+
+	WREG32(MC_SEQ_CG, MC_CG_SEQ_YCLK_SUSPEND);
+	cypress_wait_for_mc_sequencer(rdev, MC_CG_SEQ_YCLK_SUSPEND);
+
+	strobe_mode = cypress_get_strobe_mode_settings(rdev,
+						       boot_state->low.mclk);
+
+	mc_seq_cg = CG_SEQ_REQ(MC_CG_SEQ_DRAMCONF_S1);
+	mc_seq_cg |= SEQ_CG_RESP(strobe_mode);
+	WREG32(MC_SEQ_CG, mc_seq_cg);
+
+	for (i = 0; i < rdev->usec_timeout; i++) {
+		if (RREG32(MC_SEQ_STATUS_M) & PMG_PWRSTATE)
+			break;
+		udelay(1);
+	}
+
+	mc_seq_cg &= ~CG_SEQ_REQ_MASK;
+	mc_seq_cg |= CG_SEQ_REQ(MC_CG_SEQ_YCLK_RESUME);
+	WREG32(MC_SEQ_CG, mc_seq_cg);
+
+	cypress_wait_for_mc_sequencer(rdev, MC_CG_SEQ_YCLK_RESUME);
+}
+
+static void cypress_copy_ac_timing_from_s1_to_s0(struct radeon_device *rdev)
+{
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	u32 value;
+	u32 i;
+
+	for (i = 0; i < eg_pi->mc_reg_table.last; i++) {
+		value = RREG32(eg_pi->mc_reg_table.mc_reg_address[i].s1 << 2);
+		WREG32(eg_pi->mc_reg_table.mc_reg_address[i].s0 << 2, value);
+	}
+}
+
+static void cypress_force_mc_use_s0(struct radeon_device *rdev)
+{
+	struct radeon_ps *radeon_boot_state = rdev->pm.dpm.boot_ps;
+	struct rv7xx_ps *boot_state = rv770_get_ps(radeon_boot_state);
+	u32 strobe_mode;
+	u32 mc_seq_cg;
+	int i;
+
+	cypress_copy_ac_timing_from_s1_to_s0(rdev);
+	radeon_mc_wait_for_idle(rdev);
+
+	if ((rdev->family == CHIP_CYPRESS) ||
+	    (rdev->family == CHIP_HEMLOCK)) {
+		WREG32(MC_CONFIG_MCD, 0xf);
+		WREG32(MC_CG_CONFIG_MCD, 0xf);
+	} else {
+		WREG32(MC_CONFIG, 0xf);
+		WREG32(MC_CG_CONFIG, 0xf);
+	}
+
+	for (i = 0; i < rdev->num_crtc; i++)
+		radeon_wait_for_vblank(rdev, i);
+
+	WREG32(MC_SEQ_CG, MC_CG_SEQ_YCLK_SUSPEND);
+	cypress_wait_for_mc_sequencer(rdev, MC_CG_SEQ_YCLK_SUSPEND);
+
+	strobe_mode = cypress_get_strobe_mode_settings(rdev,
+						       boot_state->low.mclk);
+
+	mc_seq_cg = CG_SEQ_REQ(MC_CG_SEQ_DRAMCONF_S0);
+	mc_seq_cg |= SEQ_CG_RESP(strobe_mode);
+	WREG32(MC_SEQ_CG, mc_seq_cg);
+
+	for (i = 0; i < rdev->usec_timeout; i++) {
+		if (!(RREG32(MC_SEQ_STATUS_M) & PMG_PWRSTATE))
+			break;
+		udelay(1);
+	}
+
+	mc_seq_cg &= ~CG_SEQ_REQ_MASK;
+	mc_seq_cg |= CG_SEQ_REQ(MC_CG_SEQ_YCLK_RESUME);
+	WREG32(MC_SEQ_CG, mc_seq_cg);
+
+	cypress_wait_for_mc_sequencer(rdev, MC_CG_SEQ_YCLK_RESUME);
+}
+
+static int cypress_populate_initial_mvdd_value(struct radeon_device *rdev,
+					       RV770_SMC_VOLTAGE_VALUE *voltage)
+{
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+
+	voltage->index = eg_pi->mvdd_high_index;
+	voltage->value = cpu_to_be16(MVDD_HIGH_VALUE);
+
+	return 0;
+}
+
+int cypress_populate_smc_initial_state(struct radeon_device *rdev,
+				       struct radeon_ps *radeon_initial_state,
+				       RV770_SMC_STATETABLE *table)
+{
+	struct rv7xx_ps *initial_state = rv770_get_ps(radeon_initial_state);
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	u32 a_t;
+
+	table->initialState.levels[0].mclk.mclk770.vMPLL_AD_FUNC_CNTL =
+		cpu_to_be32(pi->clk_regs.rv770.mpll_ad_func_cntl);
+	table->initialState.levels[0].mclk.mclk770.vMPLL_AD_FUNC_CNTL_2 =
+		cpu_to_be32(pi->clk_regs.rv770.mpll_ad_func_cntl_2);
+	table->initialState.levels[0].mclk.mclk770.vMPLL_DQ_FUNC_CNTL =
+		cpu_to_be32(pi->clk_regs.rv770.mpll_dq_func_cntl);
+	table->initialState.levels[0].mclk.mclk770.vMPLL_DQ_FUNC_CNTL_2 =
+		cpu_to_be32(pi->clk_regs.rv770.mpll_dq_func_cntl_2);
+	table->initialState.levels[0].mclk.mclk770.vMCLK_PWRMGT_CNTL =
+		cpu_to_be32(pi->clk_regs.rv770.mclk_pwrmgt_cntl);
+	table->initialState.levels[0].mclk.mclk770.vDLL_CNTL =
+		cpu_to_be32(pi->clk_regs.rv770.dll_cntl);
+
+	table->initialState.levels[0].mclk.mclk770.vMPLL_SS =
+		cpu_to_be32(pi->clk_regs.rv770.mpll_ss1);
+	table->initialState.levels[0].mclk.mclk770.vMPLL_SS2 =
+		cpu_to_be32(pi->clk_regs.rv770.mpll_ss2);
+
+	table->initialState.levels[0].mclk.mclk770.mclk_value =
+		cpu_to_be32(initial_state->low.mclk);
+
+	table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL =
+		cpu_to_be32(pi->clk_regs.rv770.cg_spll_func_cntl);
+	table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_2 =
+		cpu_to_be32(pi->clk_regs.rv770.cg_spll_func_cntl_2);
+	table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_3 =
+		cpu_to_be32(pi->clk_regs.rv770.cg_spll_func_cntl_3);
+	table->initialState.levels[0].sclk.vCG_SPLL_SPREAD_SPECTRUM =
+		cpu_to_be32(pi->clk_regs.rv770.cg_spll_spread_spectrum);
+	table->initialState.levels[0].sclk.vCG_SPLL_SPREAD_SPECTRUM_2 =
+		cpu_to_be32(pi->clk_regs.rv770.cg_spll_spread_spectrum_2);
+
+	table->initialState.levels[0].sclk.sclk_value =
+		cpu_to_be32(initial_state->low.sclk);
+
+	table->initialState.levels[0].arbValue = MC_CG_ARB_FREQ_F0;
+
+	table->initialState.levels[0].ACIndex = 0;
+
+	cypress_populate_voltage_value(rdev,
+				       &eg_pi->vddc_voltage_table,
+				       initial_state->low.vddc,
+				       &table->initialState.levels[0].vddc);
+
+	if (eg_pi->vddci_control)
+		cypress_populate_voltage_value(rdev,
+					       &eg_pi->vddci_voltage_table,
+					       initial_state->low.vddci,
+					       &table->initialState.levels[0].vddci);
+
+	cypress_populate_initial_mvdd_value(rdev,
+					    &table->initialState.levels[0].mvdd);
+
+	a_t = CG_R(0xffff) | CG_L(0);
+	table->initialState.levels[0].aT = cpu_to_be32(a_t);
+
+	table->initialState.levels[0].bSP = cpu_to_be32(pi->dsp);
+
+
+	if (pi->boot_in_gen2)
+		table->initialState.levels[0].gen2PCIE = 1;
+	else
+		table->initialState.levels[0].gen2PCIE = 0;
+	if (initial_state->low.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2)
+		table->initialState.levels[0].gen2XSP = 1;
+	else
+		table->initialState.levels[0].gen2XSP = 0;
+
+	if (pi->mem_gddr5) {
+		table->initialState.levels[0].strobeMode =
+			cypress_get_strobe_mode_settings(rdev,
+							 initial_state->low.mclk);
+
+		if (initial_state->low.mclk > pi->mclk_edc_enable_threshold)
+			table->initialState.levels[0].mcFlags = SMC_MC_EDC_RD_FLAG | SMC_MC_EDC_WR_FLAG;
+		else
+			table->initialState.levels[0].mcFlags =  0;
+	}
+
+	table->initialState.levels[1] = table->initialState.levels[0];
+	table->initialState.levels[2] = table->initialState.levels[0];
+
+	table->initialState.flags |= PPSMC_SWSTATE_FLAG_DC;
+
+	return 0;
+}
+
+int cypress_populate_smc_acpi_state(struct radeon_device *rdev,
+				    RV770_SMC_STATETABLE *table)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	u32 mpll_ad_func_cntl =
+		pi->clk_regs.rv770.mpll_ad_func_cntl;
+	u32 mpll_ad_func_cntl_2 =
+		pi->clk_regs.rv770.mpll_ad_func_cntl_2;
+	u32 mpll_dq_func_cntl =
+		pi->clk_regs.rv770.mpll_dq_func_cntl;
+	u32 mpll_dq_func_cntl_2 =
+		pi->clk_regs.rv770.mpll_dq_func_cntl_2;
+	u32 spll_func_cntl =
+		pi->clk_regs.rv770.cg_spll_func_cntl;
+	u32 spll_func_cntl_2 =
+		pi->clk_regs.rv770.cg_spll_func_cntl_2;
+	u32 spll_func_cntl_3 =
+		pi->clk_regs.rv770.cg_spll_func_cntl_3;
+	u32 mclk_pwrmgt_cntl =
+		pi->clk_regs.rv770.mclk_pwrmgt_cntl;
+	u32 dll_cntl =
+		pi->clk_regs.rv770.dll_cntl;
+
+	table->ACPIState = table->initialState;
+
+	table->ACPIState.flags &= ~PPSMC_SWSTATE_FLAG_DC;
+
+	if (pi->acpi_vddc) {
+		cypress_populate_voltage_value(rdev,
+					       &eg_pi->vddc_voltage_table,
+					       pi->acpi_vddc,
+					       &table->ACPIState.levels[0].vddc);
+		if (pi->pcie_gen2) {
+			if (pi->acpi_pcie_gen2)
+				table->ACPIState.levels[0].gen2PCIE = 1;
+			else
+				table->ACPIState.levels[0].gen2PCIE = 0;
+		} else
+			table->ACPIState.levels[0].gen2PCIE = 0;
+		if (pi->acpi_pcie_gen2)
+			table->ACPIState.levels[0].gen2XSP = 1;
+		else
+			table->ACPIState.levels[0].gen2XSP = 0;
+	} else {
+		cypress_populate_voltage_value(rdev,
+					       &eg_pi->vddc_voltage_table,
+					       pi->min_vddc_in_table,
+					       &table->ACPIState.levels[0].vddc);
+		table->ACPIState.levels[0].gen2PCIE = 0;
+	}
+
+	if (eg_pi->acpi_vddci) {
+		if (eg_pi->vddci_control) {
+			cypress_populate_voltage_value(rdev,
+						       &eg_pi->vddci_voltage_table,
+						       eg_pi->acpi_vddci,
+						       &table->ACPIState.levels[0].vddci);
+		}
+	}
+
+	mpll_ad_func_cntl &= ~PDNB;
+
+	mpll_ad_func_cntl_2 |= BIAS_GEN_PDNB | RESET_EN;
+
+	if (pi->mem_gddr5)
+		mpll_dq_func_cntl &= ~PDNB;
+	mpll_dq_func_cntl_2 |= BIAS_GEN_PDNB | RESET_EN | BYPASS;
+
+	mclk_pwrmgt_cntl |= (MRDCKA0_RESET |
+			     MRDCKA1_RESET |
+			     MRDCKB0_RESET |
+			     MRDCKB1_RESET |
+			     MRDCKC0_RESET |
+			     MRDCKC1_RESET |
+			     MRDCKD0_RESET |
+			     MRDCKD1_RESET);
+
+	mclk_pwrmgt_cntl &= ~(MRDCKA0_PDNB |
+			      MRDCKA1_PDNB |
+			      MRDCKB0_PDNB |
+			      MRDCKB1_PDNB |
+			      MRDCKC0_PDNB |
+			      MRDCKC1_PDNB |
+			      MRDCKD0_PDNB |
+			      MRDCKD1_PDNB);
+
+	dll_cntl |= (MRDCKA0_BYPASS |
+		     MRDCKA1_BYPASS |
+		     MRDCKB0_BYPASS |
+		     MRDCKB1_BYPASS |
+		     MRDCKC0_BYPASS |
+		     MRDCKC1_BYPASS |
+		     MRDCKD0_BYPASS |
+		     MRDCKD1_BYPASS);
+
+	/* evergreen only */
+	if (rdev->family <= CHIP_HEMLOCK)
+		spll_func_cntl |= SPLL_RESET | SPLL_SLEEP | SPLL_BYPASS_EN;
+
+	spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK;
+	spll_func_cntl_2 |= SCLK_MUX_SEL(4);
+
+	table->ACPIState.levels[0].mclk.mclk770.vMPLL_AD_FUNC_CNTL =
+		cpu_to_be32(mpll_ad_func_cntl);
+	table->ACPIState.levels[0].mclk.mclk770.vMPLL_AD_FUNC_CNTL_2 =
+		cpu_to_be32(mpll_ad_func_cntl_2);
+	table->ACPIState.levels[0].mclk.mclk770.vMPLL_DQ_FUNC_CNTL =
+		cpu_to_be32(mpll_dq_func_cntl);
+	table->ACPIState.levels[0].mclk.mclk770.vMPLL_DQ_FUNC_CNTL_2 =
+		cpu_to_be32(mpll_dq_func_cntl_2);
+	table->ACPIState.levels[0].mclk.mclk770.vMCLK_PWRMGT_CNTL =
+		cpu_to_be32(mclk_pwrmgt_cntl);
+	table->ACPIState.levels[0].mclk.mclk770.vDLL_CNTL = cpu_to_be32(dll_cntl);
+
+	table->ACPIState.levels[0].mclk.mclk770.mclk_value = 0;
+
+	table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL =
+		cpu_to_be32(spll_func_cntl);
+	table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_2 =
+		cpu_to_be32(spll_func_cntl_2);
+	table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_3 =
+		cpu_to_be32(spll_func_cntl_3);
+
+	table->ACPIState.levels[0].sclk.sclk_value = 0;
+
+	cypress_populate_mvdd_value(rdev, 0, &table->ACPIState.levels[0].mvdd);
+
+	if (eg_pi->dynamic_ac_timing)
+		table->ACPIState.levels[0].ACIndex = 1;
+
+	table->ACPIState.levels[1] = table->ACPIState.levels[0];
+	table->ACPIState.levels[2] = table->ACPIState.levels[0];
+
+	return 0;
+}
+
+static void cypress_trim_voltage_table_to_fit_state_table(struct radeon_device *rdev,
+							  struct atom_voltage_table *voltage_table)
+{
+	unsigned int i, diff;
+
+	if (voltage_table->count <= MAX_NO_VREG_STEPS)
+		return;
+
+	diff = voltage_table->count - MAX_NO_VREG_STEPS;
+
+	for (i= 0; i < MAX_NO_VREG_STEPS; i++)
+		voltage_table->entries[i] = voltage_table->entries[i + diff];
+
+	voltage_table->count = MAX_NO_VREG_STEPS;
+}
+
+int cypress_construct_voltage_tables(struct radeon_device *rdev)
+{
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	int ret;
+
+	ret = radeon_atom_get_voltage_table(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC,
+					    &eg_pi->vddc_voltage_table);
+	if (ret)
+		return ret;
+
+	if (eg_pi->vddc_voltage_table.count > MAX_NO_VREG_STEPS)
+		cypress_trim_voltage_table_to_fit_state_table(rdev,
+							      &eg_pi->vddc_voltage_table);
+
+	if (eg_pi->vddci_control) {
+		ret = radeon_atom_get_voltage_table(rdev, SET_VOLTAGE_TYPE_ASIC_VDDCI,
+						    &eg_pi->vddci_voltage_table);
+		if (ret)
+			return ret;
+
+		if (eg_pi->vddci_voltage_table.count > MAX_NO_VREG_STEPS)
+			cypress_trim_voltage_table_to_fit_state_table(rdev,
+								      &eg_pi->vddci_voltage_table);
+	}
+
+	return 0;
+}
+
+static void cypress_populate_smc_voltage_table(struct radeon_device *rdev,
+					       struct atom_voltage_table *voltage_table,
+					       RV770_SMC_STATETABLE *table)
+{
+	unsigned int i;
+
+	for (i = 0; i < voltage_table->count; i++) {
+		table->highSMIO[i] = 0;
+		table->lowSMIO[i] |= cpu_to_be32(voltage_table->entries[i].smio_low);
+	}
+}
+
+int cypress_populate_smc_voltage_tables(struct radeon_device *rdev,
+					RV770_SMC_STATETABLE *table)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	unsigned char i;
+
+	if (eg_pi->vddc_voltage_table.count) {
+		cypress_populate_smc_voltage_table(rdev,
+						   &eg_pi->vddc_voltage_table,
+						   table);
+
+		table->voltageMaskTable.highMask[RV770_SMC_VOLTAGEMASK_VDDC] = 0;
+		table->voltageMaskTable.lowMask[RV770_SMC_VOLTAGEMASK_VDDC] =
+			cpu_to_be32(eg_pi->vddc_voltage_table.mask_low);
+
+		for (i = 0; i < eg_pi->vddc_voltage_table.count; i++) {
+			if (pi->max_vddc_in_table <=
+			    eg_pi->vddc_voltage_table.entries[i].value) {
+				table->maxVDDCIndexInPPTable = i;
+				break;
+			}
+		}
+	}
+
+	if (eg_pi->vddci_voltage_table.count) {
+		cypress_populate_smc_voltage_table(rdev,
+						   &eg_pi->vddci_voltage_table,
+						   table);
+
+		table->voltageMaskTable.highMask[RV770_SMC_VOLTAGEMASK_VDDCI] = 0;
+		table->voltageMaskTable.lowMask[RV770_SMC_VOLTAGEMASK_VDDCI] =
+			cpu_to_be32(eg_pi->vddc_voltage_table.mask_low);
+	}
+
+	return 0;
+}
+
+static u32 cypress_get_mclk_split_point(struct atom_memory_info *memory_info)
+{
+	if ((memory_info->mem_type == MEM_TYPE_GDDR3) ||
+	    (memory_info->mem_type == MEM_TYPE_DDR3))
+		return 30000;
+
+	return 0;
+}
+
+int cypress_get_mvdd_configuration(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	u8 module_index;
+	struct atom_memory_info memory_info;
+	u32 tmp = RREG32(GENERAL_PWRMGT);
+
+	if (!(tmp & BACKBIAS_PAD_EN)) {
+		eg_pi->mvdd_high_index = 0;
+		eg_pi->mvdd_low_index = 1;
+		pi->mvdd_control = false;
+		return 0;
+	}
+
+	if (tmp & BACKBIAS_VALUE)
+		eg_pi->mvdd_high_index = 1;
+	else
+		eg_pi->mvdd_high_index = 0;
+
+	eg_pi->mvdd_low_index =
+		(eg_pi->mvdd_high_index == 0) ? 1 : 0;
+
+	module_index = rv770_get_memory_module_index(rdev);
+
+	if (radeon_atom_get_memory_info(rdev, module_index, &memory_info)) {
+		pi->mvdd_control = false;
+		return 0;
+	}
+
+	pi->mvdd_split_frequency =
+		cypress_get_mclk_split_point(&memory_info);
+
+	if (pi->mvdd_split_frequency == 0) {
+		pi->mvdd_control = false;
+		return 0;
+	}
+
+	return 0;
+}
+
+static int cypress_init_smc_table(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	struct radeon_ps *radeon_boot_state = rdev->pm.dpm.boot_ps;
+	RV770_SMC_STATETABLE *table = &pi->smc_statetable;
+	int ret;
+
+	memset(table, 0, sizeof(RV770_SMC_STATETABLE));
+
+	cypress_populate_smc_voltage_tables(rdev, table);
+
+	switch (rdev->pm.int_thermal_type) {
+        case THERMAL_TYPE_EVERGREEN:
+        case THERMAL_TYPE_EMC2103_WITH_INTERNAL:
+		table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_INTERNAL;
+		break;
+        case THERMAL_TYPE_NONE:
+		table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_NONE;
+		break;
+        default:
+		table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_EXTERNAL;
+		break;
+	}
+
+	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_HARDWAREDC)
+		table->systemFlags |= PPSMC_SYSTEMFLAG_GPIO_DC;
+
+	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_REGULATOR_HOT)
+		table->systemFlags |= PPSMC_SYSTEMFLAG_REGULATOR_HOT;
+
+	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC)
+		table->systemFlags |= PPSMC_SYSTEMFLAG_STEPVDDC;
+
+	if (pi->mem_gddr5)
+		table->systemFlags |= PPSMC_SYSTEMFLAG_GDDR5;
+
+	ret = cypress_populate_smc_initial_state(rdev, radeon_boot_state, table);
+	if (ret)
+		return ret;
+
+	ret = cypress_populate_smc_acpi_state(rdev, table);
+	if (ret)
+		return ret;
+
+	table->driverState = table->initialState;
+
+	return rv770_copy_bytes_to_smc(rdev,
+				       pi->state_table_start,
+				       (u8 *)table, sizeof(RV770_SMC_STATETABLE),
+				       pi->sram_end);
+}
+
+int cypress_populate_mc_reg_table(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	struct radeon_ps *radeon_boot_state = rdev->pm.dpm.boot_ps;
+	struct rv7xx_ps *boot_state = rv770_get_ps(radeon_boot_state);
+	SMC_Evergreen_MCRegisters mc_reg_table = { 0 };
+
+	rv770_write_smc_soft_register(rdev,
+				      RV770_SMC_SOFT_REGISTER_seq_index, 1);
+
+	cypress_populate_mc_reg_addresses(rdev, &mc_reg_table);
+
+	cypress_convert_mc_reg_table_entry_to_smc(rdev,
+						  &boot_state->low,
+						  &mc_reg_table.data[0]);
+
+	cypress_convert_mc_registers(&eg_pi->mc_reg_table.mc_reg_table_entry[0],
+				     &mc_reg_table.data[1], eg_pi->mc_reg_table.last,
+				     eg_pi->mc_reg_table.valid_flag);
+
+	cypress_convert_mc_reg_table_to_smc(rdev, radeon_boot_state, &mc_reg_table);
+
+	return rv770_copy_bytes_to_smc(rdev, eg_pi->mc_reg_table_start,
+				       (u8 *)&mc_reg_table, sizeof(SMC_Evergreen_MCRegisters),
+				       pi->sram_end);
+}
+
+int cypress_get_table_locations(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	u32 tmp;
+	int ret;
+
+	ret = rv770_read_smc_sram_dword(rdev,
+					EVERGREEN_SMC_FIRMWARE_HEADER_LOCATION +
+					EVERGREEN_SMC_FIRMWARE_HEADER_stateTable,
+					&tmp, pi->sram_end);
+	if (ret)
+		return ret;
+
+	pi->state_table_start = (u16)tmp;
+
+	ret = rv770_read_smc_sram_dword(rdev,
+					EVERGREEN_SMC_FIRMWARE_HEADER_LOCATION +
+					EVERGREEN_SMC_FIRMWARE_HEADER_softRegisters,
+					&tmp, pi->sram_end);
+	if (ret)
+		return ret;
+
+	pi->soft_regs_start = (u16)tmp;
+
+	ret = rv770_read_smc_sram_dword(rdev,
+					EVERGREEN_SMC_FIRMWARE_HEADER_LOCATION +
+					EVERGREEN_SMC_FIRMWARE_HEADER_mcRegisterTable,
+					&tmp, pi->sram_end);
+	if (ret)
+		return ret;
+
+	eg_pi->mc_reg_table_start = (u16)tmp;
+
+	return 0;
+}
+
+void cypress_enable_display_gap(struct radeon_device *rdev)
+{
+	u32 tmp = RREG32(CG_DISPLAY_GAP_CNTL);
+
+	tmp &= ~(DISP1_GAP_MASK | DISP2_GAP_MASK);
+	tmp |= (DISP1_GAP(R600_PM_DISPLAY_GAP_IGNORE) |
+		DISP2_GAP(R600_PM_DISPLAY_GAP_IGNORE));
+
+	tmp &= ~(DISP1_GAP_MCHG_MASK | DISP2_GAP_MCHG_MASK);
+	tmp |= (DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK) |
+		DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE));
+	WREG32(CG_DISPLAY_GAP_CNTL, tmp);
+}
+
+static void cypress_program_display_gap(struct radeon_device *rdev)
+{
+	u32 tmp, pipe;
+	int i;
+
+	tmp = RREG32(CG_DISPLAY_GAP_CNTL) & ~(DISP1_GAP_MASK | DISP2_GAP_MASK);
+	if (rdev->pm.dpm.new_active_crtc_count > 0)
+		tmp |= DISP1_GAP(R600_PM_DISPLAY_GAP_VBLANK_OR_WM);
+	else
+		tmp |= DISP1_GAP(R600_PM_DISPLAY_GAP_IGNORE);
+
+	if (rdev->pm.dpm.new_active_crtc_count > 1)
+		tmp |= DISP2_GAP(R600_PM_DISPLAY_GAP_VBLANK_OR_WM);
+	else
+		tmp |= DISP2_GAP(R600_PM_DISPLAY_GAP_IGNORE);
+
+	WREG32(CG_DISPLAY_GAP_CNTL, tmp);
+
+	tmp = RREG32(DCCG_DISP_SLOW_SELECT_REG);
+	pipe = (tmp & DCCG_DISP1_SLOW_SELECT_MASK) >> DCCG_DISP1_SLOW_SELECT_SHIFT;
+
+	if ((rdev->pm.dpm.new_active_crtc_count > 0) &&
+	    (!(rdev->pm.dpm.new_active_crtcs & (1 << pipe)))) {
+		/* find the first active crtc */
+		for (i = 0; i < rdev->num_crtc; i++) {
+			if (rdev->pm.dpm.new_active_crtcs & (1 << i))
+				break;
+		}
+		if (i == rdev->num_crtc)
+			pipe = 0;
+		else
+			pipe = i;
+
+		tmp &= ~DCCG_DISP1_SLOW_SELECT_MASK;
+		tmp |= DCCG_DISP1_SLOW_SELECT(pipe);
+		WREG32(DCCG_DISP_SLOW_SELECT_REG, tmp);
+	}
+
+	cypress_notify_smc_display_change(rdev, rdev->pm.dpm.new_active_crtc_count > 0);
+}
+
+void cypress_dpm_setup_asic(struct radeon_device *rdev)
+{
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+
+	rv740_read_clock_registers(rdev);
+	rv770_read_voltage_smio_registers(rdev);
+	rv770_get_max_vddc(rdev);
+	rv770_get_memory_type(rdev);
+
+	if (eg_pi->pcie_performance_request)
+		eg_pi->pcie_performance_request_registered = false;
+
+	if (eg_pi->pcie_performance_request)
+		cypress_advertise_gen2_capability(rdev);
+
+	rv770_get_pcie_gen2_status(rdev);
+
+	rv770_enable_acpi_pm(rdev);
+}
+
+int cypress_dpm_enable(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+
+	if (pi->gfx_clock_gating)
+		rv770_restore_cgcg(rdev);
+
+	if (rv770_dpm_enabled(rdev))
+		return -EINVAL;
+
+	if (pi->voltage_control) {
+		rv770_enable_voltage_control(rdev, true);
+		cypress_construct_voltage_tables(rdev);
+	}
+
+	if (pi->mvdd_control)
+		cypress_get_mvdd_configuration(rdev);
+
+	if (eg_pi->dynamic_ac_timing) {
+		cypress_set_mc_reg_address_table(rdev);
+		cypress_force_mc_use_s0(rdev);
+		cypress_initialize_mc_reg_table(rdev);
+		cypress_force_mc_use_s1(rdev);
+	}
+
+	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS)
+		rv770_enable_backbias(rdev, true);
+
+	if (pi->dynamic_ss)
+		cypress_enable_spread_spectrum(rdev, true);
+
+	if (pi->thermal_protection)
+		rv770_enable_thermal_protection(rdev, true);
+
+	rv770_setup_bsp(rdev);
+	rv770_program_git(rdev);
+	rv770_program_tp(rdev);
+	rv770_program_tpp(rdev);
+	rv770_program_sstp(rdev);
+	rv770_program_engine_speed_parameters(rdev);
+	cypress_enable_display_gap(rdev);
+	rv770_program_vc(rdev);
+
+	if (pi->dynamic_pcie_gen2)
+		cypress_enable_dynamic_pcie_gen2(rdev, true);
+
+	if (rv770_upload_firmware(rdev))
+		return -EINVAL;
+
+	cypress_get_table_locations(rdev);
+
+	if (cypress_init_smc_table(rdev))
+		return -EINVAL;
+
+	if (eg_pi->dynamic_ac_timing)
+		cypress_populate_mc_reg_table(rdev);
+
+	cypress_program_response_times(rdev);
+
+	r7xx_start_smc(rdev);
+
+	cypress_notify_smc_display_change(rdev, false);
+
+	cypress_enable_sclk_control(rdev, true);
+
+	if (eg_pi->memory_transition)
+		cypress_enable_mclk_control(rdev, true);
+
+	cypress_start_dpm(rdev);
+
+	if (pi->gfx_clock_gating)
+		cypress_gfx_clock_gating_enable(rdev, true);
+
+	if (pi->mg_clock_gating)
+		cypress_mg_clock_gating_enable(rdev, true);
+
+	if (rdev->irq.installed &&
+	    r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
+		PPSMC_Result result;
+
+		rv770_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
+		rdev->irq.dpm_thermal = true;
+		radeon_irq_set(rdev);
+		result = rv770_send_msg_to_smc(rdev, PPSMC_MSG_EnableThermalInterrupt);
+
+		if (result != PPSMC_Result_OK)
+			DRM_DEBUG_KMS("Could not enable thermal interrupts.\n");
+	}
+
+	rv770_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true);
+
+	return 0;
+}
+
+void cypress_dpm_disable(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+
+	if (!rv770_dpm_enabled(rdev))
+		return;
+
+	rv770_clear_vc(rdev);
+
+	if (pi->thermal_protection)
+		rv770_enable_thermal_protection(rdev, false);
+
+	if (pi->dynamic_pcie_gen2)
+		cypress_enable_dynamic_pcie_gen2(rdev, false);
+
+	if (rdev->irq.installed &&
+	    r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
+		rdev->irq.dpm_thermal = false;
+		radeon_irq_set(rdev);
+	}
+
+	if (pi->gfx_clock_gating)
+		cypress_gfx_clock_gating_enable(rdev, false);
+
+	if (pi->mg_clock_gating)
+		cypress_mg_clock_gating_enable(rdev, false);
+
+	rv770_stop_dpm(rdev);
+	r7xx_stop_smc(rdev);
+
+	cypress_enable_spread_spectrum(rdev, false);
+
+	if (eg_pi->dynamic_ac_timing)
+		cypress_force_mc_use_s1(rdev);
+
+	rv770_reset_smio_status(rdev);
+}
+
+int cypress_dpm_set_power_state(struct radeon_device *rdev)
+{
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+
+	rv770_restrict_performance_levels_before_switch(rdev);
+
+	if (eg_pi->pcie_performance_request)
+		cypress_notify_link_speed_change_before_state_change(rdev);
+
+	rv770_halt_smc(rdev);
+	cypress_upload_sw_state(rdev);
+
+	if (eg_pi->dynamic_ac_timing)
+		cypress_upload_mc_reg_table(rdev);
+
+	cypress_program_memory_timing_parameters(rdev);
+
+	rv770_resume_smc(rdev);
+	rv770_set_sw_state(rdev);
+
+	if (eg_pi->pcie_performance_request)
+		cypress_notify_link_speed_change_after_state_change(rdev);
+
+	return 0;
+}
+
+void cypress_dpm_reset_asic(struct radeon_device *rdev)
+{
+	rv770_restrict_performance_levels_before_switch(rdev);
+	rv770_set_boot_state(rdev);
+}
+
+void cypress_dpm_display_configuration_changed(struct radeon_device *rdev)
+{
+	cypress_program_display_gap(rdev);
+}
+
+int cypress_dpm_init(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi;
+	struct evergreen_power_info *eg_pi;
+	int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info);
+	uint16_t data_offset, size;
+	uint8_t frev, crev;
+	struct atom_clock_dividers dividers;
+	int ret;
+
+	eg_pi = kzalloc(sizeof(struct evergreen_power_info), GFP_KERNEL);
+	if (eg_pi == NULL)
+		return -ENOMEM;
+	rdev->pm.dpm.priv = eg_pi;
+	pi = &eg_pi->rv7xx;
+
+	rv770_get_max_vddc(rdev);
+
+	eg_pi->ulv.supported = false;
+	pi->acpi_vddc = 0;
+	eg_pi->acpi_vddci = 0;
+	pi->min_vddc_in_table = 0;
+	pi->max_vddc_in_table = 0;
+
+	ret = rv7xx_parse_power_table(rdev);
+	if (ret)
+		return ret;
+
+	if (rdev->pm.dpm.voltage_response_time == 0)
+		rdev->pm.dpm.voltage_response_time = R600_VOLTAGERESPONSETIME_DFLT;
+	if (rdev->pm.dpm.backbias_response_time == 0)
+		rdev->pm.dpm.backbias_response_time = R600_BACKBIASRESPONSETIME_DFLT;
+
+	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
+					     0, false, &dividers);
+	if (ret)
+		pi->ref_div = dividers.ref_div + 1;
+	else
+		pi->ref_div = R600_REFERENCEDIVIDER_DFLT;
+
+	pi->mclk_strobe_mode_threshold = 40000;
+	pi->mclk_edc_enable_threshold = 40000;
+	eg_pi->mclk_edc_wr_enable_threshold = 40000;
+
+	pi->voltage_control =
+		radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC);
+
+	pi->mvdd_control =
+		radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_MVDDC);
+
+	eg_pi->vddci_control =
+		radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDCI);
+
+	if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
+                                   &frev, &crev, &data_offset)) {
+		pi->sclk_ss = true;
+		pi->mclk_ss = true;
+		pi->dynamic_ss = true;
+	} else {
+		pi->sclk_ss = false;
+		pi->mclk_ss = false;
+		pi->dynamic_ss = true;
+	}
+
+	pi->asi = RV770_ASI_DFLT;
+	pi->pasi = CYPRESS_HASI_DFLT;
+	pi->vrc = CYPRESS_VRC_DFLT;
+
+	pi->power_gating = false;
+
+	if ((rdev->family == CHIP_CYPRESS) ||
+	    (rdev->family == CHIP_HEMLOCK))
+		pi->gfx_clock_gating = false;
+	else
+		pi->gfx_clock_gating = true;
+
+	pi->mg_clock_gating = true;
+	pi->mgcgtssm = true;
+	eg_pi->ls_clock_gating = false;
+	eg_pi->sclk_deep_sleep = false;
+
+	pi->dynamic_pcie_gen2 = true;
+
+	if (pi->gfx_clock_gating &&
+	    (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE))
+		pi->thermal_protection = true;
+	else
+		pi->thermal_protection = false;
+
+	pi->display_gap = true;
+
+	if (rdev->flags & RADEON_IS_MOBILITY)
+		pi->dcodt = true;
+	else
+		pi->dcodt = false;
+
+	pi->ulps = true;
+
+	eg_pi->dynamic_ac_timing = true;
+	eg_pi->abm = true;
+	eg_pi->mcls = true;
+	eg_pi->light_sleep = true;
+	eg_pi->memory_transition = true;
+#if defined(CONFIG_ACPI)
+	eg_pi->pcie_performance_request =
+		radeon_acpi_is_pcie_performance_request_supported(rdev);
+#else
+	eg_pi->pcie_performance_request = false;
+#endif
+
+	if ((rdev->family == CHIP_CYPRESS) ||
+	    (rdev->family == CHIP_HEMLOCK) ||
+	    (rdev->family == CHIP_JUNIPER))
+		eg_pi->dll_default_on = true;
+	else
+		eg_pi->dll_default_on = false;
+
+	eg_pi->sclk_deep_sleep = false;
+	pi->mclk_stutter_mode_threshold = 0;
+
+	pi->sram_end = SMC_RAM_END;
+
+	return 0;
+}
+
+void cypress_dpm_fini(struct radeon_device *rdev)
+{
+	int i;
+
+	for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
+		kfree(rdev->pm.dpm.ps[i].ps_priv);
+	}
+	kfree(rdev->pm.dpm.ps);
+	kfree(rdev->pm.dpm.priv);
+}
diff --git a/drivers/gpu/drm/radeon/cypress_dpm.h b/drivers/gpu/drm/radeon/cypress_dpm.h
new file mode 100644
index 0000000..6cc3d3f
--- /dev/null
+++ b/drivers/gpu/drm/radeon/cypress_dpm.h
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2011 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef __CYPRESS_DPM_H__
+#define __CYPRESS_DPM_H__
+
+#include "rv770_dpm.h"
+#include "evergreen_smc.h"
+
+struct evergreen_mc_reg_entry {
+	u32 mclk_max;
+	u32 mc_data[SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE];
+};
+
+struct evergreen_mc_reg_table {
+	u8 last;
+	u8 num_entries;
+	u16 valid_flag;
+	struct evergreen_mc_reg_entry mc_reg_table_entry[MAX_AC_TIMING_ENTRIES];
+	SMC_Evergreen_MCRegisterAddress mc_reg_address[SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE];
+};
+
+struct evergreen_ulv_param {
+	bool supported;
+	struct rv7xx_pl *pl;
+};
+
+struct evergreen_arb_registers {
+	u32 mc_arb_dram_timing;
+	u32 mc_arb_dram_timing2;
+	u32 mc_arb_rfsh_rate;
+	u32 mc_arb_burst_time;
+};
+
+struct evergreen_power_info {
+	/* must be first! */
+	struct rv7xx_power_info rv7xx;
+	/* flags */
+	bool vddci_control;
+	bool dynamic_ac_timing;
+	bool abm;
+	bool mcls;
+	bool light_sleep;
+	bool memory_transition;
+	bool pcie_performance_request;
+	bool pcie_performance_request_registered;
+	bool sclk_deep_sleep;
+	bool dll_default_on;
+	bool ls_clock_gating;
+	/* stored values */
+	u16 acpi_vddci;
+	u8 mvdd_high_index;
+	u8 mvdd_low_index;
+	u32 mclk_edc_wr_enable_threshold;
+	struct evergreen_mc_reg_table mc_reg_table;
+	struct atom_voltage_table vddc_voltage_table;
+	struct atom_voltage_table vddci_voltage_table;
+	struct evergreen_arb_registers bootup_arb_registers;
+	struct evergreen_ulv_param ulv;
+	/* smc offsets */
+	u16 mc_reg_table_start;
+};
+
+#define CYPRESS_HASI_DFLT                               400000
+#define CYPRESS_MGCGTTLOCAL0_DFLT                       0x00000000
+#define CYPRESS_MGCGTTLOCAL1_DFLT                       0x00000000
+#define CYPRESS_MGCGTTLOCAL2_DFLT                       0x00000000
+#define CYPRESS_MGCGTTLOCAL3_DFLT                       0x00000000
+#define CYPRESS_MGCGCGTSSMCTRL_DFLT                     0x81944bc0
+#define REDWOOD_MGCGCGTSSMCTRL_DFLT                     0x6e944040
+#define CEDAR_MGCGCGTSSMCTRL_DFLT                       0x46944040
+#define CYPRESS_VRC_DFLT                                0xC00033
+
+#define PCIE_PERF_REQ_REMOVE_REGISTRY   0
+#define PCIE_PERF_REQ_FORCE_LOWPOWER    1
+#define PCIE_PERF_REQ_PECI_GEN1         2
+#define PCIE_PERF_REQ_PECI_GEN2         3
+#define PCIE_PERF_REQ_PECI_GEN3         4
+
+int cypress_convert_power_level_to_smc(struct radeon_device *rdev,
+				       struct rv7xx_pl *pl,
+				       RV770_SMC_HW_PERFORMANCE_LEVEL *level,
+				       u8 watermark_level);
+int cypress_populate_smc_acpi_state(struct radeon_device *rdev,
+				    RV770_SMC_STATETABLE *table);
+int cypress_populate_smc_voltage_tables(struct radeon_device *rdev,
+					RV770_SMC_STATETABLE *table);
+int cypress_populate_smc_initial_state(struct radeon_device *rdev,
+				       struct radeon_ps *radeon_initial_state,
+				       RV770_SMC_STATETABLE *table);
+u32 cypress_calculate_burst_time(struct radeon_device *rdev,
+				 u32 engine_clock, u32 memory_clock);
+void cypress_notify_link_speed_change_before_state_change(struct radeon_device *rdev);
+int cypress_upload_sw_state(struct radeon_device *rdev);
+int cypress_upload_mc_reg_table(struct radeon_device *rdev);
+void cypress_program_memory_timing_parameters(struct radeon_device *rdev);
+void cypress_notify_link_speed_change_after_state_change(struct radeon_device *rdev);
+int cypress_construct_voltage_tables(struct radeon_device *rdev);
+int cypress_get_mvdd_configuration(struct radeon_device *rdev);
+void cypress_enable_spread_spectrum(struct radeon_device *rdev,
+				    bool enable);
+void cypress_enable_display_gap(struct radeon_device *rdev);
+int cypress_get_table_locations(struct radeon_device *rdev);
+int cypress_populate_mc_reg_table(struct radeon_device *rdev);
+void cypress_program_response_times(struct radeon_device *rdev);
+int cypress_notify_smc_display_change(struct radeon_device *rdev,
+				      bool has_display);
+void cypress_enable_sclk_control(struct radeon_device *rdev,
+				 bool enable);
+void cypress_enable_mclk_control(struct radeon_device *rdev,
+				 bool enable);
+void cypress_start_dpm(struct radeon_device *rdev);
+void cypress_advertise_gen2_capability(struct radeon_device *rdev);
+
+#endif
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
index 63a1e6e..c91b1e5 100644
--- a/drivers/gpu/drm/radeon/evergreen.c
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -4167,6 +4167,7 @@ int evergreen_irq_set(struct radeon_device *rdev)
 	u32 grph1 = 0, grph2 = 0, grph3 = 0, grph4 = 0, grph5 = 0, grph6 = 0;
 	u32 afmt1 = 0, afmt2 = 0, afmt3 = 0, afmt4 = 0, afmt5 = 0, afmt6 = 0;
 	u32 dma_cntl, dma_cntl1 = 0;
+	u32 thermal_int = 0;
 
 	if (!rdev->irq.installed) {
 		WARN(1, "Can't enable IRQ/MSI because no handler is installed\n");
@@ -4186,6 +4187,8 @@ int evergreen_irq_set(struct radeon_device *rdev)
 	hpd4 = RREG32(DC_HPD4_INT_CONTROL) & ~DC_HPDx_INT_EN;
 	hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~DC_HPDx_INT_EN;
 	hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~DC_HPDx_INT_EN;
+	thermal_int = RREG32(CG_THERMAL_INT) &
+		~(THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW);
 
 	afmt1 = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET) & ~AFMT_AZ_FORMAT_WTRIG_MASK;
 	afmt2 = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET) & ~AFMT_AZ_FORMAT_WTRIG_MASK;
@@ -4231,6 +4234,11 @@ int evergreen_irq_set(struct radeon_device *rdev)
 		}
 	}
 
+	if (rdev->irq.dpm_thermal) {
+		DRM_DEBUG("dpm thermal\n");
+		thermal_int |= THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW;
+	}
+
 	if (rdev->irq.crtc_vblank_int[0] ||
 	    atomic_read(&rdev->irq.pflip[0])) {
 		DRM_DEBUG("evergreen_irq_set: vblank 0\n");
@@ -4352,6 +4360,7 @@ int evergreen_irq_set(struct radeon_device *rdev)
 	WREG32(DC_HPD4_INT_CONTROL, hpd4);
 	WREG32(DC_HPD5_INT_CONTROL, hpd5);
 	WREG32(DC_HPD6_INT_CONTROL, hpd6);
+	WREG32(CG_THERMAL_INT, thermal_int);
 
 	WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, afmt1);
 	WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, afmt2);
@@ -4543,6 +4552,7 @@ int evergreen_irq_process(struct radeon_device *rdev)
 	u32 ring_index;
 	bool queue_hotplug = false;
 	bool queue_hdmi = false;
+	bool queue_thermal = false;
 
 	if (!rdev->ih.enabled || rdev->shutdown)
 		return IRQ_NONE;
@@ -4864,6 +4874,16 @@ restart_ih:
 			DRM_DEBUG("IH: DMA trap\n");
 			radeon_fence_process(rdev, R600_RING_TYPE_DMA_INDEX);
 			break;
+		case 230: /* thermal low to high */
+			DRM_DEBUG("IH: thermal low to high\n");
+			rdev->pm.dpm.thermal.high_to_low = false;
+			queue_thermal = true;
+			break;
+		case 231: /* thermal high to low */
+			DRM_DEBUG("IH: thermal high to low\n");
+			rdev->pm.dpm.thermal.high_to_low = true;
+			queue_thermal = true;
+			break;
 		case 233: /* GUI IDLE */
 			DRM_DEBUG("IH: GUI idle\n");
 			break;
@@ -4886,6 +4906,8 @@ restart_ih:
 		schedule_work(&rdev->hotplug_work);
 	if (queue_hdmi)
 		schedule_work(&rdev->audio_work);
+	if (queue_thermal)
+		schedule_work(&rdev->pm.dpm.thermal.work);
 	rdev->ih.rptr = rptr;
 	WREG32(IH_RB_RPTR, rdev->ih.rptr);
 	atomic_set(&rdev->ih.lock, 0);
diff --git a/drivers/gpu/drm/radeon/evergreen_smc.h b/drivers/gpu/drm/radeon/evergreen_smc.h
new file mode 100644
index 0000000..76ada8c
--- /dev/null
+++ b/drivers/gpu/drm/radeon/evergreen_smc.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2011 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef __EVERGREEN_SMC_H__
+#define __EVERGREEN_SMC_H__
+
+#include "rv770_smc.h"
+
+#pragma pack(push, 1)
+
+#define SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE 16
+
+struct SMC_Evergreen_MCRegisterAddress
+{
+    uint16_t s0;
+    uint16_t s1;
+};
+
+typedef struct SMC_Evergreen_MCRegisterAddress SMC_Evergreen_MCRegisterAddress;
+
+
+struct SMC_Evergreen_MCRegisterSet
+{
+    uint32_t value[SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE];
+};
+
+typedef struct SMC_Evergreen_MCRegisterSet SMC_Evergreen_MCRegisterSet;
+
+struct SMC_Evergreen_MCRegisters
+{
+    uint8_t                             last;
+    uint8_t                             reserved[3];
+    SMC_Evergreen_MCRegisterAddress     address[SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE];
+    SMC_Evergreen_MCRegisterSet         data[5];
+};
+
+typedef struct SMC_Evergreen_MCRegisters SMC_Evergreen_MCRegisters;
+
+#define EVERGREEN_SMC_FIRMWARE_HEADER_LOCATION 0x100
+
+#define EVERGREEN_SMC_FIRMWARE_HEADER_softRegisters   0x0
+#define EVERGREEN_SMC_FIRMWARE_HEADER_stateTable      0xC
+#define EVERGREEN_SMC_FIRMWARE_HEADER_mcRegisterTable 0x20
+
+
+#pragma pack(pop)
+
+#endif
diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h
index 8603b7c..93b91a3 100644
--- a/drivers/gpu/drm/radeon/evergreend.h
+++ b/drivers/gpu/drm/radeon/evergreend.h
@@ -48,6 +48,293 @@
 #define SUMO_GB_ADDR_CONFIG_GOLDEN           0x02010002
 #define SUMO2_GB_ADDR_CONFIG_GOLDEN          0x02010002
 
+/* pm registers */
+#define	SMC_MSG						0x20c
+#define		HOST_SMC_MSG(x)				((x) << 0)
+#define		HOST_SMC_MSG_MASK			(0xff << 0)
+#define		HOST_SMC_MSG_SHIFT			0
+#define		HOST_SMC_RESP(x)			((x) << 8)
+#define		HOST_SMC_RESP_MASK			(0xff << 8)
+#define		HOST_SMC_RESP_SHIFT			8
+#define		SMC_HOST_MSG(x)				((x) << 16)
+#define		SMC_HOST_MSG_MASK			(0xff << 16)
+#define		SMC_HOST_MSG_SHIFT			16
+#define		SMC_HOST_RESP(x)			((x) << 24)
+#define		SMC_HOST_RESP_MASK			(0xff << 24)
+#define		SMC_HOST_RESP_SHIFT			24
+
+#define DCCG_DISP_SLOW_SELECT_REG                       0x4fc
+#define		DCCG_DISP1_SLOW_SELECT(x)		((x) << 0)
+#define		DCCG_DISP1_SLOW_SELECT_MASK		(7 << 0)
+#define		DCCG_DISP1_SLOW_SELECT_SHIFT		0
+#define		DCCG_DISP2_SLOW_SELECT(x)		((x) << 4)
+#define		DCCG_DISP2_SLOW_SELECT_MASK		(7 << 4)
+#define		DCCG_DISP2_SLOW_SELECT_SHIFT		4
+
+#define	CG_SPLL_FUNC_CNTL				0x600
+#define		SPLL_RESET				(1 << 0)
+#define		SPLL_SLEEP				(1 << 1)
+#define		SPLL_BYPASS_EN				(1 << 3)
+#define		SPLL_REF_DIV(x)				((x) << 4)
+#define		SPLL_REF_DIV_MASK			(0x3f << 4)
+#define		SPLL_PDIV_A(x)				((x) << 20)
+#define		SPLL_PDIV_A_MASK			(0x7f << 20)
+#define	CG_SPLL_FUNC_CNTL_2				0x604
+#define		SCLK_MUX_SEL(x)				((x) << 0)
+#define		SCLK_MUX_SEL_MASK			(0x1ff << 0)
+#define	CG_SPLL_FUNC_CNTL_3				0x608
+#define		SPLL_FB_DIV(x)				((x) << 0)
+#define		SPLL_FB_DIV_MASK			(0x3ffffff << 0)
+#define		SPLL_DITHEN				(1 << 28)
+
+#define MPLL_CNTL_MODE                                  0x61c
+#       define SS_SSEN                                  (1 << 24)
+#       define SS_DSMODE_EN                             (1 << 25)
+
+#define	MPLL_AD_FUNC_CNTL				0x624
+#define		CLKF(x)					((x) << 0)
+#define		CLKF_MASK				(0x7f << 0)
+#define		CLKR(x)					((x) << 7)
+#define		CLKR_MASK				(0x1f << 7)
+#define		CLKFRAC(x)				((x) << 12)
+#define		CLKFRAC_MASK				(0x1f << 12)
+#define		YCLK_POST_DIV(x)			((x) << 17)
+#define		YCLK_POST_DIV_MASK			(3 << 17)
+#define		IBIAS(x)				((x) << 20)
+#define		IBIAS_MASK				(0x3ff << 20)
+#define		RESET					(1 << 30)
+#define		PDNB					(1 << 31)
+#define	MPLL_AD_FUNC_CNTL_2				0x628
+#define		BYPASS					(1 << 19)
+#define		BIAS_GEN_PDNB				(1 << 24)
+#define		RESET_EN				(1 << 25)
+#define		VCO_MODE				(1 << 29)
+#define	MPLL_DQ_FUNC_CNTL				0x62c
+#define	MPLL_DQ_FUNC_CNTL_2				0x630
+
+#define GENERAL_PWRMGT                                  0x63c
+#       define GLOBAL_PWRMGT_EN                         (1 << 0)
+#       define STATIC_PM_EN                             (1 << 1)
+#       define THERMAL_PROTECTION_DIS                   (1 << 2)
+#       define THERMAL_PROTECTION_TYPE                  (1 << 3)
+#       define ENABLE_GEN2PCIE                          (1 << 4)
+#       define ENABLE_GEN2XSP                           (1 << 5)
+#       define SW_SMIO_INDEX(x)                         ((x) << 6)
+#       define SW_SMIO_INDEX_MASK                       (3 << 6)
+#       define SW_SMIO_INDEX_SHIFT                      6
+#       define LOW_VOLT_D2_ACPI                         (1 << 8)
+#       define LOW_VOLT_D3_ACPI                         (1 << 9)
+#       define VOLT_PWRMGT_EN                           (1 << 10)
+#       define BACKBIAS_PAD_EN                          (1 << 18)
+#       define BACKBIAS_VALUE                           (1 << 19)
+#       define DYN_SPREAD_SPECTRUM_EN                   (1 << 23)
+#       define AC_DC_SW                                 (1 << 24)
+
+#define SCLK_PWRMGT_CNTL                                  0x644
+#       define SCLK_PWRMGT_OFF                            (1 << 0)
+#       define SCLK_LOW_D1                                (1 << 1)
+#       define FIR_RESET                                  (1 << 4)
+#       define FIR_FORCE_TREND_SEL                        (1 << 5)
+#       define FIR_TREND_MODE                             (1 << 6)
+#       define DYN_GFX_CLK_OFF_EN                         (1 << 7)
+#       define GFX_CLK_FORCE_ON                           (1 << 8)
+#       define GFX_CLK_REQUEST_OFF                        (1 << 9)
+#       define GFX_CLK_FORCE_OFF                          (1 << 10)
+#       define GFX_CLK_OFF_ACPI_D1                        (1 << 11)
+#       define GFX_CLK_OFF_ACPI_D2                        (1 << 12)
+#       define GFX_CLK_OFF_ACPI_D3                        (1 << 13)
+#       define DYN_LIGHT_SLEEP_EN                         (1 << 14)
+#define	MCLK_PWRMGT_CNTL				0x648
+#       define DLL_SPEED(x)				((x) << 0)
+#       define DLL_SPEED_MASK				(0x1f << 0)
+#       define MPLL_PWRMGT_OFF                          (1 << 5)
+#       define DLL_READY                                (1 << 6)
+#       define MC_INT_CNTL                              (1 << 7)
+#       define MRDCKA0_PDNB                             (1 << 8)
+#       define MRDCKA1_PDNB                             (1 << 9)
+#       define MRDCKB0_PDNB                             (1 << 10)
+#       define MRDCKB1_PDNB                             (1 << 11)
+#       define MRDCKC0_PDNB                             (1 << 12)
+#       define MRDCKC1_PDNB                             (1 << 13)
+#       define MRDCKD0_PDNB                             (1 << 14)
+#       define MRDCKD1_PDNB                             (1 << 15)
+#       define MRDCKA0_RESET                            (1 << 16)
+#       define MRDCKA1_RESET                            (1 << 17)
+#       define MRDCKB0_RESET                            (1 << 18)
+#       define MRDCKB1_RESET                            (1 << 19)
+#       define MRDCKC0_RESET                            (1 << 20)
+#       define MRDCKC1_RESET                            (1 << 21)
+#       define MRDCKD0_RESET                            (1 << 22)
+#       define MRDCKD1_RESET                            (1 << 23)
+#       define DLL_READY_READ                           (1 << 24)
+#       define USE_DISPLAY_GAP                          (1 << 25)
+#       define USE_DISPLAY_URGENT_NORMAL                (1 << 26)
+#       define MPLL_TURNOFF_D2                          (1 << 28)
+#define	DLL_CNTL					0x64c
+#       define MRDCKA0_BYPASS                           (1 << 24)
+#       define MRDCKA1_BYPASS                           (1 << 25)
+#       define MRDCKB0_BYPASS                           (1 << 26)
+#       define MRDCKB1_BYPASS                           (1 << 27)
+#       define MRDCKC0_BYPASS                           (1 << 28)
+#       define MRDCKC1_BYPASS                           (1 << 29)
+#       define MRDCKD0_BYPASS                           (1 << 30)
+#       define MRDCKD1_BYPASS                           (1 << 31)
+
+#define CG_AT                                           0x6d4
+#       define CG_R(x)					((x) << 0)
+#       define CG_R_MASK				(0xffff << 0)
+#       define CG_L(x)					((x) << 16)
+#       define CG_L_MASK				(0xffff << 16)
+
+#define CG_DISPLAY_GAP_CNTL                               0x714
+#       define DISP1_GAP(x)                               ((x) << 0)
+#       define DISP1_GAP_MASK                             (3 << 0)
+#       define DISP2_GAP(x)                               ((x) << 2)
+#       define DISP2_GAP_MASK                             (3 << 2)
+#       define VBI_TIMER_COUNT(x)                         ((x) << 4)
+#       define VBI_TIMER_COUNT_MASK                       (0x3fff << 4)
+#       define VBI_TIMER_UNIT(x)                          ((x) << 20)
+#       define VBI_TIMER_UNIT_MASK                        (7 << 20)
+#       define DISP1_GAP_MCHG(x)                          ((x) << 24)
+#       define DISP1_GAP_MCHG_MASK                        (3 << 24)
+#       define DISP2_GAP_MCHG(x)                          ((x) << 26)
+#       define DISP2_GAP_MCHG_MASK                        (3 << 26)
+
+#define	CG_BIF_REQ_AND_RSP				0x7f4
+#define		CG_CLIENT_REQ(x)			((x) << 0)
+#define		CG_CLIENT_REQ_MASK			(0xff << 0)
+#define		CG_CLIENT_REQ_SHIFT			0
+#define		CG_CLIENT_RESP(x)			((x) << 8)
+#define		CG_CLIENT_RESP_MASK			(0xff << 8)
+#define		CG_CLIENT_RESP_SHIFT			8
+#define		CLIENT_CG_REQ(x)			((x) << 16)
+#define		CLIENT_CG_REQ_MASK			(0xff << 16)
+#define		CLIENT_CG_REQ_SHIFT			16
+#define		CLIENT_CG_RESP(x)			((x) << 24)
+#define		CLIENT_CG_RESP_MASK			(0xff << 24)
+#define		CLIENT_CG_RESP_SHIFT			24
+
+#define	CG_SPLL_SPREAD_SPECTRUM				0x790
+#define		SSEN					(1 << 0)
+#define	CG_SPLL_SPREAD_SPECTRUM_2			0x794
+
+#define	MPLL_SS1					0x85c
+#define		CLKV(x)					((x) << 0)
+#define		CLKV_MASK				(0x3ffffff << 0)
+#define	MPLL_SS2					0x860
+#define		CLKS(x)					((x) << 0)
+#define		CLKS_MASK				(0xfff << 0)
+
+#define	CG_IND_ADDR					0x8f8
+#define	CG_IND_DATA					0x8fc
+/* CGIND regs */
+#define	CG_CGTT_LOCAL_0					0x00
+#define	CG_CGTT_LOCAL_1					0x01
+#define	CG_CGTT_LOCAL_2					0x02
+#define	CG_CGTT_LOCAL_3					0x03
+#define	CG_CGLS_TILE_0					0x20
+#define	CG_CGLS_TILE_1					0x21
+#define	CG_CGLS_TILE_2					0x22
+#define	CG_CGLS_TILE_3					0x23
+#define	CG_CGLS_TILE_4					0x24
+#define	CG_CGLS_TILE_5					0x25
+#define	CG_CGLS_TILE_6					0x26
+#define	CG_CGLS_TILE_7					0x27
+#define	CG_CGLS_TILE_8					0x28
+#define	CG_CGLS_TILE_9					0x29
+#define	CG_CGLS_TILE_10					0x2a
+#define	CG_CGLS_TILE_11					0x2b
+
+#define VM_L2_CG                                        0x15c0
+
+#define MC_CONFIG                                       0x2000
+
+#define MC_CONFIG_MCD                                   0x20a0
+#define MC_CG_CONFIG_MCD                                0x20a4
+#define		MC_RD_ENABLE_MCD(x)			((x) << 8)
+#define		MC_RD_ENABLE_MCD_MASK			(7 << 8)
+
+#define MC_HUB_MISC_HUB_CG                              0x20b8
+#define MC_HUB_MISC_VM_CG                               0x20bc
+#define MC_HUB_MISC_SIP_CG                              0x20c0
+
+#define MC_XPB_CLK_GAT                                  0x2478
+
+#define MC_CG_CONFIG                                    0x25bc
+#define		MC_RD_ENABLE(x)				((x) << 4)
+#define		MC_RD_ENABLE_MASK			(3 << 4)
+
+#define MC_CITF_MISC_RD_CG                              0x2648
+#define MC_CITF_MISC_WR_CG                              0x264c
+#define MC_CITF_MISC_VM_CG                              0x2650
+#       define MEM_LS_ENABLE                            (1 << 19)
+
+#define MC_ARB_BURST_TIME                               0x2808
+#define		STATE0(x)				((x) << 0)
+#define		STATE0_MASK				(0x1f << 0)
+#define		STATE1(x)				((x) << 5)
+#define		STATE1_MASK				(0x1f << 5)
+#define		STATE2(x)				((x) << 10)
+#define		STATE2_MASK				(0x1f << 10)
+#define		STATE3(x)				((x) << 15)
+#define		STATE3_MASK				(0x1f << 15)
+
+#define MC_SEQ_RAS_TIMING                               0x28a0
+#define MC_SEQ_CAS_TIMING                               0x28a4
+#define MC_SEQ_MISC_TIMING                              0x28a8
+#define MC_SEQ_MISC_TIMING2                             0x28ac
+
+#define MC_SEQ_RD_CTL_D0                                0x28b4
+#define MC_SEQ_RD_CTL_D1                                0x28b8
+#define MC_SEQ_WR_CTL_D0                                0x28bc
+#define MC_SEQ_WR_CTL_D1                                0x28c0
+
+#define MC_SEQ_STATUS_M                                 0x29f4
+#       define PMG_PWRSTATE                             (1 << 16)
+
+#define MC_SEQ_MISC1                                    0x2a04
+#define MC_SEQ_RESERVE_M                                0x2a08
+#define MC_PMG_CMD_EMRS                                 0x2a0c
+
+#define MC_SEQ_MISC3                                    0x2a2c
+
+#define MC_SEQ_MISC5                                    0x2a54
+#define MC_SEQ_MISC6                                    0x2a58
+
+#define MC_SEQ_MISC7                                    0x2a64
+
+#define MC_SEQ_CG                                       0x2a68
+#define		CG_SEQ_REQ(x)				((x) << 0)
+#define		CG_SEQ_REQ_MASK				(0xff << 0)
+#define		CG_SEQ_REQ_SHIFT			0
+#define		CG_SEQ_RESP(x)				((x) << 8)
+#define		CG_SEQ_RESP_MASK			(0xff << 8)
+#define		CG_SEQ_RESP_SHIFT			8
+#define		SEQ_CG_REQ(x)				((x) << 16)
+#define		SEQ_CG_REQ_MASK				(0xff << 16)
+#define		SEQ_CG_REQ_SHIFT			16
+#define		SEQ_CG_RESP(x)				((x) << 24)
+#define		SEQ_CG_RESP_MASK			(0xff << 24)
+#define		SEQ_CG_RESP_SHIFT			24
+#define MC_SEQ_RAS_TIMING_LP                            0x2a6c
+#define MC_SEQ_CAS_TIMING_LP                            0x2a70
+#define MC_SEQ_MISC_TIMING_LP                           0x2a74
+#define MC_SEQ_MISC_TIMING2_LP                          0x2a78
+#define MC_SEQ_WR_CTL_D0_LP                             0x2a7c
+#define MC_SEQ_WR_CTL_D1_LP                             0x2a80
+#define MC_SEQ_PMG_CMD_EMRS_LP                          0x2a84
+#define MC_SEQ_PMG_CMD_MRS_LP                           0x2a88
+
+#define MC_PMG_CMD_MRS                                  0x2aac
+
+#define MC_SEQ_RD_CTL_D0_LP                             0x2b1c
+#define MC_SEQ_RD_CTL_D1_LP                             0x2b20
+
+#define MC_PMG_CMD_MRS1                                 0x2b44
+#define MC_SEQ_PMG_CMD_MRS1_LP                          0x2b48
+
+#define CGTS_SM_CTRL_REG                                0x9150
+
 /* Registers */
 
 #define RCU_IND_INDEX           			0x100
@@ -522,6 +809,20 @@
 #define	CG_THERMAL_CTRL					0x72c
 #define		TOFFSET_MASK			        0x00003FE0
 #define		TOFFSET_SHIFT			        5
+#define		DIG_THERM_DPM(x)			((x) << 14)
+#define		DIG_THERM_DPM_MASK			0x003FC000
+#define		DIG_THERM_DPM_SHIFT			14
+
+#define	CG_THERMAL_INT					0x734
+#define		DIG_THERM_INTH(x)			((x) << 8)
+#define		DIG_THERM_INTH_MASK			0x0000FF00
+#define		DIG_THERM_INTH_SHIFT			8
+#define		DIG_THERM_INTL(x)			((x) << 16)
+#define		DIG_THERM_INTL_MASK			0x00FF0000
+#define		DIG_THERM_INTL_SHIFT			16
+#define 	THERM_INT_MASK_HIGH			(1 << 24)
+#define 	THERM_INT_MASK_LOW			(1 << 25)
+
 #define	CG_MULT_THERMAL_STATUS				0x740
 #define		ASIC_T(x)			        ((x) << 16)
 #define		ASIC_T_MASK			        0x07FF0000
@@ -529,6 +830,7 @@
 #define	CG_TS0_STATUS					0x760
 #define		TS0_ADC_DOUT_MASK			0x000003FF
 #define		TS0_ADC_DOUT_SHIFT			0
+
 /* APU */
 #define	CG_THERMAL_STATUS			        0x678
 
@@ -1039,6 +1341,9 @@
 #       define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_MASK      (0x3 << 8)
 #       define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_SHIFT     3
 #       define LC_CURRENT_DATA_RATE                       (1 << 11)
+#       define LC_HW_VOLTAGE_IF_CONTROL(x)                ((x) << 12)
+#       define LC_HW_VOLTAGE_IF_CONTROL_MASK              (3 << 12)
+#       define LC_HW_VOLTAGE_IF_CONTROL_SHIFT             12
 #       define LC_VOLTAGE_TIMER_SEL_MASK                  (0xf << 14)
 #       define LC_CLR_FAILED_SPD_CHANGE_CNT               (1 << 21)
 #       define LC_OTHER_SIDE_EVER_SENT_GEN2               (1 << 23)
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index 0688016..dcac7fd 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -70,15 +70,19 @@ MODULE_FIRMWARE("radeon/R700_rlc.bin");
 MODULE_FIRMWARE("radeon/CEDAR_pfp.bin");
 MODULE_FIRMWARE("radeon/CEDAR_me.bin");
 MODULE_FIRMWARE("radeon/CEDAR_rlc.bin");
+MODULE_FIRMWARE("radeon/CEDAR_smc.bin");
 MODULE_FIRMWARE("radeon/REDWOOD_pfp.bin");
 MODULE_FIRMWARE("radeon/REDWOOD_me.bin");
 MODULE_FIRMWARE("radeon/REDWOOD_rlc.bin");
+MODULE_FIRMWARE("radeon/REDWOOD_smc.bin");
 MODULE_FIRMWARE("radeon/JUNIPER_pfp.bin");
 MODULE_FIRMWARE("radeon/JUNIPER_me.bin");
 MODULE_FIRMWARE("radeon/JUNIPER_rlc.bin");
+MODULE_FIRMWARE("radeon/JUNIPER_smc.bin");
 MODULE_FIRMWARE("radeon/CYPRESS_pfp.bin");
 MODULE_FIRMWARE("radeon/CYPRESS_me.bin");
 MODULE_FIRMWARE("radeon/CYPRESS_rlc.bin");
+MODULE_FIRMWARE("radeon/CYPRESS_smc.bin");
 MODULE_FIRMWARE("radeon/PALM_pfp.bin");
 MODULE_FIRMWARE("radeon/PALM_me.bin");
 MODULE_FIRMWARE("radeon/SUMO_rlc.bin");
@@ -2214,19 +2218,27 @@ int r600_init_microcode(struct radeon_device *rdev)
 	case CHIP_CEDAR:
 		chip_name = "CEDAR";
 		rlc_chip_name = "CEDAR";
+		smc_chip_name = "CEDAR";
+		smc_req_size = ALIGN(CEDAR_SMC_UCODE_SIZE, 4);
 		break;
 	case CHIP_REDWOOD:
 		chip_name = "REDWOOD";
 		rlc_chip_name = "REDWOOD";
+		smc_chip_name = "REDWOOD";
+		smc_req_size = ALIGN(REDWOOD_SMC_UCODE_SIZE, 4);
 		break;
 	case CHIP_JUNIPER:
 		chip_name = "JUNIPER";
 		rlc_chip_name = "JUNIPER";
+		smc_chip_name = "JUNIPER";
+		smc_req_size = ALIGN(JUNIPER_SMC_UCODE_SIZE, 4);
 		break;
 	case CHIP_CYPRESS:
 	case CHIP_HEMLOCK:
 		chip_name = "CYPRESS";
 		rlc_chip_name = "CYPRESS";
+		smc_chip_name = "CYPRESS";
+		smc_req_size = ALIGN(CYPRESS_SMC_UCODE_SIZE, 4);
 		break;
 	case CHIP_PALM:
 		chip_name = "PALM";
@@ -2293,7 +2305,7 @@ int r600_init_microcode(struct radeon_device *rdev)
 		err = -EINVAL;
 	}
 
-	if ((rdev->family >= CHIP_RV770) && (rdev->family <= CHIP_RV740)) {
+	if ((rdev->family >= CHIP_RV770) && (rdev->family <= CHIP_HEMLOCK)) {
 		snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", smc_chip_name);
 		err = request_firmware(&rdev->smc_fw, fw_name, &pdev->dev);
 		if (err)
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 3e94920..037773d 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -2132,6 +2132,15 @@ void r100_pll_errata_after_index(struct radeon_device *rdev);
 #define ASIC_IS_NODCE(rdev) ((rdev->family == CHIP_HAINAN))
 #define ASIC_IS_DCE8(rdev) ((rdev->family >= CHIP_BONAIRE))
 
+#define ASIC_IS_LOMBOK(rdev) ((rdev->ddev->pdev->device == 0x6849) || \
+			      (rdev->ddev->pdev->device == 0x6850) || \
+			      (rdev->ddev->pdev->device == 0x6858) || \
+			      (rdev->ddev->pdev->device == 0x6859) || \
+			      (rdev->ddev->pdev->device == 0x6840) || \
+			      (rdev->ddev->pdev->device == 0x6841) || \
+			      (rdev->ddev->pdev->device == 0x6842) || \
+			      (rdev->ddev->pdev->device == 0x6843))
+
 /*
  * BIOS helpers.
  */
@@ -2356,6 +2365,10 @@ extern int ni_mc_load_microcode(struct radeon_device *rdev);
 #if defined(CONFIG_ACPI)
 extern int radeon_acpi_init(struct radeon_device *rdev);
 extern void radeon_acpi_fini(struct radeon_device *rdev);
+extern bool radeon_acpi_is_pcie_performance_request_supported(struct radeon_device *rdev);
+extern int radeon_acpi_pcie_performance_request(struct radeon_device *rdev,
+						u8 ref_req, bool advertise);
+extern int radeon_acpi_pcie_notify_device_ready(struct radeon_device *rdev);
 #else
 static inline int radeon_acpi_init(struct radeon_device *rdev) { return 0; }
 static inline void radeon_acpi_fini(struct radeon_device *rdev) { }
diff --git a/drivers/gpu/drm/radeon/radeon_acpi.c b/drivers/gpu/drm/radeon/radeon_acpi.c
index 196d28d..87419a4 100644
--- a/drivers/gpu/drm/radeon/radeon_acpi.c
+++ b/drivers/gpu/drm/radeon/radeon_acpi.c
@@ -78,6 +78,29 @@ struct atcs_verify_interface {
 	u32 function_bits;	/* supported functions bit vector */
 } __packed;
 
+bool radeon_acpi_is_pcie_performance_request_supported(struct radeon_device *rdev)
+{
+	/* XXX: query ATIF */
+
+	return false;
+}
+
+int radeon_acpi_pcie_notify_device_ready(struct radeon_device *rdev)
+{
+	/* XXX: call appropriate ATIF method */
+
+	return -EINVAL;
+
+}
+
+int radeon_acpi_pcie_performance_request(struct radeon_device *rdev,
+					 u8 ref_req, bool advertise)
+{
+	/* XXX: call appropriate ATIF method */
+
+	return -EINVAL;
+}
+
 /* Call the ATIF method
  */
 /**
diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c
index dbbcf33..077448f 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.c
+++ b/drivers/gpu/drm/radeon/radeon_asic.c
@@ -1428,6 +1428,18 @@ static struct radeon_asic evergreen_asic = {
 		.set_uvd_clocks = &evergreen_set_uvd_clocks,
 		.get_temperature = &evergreen_get_temp,
 	},
+	.dpm = {
+		.init = &cypress_dpm_init,
+		.setup_asic = &cypress_dpm_setup_asic,
+		.enable = &cypress_dpm_enable,
+		.disable = &cypress_dpm_disable,
+		.set_power_state = &cypress_dpm_set_power_state,
+		.display_configuration_changed = &cypress_dpm_display_configuration_changed,
+		.fini = &cypress_dpm_fini,
+		.get_sclk = &rv770_dpm_get_sclk,
+		.get_mclk = &rv770_dpm_get_mclk,
+		.print_power_state = &rv770_dpm_print_power_state,
+	},
 	.pflip = {
 		.pre_page_flip = &evergreen_pre_page_flip,
 		.page_flip = &evergreen_page_flip,
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index f7041a7..1f25b683 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -523,6 +523,13 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode
 int evergreen_get_temp(struct radeon_device *rdev);
 int sumo_get_temp(struct radeon_device *rdev);
 int tn_get_temp(struct radeon_device *rdev);
+int cypress_dpm_init(struct radeon_device *rdev);
+void cypress_dpm_setup_asic(struct radeon_device *rdev);
+int cypress_dpm_enable(struct radeon_device *rdev);
+void cypress_dpm_disable(struct radeon_device *rdev);
+int cypress_dpm_set_power_state(struct radeon_device *rdev);
+void cypress_dpm_display_configuration_changed(struct radeon_device *rdev);
+void cypress_dpm_fini(struct radeon_device *rdev);
 
 /*
  * cayman
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
index 595607c..d2265f4 100644
--- a/drivers/gpu/drm/radeon/radeon_pm.c
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
@@ -1044,6 +1044,11 @@ int radeon_pm_init(struct radeon_device *rdev)
 	case CHIP_RV730:
 	case CHIP_RV710:
 	case CHIP_RV740:
+	case CHIP_CEDAR:
+	case CHIP_REDWOOD:
+	case CHIP_JUNIPER:
+	case CHIP_CYPRESS:
+	case CHIP_HEMLOCK:
 		if (radeon_dpm == 1)
 			rdev->pm.pm_method = PM_METHOD_DPM;
 		else
diff --git a/drivers/gpu/drm/radeon/radeon_ucode.h b/drivers/gpu/drm/radeon/radeon_ucode.h
index 1910545..cb9c813 100644
--- a/drivers/gpu/drm/radeon/radeon_ucode.h
+++ b/drivers/gpu/drm/radeon/radeon_ucode.h
@@ -65,4 +65,24 @@
 #define RV740_SMC_INT_VECTOR_START   0xffc0
 #define RV740_SMC_INT_VECTOR_SIZE    0x0040
 
+#define CEDAR_SMC_UCODE_START        0x0100
+#define CEDAR_SMC_UCODE_SIZE         0x5d50
+#define CEDAR_SMC_INT_VECTOR_START   0xffc0
+#define CEDAR_SMC_INT_VECTOR_SIZE    0x0040
+
+#define REDWOOD_SMC_UCODE_START      0x0100
+#define REDWOOD_SMC_UCODE_SIZE       0x5f0a
+#define REDWOOD_SMC_INT_VECTOR_START 0xffc0
+#define REDWOOD_SMC_INT_VECTOR_SIZE  0x0040
+
+#define JUNIPER_SMC_UCODE_START      0x0100
+#define JUNIPER_SMC_UCODE_SIZE       0x5f1f
+#define JUNIPER_SMC_INT_VECTOR_START 0xffc0
+#define JUNIPER_SMC_INT_VECTOR_SIZE  0x0040
+
+#define CYPRESS_SMC_UCODE_START      0x0100
+#define CYPRESS_SMC_UCODE_SIZE       0x61f7
+#define CYPRESS_SMC_INT_VECTOR_START 0xffc0
+#define CYPRESS_SMC_INT_VECTOR_SIZE  0x0040
+
 #endif
diff --git a/drivers/gpu/drm/radeon/rv770_dpm.c b/drivers/gpu/drm/radeon/rv770_dpm.c
index 81660a6..8ea6d69 100644
--- a/drivers/gpu/drm/radeon/rv770_dpm.c
+++ b/drivers/gpu/drm/radeon/rv770_dpm.c
@@ -27,6 +27,7 @@
 #include "rv770d.h"
 #include "r600_dpm.h"
 #include "rv770_dpm.h"
+#include "cypress_dpm.h"
 #include "atom.h"
 
 #define MC_CG_ARB_FREQ_F0           0x0a
@@ -56,6 +57,13 @@ struct rv7xx_power_info *rv770_get_pi(struct radeon_device *rdev)
 	return pi;
 }
 
+struct evergreen_power_info *evergreen_get_pi(struct radeon_device *rdev)
+{
+	struct evergreen_power_info *pi = rdev->pm.dpm.priv;
+
+	return pi;
+}
+
 static void rv770_enable_bif_dynamic_pcie_gen2(struct radeon_device *rdev,
 					       bool enable)
 {
@@ -1795,8 +1803,8 @@ void rv770_enable_auto_throttle_source(struct radeon_device *rdev,
 	}
 }
 
-static int rv770_set_thermal_temperature_range(struct radeon_device *rdev,
-					       int min_temp, int max_temp)
+int rv770_set_thermal_temperature_range(struct radeon_device *rdev,
+					int min_temp, int max_temp)
 {
 	int low_temp = 0 * 1000;
 	int high_temp = 255 * 1000;
@@ -2045,6 +2053,7 @@ static void rv7xx_parse_pplib_clock_info(struct radeon_device *rdev,
 					 union pplib_clock_info *clock_info)
 {
 	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
 	struct rv7xx_ps *ps = rv770_get_ps(rps);
 	u32 sclk, mclk;
 	u16 vddc;
@@ -2063,13 +2072,24 @@ static void rv7xx_parse_pplib_clock_info(struct radeon_device *rdev,
 		break;
 	}
 
-	sclk = le16_to_cpu(clock_info->r600.usEngineClockLow);
-	sclk |= clock_info->r600.ucEngineClockHigh << 16;
-	mclk = le16_to_cpu(clock_info->r600.usMemoryClockLow);
-	mclk |= clock_info->r600.ucMemoryClockHigh << 16;
+	if (rdev->family >= CHIP_CEDAR) {
+		sclk = le16_to_cpu(clock_info->evergreen.usEngineClockLow);
+		sclk |= clock_info->evergreen.ucEngineClockHigh << 16;
+		mclk = le16_to_cpu(clock_info->evergreen.usMemoryClockLow);
+		mclk |= clock_info->evergreen.ucMemoryClockHigh << 16;
+
+		pl->vddc = le16_to_cpu(clock_info->evergreen.usVDDC);
+		pl->vddci = le16_to_cpu(clock_info->evergreen.usVDDCI);
+		pl->flags = le32_to_cpu(clock_info->evergreen.ulFlags);
+	} else {
+		sclk = le16_to_cpu(clock_info->r600.usEngineClockLow);
+		sclk |= clock_info->r600.ucEngineClockHigh << 16;
+		mclk = le16_to_cpu(clock_info->r600.usMemoryClockLow);
+		mclk |= clock_info->r600.ucMemoryClockHigh << 16;
 
-	pl->vddc = le16_to_cpu(clock_info->r600.usVDDC);
-	pl->flags = le32_to_cpu(clock_info->r600.ulFlags);
+		pl->vddc = le16_to_cpu(clock_info->r600.usVDDC);
+		pl->flags = le32_to_cpu(clock_info->r600.ulFlags);
+	}
 
 	pl->mclk = mclk;
 	pl->sclk = sclk;
@@ -2082,12 +2102,21 @@ static void rv7xx_parse_pplib_clock_info(struct radeon_device *rdev,
 
 	if (rps->class & ATOM_PPLIB_CLASSIFICATION_ACPI) {
 		pi->acpi_vddc = pl->vddc;
+		if (rdev->family >= CHIP_CEDAR)
+			eg_pi->acpi_vddci = pl->vddci;
 		if (ps->low.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2)
 			pi->acpi_pcie_gen2 = true;
 		else
 			pi->acpi_pcie_gen2 = false;
 	}
 
+	if (rps->class2 & ATOM_PPLIB_CLASSIFICATION2_ULV) {
+		if (rdev->family >= CHIP_BARTS) {
+			eg_pi->ulv.supported = true;
+			eg_pi->ulv.pl = pl;
+		}
+	}
+
 	if (pi->min_vddc_in_table > pl->vddc)
 		pi->min_vddc_in_table = pl->vddc;
 
diff --git a/drivers/gpu/drm/radeon/rv770_dpm.h b/drivers/gpu/drm/radeon/rv770_dpm.h
index df9aae5..bd6ea7b 100644
--- a/drivers/gpu/drm/radeon/rv770_dpm.h
+++ b/drivers/gpu/drm/radeon/rv770_dpm.h
@@ -269,4 +269,8 @@ int rv770_read_smc_soft_register(struct radeon_device *rdev,
 int rv770_write_smc_soft_register(struct radeon_device *rdev,
 				  u16 reg_offset, u32 value);
 
+/* thermal */
+int rv770_set_thermal_temperature_range(struct radeon_device *rdev,
+					int min_temp, int max_temp);
+
 #endif
diff --git a/drivers/gpu/drm/radeon/rv770_smc.c b/drivers/gpu/drm/radeon/rv770_smc.c
index 8e07153..168aedb 100644
--- a/drivers/gpu/drm/radeon/rv770_smc.c
+++ b/drivers/gpu/drm/radeon/rv770_smc.c
@@ -114,6 +114,86 @@ static const u8 rv740_smc_int_vectors[] =
 	0x03, 0x51, 0x03, 0x51
 };
 
+static const u8 cedar_smc_int_vectors[] =
+{
+	0x0B, 0x05, 0x0B, 0x05,
+	0x0B, 0x05, 0x0B, 0x05,
+	0x0B, 0x05, 0x0B, 0x05,
+	0x0B, 0x05, 0x0B, 0x05,
+	0x0B, 0x05, 0x0B, 0x05,
+	0x0B, 0x05, 0x0B, 0x05,
+	0x0B, 0x05, 0x0B, 0x05,
+	0x0B, 0x05, 0x0B, 0x05,
+	0x0B, 0x05, 0x0B, 0x05,
+	0x0B, 0x05, 0x0B, 0x05,
+	0x0B, 0x05, 0x0B, 0x05,
+	0x0B, 0x05, 0x0B, 0x05,
+	0x0B, 0x05, 0x11, 0x8B,
+	0x0B, 0x20, 0x0B, 0x05,
+	0x04, 0xF6, 0x04, 0xF6,
+	0x04, 0xF6, 0x04, 0xF6
+};
+
+static const u8 redwood_smc_int_vectors[] =
+{
+	0x0B, 0x05, 0x0B, 0x05,
+	0x0B, 0x05, 0x0B, 0x05,
+	0x0B, 0x05, 0x0B, 0x05,
+	0x0B, 0x05, 0x0B, 0x05,
+	0x0B, 0x05, 0x0B, 0x05,
+	0x0B, 0x05, 0x0B, 0x05,
+	0x0B, 0x05, 0x0B, 0x05,
+	0x0B, 0x05, 0x0B, 0x05,
+	0x0B, 0x05, 0x0B, 0x05,
+	0x0B, 0x05, 0x0B, 0x05,
+	0x0B, 0x05, 0x0B, 0x05,
+	0x0B, 0x05, 0x0B, 0x05,
+	0x0B, 0x05, 0x11, 0x8B,
+	0x0B, 0x20, 0x0B, 0x05,
+	0x04, 0xF6, 0x04, 0xF6,
+	0x04, 0xF6, 0x04, 0xF6
+};
+
+static const u8 juniper_smc_int_vectors[] =
+{
+	0x0B, 0x05, 0x0B, 0x05,
+	0x0B, 0x05, 0x0B, 0x05,
+	0x0B, 0x05, 0x0B, 0x05,
+	0x0B, 0x05, 0x0B, 0x05,
+	0x0B, 0x05, 0x0B, 0x05,
+	0x0B, 0x05, 0x0B, 0x05,
+	0x0B, 0x05, 0x0B, 0x05,
+	0x0B, 0x05, 0x0B, 0x05,
+	0x0B, 0x05, 0x0B, 0x05,
+	0x0B, 0x05, 0x0B, 0x05,
+	0x0B, 0x05, 0x0B, 0x05,
+	0x0B, 0x05, 0x0B, 0x05,
+	0x0B, 0x05, 0x11, 0x8B,
+	0x0B, 0x20, 0x0B, 0x05,
+	0x04, 0xF6, 0x04, 0xF6,
+	0x04, 0xF6, 0x04, 0xF6
+};
+
+static const u8 cypress_smc_int_vectors[] =
+{
+	0x0B, 0x05, 0x0B, 0x05,
+	0x0B, 0x05, 0x0B, 0x05,
+	0x0B, 0x05, 0x0B, 0x05,
+	0x0B, 0x05, 0x0B, 0x05,
+	0x0B, 0x05, 0x0B, 0x05,
+	0x0B, 0x05, 0x0B, 0x05,
+	0x0B, 0x05, 0x0B, 0x05,
+	0x0B, 0x05, 0x0B, 0x05,
+	0x0B, 0x05, 0x0B, 0x05,
+	0x0B, 0x05, 0x0B, 0x05,
+	0x0B, 0x05, 0x0B, 0x05,
+	0x0B, 0x05, 0x0B, 0x05,
+	0x0B, 0x05, 0x11, 0x8B,
+	0x0B, 0x20, 0x0B, 0x05,
+	0x04, 0xF6, 0x04, 0xF6,
+	0x04, 0xF6, 0x04, 0xF6
+};
+
 int rv770_set_smc_sram_address(struct radeon_device *rdev,
 			       u16 smc_address, u16 limit)
 {
@@ -354,6 +434,35 @@ int rv770_load_smc_ucode(struct radeon_device *rdev,
 		int_vect_start_address = RV740_SMC_INT_VECTOR_START;
 		int_vect_size = RV740_SMC_INT_VECTOR_SIZE;
 		break;
+	case CHIP_CEDAR:
+		ucode_start_address = CEDAR_SMC_UCODE_START;
+		ucode_size = CEDAR_SMC_UCODE_SIZE;
+		int_vect = (const u8 *)&cedar_smc_int_vectors;
+		int_vect_start_address = CEDAR_SMC_INT_VECTOR_START;
+		int_vect_size = CEDAR_SMC_INT_VECTOR_SIZE;
+		break;
+	case CHIP_REDWOOD:
+		ucode_start_address = REDWOOD_SMC_UCODE_START;
+		ucode_size = REDWOOD_SMC_UCODE_SIZE;
+		int_vect = (const u8 *)&redwood_smc_int_vectors;
+		int_vect_start_address = REDWOOD_SMC_INT_VECTOR_START;
+		int_vect_size = REDWOOD_SMC_INT_VECTOR_SIZE;
+		break;
+	case CHIP_JUNIPER:
+		ucode_start_address = JUNIPER_SMC_UCODE_START;
+		ucode_size = JUNIPER_SMC_UCODE_SIZE;
+		int_vect = (const u8 *)&juniper_smc_int_vectors;
+		int_vect_start_address = JUNIPER_SMC_INT_VECTOR_START;
+		int_vect_size = JUNIPER_SMC_INT_VECTOR_SIZE;
+		break;
+	case CHIP_CYPRESS:
+	case CHIP_HEMLOCK:
+		ucode_start_address = CYPRESS_SMC_UCODE_START;
+		ucode_size = CYPRESS_SMC_UCODE_SIZE;
+		int_vect = (const u8 *)&cypress_smc_int_vectors;
+		int_vect_start_address = CYPRESS_SMC_INT_VECTOR_START;
+		int_vect_size = CYPRESS_SMC_INT_VECTOR_SIZE;
+		break;
 	default:
 		DRM_ERROR("unknown asic in smc ucode loader\n");
 		BUG();
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 079/165] drm/radeon/kms: add dpm support for btc (v2)
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (78 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 078/165] drm/radeon/kms: add dpm support for evergreen (v2) alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 080/165] drm/radeon/kms: add dpm support for sumo asics alexdeucher
                   ` (33 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

This adds dpm support for btc asics.  This includes:
- clockgating
- dynamic engine clock scaling
- dynamic memory clock scaling
- dynamic voltage scaling
- dynamic pcie gen1/gen2 switching (requires additional acpi support)

Set radeon.dpm=1 to enable.

v2: reduce stack usage

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/Makefile       |    2 +-
 drivers/gpu/drm/radeon/btc_dpm.c      | 2183 +++++++++++++++++++++++++++++++++
 drivers/gpu/drm/radeon/btc_dpm.h      |   32 +
 drivers/gpu/drm/radeon/btcd.h         |  181 +++
 drivers/gpu/drm/radeon/ni.c           |   21 +
 drivers/gpu/drm/radeon/radeon_asic.c  |   12 +
 drivers/gpu/drm/radeon/radeon_asic.h  |    6 +
 drivers/gpu/drm/radeon/radeon_pm.c    |    3 +
 drivers/gpu/drm/radeon/radeon_ucode.h |   15 +
 drivers/gpu/drm/radeon/rv770_smc.c    |   81 ++
 10 files changed, 2535 insertions(+), 1 deletions(-)
 create mode 100644 drivers/gpu/drm/radeon/btc_dpm.c
 create mode 100644 drivers/gpu/drm/radeon/btc_dpm.h
 create mode 100644 drivers/gpu/drm/radeon/btcd.h

diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile
index 7092c96..af3dd8f 100644
--- a/drivers/gpu/drm/radeon/Makefile
+++ b/drivers/gpu/drm/radeon/Makefile
@@ -78,7 +78,7 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \
 	atombios_encoders.o radeon_semaphore.o radeon_sa.o atombios_i2c.o si.o \
 	si_blit_shaders.o radeon_prime.o radeon_uvd.o cik.o cik_blit_shaders.o \
 	r600_dpm.o rs780_dpm.o rv6xx_dpm.o rv770_dpm.o rv730_dpm.o rv740_dpm.o \
-	rv770_smc.o cypress_dpm.o
+	rv770_smc.o cypress_dpm.o btc_dpm.o
 
 radeon-$(CONFIG_COMPAT) += radeon_ioc32.o
 radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o
diff --git a/drivers/gpu/drm/radeon/btc_dpm.c b/drivers/gpu/drm/radeon/btc_dpm.c
new file mode 100644
index 0000000..6780120
--- /dev/null
+++ b/drivers/gpu/drm/radeon/btc_dpm.c
@@ -0,0 +1,2183 @@
+/*
+ * Copyright 2011 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Alex Deucher
+ */
+
+#include "drmP.h"
+#include "radeon.h"
+#include "btcd.h"
+#include "r600_dpm.h"
+#include "cypress_dpm.h"
+#include "btc_dpm.h"
+#include "atom.h"
+
+#define MC_CG_ARB_FREQ_F0           0x0a
+#define MC_CG_ARB_FREQ_F1           0x0b
+#define MC_CG_ARB_FREQ_F2           0x0c
+#define MC_CG_ARB_FREQ_F3           0x0d
+
+#define MC_CG_SEQ_DRAMCONF_S0       0x05
+#define MC_CG_SEQ_DRAMCONF_S1       0x06
+#define MC_CG_SEQ_YCLK_SUSPEND      0x04
+#define MC_CG_SEQ_YCLK_RESUME       0x0a
+
+#define SMC_RAM_END 0x8000
+
+#ifndef BTC_MGCG_SEQUENCE
+#define BTC_MGCG_SEQUENCE  300
+
+struct rv7xx_ps *rv770_get_ps(struct radeon_ps *rps);
+struct rv7xx_power_info *rv770_get_pi(struct radeon_device *rdev);
+struct evergreen_power_info *evergreen_get_pi(struct radeon_device *rdev);
+
+
+//********* BARTS **************//
+static const u32 barts_cgcg_cgls_default[] =
+{
+	/* Register,   Value,     Mask bits */
+	0x000008f8, 0x00000010, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000011, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000012, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000013, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000014, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000015, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000016, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000017, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000018, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000019, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x0000001a, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x0000001b, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000020, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000021, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000022, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000023, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000024, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000025, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000026, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000027, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000028, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000029, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x0000002a, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x0000002b, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff
+};
+#define BARTS_CGCG_CGLS_DEFAULT_LENGTH sizeof(barts_cgcg_cgls_default) / (3 * sizeof(u32))
+
+static const u32 barts_cgcg_cgls_disable[] =
+{
+	0x000008f8, 0x00000010, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000011, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000012, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000013, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000014, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000015, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000016, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000017, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000018, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000019, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x0000001a, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x0000001b, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000020, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000021, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000022, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000023, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000024, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000025, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000026, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000027, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000028, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000029, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x0000002a, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x0000002b, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x00000644, 0x000f7912, 0x001f4180,
+	0x00000644, 0x000f3812, 0x001f4180
+};
+#define BARTS_CGCG_CGLS_DISABLE_LENGTH sizeof(barts_cgcg_cgls_disable) / (3 * sizeof(u32))
+
+static const u32 barts_cgcg_cgls_enable[] =
+{
+	/* 0x0000c124, 0x84180000, 0x00180000, */
+	0x00000644, 0x000f7892, 0x001f4080,
+	0x000008f8, 0x00000010, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000011, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000012, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000013, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000014, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000015, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000016, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000017, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000018, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000019, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x0000001a, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x0000001b, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000020, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000021, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000022, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000023, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000024, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000025, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000026, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000027, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000028, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000029, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x0000002a, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x0000002b, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff
+};
+#define BARTS_CGCG_CGLS_ENABLE_LENGTH sizeof(barts_cgcg_cgls_enable) / (3 * sizeof(u32))
+
+static const u32 barts_mgcg_default[] =
+{
+	0x0000802c, 0xc0000000, 0xffffffff,
+	0x00005448, 0x00000100, 0xffffffff,
+	0x000055e4, 0x00600100, 0xffffffff,
+	0x0000160c, 0x00000100, 0xffffffff,
+	0x0000c164, 0x00000100, 0xffffffff,
+	0x00008a18, 0x00000100, 0xffffffff,
+	0x0000897c, 0x06000100, 0xffffffff,
+	0x00008b28, 0x00000100, 0xffffffff,
+	0x00009144, 0x00000100, 0xffffffff,
+	0x00009a60, 0x00000100, 0xffffffff,
+	0x00009868, 0x00000100, 0xffffffff,
+	0x00008d58, 0x00000100, 0xffffffff,
+	0x00009510, 0x00000100, 0xffffffff,
+	0x0000949c, 0x00000100, 0xffffffff,
+	0x00009654, 0x00000100, 0xffffffff,
+	0x00009030, 0x00000100, 0xffffffff,
+	0x00009034, 0x00000100, 0xffffffff,
+	0x00009038, 0x00000100, 0xffffffff,
+	0x0000903c, 0x00000100, 0xffffffff,
+	0x00009040, 0x00000100, 0xffffffff,
+	0x0000a200, 0x00000100, 0xffffffff,
+	0x0000a204, 0x00000100, 0xffffffff,
+	0x0000a208, 0x00000100, 0xffffffff,
+	0x0000a20c, 0x00000100, 0xffffffff,
+	0x0000977c, 0x00000100, 0xffffffff,
+	0x00003f80, 0x00000100, 0xffffffff,
+	0x0000a210, 0x00000100, 0xffffffff,
+	0x0000a214, 0x00000100, 0xffffffff,
+	0x000004d8, 0x00000100, 0xffffffff,
+	0x00009784, 0x00000100, 0xffffffff,
+	0x00009698, 0x00000100, 0xffffffff,
+	0x000004d4, 0x00000200, 0xffffffff,
+	0x000004d0, 0x00000000, 0xffffffff,
+	0x000030cc, 0x00000100, 0xffffffff,
+	0x0000d0c0, 0xff000100, 0xffffffff,
+	0x0000802c, 0x40000000, 0xffffffff,
+	0x0000915c, 0x00010000, 0xffffffff,
+	0x00009160, 0x00030002, 0xffffffff,
+	0x00009164, 0x00050004, 0xffffffff,
+	0x00009168, 0x00070006, 0xffffffff,
+	0x00009178, 0x00070000, 0xffffffff,
+	0x0000917c, 0x00030002, 0xffffffff,
+	0x00009180, 0x00050004, 0xffffffff,
+	0x0000918c, 0x00010006, 0xffffffff,
+	0x00009190, 0x00090008, 0xffffffff,
+	0x00009194, 0x00070000, 0xffffffff,
+	0x00009198, 0x00030002, 0xffffffff,
+	0x0000919c, 0x00050004, 0xffffffff,
+	0x000091a8, 0x00010006, 0xffffffff,
+	0x000091ac, 0x00090008, 0xffffffff,
+	0x000091b0, 0x00070000, 0xffffffff,
+	0x000091b4, 0x00030002, 0xffffffff,
+	0x000091b8, 0x00050004, 0xffffffff,
+	0x000091c4, 0x00010006, 0xffffffff,
+	0x000091c8, 0x00090008, 0xffffffff,
+	0x000091cc, 0x00070000, 0xffffffff,
+	0x000091d0, 0x00030002, 0xffffffff,
+	0x000091d4, 0x00050004, 0xffffffff,
+	0x000091e0, 0x00010006, 0xffffffff,
+	0x000091e4, 0x00090008, 0xffffffff,
+	0x000091e8, 0x00000000, 0xffffffff,
+	0x000091ec, 0x00070000, 0xffffffff,
+	0x000091f0, 0x00030002, 0xffffffff,
+	0x000091f4, 0x00050004, 0xffffffff,
+	0x00009200, 0x00010006, 0xffffffff,
+	0x00009204, 0x00090008, 0xffffffff,
+	0x00009208, 0x00070000, 0xffffffff,
+	0x0000920c, 0x00030002, 0xffffffff,
+	0x00009210, 0x00050004, 0xffffffff,
+	0x0000921c, 0x00010006, 0xffffffff,
+	0x00009220, 0x00090008, 0xffffffff,
+	0x00009224, 0x00070000, 0xffffffff,
+	0x00009228, 0x00030002, 0xffffffff,
+	0x0000922c, 0x00050004, 0xffffffff,
+	0x00009238, 0x00010006, 0xffffffff,
+	0x0000923c, 0x00090008, 0xffffffff,
+	0x00009294, 0x00000000, 0xffffffff,
+	0x0000802c, 0x40010000, 0xffffffff,
+	0x0000915c, 0x00010000, 0xffffffff,
+	0x00009160, 0x00030002, 0xffffffff,
+	0x00009164, 0x00050004, 0xffffffff,
+	0x00009168, 0x00070006, 0xffffffff,
+	0x00009178, 0x00070000, 0xffffffff,
+	0x0000917c, 0x00030002, 0xffffffff,
+	0x00009180, 0x00050004, 0xffffffff,
+	0x0000918c, 0x00010006, 0xffffffff,
+	0x00009190, 0x00090008, 0xffffffff,
+	0x00009194, 0x00070000, 0xffffffff,
+	0x00009198, 0x00030002, 0xffffffff,
+	0x0000919c, 0x00050004, 0xffffffff,
+	0x000091a8, 0x00010006, 0xffffffff,
+	0x000091ac, 0x00090008, 0xffffffff,
+	0x000091b0, 0x00070000, 0xffffffff,
+	0x000091b4, 0x00030002, 0xffffffff,
+	0x000091b8, 0x00050004, 0xffffffff,
+	0x000091c4, 0x00010006, 0xffffffff,
+	0x000091c8, 0x00090008, 0xffffffff,
+	0x000091cc, 0x00070000, 0xffffffff,
+	0x000091d0, 0x00030002, 0xffffffff,
+	0x000091d4, 0x00050004, 0xffffffff,
+	0x000091e0, 0x00010006, 0xffffffff,
+	0x000091e4, 0x00090008, 0xffffffff,
+	0x000091e8, 0x00000000, 0xffffffff,
+	0x000091ec, 0x00070000, 0xffffffff,
+	0x000091f0, 0x00030002, 0xffffffff,
+	0x000091f4, 0x00050004, 0xffffffff,
+	0x00009200, 0x00010006, 0xffffffff,
+	0x00009204, 0x00090008, 0xffffffff,
+	0x00009208, 0x00070000, 0xffffffff,
+	0x0000920c, 0x00030002, 0xffffffff,
+	0x00009210, 0x00050004, 0xffffffff,
+	0x0000921c, 0x00010006, 0xffffffff,
+	0x00009220, 0x00090008, 0xffffffff,
+	0x00009224, 0x00070000, 0xffffffff,
+	0x00009228, 0x00030002, 0xffffffff,
+	0x0000922c, 0x00050004, 0xffffffff,
+	0x00009238, 0x00010006, 0xffffffff,
+	0x0000923c, 0x00090008, 0xffffffff,
+	0x00009294, 0x00000000, 0xffffffff,
+	0x0000802c, 0xc0000000, 0xffffffff,
+	0x000008f8, 0x00000010, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000011, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000012, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000013, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000014, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000015, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000016, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000017, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000018, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000019, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x0000001a, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x0000001b, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff
+};
+#define BARTS_MGCG_DEFAULT_LENGTH sizeof(barts_mgcg_default) / (3 * sizeof(u32))
+
+static const u32 barts_mgcg_disable[] =
+{
+	0x0000802c, 0xc0000000, 0xffffffff,
+	0x000008f8, 0x00000000, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000001, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000002, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000003, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x00009150, 0x00600000, 0xffffffff
+};
+#define BARTS_MGCG_DISABLE_LENGTH sizeof(barts_mgcg_disable) / (3 * sizeof(u32))
+
+static const u32 barts_mgcg_enable[] =
+{
+	0x0000802c, 0xc0000000, 0xffffffff,
+	0x000008f8, 0x00000000, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000001, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000002, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000003, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x00009150, 0x81944000, 0xffffffff
+};
+#define BARTS_MGCG_ENABLE_LENGTH sizeof(barts_mgcg_enable) / (3 * sizeof(u32))
+
+//********* CAICOS **************//
+static const u32 caicos_cgcg_cgls_default[] =
+{
+	0x000008f8, 0x00000010, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000011, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000012, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000013, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000014, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000015, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000016, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000017, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000018, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000019, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x0000001a, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x0000001b, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000020, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000021, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000022, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000023, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000024, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000025, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000026, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000027, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000028, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000029, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x0000002a, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x0000002b, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff
+};
+#define CAICOS_CGCG_CGLS_DEFAULT_LENGTH sizeof(caicos_cgcg_cgls_default) / (3 * sizeof(u32))
+
+static const u32 caicos_cgcg_cgls_disable[] =
+{
+	0x000008f8, 0x00000010, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000011, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000012, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000013, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000014, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000015, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000016, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000017, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000018, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000019, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x0000001a, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x0000001b, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000020, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000021, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000022, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000023, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000024, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000025, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000026, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000027, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000028, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000029, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x0000002a, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x0000002b, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x00000644, 0x000f7912, 0x001f4180,
+	0x00000644, 0x000f3812, 0x001f4180
+};
+#define CAICOS_CGCG_CGLS_DISABLE_LENGTH sizeof(caicos_cgcg_cgls_disable) / (3 * sizeof(u32))
+
+static const u32 caicos_cgcg_cgls_enable[] =
+{
+	/* 0x0000c124, 0x84180000, 0x00180000, */
+	0x00000644, 0x000f7892, 0x001f4080,
+	0x000008f8, 0x00000010, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000011, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000012, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000013, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000014, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000015, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000016, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000017, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000018, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000019, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x0000001a, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x0000001b, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000020, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000021, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000022, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000023, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000024, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000025, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000026, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000027, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000028, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000029, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x0000002a, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x0000002b, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff
+};
+#define CAICOS_CGCG_CGLS_ENABLE_LENGTH sizeof(caicos_cgcg_cgls_enable) / (3 * sizeof(u32))
+
+static const u32 caicos_mgcg_default[] =
+{
+	0x0000802c, 0xc0000000, 0xffffffff,
+	0x00005448, 0x00000100, 0xffffffff,
+	0x000055e4, 0x00600100, 0xffffffff,
+	0x0000160c, 0x00000100, 0xffffffff,
+	0x0000c164, 0x00000100, 0xffffffff,
+	0x00008a18, 0x00000100, 0xffffffff,
+	0x0000897c, 0x06000100, 0xffffffff,
+	0x00008b28, 0x00000100, 0xffffffff,
+	0x00009144, 0x00000100, 0xffffffff,
+	0x00009a60, 0x00000100, 0xffffffff,
+	0x00009868, 0x00000100, 0xffffffff,
+	0x00008d58, 0x00000100, 0xffffffff,
+	0x00009510, 0x00000100, 0xffffffff,
+	0x0000949c, 0x00000100, 0xffffffff,
+	0x00009654, 0x00000100, 0xffffffff,
+	0x00009030, 0x00000100, 0xffffffff,
+	0x00009034, 0x00000100, 0xffffffff,
+	0x00009038, 0x00000100, 0xffffffff,
+	0x0000903c, 0x00000100, 0xffffffff,
+	0x00009040, 0x00000100, 0xffffffff,
+	0x0000a200, 0x00000100, 0xffffffff,
+	0x0000a204, 0x00000100, 0xffffffff,
+	0x0000a208, 0x00000100, 0xffffffff,
+	0x0000a20c, 0x00000100, 0xffffffff,
+	0x0000977c, 0x00000100, 0xffffffff,
+	0x00003f80, 0x00000100, 0xffffffff,
+	0x0000a210, 0x00000100, 0xffffffff,
+	0x0000a214, 0x00000100, 0xffffffff,
+	0x000004d8, 0x00000100, 0xffffffff,
+	0x00009784, 0x00000100, 0xffffffff,
+	0x00009698, 0x00000100, 0xffffffff,
+	0x000004d4, 0x00000200, 0xffffffff,
+	0x000004d0, 0x00000000, 0xffffffff,
+	0x000030cc, 0x00000100, 0xffffffff,
+	0x0000d0c0, 0xff000100, 0xffffffff,
+	0x0000915c, 0x00010000, 0xffffffff,
+	0x00009160, 0x00030002, 0xffffffff,
+	0x00009164, 0x00050004, 0xffffffff,
+	0x00009168, 0x00070006, 0xffffffff,
+	0x00009178, 0x00070000, 0xffffffff,
+	0x0000917c, 0x00030002, 0xffffffff,
+	0x00009180, 0x00050004, 0xffffffff,
+	0x0000918c, 0x00010006, 0xffffffff,
+	0x00009190, 0x00090008, 0xffffffff,
+	0x00009194, 0x00070000, 0xffffffff,
+	0x00009198, 0x00030002, 0xffffffff,
+	0x0000919c, 0x00050004, 0xffffffff,
+	0x000091a8, 0x00010006, 0xffffffff,
+	0x000091ac, 0x00090008, 0xffffffff,
+	0x000091e8, 0x00000000, 0xffffffff,
+	0x00009294, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000010, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000011, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000012, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000013, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000014, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000015, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000016, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000017, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000018, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000019, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x0000001a, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x0000001b, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff
+};
+#define CAICOS_MGCG_DEFAULT_LENGTH sizeof(caicos_mgcg_default) / (3 * sizeof(u32))
+
+static const u32 caicos_mgcg_disable[] =
+{
+	0x0000802c, 0xc0000000, 0xffffffff,
+	0x000008f8, 0x00000000, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000001, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000002, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000003, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x00009150, 0x00600000, 0xffffffff
+};
+#define CAICOS_MGCG_DISABLE_LENGTH sizeof(caicos_mgcg_disable) / (3 * sizeof(u32))
+
+static const u32 caicos_mgcg_enable[] =
+{
+	0x0000802c, 0xc0000000, 0xffffffff,
+	0x000008f8, 0x00000000, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000001, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000002, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000003, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x00009150, 0x46944040, 0xffffffff
+};
+#define CAICOS_MGCG_ENABLE_LENGTH sizeof(caicos_mgcg_enable) / (3 * sizeof(u32))
+
+//********* TURKS **************//
+static const u32 turks_cgcg_cgls_default[] =
+{
+	0x000008f8, 0x00000010, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000011, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000012, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000013, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000014, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000015, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000016, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000017, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000018, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000019, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x0000001a, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x0000001b, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000020, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000021, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000022, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000023, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000024, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000025, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000026, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000027, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000028, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000029, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x0000002a, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x0000002b, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff
+};
+#define TURKS_CGCG_CGLS_DEFAULT_LENGTH  sizeof(turks_cgcg_cgls_default) / (3 * sizeof(u32))
+
+static const u32 turks_cgcg_cgls_disable[] =
+{
+	0x000008f8, 0x00000010, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000011, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000012, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000013, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000014, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000015, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000016, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000017, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000018, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000019, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x0000001a, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x0000001b, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000020, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000021, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000022, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000023, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000024, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000025, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000026, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000027, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000028, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000029, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x0000002a, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x0000002b, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x00000644, 0x000f7912, 0x001f4180,
+	0x00000644, 0x000f3812, 0x001f4180
+};
+#define TURKS_CGCG_CGLS_DISABLE_LENGTH sizeof(turks_cgcg_cgls_disable) / (3 * sizeof(u32))
+
+static const u32 turks_cgcg_cgls_enable[] =
+{
+	/* 0x0000c124, 0x84180000, 0x00180000, */
+	0x00000644, 0x000f7892, 0x001f4080,
+	0x000008f8, 0x00000010, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000011, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000012, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000013, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000014, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000015, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000016, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000017, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000018, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000019, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x0000001a, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x0000001b, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000020, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000021, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000022, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000023, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000024, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000025, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000026, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000027, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000028, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000029, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x0000002a, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x0000002b, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff
+};
+#define TURKS_CGCG_CGLS_ENABLE_LENGTH sizeof(turks_cgcg_cgls_enable) / (3 * sizeof(u32))
+
+// These are the sequences for turks_mgcg_shls
+static const u32 turks_mgcg_default[] =
+{
+	0x0000802c, 0xc0000000, 0xffffffff,
+	0x00005448, 0x00000100, 0xffffffff,
+	0x000055e4, 0x00600100, 0xffffffff,
+	0x0000160c, 0x00000100, 0xffffffff,
+	0x0000c164, 0x00000100, 0xffffffff,
+	0x00008a18, 0x00000100, 0xffffffff,
+	0x0000897c, 0x06000100, 0xffffffff,
+	0x00008b28, 0x00000100, 0xffffffff,
+	0x00009144, 0x00000100, 0xffffffff,
+	0x00009a60, 0x00000100, 0xffffffff,
+	0x00009868, 0x00000100, 0xffffffff,
+	0x00008d58, 0x00000100, 0xffffffff,
+	0x00009510, 0x00000100, 0xffffffff,
+	0x0000949c, 0x00000100, 0xffffffff,
+	0x00009654, 0x00000100, 0xffffffff,
+	0x00009030, 0x00000100, 0xffffffff,
+	0x00009034, 0x00000100, 0xffffffff,
+	0x00009038, 0x00000100, 0xffffffff,
+	0x0000903c, 0x00000100, 0xffffffff,
+	0x00009040, 0x00000100, 0xffffffff,
+	0x0000a200, 0x00000100, 0xffffffff,
+	0x0000a204, 0x00000100, 0xffffffff,
+	0x0000a208, 0x00000100, 0xffffffff,
+	0x0000a20c, 0x00000100, 0xffffffff,
+	0x0000977c, 0x00000100, 0xffffffff,
+	0x00003f80, 0x00000100, 0xffffffff,
+	0x0000a210, 0x00000100, 0xffffffff,
+	0x0000a214, 0x00000100, 0xffffffff,
+	0x000004d8, 0x00000100, 0xffffffff,
+	0x00009784, 0x00000100, 0xffffffff,
+	0x00009698, 0x00000100, 0xffffffff,
+	0x000004d4, 0x00000200, 0xffffffff,
+	0x000004d0, 0x00000000, 0xffffffff,
+	0x000030cc, 0x00000100, 0xffffffff,
+	0x0000d0c0, 0x00000100, 0xffffffff,
+	0x0000915c, 0x00010000, 0xffffffff,
+	0x00009160, 0x00030002, 0xffffffff,
+	0x00009164, 0x00050004, 0xffffffff,
+	0x00009168, 0x00070006, 0xffffffff,
+	0x00009178, 0x00070000, 0xffffffff,
+	0x0000917c, 0x00030002, 0xffffffff,
+	0x00009180, 0x00050004, 0xffffffff,
+	0x0000918c, 0x00010006, 0xffffffff,
+	0x00009190, 0x00090008, 0xffffffff,
+	0x00009194, 0x00070000, 0xffffffff,
+	0x00009198, 0x00030002, 0xffffffff,
+	0x0000919c, 0x00050004, 0xffffffff,
+	0x000091a8, 0x00010006, 0xffffffff,
+	0x000091ac, 0x00090008, 0xffffffff,
+	0x000091b0, 0x00070000, 0xffffffff,
+	0x000091b4, 0x00030002, 0xffffffff,
+	0x000091b8, 0x00050004, 0xffffffff,
+	0x000091c4, 0x00010006, 0xffffffff,
+	0x000091c8, 0x00090008, 0xffffffff,
+	0x000091cc, 0x00070000, 0xffffffff,
+	0x000091d0, 0x00030002, 0xffffffff,
+	0x000091d4, 0x00050004, 0xffffffff,
+	0x000091e0, 0x00010006, 0xffffffff,
+	0x000091e4, 0x00090008, 0xffffffff,
+	0x000091e8, 0x00000000, 0xffffffff,
+	0x000091ec, 0x00070000, 0xffffffff,
+	0x000091f0, 0x00030002, 0xffffffff,
+	0x000091f4, 0x00050004, 0xffffffff,
+	0x00009200, 0x00010006, 0xffffffff,
+	0x00009204, 0x00090008, 0xffffffff,
+	0x00009208, 0x00070000, 0xffffffff,
+	0x0000920c, 0x00030002, 0xffffffff,
+	0x00009210, 0x00050004, 0xffffffff,
+	0x0000921c, 0x00010006, 0xffffffff,
+	0x00009220, 0x00090008, 0xffffffff,
+	0x00009294, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000010, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000011, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000012, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000013, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000014, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000015, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000016, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000017, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000018, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000019, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x0000001a, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x0000001b, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff
+};
+#define TURKS_MGCG_DEFAULT_LENGTH sizeof(turks_mgcg_default) / (3 * sizeof(u32))
+
+static const u32 turks_mgcg_disable[] =
+{
+	0x0000802c, 0xc0000000, 0xffffffff,
+	0x000008f8, 0x00000000, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000001, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000002, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000003, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x00009150, 0x00600000, 0xffffffff
+};
+#define TURKS_MGCG_DISABLE_LENGTH sizeof(turks_mgcg_disable) / (3 * sizeof(u32))
+
+static const u32 turks_mgcg_enable[] =
+{
+	0x0000802c, 0xc0000000, 0xffffffff,
+	0x000008f8, 0x00000000, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000001, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000002, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000003, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x00009150, 0x6e944000, 0xffffffff
+};
+#define TURKS_MGCG_ENABLE_LENGTH sizeof(turks_mgcg_enable) / (3 * sizeof(u32))
+
+#endif
+
+#ifndef BTC_SYSLS_SEQUENCE
+#define BTC_SYSLS_SEQUENCE  100
+
+
+//********* BARTS **************//
+static const u32 barts_sysls_default[] =
+{
+	/* Register,   Value,     Mask bits */
+	0x000055e8, 0x00000000, 0xffffffff,
+	0x0000d0bc, 0x00000000, 0xffffffff,
+	0x000015c0, 0x000c1401, 0xffffffff,
+	0x0000264c, 0x000c0400, 0xffffffff,
+	0x00002648, 0x000c0400, 0xffffffff,
+	0x00002650, 0x000c0400, 0xffffffff,
+	0x000020b8, 0x000c0400, 0xffffffff,
+	0x000020bc, 0x000c0400, 0xffffffff,
+	0x000020c0, 0x000c0c80, 0xffffffff,
+	0x0000f4a0, 0x000000c0, 0xffffffff,
+	0x0000f4a4, 0x00680fff, 0xffffffff,
+	0x000004c8, 0x00000001, 0xffffffff,
+	0x000064ec, 0x00000000, 0xffffffff,
+	0x00000c7c, 0x00000000, 0xffffffff,
+	0x00006dfc, 0x00000000, 0xffffffff
+};
+#define BARTS_SYSLS_DEFAULT_LENGTH sizeof(barts_sysls_default) / (3 * sizeof(u32))
+
+static const u32 barts_sysls_disable[] =
+{
+	0x000055e8, 0x00000000, 0xffffffff,
+	0x0000d0bc, 0x00000000, 0xffffffff,
+	0x000015c0, 0x00041401, 0xffffffff,
+	0x0000264c, 0x00040400, 0xffffffff,
+	0x00002648, 0x00040400, 0xffffffff,
+	0x00002650, 0x00040400, 0xffffffff,
+	0x000020b8, 0x00040400, 0xffffffff,
+	0x000020bc, 0x00040400, 0xffffffff,
+	0x000020c0, 0x00040c80, 0xffffffff,
+	0x0000f4a0, 0x000000c0, 0xffffffff,
+	0x0000f4a4, 0x00680000, 0xffffffff,
+	0x000004c8, 0x00000001, 0xffffffff,
+	0x000064ec, 0x00007ffd, 0xffffffff,
+	0x00000c7c, 0x0000ff00, 0xffffffff,
+	0x00006dfc, 0x0000007f, 0xffffffff
+};
+#define BARTS_SYSLS_DISABLE_LENGTH sizeof(barts_sysls_disable) / (3 * sizeof(u32))
+
+static const u32 barts_sysls_enable[] =
+{
+	0x000055e8, 0x00000001, 0xffffffff,
+	0x0000d0bc, 0x00000100, 0xffffffff,
+	0x000015c0, 0x000c1401, 0xffffffff,
+	0x0000264c, 0x000c0400, 0xffffffff,
+	0x00002648, 0x000c0400, 0xffffffff,
+	0x00002650, 0x000c0400, 0xffffffff,
+	0x000020b8, 0x000c0400, 0xffffffff,
+	0x000020bc, 0x000c0400, 0xffffffff,
+	0x000020c0, 0x000c0c80, 0xffffffff,
+	0x0000f4a0, 0x000000c0, 0xffffffff,
+	0x0000f4a4, 0x00680fff, 0xffffffff,
+	0x000004c8, 0x00000000, 0xffffffff,
+	0x000064ec, 0x00000000, 0xffffffff,
+	0x00000c7c, 0x00000000, 0xffffffff,
+	0x00006dfc, 0x00000000, 0xffffffff
+};
+#define BARTS_SYSLS_ENABLE_LENGTH sizeof(barts_sysls_enable) / (3 * sizeof(u32))
+
+//********* CAICOS **************//
+static const u32 caicos_sysls_default[] =
+{
+	0x000055e8, 0x00000000, 0xffffffff,
+	0x0000d0bc, 0x00000000, 0xffffffff,
+	0x000015c0, 0x000c1401, 0xffffffff,
+	0x0000264c, 0x000c0400, 0xffffffff,
+	0x00002648, 0x000c0400, 0xffffffff,
+	0x00002650, 0x000c0400, 0xffffffff,
+	0x000020b8, 0x000c0400, 0xffffffff,
+	0x000020bc, 0x000c0400, 0xffffffff,
+	0x0000f4a0, 0x000000c0, 0xffffffff,
+	0x0000f4a4, 0x00680fff, 0xffffffff,
+	0x000004c8, 0x00000001, 0xffffffff,
+	0x000064ec, 0x00000000, 0xffffffff,
+	0x00000c7c, 0x00000000, 0xffffffff,
+	0x00006dfc, 0x00000000, 0xffffffff
+};
+#define CAICOS_SYSLS_DEFAULT_LENGTH sizeof(caicos_sysls_default) / (3 * sizeof(u32))
+
+static const u32 caicos_sysls_disable[] =
+{
+	0x000055e8, 0x00000000, 0xffffffff,
+	0x0000d0bc, 0x00000000, 0xffffffff,
+	0x000015c0, 0x00041401, 0xffffffff,
+	0x0000264c, 0x00040400, 0xffffffff,
+	0x00002648, 0x00040400, 0xffffffff,
+	0x00002650, 0x00040400, 0xffffffff,
+	0x000020b8, 0x00040400, 0xffffffff,
+	0x000020bc, 0x00040400, 0xffffffff,
+	0x0000f4a0, 0x000000c0, 0xffffffff,
+	0x0000f4a4, 0x00680000, 0xffffffff,
+	0x000004c8, 0x00000001, 0xffffffff,
+	0x000064ec, 0x00007ffd, 0xffffffff,
+	0x00000c7c, 0x0000ff00, 0xffffffff,
+	0x00006dfc, 0x0000007f, 0xffffffff
+};
+#define CAICOS_SYSLS_DISABLE_LENGTH sizeof(caicos_sysls_disable) / (3 * sizeof(u32))
+
+static const u32 caicos_sysls_enable[] =
+{
+	0x000055e8, 0x00000001, 0xffffffff,
+	0x0000d0bc, 0x00000100, 0xffffffff,
+	0x000015c0, 0x000c1401, 0xffffffff,
+	0x0000264c, 0x000c0400, 0xffffffff,
+	0x00002648, 0x000c0400, 0xffffffff,
+	0x00002650, 0x000c0400, 0xffffffff,
+	0x000020b8, 0x000c0400, 0xffffffff,
+	0x000020bc, 0x000c0400, 0xffffffff,
+	0x0000f4a0, 0x000000c0, 0xffffffff,
+	0x0000f4a4, 0x00680fff, 0xffffffff,
+	0x000064ec, 0x00000000, 0xffffffff,
+	0x00000c7c, 0x00000000, 0xffffffff,
+	0x00006dfc, 0x00000000, 0xffffffff,
+	0x000004c8, 0x00000000, 0xffffffff
+};
+#define CAICOS_SYSLS_ENABLE_LENGTH sizeof(caicos_sysls_enable) / (3 * sizeof(u32))
+
+//********* TURKS **************//
+static const u32 turks_sysls_default[] =
+{
+	0x000055e8, 0x00000000, 0xffffffff,
+	0x0000d0bc, 0x00000000, 0xffffffff,
+	0x000015c0, 0x000c1401, 0xffffffff,
+	0x0000264c, 0x000c0400, 0xffffffff,
+	0x00002648, 0x000c0400, 0xffffffff,
+	0x00002650, 0x000c0400, 0xffffffff,
+	0x000020b8, 0x000c0400, 0xffffffff,
+	0x000020bc, 0x000c0400, 0xffffffff,
+	0x000020c0, 0x000c0c80, 0xffffffff,
+	0x0000f4a0, 0x000000c0, 0xffffffff,
+	0x0000f4a4, 0x00680fff, 0xffffffff,
+	0x000004c8, 0x00000001, 0xffffffff,
+	0x000064ec, 0x00000000, 0xffffffff,
+	0x00000c7c, 0x00000000, 0xffffffff,
+	0x00006dfc, 0x00000000, 0xffffffff
+};
+#define TURKS_SYSLS_DEFAULT_LENGTH sizeof(turks_sysls_default) / (3 * sizeof(u32))
+
+static const u32 turks_sysls_disable[] =
+{
+	0x000055e8, 0x00000000, 0xffffffff,
+	0x0000d0bc, 0x00000000, 0xffffffff,
+	0x000015c0, 0x00041401, 0xffffffff,
+	0x0000264c, 0x00040400, 0xffffffff,
+	0x00002648, 0x00040400, 0xffffffff,
+	0x00002650, 0x00040400, 0xffffffff,
+	0x000020b8, 0x00040400, 0xffffffff,
+	0x000020bc, 0x00040400, 0xffffffff,
+	0x000020c0, 0x00040c80, 0xffffffff,
+	0x0000f4a0, 0x000000c0, 0xffffffff,
+	0x0000f4a4, 0x00680000, 0xffffffff,
+	0x000004c8, 0x00000001, 0xffffffff,
+	0x000064ec, 0x00007ffd, 0xffffffff,
+	0x00000c7c, 0x0000ff00, 0xffffffff,
+	0x00006dfc, 0x0000007f, 0xffffffff
+};
+#define TURKS_SYSLS_DISABLE_LENGTH sizeof(turks_sysls_disable) / (3 * sizeof(u32))
+
+static const u32 turks_sysls_enable[] =
+{
+	0x000055e8, 0x00000001, 0xffffffff,
+	0x0000d0bc, 0x00000100, 0xffffffff,
+	0x000015c0, 0x000c1401, 0xffffffff,
+	0x0000264c, 0x000c0400, 0xffffffff,
+	0x00002648, 0x000c0400, 0xffffffff,
+	0x00002650, 0x000c0400, 0xffffffff,
+	0x000020b8, 0x000c0400, 0xffffffff,
+	0x000020bc, 0x000c0400, 0xffffffff,
+	0x000020c0, 0x000c0c80, 0xffffffff,
+	0x0000f4a0, 0x000000c0, 0xffffffff,
+	0x0000f4a4, 0x00680fff, 0xffffffff,
+	0x000004c8, 0x00000000, 0xffffffff,
+	0x000064ec, 0x00000000, 0xffffffff,
+	0x00000c7c, 0x00000000, 0xffffffff,
+	0x00006dfc, 0x00000000, 0xffffffff
+};
+#define TURKS_SYSLS_ENABLE_LENGTH sizeof(turks_sysls_enable) / (3 * sizeof(u32))
+
+#endif
+
+static void btc_enable_bif_dynamic_pcie_gen2(struct radeon_device *rdev,
+					     bool enable)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	u32 tmp, bif;
+
+	tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL);
+	if (enable) {
+		if ((tmp & LC_OTHER_SIDE_EVER_SENT_GEN2) &&
+		    (tmp & LC_OTHER_SIDE_SUPPORTS_GEN2)) {
+			if (!pi->boot_in_gen2) {
+				bif = RREG32(CG_BIF_REQ_AND_RSP) & ~CG_CLIENT_REQ_MASK;
+				bif |= CG_CLIENT_REQ(0xd);
+				WREG32(CG_BIF_REQ_AND_RSP, bif);
+
+				tmp &= ~LC_HW_VOLTAGE_IF_CONTROL_MASK;
+				tmp |= LC_HW_VOLTAGE_IF_CONTROL(1);
+				tmp |= LC_GEN2_EN_STRAP;
+
+				tmp |= LC_CLR_FAILED_SPD_CHANGE_CNT;
+				WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp);
+				udelay(10);
+				tmp &= ~LC_CLR_FAILED_SPD_CHANGE_CNT;
+				WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp);
+			}
+		}
+	} else {
+		if ((tmp & LC_OTHER_SIDE_EVER_SENT_GEN2) ||
+		    (tmp & LC_OTHER_SIDE_SUPPORTS_GEN2)) {
+			if (!pi->boot_in_gen2) {
+				bif = RREG32(CG_BIF_REQ_AND_RSP) & ~CG_CLIENT_REQ_MASK;
+				bif |= CG_CLIENT_REQ(0xd);
+				WREG32(CG_BIF_REQ_AND_RSP, bif);
+
+				tmp &= ~LC_HW_VOLTAGE_IF_CONTROL_MASK;
+				tmp &= ~LC_GEN2_EN_STRAP;
+			}
+			WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp);
+		}
+	}
+}
+
+static void btc_enable_dynamic_pcie_gen2(struct radeon_device *rdev,
+					 bool enable)
+{
+	btc_enable_bif_dynamic_pcie_gen2(rdev, enable);
+
+	if (enable)
+		WREG32_P(GENERAL_PWRMGT, ENABLE_GEN2PCIE, ~ENABLE_GEN2PCIE);
+	else
+		WREG32_P(GENERAL_PWRMGT, 0, ~ENABLE_GEN2PCIE);
+}
+
+static int btc_disable_ulv(struct radeon_device *rdev)
+{
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+
+	if (eg_pi->ulv.supported) {
+		if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_DisableULV) != PPSMC_Result_OK)
+			return -EINVAL;
+	}
+	return 0;
+}
+
+static int btc_populate_ulv_state(struct radeon_device *rdev,
+				  RV770_SMC_STATETABLE *table)
+{
+	int ret = -EINVAL;
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	struct rv7xx_pl *ulv_pl = eg_pi->ulv.pl;
+
+	if (ulv_pl->vddc) {
+		ret = cypress_convert_power_level_to_smc(rdev,
+							 ulv_pl,
+							 &table->ULVState.levels[0],
+							 PPSMC_DISPLAY_WATERMARK_LOW);
+		if (ret == 0) {
+			table->ULVState.levels[0].arbValue = MC_CG_ARB_FREQ_F0;
+			table->ULVState.levels[0].ACIndex = 1;
+
+			table->ULVState.levels[1] = table->ULVState.levels[0];
+			table->ULVState.levels[2] = table->ULVState.levels[0];
+
+			table->ULVState.flags |= PPSMC_SWSTATE_FLAG_DC;
+
+			WREG32(CG_ULV_CONTROL, BTC_CGULVCONTROL_DFLT);
+			WREG32(CG_ULV_PARAMETER, BTC_CGULVPARAMETER_DFLT);
+		}
+	}
+
+	return ret;
+}
+
+static int btc_populate_smc_acpi_state(struct radeon_device *rdev,
+				       RV770_SMC_STATETABLE *table)
+{
+	int ret = cypress_populate_smc_acpi_state(rdev, table);
+
+	if (ret == 0) {
+		table->ACPIState.levels[0].ACIndex = 0;
+		table->ACPIState.levels[1].ACIndex = 0;
+		table->ACPIState.levels[2].ACIndex = 0;
+	}
+
+	return ret;
+}
+
+static void btc_program_mgcg_hw_sequence(struct radeon_device *rdev,
+					 const u32 *sequence, u32 count)
+{
+	u32 i, length = count * 3;
+	u32 tmp;
+
+	for (i = 0; i < length; i+=3) {
+		tmp = RREG32(sequence[i]);
+		tmp &= ~sequence[i+2];
+		tmp |= sequence[i+1] & sequence[i+2];
+		WREG32(sequence[i], tmp);
+	}
+}
+
+static void btc_cg_clock_gating_default(struct radeon_device *rdev)
+{
+	u32 count;
+	const u32 *p = NULL;
+
+	if (rdev->family == CHIP_BARTS) {
+		p = (const u32 *)&barts_cgcg_cgls_default;
+		count = BARTS_CGCG_CGLS_DEFAULT_LENGTH;
+	} else if (rdev->family == CHIP_TURKS) {
+		p = (const u32 *)&turks_cgcg_cgls_default;
+		count = TURKS_CGCG_CGLS_DEFAULT_LENGTH;
+	} else if (rdev->family == CHIP_CAICOS) {
+		p = (const u32 *)&caicos_cgcg_cgls_default;
+		count = CAICOS_CGCG_CGLS_DEFAULT_LENGTH;
+	} else
+		return;
+
+	btc_program_mgcg_hw_sequence(rdev, p, count);
+}
+
+static void btc_cg_clock_gating_enable(struct radeon_device *rdev,
+				       bool enable)
+{
+	u32 count;
+	const u32 *p = NULL;
+
+	if (enable) {
+		if (rdev->family == CHIP_BARTS) {
+			p = (const u32 *)&barts_cgcg_cgls_enable;
+			count = BARTS_CGCG_CGLS_ENABLE_LENGTH;
+		} else if (rdev->family == CHIP_TURKS) {
+			p = (const u32 *)&turks_cgcg_cgls_enable;
+			count = TURKS_CGCG_CGLS_ENABLE_LENGTH;
+		} else if (rdev->family == CHIP_CAICOS) {
+			p = (const u32 *)&caicos_cgcg_cgls_enable;
+			count = CAICOS_CGCG_CGLS_ENABLE_LENGTH;
+		} else
+			return;
+	} else {
+		if (rdev->family == CHIP_BARTS) {
+			p = (const u32 *)&barts_cgcg_cgls_disable;
+			count = BARTS_CGCG_CGLS_DISABLE_LENGTH;
+		} else if (rdev->family == CHIP_TURKS) {
+			p = (const u32 *)&turks_cgcg_cgls_disable;
+			count = TURKS_CGCG_CGLS_DISABLE_LENGTH;
+		} else if (rdev->family == CHIP_CAICOS) {
+			p = (const u32 *)&caicos_cgcg_cgls_disable;
+			count = CAICOS_CGCG_CGLS_DISABLE_LENGTH;
+		} else
+			return;
+	}
+
+	btc_program_mgcg_hw_sequence(rdev, p, count);
+}
+
+static void btc_mg_clock_gating_default(struct radeon_device *rdev)
+{
+	u32 count;
+	const u32 *p = NULL;
+
+	if (rdev->family == CHIP_BARTS) {
+		p = (const u32 *)&barts_mgcg_default;
+		count = BARTS_MGCG_DEFAULT_LENGTH;
+	} else if (rdev->family == CHIP_TURKS) {
+		p = (const u32 *)&turks_mgcg_default;
+		count = TURKS_MGCG_DEFAULT_LENGTH;
+	} else if (rdev->family == CHIP_CAICOS) {
+		p = (const u32 *)&caicos_mgcg_default;
+		count = CAICOS_MGCG_DEFAULT_LENGTH;
+	} else
+		return;
+
+	btc_program_mgcg_hw_sequence(rdev, p, count);
+}
+
+static void btc_mg_clock_gating_enable(struct radeon_device *rdev,
+				       bool enable)
+{
+	u32 count;
+	const u32 *p = NULL;
+
+	if (enable) {
+		if (rdev->family == CHIP_BARTS) {
+			p = (const u32 *)&barts_mgcg_enable;
+			count = BARTS_MGCG_ENABLE_LENGTH;
+		} else if (rdev->family == CHIP_TURKS) {
+			p = (const u32 *)&turks_mgcg_enable;
+			count = TURKS_MGCG_ENABLE_LENGTH;
+		} else if (rdev->family == CHIP_CAICOS) {
+			p = (const u32 *)&caicos_mgcg_enable;
+			count = CAICOS_MGCG_ENABLE_LENGTH;
+		} else
+			return;
+	} else {
+		if (rdev->family == CHIP_BARTS) {
+			p = (const u32 *)&barts_mgcg_disable[0];
+			count = BARTS_MGCG_DISABLE_LENGTH;
+		} else if (rdev->family == CHIP_TURKS) {
+			p = (const u32 *)&turks_mgcg_disable[0];
+			count = TURKS_MGCG_DISABLE_LENGTH;
+		} else if (rdev->family == CHIP_CAICOS) {
+			p = (const u32 *)&caicos_mgcg_disable[0];
+			count = CAICOS_MGCG_DISABLE_LENGTH;
+		} else
+			return;
+	}
+
+	btc_program_mgcg_hw_sequence(rdev, p, count);
+}
+
+static void btc_ls_clock_gating_default(struct radeon_device *rdev)
+{
+	u32 count;
+	const u32 *p = NULL;
+
+	if (rdev->family == CHIP_BARTS) {
+		p = (const u32 *)&barts_sysls_default;
+		count = BARTS_SYSLS_DEFAULT_LENGTH;
+	} else if (rdev->family == CHIP_TURKS) {
+		p = (const u32 *)&turks_sysls_default;
+		count = TURKS_SYSLS_DEFAULT_LENGTH;
+	} else if (rdev->family == CHIP_CAICOS) {
+		p = (const u32 *)&caicos_sysls_default;
+		count = CAICOS_SYSLS_DEFAULT_LENGTH;
+	} else
+		return;
+
+	btc_program_mgcg_hw_sequence(rdev, p, count);
+}
+
+static void btc_ls_clock_gating_enable(struct radeon_device *rdev,
+				       bool enable)
+{
+	u32 count;
+	const u32 *p = NULL;
+
+	if (enable) {
+		if (rdev->family == CHIP_BARTS) {
+			p = (const u32 *)&barts_sysls_enable;
+			count = BARTS_SYSLS_ENABLE_LENGTH;
+		} else if (rdev->family == CHIP_TURKS) {
+			p = (const u32 *)&turks_sysls_enable;
+			count = TURKS_SYSLS_ENABLE_LENGTH;
+		} else if (rdev->family == CHIP_CAICOS) {
+			p = (const u32 *)&caicos_sysls_enable;
+			count = CAICOS_SYSLS_ENABLE_LENGTH;
+		} else
+			return;
+	} else {
+		if (rdev->family == CHIP_BARTS) {
+			p = (const u32 *)&barts_sysls_disable;
+			count = BARTS_SYSLS_DISABLE_LENGTH;
+		} else if (rdev->family == CHIP_TURKS) {
+			p = (const u32 *)&turks_sysls_disable;
+			count = TURKS_SYSLS_DISABLE_LENGTH;
+		} else if (rdev->family == CHIP_CAICOS) {
+			p = (const u32 *)&caicos_sysls_disable;
+			count = CAICOS_SYSLS_DISABLE_LENGTH;
+		} else
+			return;
+	}
+
+	btc_program_mgcg_hw_sequence(rdev, p, count);
+}
+
+static bool btc_dpm_enabled(struct radeon_device *rdev)
+{
+	if (rv770_is_smc_running(rdev))
+		return true;
+	else
+		return false;
+}
+
+static int btc_init_smc_table(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	struct radeon_ps *radeon_boot_state = rdev->pm.dpm.boot_ps;
+	RV770_SMC_STATETABLE *table = &pi->smc_statetable;
+	int ret;
+
+	memset(table, 0, sizeof(RV770_SMC_STATETABLE));
+
+	cypress_populate_smc_voltage_tables(rdev, table);
+
+	switch (rdev->pm.int_thermal_type) {
+        case THERMAL_TYPE_EVERGREEN:
+        case THERMAL_TYPE_EMC2103_WITH_INTERNAL:
+		table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_INTERNAL;
+		break;
+        case THERMAL_TYPE_NONE:
+		table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_NONE;
+		break;
+        default:
+		table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_EXTERNAL;
+		break;
+	}
+
+	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_HARDWAREDC)
+		table->systemFlags |= PPSMC_SYSTEMFLAG_GPIO_DC;
+
+	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_REGULATOR_HOT)
+		table->systemFlags |= PPSMC_SYSTEMFLAG_REGULATOR_HOT;
+
+	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC)
+		table->systemFlags |= PPSMC_SYSTEMFLAG_STEPVDDC;
+
+	if (pi->mem_gddr5)
+		table->systemFlags |= PPSMC_SYSTEMFLAG_GDDR5;
+
+	ret = cypress_populate_smc_initial_state(rdev, radeon_boot_state, table);
+	if (ret)
+		return ret;
+
+	if (eg_pi->sclk_deep_sleep)
+		WREG32_P(SCLK_PSKIP_CNTL, PSKIP_ON_ALLOW_STOP_HI(32),
+			 ~PSKIP_ON_ALLOW_STOP_HI_MASK);
+
+	ret = btc_populate_smc_acpi_state(rdev, table);
+	if (ret)
+		return ret;
+
+	if (eg_pi->ulv.supported) {
+		ret = btc_populate_ulv_state(rdev, table);
+		if (ret)
+			eg_pi->ulv.supported = false;
+	}
+
+	table->driverState = table->initialState;
+
+	return rv770_copy_bytes_to_smc(rdev,
+				       pi->state_table_start,
+				       (u8 *)table,
+				       sizeof(RV770_SMC_STATETABLE),
+				       pi->sram_end);
+}
+
+static int btc_reset_to_default(struct radeon_device *rdev)
+{
+	if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_ResetToDefaults) != PPSMC_Result_OK)
+		return -EINVAL;
+
+	return 0;
+}
+
+static void btc_stop_smc(struct radeon_device *rdev)
+{
+	int i;
+
+	for (i = 0; i < rdev->usec_timeout; i++) {
+		if (((RREG32(LB_SYNC_RESET_SEL) & LB_SYNC_RESET_SEL_MASK) >> LB_SYNC_RESET_SEL_SHIFT) != 1)
+			break;
+		udelay(1);
+	}
+	udelay(100);
+
+	r7xx_stop_smc(rdev);
+}
+
+static void btc_read_arb_registers(struct radeon_device *rdev)
+{
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	struct evergreen_arb_registers *arb_registers =
+		&eg_pi->bootup_arb_registers;
+
+	arb_registers->mc_arb_dram_timing = RREG32(MC_ARB_DRAM_TIMING);
+	arb_registers->mc_arb_dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2);
+	arb_registers->mc_arb_rfsh_rate = RREG32(MC_ARB_RFSH_RATE);
+	arb_registers->mc_arb_burst_time = RREG32(MC_ARB_BURST_TIME);
+}
+
+
+static void btc_set_arb0_registers(struct radeon_device *rdev,
+				   struct evergreen_arb_registers *arb_registers)
+{
+	u32 val;
+
+	WREG32(MC_ARB_DRAM_TIMING,  arb_registers->mc_arb_dram_timing);
+	WREG32(MC_ARB_DRAM_TIMING2, arb_registers->mc_arb_dram_timing2);
+
+	val = (arb_registers->mc_arb_rfsh_rate & POWERMODE0_MASK) >>
+		POWERMODE0_SHIFT;
+	WREG32_P(MC_ARB_RFSH_RATE, POWERMODE0(val), ~POWERMODE0_MASK);
+
+	val = (arb_registers->mc_arb_burst_time & STATE0_MASK) >>
+		STATE0_SHIFT;
+	WREG32_P(MC_ARB_BURST_TIME, STATE0(val), ~STATE0_MASK);
+}
+
+static void btc_set_boot_state_timing(struct radeon_device *rdev)
+{
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+
+	if (eg_pi->ulv.supported)
+		btc_set_arb0_registers(rdev, &eg_pi->bootup_arb_registers);
+}
+
+static bool btc_is_state_ulv_compatible(struct radeon_device *rdev,
+					struct radeon_ps *radeon_state)
+{
+	struct rv7xx_ps *state = rv770_get_ps(radeon_state);
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	struct rv7xx_pl *ulv_pl = eg_pi->ulv.pl;
+
+	if (state->low.mclk != ulv_pl->mclk)
+		return false;
+
+	if (state->low.vddci != ulv_pl->vddci)
+		return false;
+
+	/* XXX check minclocks, etc. */
+
+	return true;
+}
+
+
+static int btc_set_ulv_dram_timing(struct radeon_device *rdev)
+{
+	u32 val;
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	struct rv7xx_pl *ulv_pl = eg_pi->ulv.pl;
+
+	radeon_atom_set_engine_dram_timings(rdev,
+					    ulv_pl->sclk,
+					    ulv_pl->mclk);
+
+	val = rv770_calculate_memory_refresh_rate(rdev, ulv_pl->sclk);
+	WREG32_P(MC_ARB_RFSH_RATE, POWERMODE0(val), ~POWERMODE0_MASK);
+
+	val = cypress_calculate_burst_time(rdev, ulv_pl->sclk, ulv_pl->mclk);
+	WREG32_P(MC_ARB_BURST_TIME, STATE0(val), ~STATE0_MASK);
+
+	return 0;
+}
+
+static int btc_enable_ulv(struct radeon_device *rdev)
+{
+	if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_EnableULV) != PPSMC_Result_OK)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int btc_set_power_state_conditionally_enable_ulv(struct radeon_device *rdev)
+{
+	int ret = 0;
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	struct radeon_ps *radeon_new_state = rdev->pm.dpm.requested_ps;
+
+	if (eg_pi->ulv.supported) {
+		if (btc_is_state_ulv_compatible(rdev, radeon_new_state)) {
+			// Set ARB[0] to reflect the DRAM timing needed for ULV.
+			ret = btc_set_ulv_dram_timing(rdev);
+			if (ret == 0)
+				ret = btc_enable_ulv(rdev);
+		}
+	}
+
+	return ret;
+}
+
+static bool btc_check_s0_mc_reg_index(u16 in_reg, u16 *out_reg)
+{
+	bool result = true;
+
+	switch (in_reg) {
+	case MC_SEQ_RAS_TIMING >> 2:
+		*out_reg = MC_SEQ_RAS_TIMING_LP >> 2;
+		break;
+        case MC_SEQ_CAS_TIMING >> 2:
+		*out_reg = MC_SEQ_CAS_TIMING_LP >> 2;
+		break;
+        case MC_SEQ_MISC_TIMING >> 2:
+		*out_reg = MC_SEQ_MISC_TIMING_LP >> 2;
+		break;
+        case MC_SEQ_MISC_TIMING2 >> 2:
+		*out_reg = MC_SEQ_MISC_TIMING2_LP >> 2;
+		break;
+        case MC_SEQ_RD_CTL_D0 >> 2:
+		*out_reg = MC_SEQ_RD_CTL_D0_LP >> 2;
+		break;
+        case MC_SEQ_RD_CTL_D1 >> 2:
+		*out_reg = MC_SEQ_RD_CTL_D1_LP >> 2;
+		break;
+        case MC_SEQ_WR_CTL_D0 >> 2:
+		*out_reg = MC_SEQ_WR_CTL_D0_LP >> 2;
+		break;
+        case MC_SEQ_WR_CTL_D1 >> 2:
+		*out_reg = MC_SEQ_WR_CTL_D1_LP >> 2;
+		break;
+        case MC_PMG_CMD_EMRS >> 2:
+		*out_reg = MC_SEQ_PMG_CMD_EMRS_LP >> 2;
+		break;
+        case MC_PMG_CMD_MRS >> 2:
+		*out_reg = MC_SEQ_PMG_CMD_MRS_LP >> 2;
+		break;
+        case MC_PMG_CMD_MRS1 >> 2:
+		*out_reg = MC_SEQ_PMG_CMD_MRS1_LP >> 2;
+		break;
+        default:
+		result = false;
+		break;
+	}
+
+	return result;
+}
+
+static void btc_set_valid_flag(struct evergreen_mc_reg_table *table)
+{
+	u8 i, j;
+
+	for (i = 0; i < table->last; i++) {
+		for (j = 1; j < table->num_entries; j++) {
+			if (table->mc_reg_table_entry[j-1].mc_data[i] !=
+			    table->mc_reg_table_entry[j].mc_data[i]) {
+				table->valid_flag |= (1 << i);
+				break;
+			}
+		}
+	}
+}
+
+static int btc_set_mc_special_registers(struct radeon_device *rdev,
+					struct evergreen_mc_reg_table *table)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	u8 i, j, k;
+	u32 tmp;
+
+	for (i = 0, j = table->last; i < table->last; i++) {
+		switch (table->mc_reg_address[i].s1) {
+		case MC_SEQ_MISC1 >> 2:
+			tmp = RREG32(MC_PMG_CMD_EMRS);
+			table->mc_reg_address[j].s1 = MC_PMG_CMD_EMRS >> 2;
+			table->mc_reg_address[j].s0 = MC_SEQ_PMG_CMD_EMRS_LP >> 2;
+			for (k = 0; k < table->num_entries; k++) {
+				table->mc_reg_table_entry[k].mc_data[j] =
+					((tmp & 0xffff0000)) |
+					((table->mc_reg_table_entry[k].mc_data[i] & 0xffff0000) >> 16);
+			}
+			j++;
+
+			if (j > SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE)
+				return -EINVAL;
+
+			tmp = RREG32(MC_PMG_CMD_MRS);
+			table->mc_reg_address[j].s1 = MC_PMG_CMD_MRS >> 2;
+			table->mc_reg_address[j].s0 = MC_SEQ_PMG_CMD_MRS_LP >> 2;
+			for (k = 0; k < table->num_entries; k++) {
+				table->mc_reg_table_entry[k].mc_data[j] =
+					(tmp & 0xffff0000) |
+					(table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff);
+				if (!pi->mem_gddr5)
+					table->mc_reg_table_entry[k].mc_data[j] |= 0x100;
+			}
+			j++;
+
+			if (j > SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE)
+				return -EINVAL;
+			break;
+		case MC_SEQ_RESERVE_M >> 2:
+			tmp = RREG32(MC_PMG_CMD_MRS1);
+			table->mc_reg_address[j].s1 = MC_PMG_CMD_MRS1 >> 2;
+			table->mc_reg_address[j].s0 = MC_SEQ_PMG_CMD_MRS1_LP >> 2;
+			for (k = 0; k < table->num_entries; k++) {
+				table->mc_reg_table_entry[k].mc_data[j] =
+					(tmp & 0xffff0000) |
+					(table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff);
+			}
+			j++;
+
+			if (j > SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE)
+				return -EINVAL;
+			break;
+		default:
+			break;
+		}
+	}
+
+	table->last = j;
+
+	return 0;
+}
+
+static void btc_set_s0_mc_reg_index(struct evergreen_mc_reg_table *table)
+{
+	u32 i;
+	u16 address;
+
+	for (i = 0; i < table->last; i++) {
+		table->mc_reg_address[i].s0 =
+			btc_check_s0_mc_reg_index(table->mc_reg_address[i].s1, &address) ?
+			address : table->mc_reg_address[i].s1;
+	}
+}
+
+static int btc_copy_vbios_mc_reg_table(struct atom_mc_reg_table *table,
+				       struct evergreen_mc_reg_table *eg_table)
+{
+	u8 i, j;
+
+	if (table->last > SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE)
+		return -EINVAL;
+
+	if (table->num_entries > MAX_AC_TIMING_ENTRIES)
+		return -EINVAL;
+
+	for (i = 0; i < table->last; i++)
+		eg_table->mc_reg_address[i].s1 = table->mc_reg_address[i].s1;
+	eg_table->last = table->last;
+
+	for (i = 0; i < table->num_entries; i++) {
+		eg_table->mc_reg_table_entry[i].mclk_max =
+			table->mc_reg_table_entry[i].mclk_max;
+		for(j = 0; j < table->last; j++)
+			eg_table->mc_reg_table_entry[i].mc_data[j] =
+				table->mc_reg_table_entry[i].mc_data[j];
+	}
+	eg_table->num_entries = table->num_entries;
+
+	return 0;
+}
+
+static int btc_initialize_mc_reg_table(struct radeon_device *rdev)
+{
+	int ret;
+	struct atom_mc_reg_table *table;
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	struct evergreen_mc_reg_table *eg_table = &eg_pi->mc_reg_table;
+	u8 module_index = rv770_get_memory_module_index(rdev);
+
+	table = kzalloc(sizeof(struct atom_mc_reg_table), GFP_KERNEL);
+	if (!table)
+		return -ENOMEM;
+
+	/* Program additional LP registers that are no longer programmed by VBIOS */
+	WREG32(MC_SEQ_RAS_TIMING_LP, RREG32(MC_SEQ_RAS_TIMING));
+	WREG32(MC_SEQ_CAS_TIMING_LP, RREG32(MC_SEQ_CAS_TIMING));
+	WREG32(MC_SEQ_MISC_TIMING_LP, RREG32(MC_SEQ_MISC_TIMING));
+	WREG32(MC_SEQ_MISC_TIMING2_LP, RREG32(MC_SEQ_MISC_TIMING2));
+	WREG32(MC_SEQ_RD_CTL_D0_LP, RREG32(MC_SEQ_RD_CTL_D0));
+	WREG32(MC_SEQ_RD_CTL_D1_LP, RREG32(MC_SEQ_RD_CTL_D1));
+	WREG32(MC_SEQ_WR_CTL_D0_LP, RREG32(MC_SEQ_WR_CTL_D0));
+	WREG32(MC_SEQ_WR_CTL_D1_LP, RREG32(MC_SEQ_WR_CTL_D1));
+	WREG32(MC_SEQ_PMG_CMD_EMRS_LP, RREG32(MC_PMG_CMD_EMRS));
+	WREG32(MC_SEQ_PMG_CMD_MRS_LP, RREG32(MC_PMG_CMD_MRS));
+	WREG32(MC_SEQ_PMG_CMD_MRS1_LP, RREG32(MC_PMG_CMD_MRS1));
+
+	ret = radeon_atom_init_mc_reg_table(rdev, module_index, table);
+
+	if (ret)
+		goto init_mc_done;
+
+	ret = btc_copy_vbios_mc_reg_table(table, eg_table);
+
+	if (ret)
+		goto init_mc_done;
+
+	btc_set_s0_mc_reg_index(eg_table);
+	ret = btc_set_mc_special_registers(rdev, eg_table);
+
+	if (ret)
+		goto init_mc_done;
+
+	btc_set_valid_flag(eg_table);
+
+init_mc_done:
+	kfree(table);
+
+	return ret;
+}
+
+static void btc_init_stutter_mode(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	u32 tmp;
+
+	if (pi->mclk_stutter_mode_threshold) {
+		if (pi->mem_gddr5) {
+			tmp = RREG32(MC_PMG_AUTO_CFG);
+			if ((0x200 & tmp) == 0) {
+				tmp = (tmp & 0xfffffc0b) | 0x204;
+				WREG32(MC_PMG_AUTO_CFG, tmp);
+			}
+		}
+	}
+}
+
+void btc_dpm_reset_asic(struct radeon_device *rdev)
+{
+	rv770_restrict_performance_levels_before_switch(rdev);
+	btc_disable_ulv(rdev);
+	btc_set_boot_state_timing(rdev);
+	rv770_set_boot_state(rdev);
+}
+
+int btc_dpm_set_power_state(struct radeon_device *rdev)
+{
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+
+	btc_disable_ulv(rdev);
+	btc_set_boot_state_timing(rdev);
+	rv770_restrict_performance_levels_before_switch(rdev);
+
+	if (eg_pi->pcie_performance_request)
+		cypress_notify_link_speed_change_before_state_change(rdev);
+
+	rv770_halt_smc(rdev);
+	cypress_upload_sw_state(rdev);
+
+	if (eg_pi->dynamic_ac_timing)
+		cypress_upload_mc_reg_table(rdev);
+
+	cypress_program_memory_timing_parameters(rdev);
+
+	rv770_resume_smc(rdev);
+	rv770_set_sw_state(rdev);
+
+	if (eg_pi->pcie_performance_request)
+		cypress_notify_link_speed_change_after_state_change(rdev);
+
+	btc_set_power_state_conditionally_enable_ulv(rdev);
+
+	return 0;
+}
+
+int btc_dpm_enable(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+
+	if (pi->gfx_clock_gating)
+		btc_cg_clock_gating_default(rdev);
+
+	if (btc_dpm_enabled(rdev))
+		return -EINVAL;
+
+	if (pi->mg_clock_gating)
+		btc_mg_clock_gating_default(rdev);
+
+	if (eg_pi->ls_clock_gating)
+		btc_ls_clock_gating_default(rdev);
+
+	if (pi->voltage_control) {
+		rv770_enable_voltage_control(rdev, true);
+		cypress_construct_voltage_tables(rdev);
+	}
+
+	if (pi->mvdd_control)
+		cypress_get_mvdd_configuration(rdev);
+
+	if (eg_pi->dynamic_ac_timing)
+		btc_initialize_mc_reg_table(rdev);
+
+	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS)
+		rv770_enable_backbias(rdev, true);
+
+	if (pi->dynamic_ss)
+		cypress_enable_spread_spectrum(rdev, true);
+
+	if (pi->thermal_protection)
+		rv770_enable_thermal_protection(rdev, true);
+
+	rv770_setup_bsp(rdev);
+	rv770_program_git(rdev);
+	rv770_program_tp(rdev);
+	rv770_program_tpp(rdev);
+	rv770_program_sstp(rdev);
+	rv770_program_engine_speed_parameters(rdev);
+	cypress_enable_display_gap(rdev);
+	rv770_program_vc(rdev);
+
+	if (pi->dynamic_pcie_gen2)
+		btc_enable_dynamic_pcie_gen2(rdev, true);
+
+	if (rv770_upload_firmware(rdev))
+		return -EINVAL;
+
+	cypress_get_table_locations(rdev);
+	btc_init_smc_table(rdev);
+
+	if (eg_pi->dynamic_ac_timing)
+		cypress_populate_mc_reg_table(rdev);
+
+	cypress_program_response_times(rdev);
+	r7xx_start_smc(rdev);
+	cypress_notify_smc_display_change(rdev, false);
+	cypress_enable_sclk_control(rdev, true);
+
+	if (eg_pi->memory_transition)
+		cypress_enable_mclk_control(rdev, true);
+
+	cypress_start_dpm(rdev);
+
+	if (pi->gfx_clock_gating)
+		btc_cg_clock_gating_enable(rdev, true);
+
+	if (pi->mg_clock_gating)
+		btc_mg_clock_gating_enable(rdev, true);
+
+	if (eg_pi->ls_clock_gating)
+		btc_ls_clock_gating_enable(rdev, true);
+
+	if (rdev->irq.installed &&
+	    r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
+		PPSMC_Result result;
+
+		rv770_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
+		rdev->irq.dpm_thermal = true;
+		radeon_irq_set(rdev);
+		result = rv770_send_msg_to_smc(rdev, PPSMC_MSG_EnableThermalInterrupt);
+
+		if (result != PPSMC_Result_OK)
+			DRM_DEBUG_KMS("Could not enable thermal interrupts.\n");
+	}
+
+	rv770_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true);
+
+	btc_init_stutter_mode(rdev);
+
+	return 0;
+};
+
+void btc_dpm_disable(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+
+	if (!btc_dpm_enabled(rdev))
+		return;
+
+	rv770_clear_vc(rdev);
+
+	if (pi->thermal_protection)
+		rv770_enable_thermal_protection(rdev, false);
+
+	if (pi->dynamic_pcie_gen2)
+		btc_enable_dynamic_pcie_gen2(rdev, false);
+
+	if (rdev->irq.installed &&
+	    r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
+		rdev->irq.dpm_thermal = false;
+		radeon_irq_set(rdev);
+	}
+
+	if (pi->gfx_clock_gating)
+		btc_cg_clock_gating_enable(rdev, false);
+
+	if (pi->mg_clock_gating)
+		btc_mg_clock_gating_enable(rdev, false);
+
+	if (eg_pi->ls_clock_gating)
+		btc_ls_clock_gating_enable(rdev, false);
+
+	rv770_stop_dpm(rdev);
+	btc_reset_to_default(rdev);
+	btc_stop_smc(rdev);
+	cypress_enable_spread_spectrum(rdev, false);
+}
+
+void btc_dpm_setup_asic(struct radeon_device *rdev)
+{
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+
+	rv770_get_memory_type(rdev);
+	rv740_read_clock_registers(rdev);
+	btc_read_arb_registers(rdev);
+	rv770_read_voltage_smio_registers(rdev);
+
+	if (eg_pi->pcie_performance_request)
+		cypress_advertise_gen2_capability(rdev);
+
+	rv770_get_pcie_gen2_status(rdev);
+	rv770_enable_acpi_pm(rdev);
+}
+
+int btc_dpm_init(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi;
+	struct evergreen_power_info *eg_pi;
+	int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info);
+	u16 data_offset, size;
+	u8 frev, crev;
+	struct atom_clock_dividers dividers;
+	int ret;
+
+	eg_pi = kzalloc(sizeof(struct evergreen_power_info), GFP_KERNEL);
+	if (eg_pi == NULL)
+		return -ENOMEM;
+	rdev->pm.dpm.priv = eg_pi;
+	pi = &eg_pi->rv7xx;
+
+	rv770_get_max_vddc(rdev);
+
+	eg_pi->ulv.supported = false;
+	pi->acpi_vddc = 0;
+	eg_pi->acpi_vddci = 0;
+	pi->min_vddc_in_table = 0;
+	pi->max_vddc_in_table = 0;
+
+	ret = rv7xx_parse_power_table(rdev);
+	if (ret)
+		return ret;
+
+	if (rdev->pm.dpm.voltage_response_time == 0)
+		rdev->pm.dpm.voltage_response_time = R600_VOLTAGERESPONSETIME_DFLT;
+	if (rdev->pm.dpm.backbias_response_time == 0)
+		rdev->pm.dpm.backbias_response_time = R600_BACKBIASRESPONSETIME_DFLT;
+
+	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
+					     0, false, &dividers);
+	if (ret)
+		pi->ref_div = dividers.ref_div + 1;
+	else
+		pi->ref_div = R600_REFERENCEDIVIDER_DFLT;
+
+	pi->mclk_strobe_mode_threshold = 40000;
+	pi->mclk_edc_enable_threshold = 40000;
+	eg_pi->mclk_edc_wr_enable_threshold = 40000;
+
+	pi->voltage_control =
+		radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC);
+
+	pi->mvdd_control =
+		radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_MVDDC);
+
+	eg_pi->vddci_control =
+		radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDCI);
+
+	if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
+                                   &frev, &crev, &data_offset)) {
+		pi->sclk_ss = true;
+		pi->mclk_ss = true;
+		pi->dynamic_ss = true;
+	} else {
+		pi->sclk_ss = false;
+		pi->mclk_ss = false;
+		pi->dynamic_ss = true;
+	}
+
+	pi->asi = RV770_ASI_DFLT;
+	pi->pasi = CYPRESS_HASI_DFLT;
+	pi->vrc = CYPRESS_VRC_DFLT;
+
+	pi->power_gating = false;
+
+	pi->gfx_clock_gating = true;
+
+	pi->mg_clock_gating = true;
+	pi->mgcgtssm = true;
+	eg_pi->ls_clock_gating = false;
+	eg_pi->sclk_deep_sleep = false;
+
+	pi->dynamic_pcie_gen2 = true;
+
+	if (pi->gfx_clock_gating &&
+	    (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE))
+		pi->thermal_protection = true;
+	else
+		pi->thermal_protection = false;
+
+	pi->display_gap = true;
+
+	if (rdev->flags & RADEON_IS_MOBILITY)
+		pi->dcodt = true;
+	else
+		pi->dcodt = false;
+
+	pi->ulps = true;
+
+	eg_pi->dynamic_ac_timing = true;
+	eg_pi->abm = true;
+	eg_pi->mcls = true;
+	eg_pi->light_sleep = true;
+	eg_pi->memory_transition = true;
+#if defined(CONFIG_ACPI)
+	eg_pi->pcie_performance_request =
+		radeon_acpi_is_pcie_performance_request_supported(rdev);
+#else
+	eg_pi->pcie_performance_request = false;
+#endif
+
+	if (rdev->family == CHIP_BARTS)
+		eg_pi->dll_default_on = true;
+	else
+		eg_pi->dll_default_on = false;
+
+	eg_pi->sclk_deep_sleep = false;
+	if (ASIC_IS_LOMBOK(rdev))
+		pi->mclk_stutter_mode_threshold = 30000;
+	else
+		pi->mclk_stutter_mode_threshold = 0;
+
+	pi->sram_end = SMC_RAM_END;
+
+	return 0;
+}
+
+void btc_dpm_fini(struct radeon_device *rdev)
+{
+	int i;
+
+	for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
+		kfree(rdev->pm.dpm.ps[i].ps_priv);
+	}
+	kfree(rdev->pm.dpm.ps);
+	kfree(rdev->pm.dpm.priv);
+}
diff --git a/drivers/gpu/drm/radeon/btc_dpm.h b/drivers/gpu/drm/radeon/btc_dpm.h
new file mode 100644
index 0000000..a095d40
--- /dev/null
+++ b/drivers/gpu/drm/radeon/btc_dpm.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2011 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef __BTC_DPM_H__
+#define __BTC_DPM_H__
+
+#define BARTS_MGCGCGTSSMCTRL_DFLT                     0x81944000
+#define TURKS_MGCGCGTSSMCTRL_DFLT                     0x6e944000
+#define CAICOS_MGCGCGTSSMCTRL_DFLT                    0x46944040
+#define BTC_CGULVPARAMETER_DFLT                       0x00040035
+#define BTC_CGULVCONTROL_DFLT                         0x00001450
+
+#endif
diff --git a/drivers/gpu/drm/radeon/btcd.h b/drivers/gpu/drm/radeon/btcd.h
new file mode 100644
index 0000000..29e32de
--- /dev/null
+++ b/drivers/gpu/drm/radeon/btcd.h
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2010 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Alex Deucher
+ */
+#ifndef _BTCD_H_
+#define _BTCD_H_
+
+/* pm registers */
+
+#define GENERAL_PWRMGT                                  0x63c
+#       define GLOBAL_PWRMGT_EN                         (1 << 0)
+#       define STATIC_PM_EN                             (1 << 1)
+#       define THERMAL_PROTECTION_DIS                   (1 << 2)
+#       define THERMAL_PROTECTION_TYPE                  (1 << 3)
+#       define ENABLE_GEN2PCIE                          (1 << 4)
+#       define ENABLE_GEN2XSP                           (1 << 5)
+#       define SW_SMIO_INDEX(x)                         ((x) << 6)
+#       define SW_SMIO_INDEX_MASK                       (3 << 6)
+#       define SW_SMIO_INDEX_SHIFT                      6
+#       define LOW_VOLT_D2_ACPI                         (1 << 8)
+#       define LOW_VOLT_D3_ACPI                         (1 << 9)
+#       define VOLT_PWRMGT_EN                           (1 << 10)
+#       define BACKBIAS_PAD_EN                          (1 << 18)
+#       define BACKBIAS_VALUE                           (1 << 19)
+#       define DYN_SPREAD_SPECTRUM_EN                   (1 << 23)
+#       define AC_DC_SW                                 (1 << 24)
+
+#define	CG_BIF_REQ_AND_RSP				0x7f4
+#define		CG_CLIENT_REQ(x)			((x) << 0)
+#define		CG_CLIENT_REQ_MASK			(0xff << 0)
+#define		CG_CLIENT_REQ_SHIFT			0
+#define		CG_CLIENT_RESP(x)			((x) << 8)
+#define		CG_CLIENT_RESP_MASK			(0xff << 8)
+#define		CG_CLIENT_RESP_SHIFT			8
+#define		CLIENT_CG_REQ(x)			((x) << 16)
+#define		CLIENT_CG_REQ_MASK			(0xff << 16)
+#define		CLIENT_CG_REQ_SHIFT			16
+#define		CLIENT_CG_RESP(x)			((x) << 24)
+#define		CLIENT_CG_RESP_MASK			(0xff << 24)
+#define		CLIENT_CG_RESP_SHIFT			24
+
+#define	SCLK_PSKIP_CNTL					0x8c0
+#define		PSKIP_ON_ALLOW_STOP_HI(x)		((x) << 16)
+#define		PSKIP_ON_ALLOW_STOP_HI_MASK		(0xff << 16)
+#define		PSKIP_ON_ALLOW_STOP_HI_SHIFT		16
+
+#define	CG_ULV_CONTROL					0x8c8
+#define	CG_ULV_PARAMETER				0x8cc
+
+#define	MC_ARB_DRAM_TIMING				0x2774
+#define	MC_ARB_DRAM_TIMING2				0x2778
+
+#define	MC_ARB_RFSH_RATE				0x27b0
+#define		POWERMODE0(x)				((x) << 0)
+#define		POWERMODE0_MASK				(0xff << 0)
+#define		POWERMODE0_SHIFT			0
+#define		POWERMODE1(x)				((x) << 8)
+#define		POWERMODE1_MASK				(0xff << 8)
+#define		POWERMODE1_SHIFT			8
+#define		POWERMODE2(x)				((x) << 16)
+#define		POWERMODE2_MASK				(0xff << 16)
+#define		POWERMODE2_SHIFT			16
+#define		POWERMODE3(x)				((x) << 24)
+#define		POWERMODE3_MASK				(0xff << 24)
+#define		POWERMODE3_SHIFT			24
+
+#define MC_ARB_BURST_TIME                               0x2808
+#define		STATE0(x)				((x) << 0)
+#define		STATE0_MASK				(0x1f << 0)
+#define		STATE0_SHIFT				0
+#define		STATE1(x)				((x) << 5)
+#define		STATE1_MASK				(0x1f << 5)
+#define		STATE1_SHIFT				5
+#define		STATE2(x)				((x) << 10)
+#define		STATE2_MASK				(0x1f << 10)
+#define		STATE2_SHIFT				10
+#define		STATE3(x)				((x) << 15)
+#define		STATE3_MASK				(0x1f << 15)
+#define		STATE3_SHIFT				15
+
+#define MC_SEQ_RAS_TIMING                               0x28a0
+#define MC_SEQ_CAS_TIMING                               0x28a4
+#define MC_SEQ_MISC_TIMING                              0x28a8
+#define MC_SEQ_MISC_TIMING2                             0x28ac
+
+#define MC_SEQ_RD_CTL_D0                                0x28b4
+#define MC_SEQ_RD_CTL_D1                                0x28b8
+#define MC_SEQ_WR_CTL_D0                                0x28bc
+#define MC_SEQ_WR_CTL_D1                                0x28c0
+
+#define MC_PMG_AUTO_CFG                                 0x28d4
+
+#define MC_SEQ_STATUS_M                                 0x29f4
+#       define PMG_PWRSTATE                             (1 << 16)
+
+#define MC_SEQ_MISC0                                    0x2a00
+#define         MC_SEQ_MISC0_GDDR5_SHIFT                28
+#define         MC_SEQ_MISC0_GDDR5_MASK                 0xf0000000
+#define         MC_SEQ_MISC0_GDDR5_VALUE                5
+#define MC_SEQ_MISC1                                    0x2a04
+#define MC_SEQ_RESERVE_M                                0x2a08
+#define MC_PMG_CMD_EMRS                                 0x2a0c
+
+#define MC_SEQ_MISC3                                    0x2a2c
+
+#define MC_SEQ_MISC5                                    0x2a54
+#define MC_SEQ_MISC6                                    0x2a58
+
+#define MC_SEQ_MISC7                                    0x2a64
+
+#define MC_SEQ_CG                                       0x2a68
+#define		CG_SEQ_REQ(x)				((x) << 0)
+#define		CG_SEQ_REQ_MASK				(0xff << 0)
+#define		CG_SEQ_REQ_SHIFT			0
+#define		CG_SEQ_RESP(x)				((x) << 8)
+#define		CG_SEQ_RESP_MASK			(0xff << 8)
+#define		CG_SEQ_RESP_SHIFT			8
+#define		SEQ_CG_REQ(x)				((x) << 16)
+#define		SEQ_CG_REQ_MASK				(0xff << 16)
+#define		SEQ_CG_REQ_SHIFT			16
+#define		SEQ_CG_RESP(x)				((x) << 24)
+#define		SEQ_CG_RESP_MASK			(0xff << 24)
+#define		SEQ_CG_RESP_SHIFT			24
+#define MC_SEQ_RAS_TIMING_LP                            0x2a6c
+#define MC_SEQ_CAS_TIMING_LP                            0x2a70
+#define MC_SEQ_MISC_TIMING_LP                           0x2a74
+#define MC_SEQ_MISC_TIMING2_LP                          0x2a78
+#define MC_SEQ_WR_CTL_D0_LP                             0x2a7c
+#define MC_SEQ_WR_CTL_D1_LP                             0x2a80
+#define MC_SEQ_PMG_CMD_EMRS_LP                          0x2a84
+#define MC_SEQ_PMG_CMD_MRS_LP                           0x2a88
+
+#define MC_PMG_CMD_MRS                                  0x2aac
+
+#define MC_SEQ_RD_CTL_D0_LP                             0x2b1c
+#define MC_SEQ_RD_CTL_D1_LP                             0x2b20
+
+#define MC_PMG_CMD_MRS1                                 0x2b44
+#define MC_SEQ_PMG_CMD_MRS1_LP                          0x2b48
+
+#define	LB_SYNC_RESET_SEL				0x6b28
+#define		LB_SYNC_RESET_SEL_MASK			(3 << 0)
+#define		LB_SYNC_RESET_SEL_SHIFT			0
+
+/* PCIE link stuff */
+#define PCIE_LC_SPEED_CNTL                                0xa4 /* PCIE_P */
+#       define LC_GEN2_EN_STRAP                           (1 << 0)
+#       define LC_TARGET_LINK_SPEED_OVERRIDE_EN           (1 << 1)
+#       define LC_FORCE_EN_HW_SPEED_CHANGE                (1 << 5)
+#       define LC_FORCE_DIS_HW_SPEED_CHANGE               (1 << 6)
+#       define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_MASK      (0x3 << 8)
+#       define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_SHIFT     3
+#       define LC_CURRENT_DATA_RATE                       (1 << 11)
+#       define LC_HW_VOLTAGE_IF_CONTROL(x)                ((x) << 12)
+#       define LC_HW_VOLTAGE_IF_CONTROL_MASK              (3 << 12)
+#       define LC_HW_VOLTAGE_IF_CONTROL_SHIFT             12
+#       define LC_VOLTAGE_TIMER_SEL_MASK                  (0xf << 14)
+#       define LC_CLR_FAILED_SPD_CHANGE_CNT               (1 << 21)
+#       define LC_OTHER_SIDE_EVER_SENT_GEN2               (1 << 23)
+#       define LC_OTHER_SIDE_SUPPORTS_GEN2                (1 << 24)
+
+#endif
diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c
index c73d713..7407762 100644
--- a/drivers/gpu/drm/radeon/ni.c
+++ b/drivers/gpu/drm/radeon/ni.c
@@ -180,13 +180,16 @@ extern int sumo_rlc_init(struct radeon_device *rdev);
 MODULE_FIRMWARE("radeon/BARTS_pfp.bin");
 MODULE_FIRMWARE("radeon/BARTS_me.bin");
 MODULE_FIRMWARE("radeon/BARTS_mc.bin");
+MODULE_FIRMWARE("radeon/BARTS_smc.bin");
 MODULE_FIRMWARE("radeon/BTC_rlc.bin");
 MODULE_FIRMWARE("radeon/TURKS_pfp.bin");
 MODULE_FIRMWARE("radeon/TURKS_me.bin");
 MODULE_FIRMWARE("radeon/TURKS_mc.bin");
+MODULE_FIRMWARE("radeon/TURKS_smc.bin");
 MODULE_FIRMWARE("radeon/CAICOS_pfp.bin");
 MODULE_FIRMWARE("radeon/CAICOS_me.bin");
 MODULE_FIRMWARE("radeon/CAICOS_mc.bin");
+MODULE_FIRMWARE("radeon/CAICOS_smc.bin");
 MODULE_FIRMWARE("radeon/CAYMAN_pfp.bin");
 MODULE_FIRMWARE("radeon/CAYMAN_me.bin");
 MODULE_FIRMWARE("radeon/CAYMAN_mc.bin");
@@ -683,6 +686,7 @@ int ni_init_microcode(struct radeon_device *rdev)
 	const char *chip_name;
 	const char *rlc_chip_name;
 	size_t pfp_req_size, me_req_size, rlc_req_size, mc_req_size;
+	size_t smc_req_size = 0;
 	char fw_name[30];
 	int err;
 
@@ -703,6 +707,7 @@ int ni_init_microcode(struct radeon_device *rdev)
 		me_req_size = EVERGREEN_PM4_UCODE_SIZE * 4;
 		rlc_req_size = EVERGREEN_RLC_UCODE_SIZE * 4;
 		mc_req_size = BTC_MC_UCODE_SIZE * 4;
+		smc_req_size = ALIGN(BARTS_SMC_UCODE_SIZE, 4);
 		break;
 	case CHIP_TURKS:
 		chip_name = "TURKS";
@@ -711,6 +716,7 @@ int ni_init_microcode(struct radeon_device *rdev)
 		me_req_size = EVERGREEN_PM4_UCODE_SIZE * 4;
 		rlc_req_size = EVERGREEN_RLC_UCODE_SIZE * 4;
 		mc_req_size = BTC_MC_UCODE_SIZE * 4;
+		smc_req_size = ALIGN(TURKS_SMC_UCODE_SIZE, 4);
 		break;
 	case CHIP_CAICOS:
 		chip_name = "CAICOS";
@@ -719,6 +725,7 @@ int ni_init_microcode(struct radeon_device *rdev)
 		me_req_size = EVERGREEN_PM4_UCODE_SIZE * 4;
 		rlc_req_size = EVERGREEN_RLC_UCODE_SIZE * 4;
 		mc_req_size = BTC_MC_UCODE_SIZE * 4;
+		smc_req_size = ALIGN(CAICOS_SMC_UCODE_SIZE, 4);
 		break;
 	case CHIP_CAYMAN:
 		chip_name = "CAYMAN";
@@ -789,6 +796,20 @@ int ni_init_microcode(struct radeon_device *rdev)
 			err = -EINVAL;
 		}
 	}
+
+	if ((rdev->family >= CHIP_BARTS) && (rdev->family <= CHIP_CAICOS)) {
+		snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", chip_name);
+		err = request_firmware(&rdev->smc_fw, fw_name, &pdev->dev);
+		if (err)
+			goto out;
+		if (rdev->smc_fw->size != smc_req_size) {
+			printk(KERN_ERR
+			       "ni_mc: Bogus length %zu in firmware \"%s\"\n",
+			       rdev->mc_fw->size, fw_name);
+			err = -EINVAL;
+		}
+	}
+
 out:
 	platform_device_unregister(pdev);
 
diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c
index 077448f..20f65ad 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.c
+++ b/drivers/gpu/drm/radeon/radeon_asic.c
@@ -1638,6 +1638,18 @@ static struct radeon_asic btc_asic = {
 		.set_uvd_clocks = &evergreen_set_uvd_clocks,
 		.get_temperature = &evergreen_get_temp,
 	},
+	.dpm = {
+		.init = &btc_dpm_init,
+		.setup_asic = &btc_dpm_setup_asic,
+		.enable = &btc_dpm_enable,
+		.disable = &btc_dpm_disable,
+		.set_power_state = &btc_dpm_set_power_state,
+		.display_configuration_changed = &cypress_dpm_display_configuration_changed,
+		.fini = &btc_dpm_fini,
+		.get_sclk = &rv770_dpm_get_sclk,
+		.get_mclk = &rv770_dpm_get_mclk,
+		.print_power_state = &rv770_dpm_print_power_state,
+	},
 	.pflip = {
 		.pre_page_flip = &evergreen_pre_page_flip,
 		.page_flip = &evergreen_page_flip,
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index 1f25b683..214429b 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -530,6 +530,12 @@ void cypress_dpm_disable(struct radeon_device *rdev);
 int cypress_dpm_set_power_state(struct radeon_device *rdev);
 void cypress_dpm_display_configuration_changed(struct radeon_device *rdev);
 void cypress_dpm_fini(struct radeon_device *rdev);
+int btc_dpm_init(struct radeon_device *rdev);
+void btc_dpm_setup_asic(struct radeon_device *rdev);
+int btc_dpm_enable(struct radeon_device *rdev);
+void btc_dpm_disable(struct radeon_device *rdev);
+int btc_dpm_set_power_state(struct radeon_device *rdev);
+void btc_dpm_fini(struct radeon_device *rdev);
 
 /*
  * cayman
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
index d2265f4..0a770b5 100644
--- a/drivers/gpu/drm/radeon/radeon_pm.c
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
@@ -1049,6 +1049,9 @@ int radeon_pm_init(struct radeon_device *rdev)
 	case CHIP_JUNIPER:
 	case CHIP_CYPRESS:
 	case CHIP_HEMLOCK:
+	case CHIP_BARTS:
+	case CHIP_TURKS:
+	case CHIP_CAICOS:
 		if (radeon_dpm == 1)
 			rdev->pm.pm_method = PM_METHOD_DPM;
 		else
diff --git a/drivers/gpu/drm/radeon/radeon_ucode.h b/drivers/gpu/drm/radeon/radeon_ucode.h
index cb9c813..e592e27 100644
--- a/drivers/gpu/drm/radeon/radeon_ucode.h
+++ b/drivers/gpu/drm/radeon/radeon_ucode.h
@@ -85,4 +85,19 @@
 #define CYPRESS_SMC_INT_VECTOR_START 0xffc0
 #define CYPRESS_SMC_INT_VECTOR_SIZE  0x0040
 
+#define BARTS_SMC_UCODE_START        0x0100
+#define BARTS_SMC_UCODE_SIZE         0x6107
+#define BARTS_SMC_INT_VECTOR_START   0xffc0
+#define BARTS_SMC_INT_VECTOR_SIZE    0x0040
+
+#define TURKS_SMC_UCODE_START        0x0100
+#define TURKS_SMC_UCODE_SIZE         0x605b
+#define TURKS_SMC_INT_VECTOR_START   0xffc0
+#define TURKS_SMC_INT_VECTOR_SIZE    0x0040
+
+#define CAICOS_SMC_UCODE_START       0x0100
+#define CAICOS_SMC_UCODE_SIZE        0x5fbd
+#define CAICOS_SMC_INT_VECTOR_START  0xffc0
+#define CAICOS_SMC_INT_VECTOR_SIZE   0x0040
+
 #endif
diff --git a/drivers/gpu/drm/radeon/rv770_smc.c b/drivers/gpu/drm/radeon/rv770_smc.c
index 168aedb..0078c59 100644
--- a/drivers/gpu/drm/radeon/rv770_smc.c
+++ b/drivers/gpu/drm/radeon/rv770_smc.c
@@ -194,6 +194,66 @@ static const u8 cypress_smc_int_vectors[] =
 	0x04, 0xF6, 0x04, 0xF6
 };
 
+static const u8 barts_smc_int_vectors[] =
+{
+	0x0C, 0x14, 0x0C, 0x14,
+	0x0C, 0x14, 0x0C, 0x14,
+	0x0C, 0x14, 0x0C, 0x14,
+	0x0C, 0x14, 0x0C, 0x14,
+	0x0C, 0x14, 0x0C, 0x14,
+	0x0C, 0x14, 0x0C, 0x14,
+	0x0C, 0x14, 0x0C, 0x14,
+	0x0C, 0x14, 0x0C, 0x14,
+	0x0C, 0x14, 0x0C, 0x14,
+	0x0C, 0x14, 0x0C, 0x14,
+	0x0C, 0x14, 0x0C, 0x14,
+	0x0C, 0x14, 0x0C, 0x14,
+	0x0C, 0x14, 0x12, 0xAA,
+	0x0C, 0x2F, 0x15, 0xF6,
+	0x15, 0xF6, 0x05, 0x0A,
+	0x05, 0x0A, 0x05, 0x0A
+};
+
+static const u8 turks_smc_int_vectors[] =
+{
+	0x0C, 0x14, 0x0C, 0x14,
+	0x0C, 0x14, 0x0C, 0x14,
+	0x0C, 0x14, 0x0C, 0x14,
+	0x0C, 0x14, 0x0C, 0x14,
+	0x0C, 0x14, 0x0C, 0x14,
+	0x0C, 0x14, 0x0C, 0x14,
+	0x0C, 0x14, 0x0C, 0x14,
+	0x0C, 0x14, 0x0C, 0x14,
+	0x0C, 0x14, 0x0C, 0x14,
+	0x0C, 0x14, 0x0C, 0x14,
+	0x0C, 0x14, 0x0C, 0x14,
+	0x0C, 0x14, 0x0C, 0x14,
+	0x0C, 0x14, 0x12, 0xAA,
+	0x0C, 0x2F, 0x15, 0xF6,
+	0x15, 0xF6, 0x05, 0x0A,
+	0x05, 0x0A, 0x05, 0x0A
+};
+
+static const u8 caicos_smc_int_vectors[] =
+{
+	0x0C, 0x14, 0x0C, 0x14,
+	0x0C, 0x14, 0x0C, 0x14,
+	0x0C, 0x14, 0x0C, 0x14,
+	0x0C, 0x14, 0x0C, 0x14,
+	0x0C, 0x14, 0x0C, 0x14,
+	0x0C, 0x14, 0x0C, 0x14,
+	0x0C, 0x14, 0x0C, 0x14,
+	0x0C, 0x14, 0x0C, 0x14,
+	0x0C, 0x14, 0x0C, 0x14,
+	0x0C, 0x14, 0x0C, 0x14,
+	0x0C, 0x14, 0x0C, 0x14,
+	0x0C, 0x14, 0x0C, 0x14,
+	0x0C, 0x14, 0x12, 0xAA,
+	0x0C, 0x2F, 0x15, 0xF6,
+	0x15, 0xF6, 0x05, 0x0A,
+	0x05, 0x0A, 0x05, 0x0A
+};
+
 int rv770_set_smc_sram_address(struct radeon_device *rdev,
 			       u16 smc_address, u16 limit)
 {
@@ -463,6 +523,27 @@ int rv770_load_smc_ucode(struct radeon_device *rdev,
 		int_vect_start_address = CYPRESS_SMC_INT_VECTOR_START;
 		int_vect_size = CYPRESS_SMC_INT_VECTOR_SIZE;
 		break;
+	case CHIP_BARTS:
+		ucode_start_address = BARTS_SMC_UCODE_START;
+		ucode_size = BARTS_SMC_UCODE_SIZE;
+		int_vect = (const u8 *)&barts_smc_int_vectors;
+		int_vect_start_address = BARTS_SMC_INT_VECTOR_START;
+		int_vect_size = BARTS_SMC_INT_VECTOR_SIZE;
+		break;
+	case CHIP_TURKS:
+		ucode_start_address = TURKS_SMC_UCODE_START;
+		ucode_size = TURKS_SMC_UCODE_SIZE;
+		int_vect = (const u8 *)&turks_smc_int_vectors;
+		int_vect_start_address = TURKS_SMC_INT_VECTOR_START;
+		int_vect_size = TURKS_SMC_INT_VECTOR_SIZE;
+		break;
+	case CHIP_CAICOS:
+		ucode_start_address = CAICOS_SMC_UCODE_START;
+		ucode_size = CAICOS_SMC_UCODE_SIZE;
+		int_vect = (const u8 *)&caicos_smc_int_vectors;
+		int_vect_start_address = CAICOS_SMC_INT_VECTOR_START;
+		int_vect_size = CAICOS_SMC_INT_VECTOR_SIZE;
+		break;
 	default:
 		DRM_ERROR("unknown asic in smc ucode loader\n");
 		BUG();
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 080/165] drm/radeon/kms: add dpm support for sumo asics
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (79 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 079/165] drm/radeon/kms: add dpm support for btc (v2) alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 11:19   ` Jerome Glisse
  2013-06-26 13:22 ` [PATCH 081/165] drm/radeon/kms: add dpm support for trinity asics alexdeucher
                   ` (32 subsequent siblings)
  113 siblings, 1 reply; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

This adds dpm support for sumo asics.  This includes:
- clockgating
- powergating
- dynamic engine clock scaling
- dynamic voltage scaling

set radeon.dpm=1 to enable it.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/Makefile      |    2 +-
 drivers/gpu/drm/radeon/radeon_asic.c |   12 +
 drivers/gpu/drm/radeon/radeon_asic.h |   11 +
 drivers/gpu/drm/radeon/radeon_pm.c   |    3 +
 drivers/gpu/drm/radeon/sumo_dpm.c    | 1677 ++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/radeon/sumo_dpm.h    |  199 ++++
 drivers/gpu/drm/radeon/sumo_smc.c    |  224 +++++
 drivers/gpu/drm/radeon/sumod.h       |  362 ++++++++
 8 files changed, 2489 insertions(+), 1 deletions(-)
 create mode 100644 drivers/gpu/drm/radeon/sumo_dpm.c
 create mode 100644 drivers/gpu/drm/radeon/sumo_dpm.h
 create mode 100644 drivers/gpu/drm/radeon/sumo_smc.c
 create mode 100644 drivers/gpu/drm/radeon/sumod.h

diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile
index af3dd8f..7c77e1d 100644
--- a/drivers/gpu/drm/radeon/Makefile
+++ b/drivers/gpu/drm/radeon/Makefile
@@ -78,7 +78,7 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \
 	atombios_encoders.o radeon_semaphore.o radeon_sa.o atombios_i2c.o si.o \
 	si_blit_shaders.o radeon_prime.o radeon_uvd.o cik.o cik_blit_shaders.o \
 	r600_dpm.o rs780_dpm.o rv6xx_dpm.o rv770_dpm.o rv730_dpm.o rv740_dpm.o \
-	rv770_smc.o cypress_dpm.o btc_dpm.o
+	rv770_smc.o cypress_dpm.o btc_dpm.o sumo_dpm.o sumo_smc.o
 
 radeon-$(CONFIG_COMPAT) += radeon_ioc32.o
 radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o
diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c
index 20f65ad..8b541b4 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.c
+++ b/drivers/gpu/drm/radeon/radeon_asic.c
@@ -1539,6 +1539,18 @@ static struct radeon_asic sumo_asic = {
 		.set_uvd_clocks = &sumo_set_uvd_clocks,
 		.get_temperature = &sumo_get_temp,
 	},
+	.dpm = {
+		.init = &sumo_dpm_init,
+		.setup_asic = &sumo_dpm_setup_asic,
+		.enable = &sumo_dpm_enable,
+		.disable = &sumo_dpm_disable,
+		.set_power_state = &sumo_dpm_set_power_state,
+		.display_configuration_changed = &sumo_dpm_display_configuration_changed,
+		.fini = &sumo_dpm_fini,
+		.get_sclk = &sumo_dpm_get_sclk,
+		.get_mclk = &sumo_dpm_get_mclk,
+		.print_power_state = &sumo_dpm_print_power_state,
+	},
 	.pflip = {
 		.pre_page_flip = &evergreen_pre_page_flip,
 		.page_flip = &evergreen_page_flip,
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index 214429b..f6c0984 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -536,6 +536,17 @@ int btc_dpm_enable(struct radeon_device *rdev);
 void btc_dpm_disable(struct radeon_device *rdev);
 int btc_dpm_set_power_state(struct radeon_device *rdev);
 void btc_dpm_fini(struct radeon_device *rdev);
+int sumo_dpm_init(struct radeon_device *rdev);
+int sumo_dpm_enable(struct radeon_device *rdev);
+void sumo_dpm_disable(struct radeon_device *rdev);
+int sumo_dpm_set_power_state(struct radeon_device *rdev);
+void sumo_dpm_setup_asic(struct radeon_device *rdev);
+void sumo_dpm_display_configuration_changed(struct radeon_device *rdev);
+void sumo_dpm_fini(struct radeon_device *rdev);
+u32 sumo_dpm_get_sclk(struct radeon_device *rdev, bool low);
+u32 sumo_dpm_get_mclk(struct radeon_device *rdev, bool low);
+void sumo_dpm_print_power_state(struct radeon_device *rdev,
+				struct radeon_ps *ps);
 
 /*
  * cayman
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
index 0a770b5..b924bcc1 100644
--- a/drivers/gpu/drm/radeon/radeon_pm.c
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
@@ -1049,6 +1049,9 @@ int radeon_pm_init(struct radeon_device *rdev)
 	case CHIP_JUNIPER:
 	case CHIP_CYPRESS:
 	case CHIP_HEMLOCK:
+	case CHIP_PALM:
+	case CHIP_SUMO:
+	case CHIP_SUMO2:
 	case CHIP_BARTS:
 	case CHIP_TURKS:
 	case CHIP_CAICOS:
diff --git a/drivers/gpu/drm/radeon/sumo_dpm.c b/drivers/gpu/drm/radeon/sumo_dpm.c
new file mode 100644
index 0000000..4f49450
--- /dev/null
+++ b/drivers/gpu/drm/radeon/sumo_dpm.c
@@ -0,0 +1,1677 @@
+/*
+ * Copyright 2012 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "drmP.h"
+#include "radeon.h"
+#include "sumod.h"
+#include "r600_dpm.h"
+#include "cypress_dpm.h"
+#include "sumo_dpm.h"
+#include "atom.h"
+
+#define SUMO_MAX_DEEPSLEEP_DIVIDER_ID 5
+#define SUMO_MINIMUM_ENGINE_CLOCK 800
+#define BOOST_DPM_LEVEL 7
+
+static const u32 sumo_utc[SUMO_PM_NUMBER_OF_TC] =
+{
+	SUMO_UTC_DFLT_00,
+	SUMO_UTC_DFLT_01,
+	SUMO_UTC_DFLT_02,
+	SUMO_UTC_DFLT_03,
+	SUMO_UTC_DFLT_04,
+	SUMO_UTC_DFLT_05,
+	SUMO_UTC_DFLT_06,
+	SUMO_UTC_DFLT_07,
+	SUMO_UTC_DFLT_08,
+	SUMO_UTC_DFLT_09,
+	SUMO_UTC_DFLT_10,
+	SUMO_UTC_DFLT_11,
+	SUMO_UTC_DFLT_12,
+	SUMO_UTC_DFLT_13,
+	SUMO_UTC_DFLT_14,
+};
+
+static const u32 sumo_dtc[SUMO_PM_NUMBER_OF_TC] =
+{
+	SUMO_DTC_DFLT_00,
+	SUMO_DTC_DFLT_01,
+	SUMO_DTC_DFLT_02,
+	SUMO_DTC_DFLT_03,
+	SUMO_DTC_DFLT_04,
+	SUMO_DTC_DFLT_05,
+	SUMO_DTC_DFLT_06,
+	SUMO_DTC_DFLT_07,
+	SUMO_DTC_DFLT_08,
+	SUMO_DTC_DFLT_09,
+	SUMO_DTC_DFLT_10,
+	SUMO_DTC_DFLT_11,
+	SUMO_DTC_DFLT_12,
+	SUMO_DTC_DFLT_13,
+	SUMO_DTC_DFLT_14,
+};
+
+struct sumo_ps *sumo_get_ps(struct radeon_ps *rps)
+{
+	struct sumo_ps *ps = rps->ps_priv;
+
+	return ps;
+}
+
+struct sumo_power_info *sumo_get_pi(struct radeon_device *rdev)
+{
+	struct sumo_power_info *pi = rdev->pm.dpm.priv;
+
+	return pi;
+}
+
+u32 sumo_get_xclk(struct radeon_device *rdev)
+{
+	return rdev->clock.spll.reference_freq;
+}
+
+static void sumo_gfx_clockgating_enable(struct radeon_device *rdev, bool enable)
+{
+	if (enable)
+		WREG32_P(SCLK_PWRMGT_CNTL, DYN_GFX_CLK_OFF_EN, ~DYN_GFX_CLK_OFF_EN);
+	else {
+		WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_GFX_CLK_OFF_EN);
+		WREG32_P(SCLK_PWRMGT_CNTL, GFX_CLK_FORCE_ON, ~GFX_CLK_FORCE_ON);
+		WREG32_P(SCLK_PWRMGT_CNTL, 0, ~GFX_CLK_FORCE_ON);
+		RREG32(GB_ADDR_CONFIG);
+	}
+}
+
+#define CGCG_CGTT_LOCAL0_MASK 0xE5BFFFFF
+#define CGCG_CGTT_LOCAL1_MASK 0xEFFF07FF
+
+static void sumo_mg_clockgating_enable(struct radeon_device *rdev, bool enable)
+{
+	u32 local0;
+	u32 local1;
+
+	local0 = RREG32(CG_CGTT_LOCAL_0);
+	local1 = RREG32(CG_CGTT_LOCAL_1);
+
+	if (enable) {
+		WREG32(CG_CGTT_LOCAL_0, (0 & CGCG_CGTT_LOCAL0_MASK) | (local0 & ~CGCG_CGTT_LOCAL0_MASK) );
+		WREG32(CG_CGTT_LOCAL_1, (0 & CGCG_CGTT_LOCAL1_MASK) | (local1 & ~CGCG_CGTT_LOCAL1_MASK) );
+	} else {
+		WREG32(CG_CGTT_LOCAL_0, (0xFFFFFFFF & CGCG_CGTT_LOCAL0_MASK) | (local0 & ~CGCG_CGTT_LOCAL0_MASK) );
+		WREG32(CG_CGTT_LOCAL_1, (0xFFFFCFFF & CGCG_CGTT_LOCAL1_MASK) | (local1 & ~CGCG_CGTT_LOCAL1_MASK) );
+	}
+}
+
+static void sumo_program_git(struct radeon_device *rdev)
+{
+	u32 p, u;
+	u32 xclk = sumo_get_xclk(rdev);
+
+	r600_calculate_u_and_p(SUMO_GICST_DFLT,
+			       xclk, 16, &p, &u);
+
+	WREG32_P(CG_GIT, CG_GICST(p), ~CG_GICST_MASK);
+}
+
+static void sumo_program_grsd(struct radeon_device *rdev)
+{
+	u32 p, u;
+	u32 xclk = sumo_get_xclk(rdev);
+	u32 grs = 256 * 25 / 100;
+
+	r600_calculate_u_and_p(1, xclk, 14, &p, &u);
+
+	WREG32(CG_GCOOR, PHC(grs) | SDC(p) | SU(u));
+}
+
+static void sumo_gfx_clockgating_initialize(struct radeon_device *rdev)
+{
+	sumo_program_git(rdev);
+	sumo_program_grsd(rdev);
+}
+
+static void sumo_gfx_powergating_initialize(struct radeon_device *rdev)
+{
+	u32 rcu_pwr_gating_cntl;
+	u32 p, u;
+	u32 p_c, p_p, d_p;
+	u32 r_t, i_t;
+	u32 xclk = sumo_get_xclk(rdev);
+
+	if (rdev->family == CHIP_PALM) {
+		p_c = 4;
+		d_p = 10;
+		r_t = 10;
+		i_t = 4;
+		p_p = 50 + 1000/200 + 6 * 32;
+	} else {
+		p_c = 16;
+		d_p = 50;
+		r_t = 50;
+		i_t  = 50;
+		p_p = 113;
+	}
+
+	WREG32(CG_SCRATCH2, 0x01B60A17);
+
+	r600_calculate_u_and_p(SUMO_GFXPOWERGATINGT_DFLT,
+			       xclk, 16, &p, &u);
+
+	WREG32_P(CG_PWR_GATING_CNTL, PGP(p) | PGU(u),
+		 ~(PGP_MASK | PGU_MASK));
+
+	r600_calculate_u_and_p(SUMO_VOLTAGEDROPT_DFLT,
+			       xclk, 16, &p, &u);
+
+	WREG32_P(CG_CG_VOLTAGE_CNTL, PGP(p) | PGU(u),
+		 ~(PGP_MASK | PGU_MASK));
+
+	if (rdev->family == CHIP_PALM) {
+		WREG32_RCU(RCU_PWR_GATING_SEQ0, 0x10103210);
+		WREG32_RCU(RCU_PWR_GATING_SEQ1, 0x10101010);
+	} else {
+		WREG32_RCU(RCU_PWR_GATING_SEQ0, 0x76543210);
+		WREG32_RCU(RCU_PWR_GATING_SEQ1, 0xFEDCBA98);
+	}
+
+	rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL);
+	rcu_pwr_gating_cntl &=
+		~(RSVD_MASK | PCV_MASK | PGS_MASK);
+	rcu_pwr_gating_cntl |= PCV(p_c) | PGS(1) | PWR_GATING_EN;
+	if (rdev->family == CHIP_PALM) {
+		rcu_pwr_gating_cntl &= ~PCP_MASK;
+		rcu_pwr_gating_cntl |= PCP(0x77);
+	}
+	WREG32_RCU(RCU_PWR_GATING_CNTL, rcu_pwr_gating_cntl);
+
+	rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL_2);
+	rcu_pwr_gating_cntl &= ~(MPPU_MASK | MPPD_MASK);
+	rcu_pwr_gating_cntl |= MPPU(p_p) | MPPD(50);
+	WREG32_RCU(RCU_PWR_GATING_CNTL_2, rcu_pwr_gating_cntl);
+
+	rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL_3);
+	rcu_pwr_gating_cntl &= ~(DPPU_MASK | DPPD_MASK);
+	rcu_pwr_gating_cntl |= DPPU(d_p) | DPPD(50);
+	WREG32_RCU(RCU_PWR_GATING_CNTL_3, rcu_pwr_gating_cntl);
+
+	rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL_4);
+	rcu_pwr_gating_cntl &= ~(RT_MASK | IT_MASK);
+	rcu_pwr_gating_cntl |= RT(r_t) | IT(i_t);
+	WREG32_RCU(RCU_PWR_GATING_CNTL_4, rcu_pwr_gating_cntl);
+
+	if (rdev->family == CHIP_PALM)
+		WREG32_RCU(RCU_PWR_GATING_CNTL_5, 0xA02);
+
+	sumo_smu_pg_init(rdev);
+
+	rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL);
+	rcu_pwr_gating_cntl &=
+		~(RSVD_MASK | PCV_MASK | PGS_MASK);
+	rcu_pwr_gating_cntl |= PCV(p_c) | PGS(4) | PWR_GATING_EN;
+	if (rdev->family == CHIP_PALM) {
+		rcu_pwr_gating_cntl &= ~PCP_MASK;
+		rcu_pwr_gating_cntl |= PCP(0x77);
+	}
+	WREG32_RCU(RCU_PWR_GATING_CNTL, rcu_pwr_gating_cntl);
+
+	if (rdev->family == CHIP_PALM) {
+		rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL_2);
+		rcu_pwr_gating_cntl &= ~(MPPU_MASK | MPPD_MASK);
+		rcu_pwr_gating_cntl |= MPPU(113) | MPPD(50);
+		WREG32_RCU(RCU_PWR_GATING_CNTL_2, rcu_pwr_gating_cntl);
+
+		rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL_3);
+		rcu_pwr_gating_cntl &= ~(DPPU_MASK | DPPD_MASK);
+		rcu_pwr_gating_cntl |= DPPU(16) | DPPD(50);
+		WREG32_RCU(RCU_PWR_GATING_CNTL_3, rcu_pwr_gating_cntl);
+	}
+
+	sumo_smu_pg_init(rdev);
+
+	rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL);
+	rcu_pwr_gating_cntl &=
+		~(RSVD_MASK | PCV_MASK | PGS_MASK);
+	rcu_pwr_gating_cntl |= PGS(5) | PWR_GATING_EN;
+
+	if (rdev->family == CHIP_PALM) {
+		rcu_pwr_gating_cntl |= PCV(4);
+		rcu_pwr_gating_cntl &= ~PCP_MASK;
+		rcu_pwr_gating_cntl |= PCP(0x77);
+	} else
+		rcu_pwr_gating_cntl |= PCV(11);
+	WREG32_RCU(RCU_PWR_GATING_CNTL, rcu_pwr_gating_cntl);
+
+	if (rdev->family == CHIP_PALM) {
+		rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL_2);
+		rcu_pwr_gating_cntl &= ~(MPPU_MASK | MPPD_MASK);
+		rcu_pwr_gating_cntl |= MPPU(113) | MPPD(50);
+		WREG32_RCU(RCU_PWR_GATING_CNTL_2, rcu_pwr_gating_cntl);
+
+		rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL_3);
+		rcu_pwr_gating_cntl &= ~(DPPU_MASK | DPPD_MASK);
+		rcu_pwr_gating_cntl |= DPPU(22) | DPPD(50);
+		WREG32_RCU(RCU_PWR_GATING_CNTL_3, rcu_pwr_gating_cntl);
+	}
+
+	sumo_smu_pg_init(rdev);
+}
+
+static void sumo_gfx_powergating_enable(struct radeon_device *rdev, bool enable)
+{
+	if (enable)
+		WREG32_P(CG_PWR_GATING_CNTL, DYN_PWR_DOWN_EN, ~DYN_PWR_DOWN_EN);
+	else {
+		WREG32_P(CG_PWR_GATING_CNTL, 0, ~DYN_PWR_DOWN_EN);
+		RREG32(GB_ADDR_CONFIG);
+	}
+}
+
+static int sumo_enable_clock_power_gating(struct radeon_device *rdev)
+{
+	struct sumo_power_info *pi = sumo_get_pi(rdev);
+
+	if (pi->enable_gfx_clock_gating)
+		sumo_gfx_clockgating_initialize(rdev);
+	if (pi->enable_gfx_power_gating)
+		sumo_gfx_powergating_initialize(rdev);
+	if (pi->enable_mg_clock_gating)
+		sumo_mg_clockgating_enable(rdev, true);
+	if (pi->enable_gfx_clock_gating)
+		sumo_gfx_clockgating_enable(rdev, true);
+	if (pi->enable_gfx_power_gating)
+		sumo_gfx_powergating_enable(rdev, true);
+
+	return 0;
+}
+
+static void sumo_disable_clock_power_gating(struct radeon_device *rdev)
+{
+	struct sumo_power_info *pi = sumo_get_pi(rdev);
+
+	if (pi->enable_gfx_clock_gating)
+		sumo_gfx_clockgating_enable(rdev, false);
+	if (pi->enable_gfx_power_gating)
+		sumo_gfx_powergating_enable(rdev, false);
+	if (pi->enable_mg_clock_gating)
+		sumo_mg_clockgating_enable(rdev, false);
+}
+
+static void sumo_calculate_bsp(struct radeon_device *rdev,
+			       u32 high_clk)
+{
+	struct sumo_power_info *pi = sumo_get_pi(rdev);
+	u32 xclk = sumo_get_xclk(rdev);
+
+	pi->pasi = 65535 * 100 / high_clk;
+	pi->asi = 65535 * 100 / high_clk;
+
+	r600_calculate_u_and_p(pi->asi,
+			       xclk, 16, &pi->bsp, &pi->bsu);
+
+	r600_calculate_u_and_p(pi->pasi,
+			       xclk, 16, &pi->pbsp, &pi->pbsu);
+
+	pi->dsp = BSP(pi->bsp) | BSU(pi->bsu);
+	pi->psp = BSP(pi->pbsp) | BSU(pi->pbsu);
+}
+
+static void sumo_init_bsp(struct radeon_device *rdev)
+{
+	struct sumo_power_info *pi = sumo_get_pi(rdev);
+
+	WREG32(CG_BSP_0, pi->psp);
+}
+
+
+static void sumo_program_bsp(struct radeon_device *rdev)
+{
+	struct sumo_power_info *pi = sumo_get_pi(rdev);
+	struct sumo_ps *ps = sumo_get_ps(rdev->pm.dpm.requested_ps);
+	u32 i;
+	u32 highest_engine_clock = ps->levels[ps->num_levels - 1].sclk;
+
+	if (ps->flags & SUMO_POWERSTATE_FLAGS_BOOST_STATE)
+		highest_engine_clock = pi->boost_pl.sclk;
+
+	sumo_calculate_bsp(rdev, highest_engine_clock);
+
+	for (i = 0; i < ps->num_levels - 1; i++)
+		WREG32(CG_BSP_0 + (i * 4), pi->dsp);
+
+	WREG32(CG_BSP_0 + (i * 4), pi->psp);
+
+	if (ps->flags & SUMO_POWERSTATE_FLAGS_BOOST_STATE)
+		WREG32(CG_BSP_0 + (BOOST_DPM_LEVEL * 4), pi->psp);
+}
+
+static void sumo_write_at(struct radeon_device *rdev,
+			  u32 index, u32 value)
+{
+	if (index == 0)
+		WREG32(CG_AT_0, value);
+	else if (index == 1)
+		WREG32(CG_AT_1, value);
+	else if (index == 2)
+		WREG32(CG_AT_2, value);
+	else if (index == 3)
+		WREG32(CG_AT_3, value);
+	else if (index == 4)
+		WREG32(CG_AT_4, value);
+	else if (index == 5)
+		WREG32(CG_AT_5, value);
+	else if (index == 6)
+		WREG32(CG_AT_6, value);
+	else if (index == 7)
+		WREG32(CG_AT_7, value);
+}
+
+static void sumo_program_at(struct radeon_device *rdev)
+{
+	struct sumo_power_info *pi = sumo_get_pi(rdev);
+	struct sumo_ps *ps = sumo_get_ps(rdev->pm.dpm.requested_ps);
+	u32 asi;
+	u32 i;
+	u32 m_a;
+	u32 a_t;
+	u32 r[SUMO_MAX_HARDWARE_POWERLEVELS];
+	u32 l[SUMO_MAX_HARDWARE_POWERLEVELS];
+
+	r[0] = SUMO_R_DFLT0;
+	r[1] = SUMO_R_DFLT1;
+	r[2] = SUMO_R_DFLT2;
+	r[3] = SUMO_R_DFLT3;
+	r[4] = SUMO_R_DFLT4;
+
+	l[0] = SUMO_L_DFLT0;
+	l[1] = SUMO_L_DFLT1;
+	l[2] = SUMO_L_DFLT2;
+	l[3] = SUMO_L_DFLT3;
+	l[4] = SUMO_L_DFLT4;
+
+	for (i = 0; i < ps->num_levels; i++) {
+		asi = (i == ps->num_levels - 1) ? pi->pasi : pi->asi;
+
+		m_a = asi * ps->levels[i].sclk / 100;
+
+		a_t = CG_R(m_a * r[i] / 100) | CG_L(m_a * l[i] / 100);
+
+		sumo_write_at(rdev, i, a_t);
+	}
+
+	if (ps->flags & SUMO_POWERSTATE_FLAGS_BOOST_STATE) {
+		asi = pi->pasi;
+
+		m_a = asi * pi->boost_pl.sclk / 100;
+
+		a_t = CG_R(m_a * r[ps->num_levels - 1] / 100) |
+			CG_L(m_a * l[ps->num_levels - 1] / 100);
+
+		sumo_write_at(rdev, BOOST_DPM_LEVEL, a_t);
+	}
+}
+
+static void sumo_program_tp(struct radeon_device *rdev)
+{
+	int i;
+	enum r600_td td = R600_TD_DFLT;
+
+	for (i = 0; i < SUMO_PM_NUMBER_OF_TC; i++) {
+		WREG32_P(CG_FFCT_0 + (i * 4), UTC_0(sumo_utc[i]), ~UTC_0_MASK);
+		WREG32_P(CG_FFCT_0 + (i * 4), DTC_0(sumo_dtc[i]), ~DTC_0_MASK);
+	}
+
+	if (td == R600_TD_AUTO)
+		WREG32_P(SCLK_PWRMGT_CNTL, 0, ~FIR_FORCE_TREND_SEL);
+	else
+		WREG32_P(SCLK_PWRMGT_CNTL, FIR_FORCE_TREND_SEL, ~FIR_FORCE_TREND_SEL);
+
+	if (td == R600_TD_UP)
+		WREG32_P(SCLK_PWRMGT_CNTL, 0, ~FIR_TREND_MODE);
+
+	if (td == R600_TD_DOWN)
+		WREG32_P(SCLK_PWRMGT_CNTL, FIR_TREND_MODE, ~FIR_TREND_MODE);
+}
+
+static void sumo_program_vc(struct radeon_device *rdev)
+{
+	WREG32(CG_FTV, SUMO_VRC_DFLT);
+}
+
+static void sumo_clear_vc(struct radeon_device *rdev)
+{
+	WREG32(CG_FTV, 0);
+}
+
+static void sumo_program_sstp(struct radeon_device *rdev)
+{
+	u32 p, u;
+	u32 xclk = sumo_get_xclk(rdev);
+
+	r600_calculate_u_and_p(SUMO_SST_DFLT,
+			       xclk, 16, &p, &u);
+
+	WREG32(CG_SSP, SSTU(u) | SST(p));
+}
+
+static void sumo_set_divider_value(struct radeon_device *rdev,
+				   u32 index, u32 divider)
+{
+	u32 reg_index = index / 4;
+	u32 field_index = index % 4;
+
+	if (field_index == 0)
+		WREG32_P(CG_SCLK_DPM_CTRL + (reg_index * 4),
+			 SCLK_FSTATE_0_DIV(divider), ~SCLK_FSTATE_0_DIV_MASK);
+	else if (field_index == 1)
+		WREG32_P(CG_SCLK_DPM_CTRL + (reg_index * 4),
+			 SCLK_FSTATE_1_DIV(divider), ~SCLK_FSTATE_1_DIV_MASK);
+	else if (field_index == 2)
+		WREG32_P(CG_SCLK_DPM_CTRL + (reg_index * 4),
+			 SCLK_FSTATE_2_DIV(divider), ~SCLK_FSTATE_2_DIV_MASK);
+	else if (field_index == 3)
+		WREG32_P(CG_SCLK_DPM_CTRL + (reg_index * 4),
+			 SCLK_FSTATE_3_DIV(divider), ~SCLK_FSTATE_3_DIV_MASK);
+}
+
+static void sumo_set_ds_dividers(struct radeon_device *rdev,
+				 u32 index, u32 divider)
+{
+	struct sumo_power_info *pi = sumo_get_pi(rdev);
+
+	if (pi->enable_sclk_ds) {
+		u32 dpm_ctrl = RREG32(CG_SCLK_DPM_CTRL_6);
+
+		dpm_ctrl &= ~(0x7 << (index * 3));
+		dpm_ctrl |= (divider << (index * 3));
+		WREG32(CG_SCLK_DPM_CTRL_6, dpm_ctrl);
+	}
+}
+
+static void sumo_set_ss_dividers(struct radeon_device *rdev,
+				 u32 index, u32 divider)
+{
+	struct sumo_power_info *pi = sumo_get_pi(rdev);
+
+	if (pi->enable_sclk_ds) {
+		u32 dpm_ctrl = RREG32(CG_SCLK_DPM_CTRL_11);
+
+		dpm_ctrl &= ~(0x7 << (index * 3));
+		dpm_ctrl |= (divider << (index * 3));
+		WREG32(CG_SCLK_DPM_CTRL_11, dpm_ctrl);
+	}
+}
+
+static void sumo_set_vid(struct radeon_device *rdev, u32 index, u32 vid)
+{
+	u32 voltage_cntl = RREG32(CG_DPM_VOLTAGE_CNTL);
+
+	voltage_cntl &= ~(DPM_STATE0_LEVEL_MASK << (index * 2));
+	voltage_cntl |= (vid << (DPM_STATE0_LEVEL_SHIFT + index * 2));
+	WREG32(CG_DPM_VOLTAGE_CNTL, voltage_cntl);
+}
+
+static void sumo_set_allos_gnb_slow(struct radeon_device *rdev, u32 index, u32 gnb_slow)
+{
+	struct sumo_power_info *pi = sumo_get_pi(rdev);
+	u32 temp = gnb_slow;
+	u32 cg_sclk_dpm_ctrl_3;
+
+	if (pi->driver_nbps_policy_disable)
+		temp = 1;
+
+	cg_sclk_dpm_ctrl_3 = RREG32(CG_SCLK_DPM_CTRL_3);
+	cg_sclk_dpm_ctrl_3 &= ~(GNB_SLOW_FSTATE_0_MASK << index);
+	cg_sclk_dpm_ctrl_3 |= (temp << (GNB_SLOW_FSTATE_0_SHIFT + index));
+
+	WREG32(CG_SCLK_DPM_CTRL_3, cg_sclk_dpm_ctrl_3);
+}
+
+static void sumo_program_power_level(struct radeon_device *rdev,
+				     struct sumo_pl *pl, u32 index)
+{
+	struct sumo_power_info *pi = sumo_get_pi(rdev);
+	int ret;
+	struct atom_clock_dividers dividers;
+	u32 ds_en = RREG32(DEEP_SLEEP_CNTL) & ENABLE_DS;
+
+        ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
+                                             pl->sclk, false, &dividers);
+	if (ret)
+		return;
+
+	sumo_set_divider_value(rdev, index, dividers.post_div);
+
+	sumo_set_vid(rdev, index, pl->vddc_index);
+
+	if (pl->ss_divider_index == 0 || pl->ds_divider_index == 0) {
+		if (ds_en)
+			WREG32_P(DEEP_SLEEP_CNTL, 0, ~ENABLE_DS);
+	} else {
+		sumo_set_ss_dividers(rdev, index, pl->ss_divider_index);
+		sumo_set_ds_dividers(rdev, index, pl->ds_divider_index);
+
+		if (!ds_en)
+			WREG32_P(DEEP_SLEEP_CNTL, ENABLE_DS, ~ENABLE_DS);
+	}
+
+	sumo_set_allos_gnb_slow(rdev, index, pl->allow_gnb_slow);
+
+	if (pi->enable_boost)
+		sumo_set_tdp_limit(rdev, index, pl->sclk_dpm_tdp_limit);
+}
+
+static void sumo_power_level_enable(struct radeon_device *rdev, u32 index, bool enable)
+{
+	u32 reg_index = index / 4;
+	u32 field_index = index % 4;
+
+	if (field_index == 0)
+		WREG32_P(CG_SCLK_DPM_CTRL + (reg_index * 4),
+			 enable ? SCLK_FSTATE_0_VLD : 0, ~SCLK_FSTATE_0_VLD);
+	else if (field_index == 1)
+		WREG32_P(CG_SCLK_DPM_CTRL + (reg_index * 4),
+			 enable ? SCLK_FSTATE_1_VLD : 0, ~SCLK_FSTATE_1_VLD);
+	else if (field_index == 2)
+		WREG32_P(CG_SCLK_DPM_CTRL + (reg_index * 4),
+			 enable ? SCLK_FSTATE_2_VLD : 0, ~SCLK_FSTATE_2_VLD);
+	else if (field_index == 3)
+		WREG32_P(CG_SCLK_DPM_CTRL + (reg_index * 4),
+			 enable ? SCLK_FSTATE_3_VLD : 0, ~SCLK_FSTATE_3_VLD);
+}
+
+static bool sumo_dpm_enabled(struct radeon_device *rdev)
+{
+	if (RREG32(CG_SCLK_DPM_CTRL_3) & DPM_SCLK_ENABLE)
+		return true;
+	else
+		return false;
+}
+
+static void sumo_start_dpm(struct radeon_device *rdev)
+{
+	WREG32_P(CG_SCLK_DPM_CTRL_3, DPM_SCLK_ENABLE, ~DPM_SCLK_ENABLE);
+}
+
+static void sumo_stop_dpm(struct radeon_device *rdev)
+{
+	WREG32_P(CG_SCLK_DPM_CTRL_3, 0, ~DPM_SCLK_ENABLE);
+}
+
+static void sumo_set_forced_mode(struct radeon_device *rdev, bool enable)
+{
+	if (enable)
+		WREG32_P(CG_SCLK_DPM_CTRL_3, FORCE_SCLK_STATE_EN, ~FORCE_SCLK_STATE_EN);
+	else
+		WREG32_P(CG_SCLK_DPM_CTRL_3, 0, ~FORCE_SCLK_STATE_EN);
+}
+
+static void sumo_set_forced_mode_enabled(struct radeon_device *rdev)
+{
+	int i;
+
+	sumo_set_forced_mode(rdev, true);
+	for (i = 0; i < rdev->usec_timeout; i++) {
+		if (RREG32(CG_SCLK_STATUS) & SCLK_OVERCLK_DETECT)
+			break;
+		udelay(1);
+	}
+}
+
+static void sumo_wait_for_level_0(struct radeon_device *rdev)
+{
+	int i;
+
+	for (i = 0; i < rdev->usec_timeout; i++) {
+		if ((RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURR_SCLK_INDEX_MASK) == 0)
+			break;
+		udelay(1);
+	}
+	for (i = 0; i < rdev->usec_timeout; i++) {
+		if ((RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURR_INDEX_MASK) == 0)
+			break;
+		udelay(1);
+	}
+}
+
+static void sumo_set_forced_mode_disabled(struct radeon_device *rdev)
+{
+	sumo_set_forced_mode(rdev, false);
+}
+
+static void sumo_enable_power_level_0(struct radeon_device *rdev)
+{
+	sumo_power_level_enable(rdev, 0, true);
+}
+
+static void sumo_patch_boost_state(struct radeon_device *rdev)
+{
+	struct sumo_power_info *pi = sumo_get_pi(rdev);
+	struct sumo_ps *new_ps = sumo_get_ps(rdev->pm.dpm.requested_ps);
+
+	if (new_ps->flags & SUMO_POWERSTATE_FLAGS_BOOST_STATE) {
+		pi->boost_pl = new_ps->levels[new_ps->num_levels - 1];
+		pi->boost_pl.sclk = pi->sys_info.boost_sclk;
+		pi->boost_pl.vddc_index = pi->sys_info.boost_vid_2bit;
+		pi->boost_pl.sclk_dpm_tdp_limit = pi->sys_info.sclk_dpm_tdp_limit_boost;
+	}
+}
+
+static void sumo_pre_notify_alt_vddnb_change(struct radeon_device *rdev)
+{
+	struct sumo_ps *new_ps = sumo_get_ps(rdev->pm.dpm.requested_ps);
+	struct sumo_ps *old_ps = sumo_get_ps(rdev->pm.dpm.current_ps);
+	u32 nbps1_old = 0;
+	u32 nbps1_new = 0;
+
+	if (old_ps != NULL)
+		nbps1_old = (old_ps->flags & SUMO_POWERSTATE_FLAGS_FORCE_NBPS1_STATE) ? 1 : 0;
+
+	nbps1_new = (new_ps->flags & SUMO_POWERSTATE_FLAGS_FORCE_NBPS1_STATE) ? 1 : 0;
+
+	if (nbps1_old == 1 && nbps1_new == 0)
+		sumo_smu_notify_alt_vddnb_change(rdev, 0, 0);
+}
+
+static void sumo_post_notify_alt_vddnb_change(struct radeon_device *rdev)
+{
+	struct sumo_ps *new_ps = sumo_get_ps(rdev->pm.dpm.requested_ps);
+	struct sumo_ps *old_ps = sumo_get_ps(rdev->pm.dpm.current_ps);
+	u32 nbps1_old = 0;
+	u32 nbps1_new = 0;
+
+	if (old_ps != NULL)
+		nbps1_old = (old_ps->flags & SUMO_POWERSTATE_FLAGS_FORCE_NBPS1_STATE)? 1 : 0;
+
+	nbps1_new = (new_ps->flags & SUMO_POWERSTATE_FLAGS_FORCE_NBPS1_STATE)? 1 : 0;
+
+	if (nbps1_old == 0 && nbps1_new == 1)
+		sumo_smu_notify_alt_vddnb_change(rdev, 1, 1);
+}
+
+static void sumo_enable_boost(struct radeon_device *rdev, bool enable)
+{
+	struct sumo_ps *new_ps = sumo_get_ps(rdev->pm.dpm.requested_ps);
+
+	if (enable) {
+		if (new_ps->flags & SUMO_POWERSTATE_FLAGS_BOOST_STATE)
+			sumo_boost_state_enable(rdev, true);
+	} else
+		sumo_boost_state_enable(rdev, false);
+}
+
+static void sumo_update_current_power_levels(struct radeon_device *rdev)
+{
+	struct sumo_ps *new_ps = sumo_get_ps(rdev->pm.dpm.requested_ps);
+	struct sumo_power_info *pi = sumo_get_pi(rdev);
+
+	pi->current_ps = *new_ps;
+}
+
+static void sumo_set_forced_level(struct radeon_device *rdev, u32 index)
+{
+	WREG32_P(CG_SCLK_DPM_CTRL_3, FORCE_SCLK_STATE(index), ~FORCE_SCLK_STATE_MASK);
+}
+
+static void sumo_set_forced_level_0(struct radeon_device *rdev)
+{
+	sumo_set_forced_level(rdev, 0);
+}
+
+static void sumo_program_wl(struct radeon_device *rdev)
+{
+	struct sumo_ps *new_ps = sumo_get_ps(rdev->pm.dpm.requested_ps);
+	u32 dpm_ctrl4 = RREG32(CG_SCLK_DPM_CTRL_4);
+
+	dpm_ctrl4 &= 0xFFFFFF00;
+	dpm_ctrl4 |= (1 << (new_ps->num_levels - 1));
+
+	if (new_ps->flags & SUMO_POWERSTATE_FLAGS_BOOST_STATE)
+		dpm_ctrl4 |= (1 << BOOST_DPM_LEVEL);
+
+	WREG32(CG_SCLK_DPM_CTRL_4, dpm_ctrl4);
+}
+
+static void sumo_program_power_levels_0_to_n(struct radeon_device *rdev)
+{
+	struct sumo_power_info *pi = sumo_get_pi(rdev);
+	struct sumo_ps *new_ps = sumo_get_ps(rdev->pm.dpm.requested_ps);
+	struct sumo_ps *old_ps = sumo_get_ps(rdev->pm.dpm.current_ps);
+	u32 i;
+	u32 n_current_state_levels = (old_ps == NULL) ? 1 : old_ps->num_levels;
+
+	for (i = 0; i < new_ps->num_levels; i++) {
+		sumo_program_power_level(rdev, &new_ps->levels[i], i);
+		sumo_power_level_enable(rdev, i, true);
+	}
+
+	for (i = new_ps->num_levels; i < n_current_state_levels; i++)
+		sumo_power_level_enable(rdev, i, false);
+
+	if (new_ps->flags & SUMO_POWERSTATE_FLAGS_BOOST_STATE)
+		sumo_program_power_level(rdev, &pi->boost_pl, BOOST_DPM_LEVEL);
+}
+
+static void sumo_enable_acpi_pm(struct radeon_device *rdev)
+{
+	WREG32_P(GENERAL_PWRMGT, STATIC_PM_EN, ~STATIC_PM_EN);
+}
+
+static void sumo_program_power_level_enter_state(struct radeon_device *rdev)
+{
+	WREG32_P(CG_SCLK_DPM_CTRL_5, SCLK_FSTATE_BOOTUP(0), ~SCLK_FSTATE_BOOTUP_MASK);
+}
+
+static void sumo_program_acpi_power_level(struct radeon_device *rdev)
+{
+	struct sumo_power_info *pi = sumo_get_pi(rdev);
+	struct atom_clock_dividers dividers;
+	int ret;
+
+        ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
+                                             pi->acpi_pl.sclk,
+					     false, &dividers);
+	if (ret)
+		return;
+
+	WREG32_P(CG_ACPI_CNTL, SCLK_ACPI_DIV(dividers.post_div), ~SCLK_ACPI_DIV_MASK);
+	WREG32_P(CG_ACPI_VOLTAGE_CNTL, 0, ~ACPI_VOLTAGE_EN);
+}
+
+static void sumo_program_bootup_state(struct radeon_device *rdev)
+{
+	struct sumo_power_info *pi = sumo_get_pi(rdev);
+	u32 dpm_ctrl4 = RREG32(CG_SCLK_DPM_CTRL_4);
+	u32 i;
+
+	sumo_program_power_level(rdev, &pi->boot_pl, 0);
+
+	dpm_ctrl4 &= 0xFFFFFF00;
+	WREG32(CG_SCLK_DPM_CTRL_4, dpm_ctrl4);
+
+	for (i = 1; i < 8; i++)
+		sumo_power_level_enable(rdev, i, false);
+}
+
+static void sumo_take_smu_control(struct radeon_device *rdev, bool enable)
+{
+	u32 v = RREG32(DOUT_SCRATCH3);
+
+	if (enable)
+		v |= 0x4;
+	else
+		v &= 0xFFFFFFFB;
+
+	WREG32(DOUT_SCRATCH3, v);
+}
+
+static void sumo_enable_sclk_ds(struct radeon_device *rdev, bool enable)
+{
+	if (enable) {
+		u32 deep_sleep_cntl = RREG32(DEEP_SLEEP_CNTL);
+		u32 deep_sleep_cntl2 = RREG32(DEEP_SLEEP_CNTL2);
+		u32 t = 1;
+
+		deep_sleep_cntl &= ~R_DIS;
+		deep_sleep_cntl &= ~HS_MASK;
+		deep_sleep_cntl |= HS(t > 4095 ? 4095 : t);
+
+		deep_sleep_cntl2 |= LB_UFP_EN;
+		deep_sleep_cntl2 &= INOUT_C_MASK;
+		deep_sleep_cntl2 |= INOUT_C(0xf);
+
+		WREG32(DEEP_SLEEP_CNTL2, deep_sleep_cntl2);
+		WREG32(DEEP_SLEEP_CNTL, deep_sleep_cntl);
+	} else
+		WREG32_P(DEEP_SLEEP_CNTL, 0, ~ENABLE_DS);
+}
+
+static void sumo_program_bootup_at(struct radeon_device *rdev)
+{
+	WREG32_P(CG_AT_0, CG_R(0xffff), ~CG_R_MASK);
+	WREG32_P(CG_AT_0, CG_L(0), ~CG_L_MASK);
+}
+
+static void sumo_reset_am(struct radeon_device *rdev)
+{
+	WREG32_P(SCLK_PWRMGT_CNTL, FIR_RESET, ~FIR_RESET);
+}
+
+static void sumo_start_am(struct radeon_device *rdev)
+{
+	WREG32_P(SCLK_PWRMGT_CNTL, 0, ~FIR_RESET);
+}
+
+static void sumo_program_ttp(struct radeon_device *rdev)
+{
+	u32 xclk = sumo_get_xclk(rdev);
+	u32 p, u;
+	u32 cg_sclk_dpm_ctrl_5 = RREG32(CG_SCLK_DPM_CTRL_5);
+
+	r600_calculate_u_and_p(1000,
+			       xclk, 16, &p, &u);
+
+	cg_sclk_dpm_ctrl_5 &= ~(TT_TP_MASK | TT_TU_MASK);
+	cg_sclk_dpm_ctrl_5 |= TT_TP(p) | TT_TU(u);
+
+	WREG32(CG_SCLK_DPM_CTRL_5, cg_sclk_dpm_ctrl_5);
+}
+
+static void sumo_program_ttt(struct radeon_device *rdev)
+{
+	u32 cg_sclk_dpm_ctrl_3 = RREG32(CG_SCLK_DPM_CTRL_3);
+	struct sumo_power_info *pi = sumo_get_pi(rdev);
+
+	cg_sclk_dpm_ctrl_3 &= ~(GNB_TT_MASK | GNB_THERMTHRO_MASK);
+	cg_sclk_dpm_ctrl_3 |= GNB_TT(pi->thermal_auto_throttling + 49);
+
+	WREG32(CG_SCLK_DPM_CTRL_3, cg_sclk_dpm_ctrl_3);
+}
+
+
+static void sumo_enable_voltage_scaling(struct radeon_device *rdev, bool enable)
+{
+	if (enable) {
+		WREG32_P(CG_DPM_VOLTAGE_CNTL, DPM_VOLTAGE_EN, ~DPM_VOLTAGE_EN);
+		WREG32_P(CG_CG_VOLTAGE_CNTL, 0, ~CG_VOLTAGE_EN);
+	} else {
+		WREG32_P(CG_CG_VOLTAGE_CNTL, CG_VOLTAGE_EN, ~CG_VOLTAGE_EN);
+		WREG32_P(CG_DPM_VOLTAGE_CNTL, 0, ~DPM_VOLTAGE_EN);
+	}
+}
+
+static void sumo_override_cnb_thermal_events(struct radeon_device *rdev)
+{
+	WREG32_P(CG_SCLK_DPM_CTRL_3, CNB_THERMTHRO_MASK_SCLK,
+		 ~CNB_THERMTHRO_MASK_SCLK);
+}
+
+static void sumo_program_dc_hto(struct radeon_device *rdev)
+{
+	u32 cg_sclk_dpm_ctrl_4 = RREG32(CG_SCLK_DPM_CTRL_4);
+	u32 p, u;
+	u32 xclk = sumo_get_xclk(rdev);
+
+	r600_calculate_u_and_p(100000,
+			       xclk, 14, &p, &u);
+
+	cg_sclk_dpm_ctrl_4 &= ~(DC_HDC_MASK | DC_HU_MASK);
+	cg_sclk_dpm_ctrl_4 |= DC_HDC(p) | DC_HU(u);
+
+	WREG32(CG_SCLK_DPM_CTRL_4, cg_sclk_dpm_ctrl_4);
+}
+
+static void sumo_force_nbp_state(struct radeon_device *rdev)
+{
+	struct sumo_power_info *pi = sumo_get_pi(rdev);
+	struct sumo_ps *new_ps = sumo_get_ps(rdev->pm.dpm.requested_ps);
+
+	if (!pi->driver_nbps_policy_disable) {
+		if (new_ps->flags & SUMO_POWERSTATE_FLAGS_FORCE_NBPS1_STATE)
+			WREG32_P(CG_SCLK_DPM_CTRL_3, FORCE_NB_PSTATE_1, ~FORCE_NB_PSTATE_1);
+		else
+			WREG32_P(CG_SCLK_DPM_CTRL_3, 0, ~FORCE_NB_PSTATE_1);
+	}
+}
+
+static u32 sumo_get_sleep_divider_from_id(u32 id)
+{
+	return 1 << id;
+}
+
+static u32 sumo_get_sleep_divider_id_from_clock(struct radeon_device *rdev,
+						u32 sclk,
+						u32 min_sclk_in_sr)
+{
+	struct sumo_power_info *pi = sumo_get_pi(rdev);
+	u32 i;
+	u32 temp;
+	u32 min = (min_sclk_in_sr > SUMO_MINIMUM_ENGINE_CLOCK) ?
+		min_sclk_in_sr : SUMO_MINIMUM_ENGINE_CLOCK;
+
+	if (sclk < min)
+		return 0;
+
+	if (!pi->enable_sclk_ds)
+		return 0;
+
+	for (i = SUMO_MAX_DEEPSLEEP_DIVIDER_ID;  ; i--) {
+		temp = sclk / sumo_get_sleep_divider_from_id(i);
+
+		if (temp >= min || i == 0)
+			break;
+	}
+	return i;
+}
+
+static u32 sumo_get_valid_engine_clock(struct radeon_device *rdev,
+				       u32 lower_limit)
+{
+	struct sumo_power_info *pi = sumo_get_pi(rdev);
+	u32 i;
+
+	for (i = 0; i < pi->sys_info.sclk_voltage_mapping_table.num_max_dpm_entries; i++) {
+		if (pi->sys_info.sclk_voltage_mapping_table.entries[i].sclk_frequency >= lower_limit)
+			return pi->sys_info.sclk_voltage_mapping_table.entries[i].sclk_frequency;
+	}
+
+	return pi->sys_info.sclk_voltage_mapping_table.entries[pi->sys_info.sclk_voltage_mapping_table.num_max_dpm_entries - 1].sclk_frequency;
+}
+
+static void sumo_patch_thermal_state(struct radeon_device *rdev,
+				     struct sumo_ps *ps,
+				     struct sumo_ps *current_ps)
+{
+	struct sumo_power_info *pi = sumo_get_pi(rdev);
+	u32 sclk_in_sr = pi->sys_info.min_sclk; /* ??? */
+	u32 current_vddc;
+	u32 current_sclk;
+	u32 current_index = 0;
+
+	if (current_ps) {
+		current_vddc = current_ps->levels[current_index].vddc_index;
+		current_sclk = current_ps->levels[current_index].sclk;
+	} else {
+		current_vddc = pi->boot_pl.vddc_index;
+		current_sclk = pi->boot_pl.sclk;
+	}
+
+	ps->levels[0].vddc_index = current_vddc;
+
+	if (ps->levels[0].sclk > current_sclk)
+		ps->levels[0].sclk = current_sclk;
+
+	ps->levels[0].ss_divider_index =
+		sumo_get_sleep_divider_id_from_clock(rdev, ps->levels[0].sclk, sclk_in_sr);
+
+	ps->levels[0].ds_divider_index =
+		sumo_get_sleep_divider_id_from_clock(rdev, ps->levels[0].sclk, SUMO_MINIMUM_ENGINE_CLOCK);
+
+	if (ps->levels[0].ds_divider_index > ps->levels[0].ss_divider_index + 1)
+		ps->levels[0].ds_divider_index = ps->levels[0].ss_divider_index + 1;
+
+	if (ps->levels[0].ss_divider_index == ps->levels[0].ds_divider_index) {
+		if (ps->levels[0].ss_divider_index > 1)
+			ps->levels[0].ss_divider_index = ps->levels[0].ss_divider_index - 1;
+	}
+
+	if (ps->levels[0].ss_divider_index == 0)
+		ps->levels[0].ds_divider_index = 0;
+
+	if (ps->levels[0].ds_divider_index == 0)
+		ps->levels[0].ss_divider_index = 0;
+}
+
+static void sumo_apply_state_adjust_rules(struct radeon_device *rdev)
+{
+	struct radeon_ps *rps = rdev->pm.dpm.requested_ps;
+	struct sumo_ps *ps = sumo_get_ps(rps);
+	struct sumo_ps *current_ps = sumo_get_ps(rdev->pm.dpm.current_ps);
+	struct sumo_power_info *pi = sumo_get_pi(rdev);
+	u32 min_voltage = 0; /* ??? */
+	u32 min_sclk = pi->sys_info.min_sclk; /* XXX check against disp reqs */
+	u32 sclk_in_sr = pi->sys_info.min_sclk; /* ??? */
+	u32 i;
+
+	if (rps->class & ATOM_PPLIB_CLASSIFICATION_THERMAL)
+		return sumo_patch_thermal_state(rdev, ps, current_ps);
+
+	if (pi->enable_boost) {
+		if (rps->class & ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE)
+			ps->flags |= SUMO_POWERSTATE_FLAGS_BOOST_STATE;
+	}
+
+	if ((rps->class & ATOM_PPLIB_CLASSIFICATION_UI_BATTERY) ||
+	    (rps->class & ATOM_PPLIB_CLASSIFICATION_SDSTATE) ||
+	    (rps->class & ATOM_PPLIB_CLASSIFICATION_HDSTATE))
+		ps->flags |= SUMO_POWERSTATE_FLAGS_FORCE_NBPS1_STATE;
+
+	for (i = 0; i < ps->num_levels; i++) {
+		if (ps->levels[i].vddc_index < min_voltage)
+			ps->levels[i].vddc_index = min_voltage;
+
+		if (ps->levels[i].sclk < min_sclk)
+			ps->levels[i].sclk =
+				sumo_get_valid_engine_clock(rdev, min_sclk);
+
+		ps->levels[i].ss_divider_index =
+			sumo_get_sleep_divider_id_from_clock(rdev, ps->levels[i].sclk, sclk_in_sr);
+
+		ps->levels[i].ds_divider_index =
+			sumo_get_sleep_divider_id_from_clock(rdev, ps->levels[i].sclk, SUMO_MINIMUM_ENGINE_CLOCK);
+
+		if (ps->levels[i].ds_divider_index > ps->levels[i].ss_divider_index + 1)
+			ps->levels[i].ds_divider_index = ps->levels[i].ss_divider_index + 1;
+
+		if (ps->levels[i].ss_divider_index == ps->levels[i].ds_divider_index) {
+			if (ps->levels[i].ss_divider_index > 1)
+				ps->levels[i].ss_divider_index = ps->levels[i].ss_divider_index - 1;
+		}
+
+		if (ps->levels[i].ss_divider_index == 0)
+			ps->levels[i].ds_divider_index = 0;
+
+		if (ps->levels[i].ds_divider_index == 0)
+			ps->levels[i].ss_divider_index = 0;
+
+		if (ps->flags & SUMO_POWERSTATE_FLAGS_FORCE_NBPS1_STATE)
+			ps->levels[i].allow_gnb_slow = 1;
+		else if ((rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE) ||
+			 (rps->class2 & ATOM_PPLIB_CLASSIFICATION2_MVC))
+			ps->levels[i].allow_gnb_slow = 0;
+		else if (i == ps->num_levels - 1)
+			ps->levels[i].allow_gnb_slow = 0;
+		else
+			ps->levels[i].allow_gnb_slow = 1;
+	}
+}
+
+static void sumo_cleanup_asic(struct radeon_device *rdev)
+{
+	sumo_take_smu_control(rdev, false);
+}
+
+static int sumo_set_thermal_temperature_range(struct radeon_device *rdev,
+					      int min_temp, int max_temp)
+{
+	int low_temp = 0 * 1000;
+	int high_temp = 255 * 1000;
+
+	if (low_temp < min_temp)
+		low_temp = min_temp;
+	if (high_temp > max_temp)
+		high_temp = max_temp;
+	if (high_temp < low_temp) {
+		DRM_ERROR("invalid thermal range: %d - %d\n", low_temp, high_temp);
+		return -EINVAL;
+	}
+
+	WREG32_P(CG_THERMAL_INT, DIG_THERM_INTH(49 + (high_temp / 1000)), ~DIG_THERM_INTH_MASK);
+	WREG32_P(CG_THERMAL_INT, DIG_THERM_INTL(49 + (low_temp / 1000)), ~DIG_THERM_INTL_MASK);
+
+	rdev->pm.dpm.thermal.min_temp = low_temp;
+	rdev->pm.dpm.thermal.max_temp = high_temp;
+
+	return 0;
+}
+
+int sumo_dpm_enable(struct radeon_device *rdev)
+{
+	struct sumo_power_info *pi = sumo_get_pi(rdev);
+
+	if (sumo_dpm_enabled(rdev))
+		return -EINVAL;
+
+	sumo_enable_clock_power_gating(rdev);
+	sumo_program_bootup_state(rdev);
+	sumo_init_bsp(rdev);
+	sumo_reset_am(rdev);
+	sumo_program_tp(rdev);
+	sumo_program_bootup_at(rdev);
+	sumo_start_am(rdev);
+	if (pi->enable_auto_thermal_throttling) {
+		sumo_program_ttp(rdev);
+		sumo_program_ttt(rdev);
+	}
+	sumo_program_dc_hto(rdev);
+	sumo_program_power_level_enter_state(rdev);
+	sumo_enable_voltage_scaling(rdev, true);
+	sumo_program_sstp(rdev);
+	sumo_program_vc(rdev);
+	sumo_override_cnb_thermal_events(rdev);
+	sumo_start_dpm(rdev);
+	sumo_wait_for_level_0(rdev);
+	if (pi->enable_sclk_ds)
+		sumo_enable_sclk_ds(rdev, true);
+	if (pi->enable_boost)
+		sumo_enable_boost_timer(rdev);
+
+	if (rdev->irq.installed &&
+	    r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
+		sumo_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
+		rdev->irq.dpm_thermal = true;
+		radeon_irq_set(rdev);
+	}
+
+	return 0;
+}
+
+void sumo_dpm_disable(struct radeon_device *rdev)
+{
+	struct sumo_power_info *pi = sumo_get_pi(rdev);
+
+	if (!sumo_dpm_enabled(rdev))
+		return;
+	sumo_disable_clock_power_gating(rdev);
+	if (pi->enable_sclk_ds)
+		sumo_enable_sclk_ds(rdev, false);
+	sumo_clear_vc(rdev);
+	sumo_wait_for_level_0(rdev);
+	sumo_stop_dpm(rdev);
+	sumo_enable_voltage_scaling(rdev, false);
+
+	if (rdev->irq.installed &&
+	    r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
+		rdev->irq.dpm_thermal = false;
+		radeon_irq_set(rdev);
+	}
+}
+
+int sumo_dpm_set_power_state(struct radeon_device *rdev)
+{
+	struct sumo_power_info *pi = sumo_get_pi(rdev);
+
+	if (pi->enable_dynamic_patch_ps)
+		sumo_apply_state_adjust_rules(rdev);
+	sumo_update_current_power_levels(rdev);
+	if (pi->enable_boost) {
+		sumo_enable_boost(rdev, false);
+		sumo_patch_boost_state(rdev);
+	}
+	if (pi->enable_dpm) {
+		sumo_pre_notify_alt_vddnb_change(rdev);
+		sumo_enable_power_level_0(rdev);
+		sumo_set_forced_level_0(rdev);
+		sumo_set_forced_mode_enabled(rdev);
+		sumo_wait_for_level_0(rdev);
+		sumo_program_power_levels_0_to_n(rdev);
+		sumo_program_wl(rdev);
+		sumo_program_bsp(rdev);
+		sumo_program_at(rdev);
+		sumo_force_nbp_state(rdev);
+		sumo_set_forced_mode_disabled(rdev);
+		sumo_set_forced_mode_enabled(rdev);
+		sumo_set_forced_mode_disabled(rdev);
+		sumo_post_notify_alt_vddnb_change(rdev);
+	}
+	if (pi->enable_boost)
+		sumo_enable_boost(rdev, true);
+
+	return 0;
+}
+
+void sumo_dpm_reset_asic(struct radeon_device *rdev)
+{
+	sumo_program_bootup_state(rdev);
+	sumo_enable_power_level_0(rdev);
+	sumo_set_forced_level_0(rdev);
+	sumo_set_forced_mode_enabled(rdev);
+	sumo_wait_for_level_0(rdev);
+	sumo_set_forced_mode_disabled(rdev);
+	sumo_set_forced_mode_enabled(rdev);
+	sumo_set_forced_mode_disabled(rdev);
+}
+
+void sumo_dpm_setup_asic(struct radeon_device *rdev)
+{
+	struct sumo_power_info *pi = sumo_get_pi(rdev);
+
+	sumo_initialize_m3_arb(rdev);
+	pi->fw_version = sumo_get_running_fw_version(rdev);
+	DRM_INFO("Found smc ucode version: 0x%08x\n", pi->fw_version);
+	sumo_program_acpi_power_level(rdev);
+	sumo_enable_acpi_pm(rdev);
+	sumo_take_smu_control(rdev, true);
+}
+
+void sumo_dpm_display_configuration_changed(struct radeon_device *rdev)
+{
+
+}
+
+union power_info {
+	struct _ATOM_POWERPLAY_INFO info;
+	struct _ATOM_POWERPLAY_INFO_V2 info_2;
+	struct _ATOM_POWERPLAY_INFO_V3 info_3;
+	struct _ATOM_PPLIB_POWERPLAYTABLE pplib;
+	struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2;
+	struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3;
+};
+
+union pplib_clock_info {
+	struct _ATOM_PPLIB_R600_CLOCK_INFO r600;
+	struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780;
+	struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen;
+	struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo;
+};
+
+union pplib_power_state {
+	struct _ATOM_PPLIB_STATE v1;
+	struct _ATOM_PPLIB_STATE_V2 v2;
+};
+
+static void sumo_patch_boot_state(struct radeon_device *rdev,
+				  struct sumo_ps *ps)
+{
+	struct sumo_power_info *pi = sumo_get_pi(rdev);
+
+	ps->num_levels = 1;
+	ps->flags = 0;
+	ps->levels[0] = pi->boot_pl;
+}
+
+static void sumo_parse_pplib_non_clock_info(struct radeon_device *rdev,
+					    struct radeon_ps *rps,
+					    struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info,
+					    u8 table_rev)
+{
+	struct sumo_ps *ps = sumo_get_ps(rps);
+
+	rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings);
+	rps->class = le16_to_cpu(non_clock_info->usClassification);
+	rps->class2 = le16_to_cpu(non_clock_info->usClassification2);
+
+	if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) {
+		rps->vclk = le32_to_cpu(non_clock_info->ulVCLK);
+		rps->dclk = le32_to_cpu(non_clock_info->ulDCLK);
+	} else {
+		rps->vclk = 0;
+		rps->dclk = 0;
+	}
+
+	if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) {
+		rdev->pm.dpm.boot_ps = rps;
+		sumo_patch_boot_state(rdev, ps);
+	}
+	if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
+		rdev->pm.dpm.uvd_ps = rps;
+}
+
+static void sumo_parse_pplib_clock_info(struct radeon_device *rdev,
+					struct radeon_ps *rps, int index,
+					union pplib_clock_info *clock_info)
+{
+	struct sumo_power_info *pi = sumo_get_pi(rdev);
+	struct sumo_ps *ps = sumo_get_ps(rps);
+	struct sumo_pl *pl = &ps->levels[index];
+	u32 sclk;
+
+	sclk = le16_to_cpu(clock_info->sumo.usEngineClockLow);
+	sclk |= clock_info->sumo.ucEngineClockHigh << 16;
+	pl->sclk = sclk;
+	pl->vddc_index = clock_info->sumo.vddcIndex;
+	pl->sclk_dpm_tdp_limit = clock_info->sumo.tdpLimit;
+
+	ps->num_levels = index + 1;
+
+	if (pi->enable_sclk_ds) {
+		pl->ds_divider_index = 5;
+		pl->ss_divider_index = 4;
+	}
+}
+
+static int sumo_parse_power_table(struct radeon_device *rdev)
+{
+	struct radeon_mode_info *mode_info = &rdev->mode_info;
+	struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
+	union pplib_power_state *power_state;
+	int i, j, k, non_clock_array_index, clock_array_index;
+	union pplib_clock_info *clock_info;
+	struct _StateArray *state_array;
+	struct _ClockInfoArray *clock_info_array;
+	struct _NonClockInfoArray *non_clock_info_array;
+	union power_info *power_info;
+	int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
+        u16 data_offset;
+	u8 frev, crev;
+	u8 *power_state_offset;
+	struct sumo_ps *ps;
+
+	if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
+				   &frev, &crev, &data_offset))
+		return -EINVAL;
+	power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
+
+	state_array = (struct _StateArray *)
+		(mode_info->atom_context->bios + data_offset +
+		 le16_to_cpu(power_info->pplib.usStateArrayOffset));
+	clock_info_array = (struct _ClockInfoArray *)
+		(mode_info->atom_context->bios + data_offset +
+		 le16_to_cpu(power_info->pplib.usClockInfoArrayOffset));
+	non_clock_info_array = (struct _NonClockInfoArray *)
+		(mode_info->atom_context->bios + data_offset +
+		 le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset));
+
+	rdev->pm.dpm.ps = kzalloc(sizeof(struct radeon_ps) *
+				  state_array->ucNumEntries, GFP_KERNEL);
+	if (!rdev->pm.dpm.ps)
+		return -ENOMEM;
+	power_state_offset = (u8 *)state_array->states;
+	rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps);
+	rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime);
+	rdev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime);
+	for (i = 0; i < state_array->ucNumEntries; i++) {
+		power_state = (union pplib_power_state *)power_state_offset;
+		non_clock_array_index = power_state->v2.nonClockInfoIndex;
+		non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
+			&non_clock_info_array->nonClockInfo[non_clock_array_index];
+		if (!rdev->pm.power_state[i].clock_info)
+			return -EINVAL;
+		ps = kzalloc(sizeof(struct sumo_ps), GFP_KERNEL);
+		if (ps == NULL) {
+			kfree(rdev->pm.dpm.ps);
+			return -ENOMEM;
+		}
+		rdev->pm.dpm.ps[i].ps_priv = ps;
+		k = 0;
+		for (j = 0; j < power_state->v2.ucNumDPMLevels; j++) {
+			clock_array_index = power_state->v2.clockInfoIndex[j];
+			if (k >= SUMO_MAX_HARDWARE_POWERLEVELS)
+				break;
+			clock_info = (union pplib_clock_info *)
+				&clock_info_array->clockInfo[clock_array_index * clock_info_array->ucEntrySize];
+			sumo_parse_pplib_clock_info(rdev,
+						    &rdev->pm.dpm.ps[i], k,
+						    clock_info);
+			k++;
+		}
+		sumo_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i],
+						non_clock_info,
+						non_clock_info_array->ucEntrySize);
+		power_state_offset += 2 + power_state->v2.ucNumDPMLevels;
+	}
+	rdev->pm.dpm.num_ps = state_array->ucNumEntries;
+	return 0;
+}
+
+static u32 sumo_convert_vid2_to_vid7(struct radeon_device *rdev, u32 vid_2bit)
+{
+	struct sumo_power_info *pi = sumo_get_pi(rdev);
+	u32 i;
+
+	for (i = 0; i < pi->sys_info.vid_mapping_table.num_entries; i++) {
+		if (pi->sys_info.vid_mapping_table.entries[i].vid_2bit == vid_2bit)
+			return pi->sys_info.vid_mapping_table.entries[i].vid_7bit;
+	}
+
+	return pi->sys_info.vid_mapping_table.entries[pi->sys_info.vid_mapping_table.num_entries - 1].vid_7bit;
+}
+
+static u16 sumo_convert_voltage_index_to_value(struct radeon_device *rdev,
+					       u32 vid_2bit)
+{
+	u32 vid_7bit = sumo_convert_vid2_to_vid7(rdev, vid_2bit);
+
+	if (vid_7bit > 0x7C)
+		return 0;
+
+	return (15500 - vid_7bit * 125 + 5) / 10;
+}
+
+static void sumo_construct_display_voltage_mapping_table(struct radeon_device *rdev,
+							 ATOM_CLK_VOLT_CAPABILITY *table)
+{
+	struct sumo_power_info *pi = sumo_get_pi(rdev);
+	u32 i;
+
+	for (i = 0; i < SUMO_MAX_NUMBER_VOLTAGES; i++) {
+		if (table[i].ulMaximumSupportedCLK == 0)
+			break;
+
+		pi->sys_info.disp_clk_voltage_mapping_table.display_clock_frequency[i] =
+			table[i].ulMaximumSupportedCLK;
+	}
+
+	pi->sys_info.disp_clk_voltage_mapping_table.num_max_voltage_levels = i;
+
+	if (pi->sys_info.disp_clk_voltage_mapping_table.num_max_voltage_levels == 0) {
+		pi->sys_info.disp_clk_voltage_mapping_table.display_clock_frequency[0] = 80000;
+		pi->sys_info.disp_clk_voltage_mapping_table.num_max_voltage_levels = 1;
+	}
+}
+
+static void sumo_construct_sclk_voltage_mapping_table(struct radeon_device *rdev,
+						      ATOM_AVAILABLE_SCLK_LIST *table)
+{
+	struct sumo_power_info *pi = sumo_get_pi(rdev);
+	u32 i;
+	u32 n = 0;
+	u32 prev_sclk = 0;
+
+	for (i = 0; i < SUMO_MAX_HARDWARE_POWERLEVELS; i++) {
+		if (table[i].ulSupportedSCLK > prev_sclk) {
+			pi->sys_info.sclk_voltage_mapping_table.entries[n].sclk_frequency =
+				table[i].ulSupportedSCLK;
+			pi->sys_info.sclk_voltage_mapping_table.entries[n].vid_2bit =
+				table[i].usVoltageIndex;
+			prev_sclk = table[i].ulSupportedSCLK;
+			n++;
+		}
+	}
+
+	pi->sys_info.sclk_voltage_mapping_table.num_max_dpm_entries = n;
+}
+
+static void sumo_construct_vid_mapping_table(struct radeon_device *rdev,
+					     ATOM_AVAILABLE_SCLK_LIST *table)
+{
+	struct sumo_power_info *pi = sumo_get_pi(rdev);
+	u32 i, j;
+
+	for (i = 0; i < SUMO_MAX_HARDWARE_POWERLEVELS; i++) {
+		if (table[i].ulSupportedSCLK != 0) {
+			pi->sys_info.vid_mapping_table.entries[table[i].usVoltageIndex].vid_7bit =
+				table[i].usVoltageID;
+			pi->sys_info.vid_mapping_table.entries[table[i].usVoltageIndex].vid_2bit =
+				table[i].usVoltageIndex;
+		}
+	}
+
+	for (i = 0; i < SUMO_MAX_NUMBER_VOLTAGES; i++) {
+		if (pi->sys_info.vid_mapping_table.entries[i].vid_7bit == 0) {
+			for (j = i + 1; j < SUMO_MAX_NUMBER_VOLTAGES; j++) {
+				if (pi->sys_info.vid_mapping_table.entries[j].vid_7bit != 0) {
+					pi->sys_info.vid_mapping_table.entries[i] =
+						pi->sys_info.vid_mapping_table.entries[j];
+					pi->sys_info.vid_mapping_table.entries[j].vid_7bit = 0;
+					break;
+				}
+			}
+
+			if (j == SUMO_MAX_NUMBER_VOLTAGES)
+				break;
+		}
+	}
+
+	pi->sys_info.vid_mapping_table.num_entries = i;
+}
+
+union igp_info {
+	struct _ATOM_INTEGRATED_SYSTEM_INFO info;
+	struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2;
+	struct _ATOM_INTEGRATED_SYSTEM_INFO_V5 info_5;
+	struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 info_6;
+};
+
+static int sumo_parse_sys_info_table(struct radeon_device *rdev)
+{
+	struct sumo_power_info *pi = sumo_get_pi(rdev);
+	struct radeon_mode_info *mode_info = &rdev->mode_info;
+	int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);
+	union igp_info *igp_info;
+	u8 frev, crev;
+	u16 data_offset;
+	int i;
+
+	if (atom_parse_data_header(mode_info->atom_context, index, NULL,
+				   &frev, &crev, &data_offset)) {
+		igp_info = (union igp_info *)(mode_info->atom_context->bios +
+					      data_offset);
+
+		if (crev != 6) {
+			DRM_ERROR("Unsupported IGP table: %d %d\n", frev, crev);
+			return -EINVAL;
+		}
+		pi->sys_info.bootup_sclk = le32_to_cpu(igp_info->info_6.ulBootUpEngineClock);
+		pi->sys_info.min_sclk = le32_to_cpu(igp_info->info_6.ulMinEngineClock);
+		pi->sys_info.bootup_uma_clk = le32_to_cpu(igp_info->info_6.ulBootUpUMAClock);
+		pi->sys_info.bootup_nb_voltage_index =
+			le16_to_cpu(igp_info->info_6.usBootUpNBVoltage);
+		if (igp_info->info_6.ucHtcTmpLmt == 0)
+			pi->sys_info.htc_tmp_lmt = 203;
+		else
+			pi->sys_info.htc_tmp_lmt = igp_info->info_6.ucHtcTmpLmt;
+		if (igp_info->info_6.ucHtcHystLmt == 0)
+			pi->sys_info.htc_hyst_lmt = 5;
+		else
+			pi->sys_info.htc_hyst_lmt = igp_info->info_6.ucHtcHystLmt;
+		if (pi->sys_info.htc_tmp_lmt <= pi->sys_info.htc_hyst_lmt) {
+			DRM_ERROR("The htcTmpLmt should be larger than htcHystLmt.\n");
+		}
+		for (i = 0; i < NUMBER_OF_M3ARB_PARAM_SETS; i++) {
+			pi->sys_info.csr_m3_arb_cntl_default[i] =
+				le32_to_cpu(igp_info->info_6.ulCSR_M3_ARB_CNTL_DEFAULT[i]);
+			pi->sys_info.csr_m3_arb_cntl_uvd[i] =
+				le32_to_cpu(igp_info->info_6.ulCSR_M3_ARB_CNTL_UVD[i]);
+			pi->sys_info.csr_m3_arb_cntl_fs3d[i] =
+				le32_to_cpu(igp_info->info_6.ulCSR_M3_ARB_CNTL_FS3D[i]);
+		}
+		pi->sys_info.sclk_dpm_boost_margin =
+			le32_to_cpu(igp_info->info_6.SclkDpmBoostMargin);
+		pi->sys_info.sclk_dpm_throttle_margin =
+			le32_to_cpu(igp_info->info_6.SclkDpmThrottleMargin);
+		pi->sys_info.sclk_dpm_tdp_limit_pg =
+			le16_to_cpu(igp_info->info_6.SclkDpmTdpLimitPG);
+		pi->sys_info.gnb_tdp_limit = le16_to_cpu(igp_info->info_6.GnbTdpLimit);
+		pi->sys_info.sclk_dpm_tdp_limit_boost =
+			le16_to_cpu(igp_info->info_6.SclkDpmTdpLimitBoost);
+		pi->sys_info.boost_sclk = le32_to_cpu(igp_info->info_6.ulBoostEngineCLock);
+		pi->sys_info.boost_vid_2bit = igp_info->info_6.ulBoostVid_2bit;
+		if (igp_info->info_6.EnableBoost)
+			pi->sys_info.enable_boost = true;
+		else
+			pi->sys_info.enable_boost = false;
+		sumo_construct_display_voltage_mapping_table(rdev,
+							     igp_info->info_6.sDISPCLK_Voltage);
+		sumo_construct_sclk_voltage_mapping_table(rdev,
+							  igp_info->info_6.sAvail_SCLK);
+		sumo_construct_vid_mapping_table(rdev, igp_info->info_6.sAvail_SCLK);
+
+	}
+	return 0;
+}
+
+static void sumo_construct_boot_and_acpi_state(struct radeon_device *rdev)
+{
+	struct sumo_power_info *pi = sumo_get_pi(rdev);
+
+	pi->boot_pl.sclk = pi->sys_info.bootup_sclk;
+	pi->boot_pl.vddc_index = pi->sys_info.bootup_nb_voltage_index;
+	pi->boot_pl.ds_divider_index = 0;
+	pi->boot_pl.ss_divider_index = 0;
+	pi->boot_pl.allow_gnb_slow = 1;
+	pi->acpi_pl = pi->boot_pl;
+	pi->current_ps.num_levels = 1;
+	pi->current_ps.levels[0] = pi->boot_pl;
+}
+
+int sumo_dpm_init(struct radeon_device *rdev)
+{
+	struct sumo_power_info *pi;
+	u32 hw_rev = (RREG32(HW_REV) & ATI_REV_ID_MASK) >> ATI_REV_ID_SHIFT;
+	int ret;
+
+	pi = kzalloc(sizeof(struct sumo_power_info), GFP_KERNEL);
+	if (pi == NULL)
+		return -ENOMEM;
+	rdev->pm.dpm.priv = pi;
+
+	pi->driver_nbps_policy_disable = false;
+	if ((rdev->family == CHIP_PALM) && (hw_rev < 3))
+		pi->disable_gfx_power_gating_in_uvd = true;
+	else
+		pi->disable_gfx_power_gating_in_uvd = false;
+	pi->enable_alt_vddnb = true;
+	pi->enable_sclk_ds = true;
+	pi->enable_dynamic_m3_arbiter = false;
+	pi->enable_dynamic_patch_ps = true;
+	pi->enable_gfx_power_gating = true;
+	pi->enable_gfx_clock_gating = true;
+	pi->enable_mg_clock_gating = true;
+	pi->enable_auto_thermal_throttling = true;
+
+	ret = sumo_parse_sys_info_table(rdev);
+	if (ret)
+		return ret;
+
+	sumo_construct_boot_and_acpi_state(rdev);
+
+	ret = sumo_parse_power_table(rdev);
+	if (ret)
+		return ret;
+
+	pi->pasi = CYPRESS_HASI_DFLT;
+	pi->asi = RV770_ASI_DFLT;
+	pi->thermal_auto_throttling = pi->sys_info.htc_tmp_lmt;
+	pi->enable_boost = pi->sys_info.enable_boost;
+	pi->enable_dpm = true;
+
+	return 0;
+}
+
+void sumo_dpm_print_power_state(struct radeon_device *rdev,
+				struct radeon_ps *rps)
+{
+	int i;
+	struct sumo_ps *ps = sumo_get_ps(rps);
+
+	r600_dpm_print_class_info(rps->class, rps->class2);
+	r600_dpm_print_cap_info(rps->caps);
+	printk("\tuvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
+	for (i = 0; i < ps->num_levels; i++) {
+		struct sumo_pl *pl = &ps->levels[i];
+		printk("\t\tpower level %d    sclk: %u vddc: %u\n",
+		       i, pl->sclk,
+		       sumo_convert_voltage_index_to_value(rdev, pl->vddc_index));
+	}
+	r600_dpm_print_ps_status(rdev, rps);
+}
+
+void sumo_dpm_fini(struct radeon_device *rdev)
+{
+	int i;
+
+	sumo_cleanup_asic(rdev); /* ??? */
+
+	for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
+		kfree(rdev->pm.dpm.ps[i].ps_priv);
+	}
+	kfree(rdev->pm.dpm.ps);
+	kfree(rdev->pm.dpm.priv);
+}
+
+u32 sumo_dpm_get_sclk(struct radeon_device *rdev, bool low)
+{
+	struct sumo_ps *requested_state = sumo_get_ps(rdev->pm.dpm.requested_ps);
+
+	if (low)
+		return requested_state->levels[0].sclk;
+	else
+		return requested_state->levels[requested_state->num_levels - 1].sclk;
+}
+
+u32 sumo_dpm_get_mclk(struct radeon_device *rdev, bool low)
+{
+	struct sumo_power_info *pi = sumo_get_pi(rdev);
+
+	return pi->sys_info.bootup_uma_clk;
+}
diff --git a/drivers/gpu/drm/radeon/sumo_dpm.h b/drivers/gpu/drm/radeon/sumo_dpm.h
new file mode 100644
index 0000000..561bee1
--- /dev/null
+++ b/drivers/gpu/drm/radeon/sumo_dpm.h
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2012 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef __SUMO_DPM_H__
+#define __SUMO_DPM_H__
+
+#define SUMO_MAX_HARDWARE_POWERLEVELS 5
+#define SUMO_PM_NUMBER_OF_TC 15
+
+struct sumo_pl {
+	u32 sclk;
+	u32 vddc_index;
+	u32 ds_divider_index;
+	u32 ss_divider_index;
+	u32 allow_gnb_slow;
+	u32 sclk_dpm_tdp_limit;
+};
+
+/* used for the flags field */
+#define SUMO_POWERSTATE_FLAGS_FORCE_NBPS1_STATE (1 << 0)
+#define SUMO_POWERSTATE_FLAGS_BOOST_STATE       (1 << 1)
+
+struct sumo_ps {
+	struct sumo_pl levels[SUMO_MAX_HARDWARE_POWERLEVELS];
+	u32 num_levels;
+	/* flags */
+	u32 flags;
+};
+
+#define NUMBER_OF_M3ARB_PARAM_SETS 10
+#define SUMO_MAX_NUMBER_VOLTAGES    4
+
+struct sumo_disp_clock_voltage_mapping_table {
+	u32 num_max_voltage_levels;
+	u32 display_clock_frequency[SUMO_MAX_NUMBER_VOLTAGES];
+};
+
+struct sumo_vid_mapping_entry {
+	u16 vid_2bit;
+	u16 vid_7bit;
+};
+
+struct sumo_vid_mapping_table {
+	u32 num_entries;
+	struct sumo_vid_mapping_entry entries[SUMO_MAX_NUMBER_VOLTAGES];
+};
+
+struct sumo_sclk_voltage_mapping_entry {
+	u32 sclk_frequency;
+	u16 vid_2bit;
+	u16 rsv;
+};
+
+struct sumo_sclk_voltage_mapping_table {
+	u32 num_max_dpm_entries;
+	struct sumo_sclk_voltage_mapping_entry entries[SUMO_MAX_HARDWARE_POWERLEVELS];
+};
+
+struct sumo_sys_info {
+	u32 bootup_sclk;
+	u32 min_sclk;
+	u32 bootup_uma_clk;
+	u16 bootup_nb_voltage_index;
+	u8 htc_tmp_lmt;
+	u8 htc_hyst_lmt;
+	struct sumo_sclk_voltage_mapping_table sclk_voltage_mapping_table;
+	struct sumo_disp_clock_voltage_mapping_table disp_clk_voltage_mapping_table;
+	struct sumo_vid_mapping_table vid_mapping_table;
+	u32 csr_m3_arb_cntl_default[NUMBER_OF_M3ARB_PARAM_SETS];
+	u32 csr_m3_arb_cntl_uvd[NUMBER_OF_M3ARB_PARAM_SETS];
+	u32 csr_m3_arb_cntl_fs3d[NUMBER_OF_M3ARB_PARAM_SETS];
+	u32 sclk_dpm_boost_margin;
+	u32 sclk_dpm_throttle_margin;
+	u32 sclk_dpm_tdp_limit_pg;
+	u32 gnb_tdp_limit;
+	u32 sclk_dpm_tdp_limit_boost;
+	u32 boost_sclk;
+	u32 boost_vid_2bit;
+	bool enable_boost;
+};
+
+struct sumo_power_info {
+	u32 asi;
+	u32 pasi;
+	u32 bsp;
+	u32 bsu;
+	u32 pbsp;
+	u32 pbsu;
+	u32 dsp;
+	u32 psp;
+	u32 thermal_auto_throttling;
+	u32 uvd_m3_arbiter;
+	u32 fw_version;
+	struct sumo_sys_info sys_info;
+	struct sumo_pl acpi_pl;
+	struct sumo_pl boot_pl;
+	struct sumo_pl boost_pl;
+	struct sumo_ps current_ps;
+	bool disable_gfx_power_gating_in_uvd;
+	bool driver_nbps_policy_disable;
+	bool enable_alt_vddnb;
+	bool enable_dynamic_m3_arbiter;
+	bool enable_gfx_clock_gating;
+	bool enable_gfx_power_gating;
+	bool enable_mg_clock_gating;
+	bool enable_sclk_ds;
+	bool enable_auto_thermal_throttling;
+	bool enable_dynamic_patch_ps;
+	bool enable_dpm;
+	bool enable_boost;
+};
+
+#define SUMO_UTC_DFLT_00                     0x48
+#define SUMO_UTC_DFLT_01                     0x44
+#define SUMO_UTC_DFLT_02                     0x44
+#define SUMO_UTC_DFLT_03                     0x44
+#define SUMO_UTC_DFLT_04                     0x44
+#define SUMO_UTC_DFLT_05                     0x44
+#define SUMO_UTC_DFLT_06                     0x44
+#define SUMO_UTC_DFLT_07                     0x44
+#define SUMO_UTC_DFLT_08                     0x44
+#define SUMO_UTC_DFLT_09                     0x44
+#define SUMO_UTC_DFLT_10                     0x44
+#define SUMO_UTC_DFLT_11                     0x44
+#define SUMO_UTC_DFLT_12                     0x44
+#define SUMO_UTC_DFLT_13                     0x44
+#define SUMO_UTC_DFLT_14                     0x44
+
+#define SUMO_DTC_DFLT_00                     0x48
+#define SUMO_DTC_DFLT_01                     0x44
+#define SUMO_DTC_DFLT_02                     0x44
+#define SUMO_DTC_DFLT_03                     0x44
+#define SUMO_DTC_DFLT_04                     0x44
+#define SUMO_DTC_DFLT_05                     0x44
+#define SUMO_DTC_DFLT_06                     0x44
+#define SUMO_DTC_DFLT_07                     0x44
+#define SUMO_DTC_DFLT_08                     0x44
+#define SUMO_DTC_DFLT_09                     0x44
+#define SUMO_DTC_DFLT_10                     0x44
+#define SUMO_DTC_DFLT_11                     0x44
+#define SUMO_DTC_DFLT_12                     0x44
+#define SUMO_DTC_DFLT_13                     0x44
+#define SUMO_DTC_DFLT_14                     0x44
+
+#define SUMO_AH_DFLT               5
+
+#define SUMO_R_DFLT0               70
+#define SUMO_R_DFLT1               70
+#define SUMO_R_DFLT2               70
+#define SUMO_R_DFLT3               70
+#define SUMO_R_DFLT4               100
+
+#define SUMO_L_DFLT0               0
+#define SUMO_L_DFLT1               20
+#define SUMO_L_DFLT2               20
+#define SUMO_L_DFLT3               20
+#define SUMO_L_DFLT4               20
+#define SUMO_VRC_DFLT              0x30033
+#define SUMO_MGCGTTLOCAL0_DFLT     0
+#define SUMO_MGCGTTLOCAL1_DFLT     0
+#define SUMO_GICST_DFLT            19
+#define SUMO_SST_DFLT              8
+#define SUMO_VOLTAGEDROPT_DFLT     1
+#define SUMO_GFXPOWERGATINGT_DFLT  100
+
+/* sumo_dpm.c */
+u32 sumo_get_xclk(struct radeon_device *rdev);
+
+
+/* sumo_smc.c */
+void sumo_initialize_m3_arb(struct radeon_device *rdev);
+void sumo_smu_pg_init(struct radeon_device *rdev);
+void sumo_set_tdp_limit(struct radeon_device *rdev, u32 index, u32 tdp_limit);
+void sumo_smu_notify_alt_vddnb_change(struct radeon_device *rdev,
+				      bool powersaving, bool force_nbps1);
+void sumo_boost_state_enable(struct radeon_device *rdev, bool enable);
+void sumo_enable_boost_timer(struct radeon_device *rdev);
+u32 sumo_get_running_fw_version(struct radeon_device *rdev);
+
+#endif
diff --git a/drivers/gpu/drm/radeon/sumo_smc.c b/drivers/gpu/drm/radeon/sumo_smc.c
new file mode 100644
index 0000000..9d0ae9b
--- /dev/null
+++ b/drivers/gpu/drm/radeon/sumo_smc.c
@@ -0,0 +1,224 @@
+/*
+ * Copyright 2012 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include <linux/firmware.h>
+#include "drmP.h"
+#include "radeon.h"
+#include "sumod.h"
+#include "sumo_dpm.h"
+#include "ppsmc.h"
+#include "radeon_ucode.h"
+
+#define SUMO_SMU_SERVICE_ROUTINE_PG_INIT        1
+#define SUMO_SMU_SERVICE_ROUTINE_ALTVDDNB_NOTIFY  27
+#define SUMO_SMU_SERVICE_ROUTINE_GFX_SRV_ID_20  20
+
+struct sumo_ps *sumo_get_ps(struct radeon_ps *rps);
+struct sumo_power_info *sumo_get_pi(struct radeon_device *rdev);
+
+static void sumo_send_msg_to_smu(struct radeon_device *rdev, u32 id)
+{
+	u32 gfx_int_req;
+	int i;
+
+	for (i = 0; i < rdev->usec_timeout; i++) {
+		if (RREG32(GFX_INT_STATUS) & INT_DONE)
+			break;
+		udelay(1);
+	}
+
+	gfx_int_req = SERV_INDEX(id) | INT_REQ;
+	WREG32(GFX_INT_REQ, gfx_int_req);
+
+	for (i = 0; i < rdev->usec_timeout; i++) {
+		if (RREG32(GFX_INT_REQ) & INT_REQ)
+			break;
+		udelay(1);
+	}
+
+	for (i = 0; i < rdev->usec_timeout; i++) {
+		if (RREG32(GFX_INT_STATUS) & INT_ACK)
+			break;
+		udelay(1);
+	}
+
+	for (i = 0; i < rdev->usec_timeout; i++) {
+		if (RREG32(GFX_INT_STATUS) & INT_DONE)
+			break;
+		udelay(1);
+	}
+
+	gfx_int_req &= ~INT_REQ;
+	WREG32(GFX_INT_REQ, gfx_int_req);
+}
+
+void sumo_initialize_m3_arb(struct radeon_device *rdev)
+{
+	struct sumo_power_info *pi = sumo_get_pi(rdev);
+	u32 i;
+
+	if (!pi->enable_dynamic_m3_arbiter)
+		return;
+
+	for (i = 0; i < NUMBER_OF_M3ARB_PARAM_SETS; i++)
+		WREG32_RCU(MCU_M3ARB_PARAMS + (i * 4),
+			   pi->sys_info.csr_m3_arb_cntl_default[i]);
+
+	for (; i < NUMBER_OF_M3ARB_PARAM_SETS * 2; i++)
+		WREG32_RCU(MCU_M3ARB_PARAMS + (i * 4),
+			   pi->sys_info.csr_m3_arb_cntl_uvd[i % NUMBER_OF_M3ARB_PARAM_SETS]);
+
+	for (; i < NUMBER_OF_M3ARB_PARAM_SETS * 3; i++)
+		WREG32_RCU(MCU_M3ARB_PARAMS + (i * 4),
+			   pi->sys_info.csr_m3_arb_cntl_fs3d[i % NUMBER_OF_M3ARB_PARAM_SETS]);
+}
+
+static bool sumo_is_alt_vddnb_supported(struct radeon_device *rdev)
+{
+	struct sumo_power_info *pi = sumo_get_pi(rdev);
+	bool return_code = false;
+
+	if (!pi->enable_alt_vddnb)
+		return return_code;
+
+	if ((rdev->family == CHIP_SUMO) || (rdev->family == CHIP_SUMO2)) {
+		if (pi->fw_version >= 0x00010C00)
+			return_code = true;
+	}
+
+	return return_code;
+}
+
+void sumo_smu_notify_alt_vddnb_change(struct radeon_device *rdev,
+				      bool powersaving, bool force_nbps1)
+{
+	u32 param = 0;
+
+	if (!sumo_is_alt_vddnb_supported(rdev))
+		return;
+
+	if (powersaving)
+		param |= 1;
+
+	if (force_nbps1)
+		param |= 2;
+
+	WREG32_RCU(RCU_ALTVDDNB_NOTIFY, param);
+
+	sumo_send_msg_to_smu(rdev, SUMO_SMU_SERVICE_ROUTINE_ALTVDDNB_NOTIFY);
+}
+
+void sumo_smu_pg_init(struct radeon_device *rdev)
+{
+	sumo_send_msg_to_smu(rdev, SUMO_SMU_SERVICE_ROUTINE_PG_INIT);
+}
+
+static u32 sumo_power_of_4(u32 unit)
+{
+	u32 ret = 1;
+	u32 i;
+
+	for (i = 0; i < unit; i++)
+		ret *= 4;
+
+	return ret;
+}
+
+void sumo_enable_boost_timer(struct radeon_device *rdev)
+{
+	struct sumo_power_info *pi = sumo_get_pi(rdev);
+	u32 period, unit, timer_value;
+	u32 xclk = sumo_get_xclk(rdev);
+
+	unit = (RREG32_RCU(RCU_LCLK_SCALING_CNTL) & LCLK_SCALING_TIMER_PRESCALER_MASK)
+		>> LCLK_SCALING_TIMER_PRESCALER_SHIFT;
+
+	period = 100 * (xclk / 100 / sumo_power_of_4(unit));
+
+	timer_value = (period << 16) | (unit << 4);
+
+	WREG32_RCU(RCU_GNB_PWR_REP_TIMER_CNTL, timer_value);
+	WREG32_RCU(RCU_BOOST_MARGIN, pi->sys_info.sclk_dpm_boost_margin);
+	WREG32_RCU(RCU_THROTTLE_MARGIN, pi->sys_info.sclk_dpm_throttle_margin);
+	WREG32_RCU(GNB_TDP_LIMIT, pi->sys_info.gnb_tdp_limit);
+	WREG32_RCU(RCU_SclkDpmTdpLimitPG, pi->sys_info.sclk_dpm_tdp_limit_pg);
+
+	sumo_send_msg_to_smu(rdev, SUMO_SMU_SERVICE_ROUTINE_GFX_SRV_ID_20);
+}
+
+void sumo_set_tdp_limit(struct radeon_device *rdev, u32 index, u32 tdp_limit)
+{
+	u32 regoffset = 0;
+	u32 shift = 0;
+	u32 mask = 0xFFF;
+	u32 sclk_dpm_tdp_limit;
+
+	switch (index) {
+        case 0:
+		regoffset = RCU_SclkDpmTdpLimit01;
+		shift = 16;
+		break;
+        case 1:
+		regoffset = RCU_SclkDpmTdpLimit01;
+		shift = 0;
+		break;
+        case 2:
+		regoffset = RCU_SclkDpmTdpLimit23;
+		shift = 16;
+		break;
+        case 3:
+		regoffset = RCU_SclkDpmTdpLimit23;
+		shift = 0;
+		break;
+        case 4:
+		regoffset = RCU_SclkDpmTdpLimit47;
+		shift = 16;
+		break;
+        case 7:
+		regoffset = RCU_SclkDpmTdpLimit47;
+		shift = 0;
+		break;
+        default:
+		break;
+	}
+
+	sclk_dpm_tdp_limit = RREG32_RCU(regoffset);
+	sclk_dpm_tdp_limit &= ~(mask << shift);
+	sclk_dpm_tdp_limit |= (tdp_limit << shift);
+	WREG32_RCU(regoffset, sclk_dpm_tdp_limit);
+}
+
+void sumo_boost_state_enable(struct radeon_device *rdev, bool enable)
+{
+	u32 boost_disable = RREG32_RCU(RCU_GPU_BOOST_DISABLE);
+
+	boost_disable &= 0xFFFFFFFE;
+	boost_disable |= (enable ? 0 : 1);
+	WREG32_RCU(RCU_GPU_BOOST_DISABLE, boost_disable);
+}
+
+u32 sumo_get_running_fw_version(struct radeon_device *rdev)
+{
+	return RREG32_RCU(RCU_FW_VERSION);
+}
+
diff --git a/drivers/gpu/drm/radeon/sumod.h b/drivers/gpu/drm/radeon/sumod.h
new file mode 100644
index 0000000..a5deba6
--- /dev/null
+++ b/drivers/gpu/drm/radeon/sumod.h
@@ -0,0 +1,362 @@
+/*
+ * Copyright 2012 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Alex Deucher
+ */
+#ifndef _SUMOD_H_
+#define _SUMOD_H_
+
+/* pm registers */
+
+/* rcu */
+#define RCU_FW_VERSION                                  0x30c
+
+#define RCU_PWR_GATING_SEQ0                             0x408
+#define RCU_PWR_GATING_SEQ1                             0x40c
+#define RCU_PWR_GATING_CNTL                             0x410
+#       define PWR_GATING_EN                            (1 << 0)
+#       define RSVD_MASK                                (0x3 << 1)
+#       define PCV(x)                                   ((x) << 3)
+#       define PCV_MASK                                 (0x1f << 3)
+#       define PCV_SHIFT                                3
+#       define PCP(x)                                   ((x) << 8)
+#       define PCP_MASK                                 (0xf << 8)
+#       define PCP_SHIFT                                8
+#       define RPW(x)                                   ((x) << 16)
+#       define RPW_MASK                                 (0xf << 16)
+#       define RPW_SHIFT                                16
+#       define ID(x)                                    ((x) << 24)
+#       define ID_MASK                                  (0xf << 24)
+#       define ID_SHIFT                                 24
+#       define PGS(x)                                   ((x) << 28)
+#       define PGS_MASK                                 (0xf << 28)
+#       define PGS_SHIFT                                28
+
+#define RCU_ALTVDDNB_NOTIFY                             0x430
+#define RCU_LCLK_SCALING_CNTL                           0x434
+#       define LCLK_SCALING_EN                          (1 << 0)
+#       define LCLK_SCALING_TYPE                        (1 << 1)
+#       define LCLK_SCALING_TIMER_PRESCALER(x)          ((x) << 4)
+#       define LCLK_SCALING_TIMER_PRESCALER_MASK        (0xf << 4)
+#       define LCLK_SCALING_TIMER_PRESCALER_SHIFT       4
+#       define LCLK_SCALING_TIMER_PERIOD(x)             ((x) << 16)
+#       define LCLK_SCALING_TIMER_PERIOD_MASK           (0xf << 16)
+#       define LCLK_SCALING_TIMER_PERIOD_SHIFT          16
+
+#define RCU_PWR_GATING_CNTL_2                           0x4a0
+#       define MPPU(x)                                  ((x) << 0)
+#       define MPPU_MASK                                (0xffff << 0)
+#       define MPPU_SHIFT                               0
+#       define MPPD(x)                                  ((x) << 16)
+#       define MPPD_MASK                                (0xffff << 16)
+#       define MPPD_SHIFT                               16
+#define RCU_PWR_GATING_CNTL_3                           0x4a4
+#       define DPPU(x)                                  ((x) << 0)
+#       define DPPU_MASK                                (0xffff << 0)
+#       define DPPU_SHIFT                               0
+#       define DPPD(x)                                  ((x) << 16)
+#       define DPPD_MASK                                (0xffff << 16)
+#       define DPPD_SHIFT                               16
+#define RCU_PWR_GATING_CNTL_4                           0x4a8
+#       define RT(x)                                    ((x) << 0)
+#       define RT_MASK                                  (0xffff << 0)
+#       define RT_SHIFT                                 0
+#       define IT(x)                                    ((x) << 16)
+#       define IT_MASK                                  (0xffff << 16)
+#       define IT_SHIFT                                 16
+
+/* yes these two have the same address */
+#define RCU_PWR_GATING_CNTL_5                           0x504
+#define RCU_GPU_BOOST_DISABLE                           0x508
+
+#define MCU_M3ARB_INDEX                                 0x504
+#define MCU_M3ARB_PARAMS                                0x508
+
+#define RCU_GNB_PWR_REP_TIMER_CNTL                      0x50C
+
+#define RCU_SclkDpmTdpLimit01                           0x514
+#define RCU_SclkDpmTdpLimit23                           0x518
+#define RCU_SclkDpmTdpLimit47                           0x51C
+#define RCU_SclkDpmTdpLimitPG                           0x520
+
+#define GNB_TDP_LIMIT                                   0x540
+#define RCU_BOOST_MARGIN                                0x544
+#define RCU_THROTTLE_MARGIN                             0x548
+
+#define SMU_PCIE_PG_ARGS                                0x58C
+#define SMU_PCIE_PG_ARGS_2                              0x598
+#define SMU_PCIE_PG_ARGS_3                              0x59C
+
+/* mmio */
+#define RCU_STATUS                                      0x11c
+#       define GMC_PWR_GATER_BUSY                       (1 << 8)
+#       define GFX_PWR_GATER_BUSY                       (1 << 9)
+#       define UVD_PWR_GATER_BUSY                       (1 << 10)
+#       define PCIE_PWR_GATER_BUSY                      (1 << 11)
+#       define GMC_PWR_GATER_STATE                      (1 << 12)
+#       define GFX_PWR_GATER_STATE                      (1 << 13)
+#       define UVD_PWR_GATER_STATE                      (1 << 14)
+#       define PCIE_PWR_GATER_STATE                     (1 << 15)
+#       define GFX1_PWR_GATER_BUSY                      (1 << 16)
+#       define GFX2_PWR_GATER_BUSY                      (1 << 17)
+#       define GFX1_PWR_GATER_STATE                     (1 << 18)
+#       define GFX2_PWR_GATER_STATE                     (1 << 19)
+
+#define GFX_INT_REQ                                     0x120
+#       define INT_REQ                                  (1 << 0)
+#       define SERV_INDEX(x)                            ((x) << 1)
+#       define SERV_INDEX_MASK                          (0xff << 1)
+#       define SERV_INDEX_SHIFT                         1
+#define GFX_INT_STATUS                                  0x124
+#       define INT_ACK                                  (1 << 0)
+#       define INT_DONE                                 (1 << 1)
+
+#define CG_SCLK_CNTL                                    0x600
+#       define SCLK_DIVIDER(x)                          ((x) << 0)
+#       define SCLK_DIVIDER_MASK                        (0x7f << 0)
+#       define SCLK_DIVIDER_SHIFT                       0
+#define CG_SCLK_STATUS                                  0x604
+#       define SCLK_OVERCLK_DETECT                      (1 << 2)
+
+#define GENERAL_PWRMGT                                  0x63c
+#       define STATIC_PM_EN                             (1 << 1)
+
+#define SCLK_PWRMGT_CNTL                                0x644
+#       define SCLK_PWRMGT_OFF                          (1 << 0)
+#       define SCLK_LOW_D1                              (1 << 1)
+#       define FIR_RESET                                (1 << 4)
+#       define FIR_FORCE_TREND_SEL                      (1 << 5)
+#       define FIR_TREND_MODE                           (1 << 6)
+#       define DYN_GFX_CLK_OFF_EN                       (1 << 7)
+#       define GFX_CLK_FORCE_ON                         (1 << 8)
+#       define GFX_CLK_REQUEST_OFF                      (1 << 9)
+#       define GFX_CLK_FORCE_OFF                        (1 << 10)
+#       define GFX_CLK_OFF_ACPI_D1                      (1 << 11)
+#       define GFX_CLK_OFF_ACPI_D2                      (1 << 12)
+#       define GFX_CLK_OFF_ACPI_D3                      (1 << 13)
+#       define GFX_VOLTAGE_CHANGE_EN                    (1 << 16)
+#       define GFX_VOLTAGE_CHANGE_MODE                  (1 << 17)
+
+#define TARGET_AND_CURRENT_PROFILE_INDEX                0x66c
+#       define TARG_SCLK_INDEX(x)                       ((x) << 6)
+#       define TARG_SCLK_INDEX_MASK                     (0x7 << 6)
+#       define TARG_SCLK_INDEX_SHIFT                    6
+#       define CURR_SCLK_INDEX(x)                       ((x) << 9)
+#       define CURR_SCLK_INDEX_MASK                     (0x7 << 9)
+#       define CURR_SCLK_INDEX_SHIFT                    9
+#       define TARG_INDEX(x)                            ((x) << 12)
+#       define TARG_INDEX_MASK                          (0x7 << 12)
+#       define TARG_INDEX_SHIFT                         12
+#       define CURR_INDEX(x)                            ((x) << 15)
+#       define CURR_INDEX_MASK                          (0x7 << 15)
+#       define CURR_INDEX_SHIFT                         15
+
+#define CG_SCLK_DPM_CTRL                                0x684
+#       define SCLK_FSTATE_0_DIV(x)                     ((x) << 0)
+#       define SCLK_FSTATE_0_DIV_MASK                   (0x7f << 0)
+#       define SCLK_FSTATE_0_DIV_SHIFT                  0
+#       define SCLK_FSTATE_0_VLD                        (1 << 7)
+#       define SCLK_FSTATE_1_DIV(x)                     ((x) << 8)
+#       define SCLK_FSTATE_1_DIV_MASK                   (0x7f << 8)
+#       define SCLK_FSTATE_1_DIV_SHIFT                  8
+#       define SCLK_FSTATE_1_VLD                        (1 << 15)
+#       define SCLK_FSTATE_2_DIV(x)                     ((x) << 16)
+#       define SCLK_FSTATE_2_DIV_MASK                   (0x7f << 16)
+#       define SCLK_FSTATE_2_DIV_SHIFT                  16
+#       define SCLK_FSTATE_2_VLD                        (1 << 23)
+#       define SCLK_FSTATE_3_DIV(x)                     ((x) << 24)
+#       define SCLK_FSTATE_3_DIV_MASK                   (0x7f << 24)
+#       define SCLK_FSTATE_3_DIV_SHIFT                  24
+#       define SCLK_FSTATE_3_VLD                        (1 << 31)
+#define CG_SCLK_DPM_CTRL_2                              0x688
+#define CG_GCOOR                                        0x68c
+#       define PHC(x)                                   ((x) << 0)
+#       define PHC_MASK                                 (0x1f << 0)
+#       define PHC_SHIFT                                0
+#       define SDC(x)                                   ((x) << 9)
+#       define SDC_MASK                                 (0x3ff << 9)
+#       define SDC_SHIFT                                9
+#       define SU(x)                                    ((x) << 23)
+#       define SU_MASK                                  (0xf << 23)
+#       define SU_SHIFT                                 23
+#       define DIV_ID(x)                                ((x) << 28)
+#       define DIV_ID_MASK                              (0x7 << 28)
+#       define DIV_ID_SHIFT                             28
+
+#define CG_FTV                                          0x690
+#define CG_FFCT_0                                       0x694
+#       define UTC_0(x)                                 ((x) << 0)
+#       define UTC_0_MASK                               (0x3ff << 0)
+#       define UTC_0_SHIFT                              0
+#       define DTC_0(x)                                 ((x) << 10)
+#       define DTC_0_MASK                               (0x3ff << 10)
+#       define DTC_0_SHIFT                              10
+
+#define CG_GIT                                          0x6d8
+#       define CG_GICST(x)                              ((x) << 0)
+#       define CG_GICST_MASK                            (0xffff << 0)
+#       define CG_GICST_SHIFT                           0
+#       define CG_GIPOT(x)                              ((x) << 16)
+#       define CG_GIPOT_MASK                            (0xffff << 16)
+#       define CG_GIPOT_SHIFT                           16
+
+#define CG_SCLK_DPM_CTRL_3                              0x6e0
+#       define FORCE_SCLK_STATE(x)                      ((x) << 0)
+#       define FORCE_SCLK_STATE_MASK                    (0x7 << 0)
+#       define FORCE_SCLK_STATE_SHIFT                   0
+#       define FORCE_SCLK_STATE_EN                      (1 << 3)
+#       define GNB_TT(x)                                ((x) << 8)
+#       define GNB_TT_MASK                              (0xff << 8)
+#       define GNB_TT_SHIFT                             8
+#       define GNB_THERMTHRO_MASK                       (1 << 16)
+#       define CNB_THERMTHRO_MASK_SCLK                  (1 << 17)
+#       define DPM_SCLK_ENABLE                          (1 << 18)
+#       define GNB_SLOW_FSTATE_0_MASK                   (1 << 23)
+#       define GNB_SLOW_FSTATE_0_SHIFT                  23
+#       define FORCE_NB_PSTATE_1                        (1 << 31)
+
+#define CG_SSP                                          0x6e8
+#       define SST(x)                                   ((x) << 0)
+#       define SST_MASK                                 (0xffff << 0)
+#       define SST_SHIFT                                0
+#       define SSTU(x)                                  ((x) << 16)
+#       define SSTU_MASK                                (0xffff << 16)
+#       define SSTU_SHIFT                               16
+
+#define CG_ACPI_CNTL                                    0x70c
+#       define SCLK_ACPI_DIV(x)                         ((x) << 0)
+#       define SCLK_ACPI_DIV_MASK                       (0x7f << 0)
+#       define SCLK_ACPI_DIV_SHIFT                      0
+
+#define CG_SCLK_DPM_CTRL_4                              0x71c
+#       define DC_HDC(x)                                ((x) << 14)
+#       define DC_HDC_MASK                              (0x3fff << 14)
+#       define DC_HDC_SHIFT                             14
+#       define DC_HU(x)                                 ((x) << 28)
+#       define DC_HU_MASK                               (0xf << 28)
+#       define DC_HU_SHIFT                              28
+#define CG_SCLK_DPM_CTRL_5                              0x720
+#       define SCLK_FSTATE_BOOTUP(x)                    ((x) << 0)
+#       define SCLK_FSTATE_BOOTUP_MASK                  (0x7 << 0)
+#       define SCLK_FSTATE_BOOTUP_SHIFT                 0
+#       define TT_TP(x)                                 ((x) << 3)
+#       define TT_TP_MASK                               (0xffff << 3)
+#       define TT_TP_SHIFT                              3
+#       define TT_TU(x)                                 ((x) << 19)
+#       define TT_TU_MASK                               (0xff << 19)
+#       define TT_TU_SHIFT                              19
+#define CG_SCLK_DPM_CTRL_6                              0x724
+#define CG_AT_0                                         0x728
+#       define CG_R(x)                                  ((x) << 0)
+#       define CG_R_MASK                                (0xffff << 0)
+#       define CG_R_SHIFT                               0
+#       define CG_L(x)                                  ((x) << 16)
+#       define CG_L_MASK                                (0xffff << 16)
+#       define CG_L_SHIFT                               16
+#define CG_AT_1                                         0x72c
+#define CG_AT_2                                         0x730
+#define	CG_THERMAL_INT					0x734
+#define		DIG_THERM_INTH(x)			((x) << 8)
+#define		DIG_THERM_INTH_MASK			0x0000FF00
+#define		DIG_THERM_INTH_SHIFT			8
+#define		DIG_THERM_INTL(x)			((x) << 16)
+#define		DIG_THERM_INTL_MASK			0x00FF0000
+#define		DIG_THERM_INTL_SHIFT			16
+#define 	THERM_INT_MASK_HIGH			(1 << 24)
+#define 	THERM_INT_MASK_LOW			(1 << 25)
+#define CG_AT_3                                         0x738
+#define CG_AT_4                                         0x73c
+#define CG_AT_5                                         0x740
+#define CG_AT_6                                         0x744
+#define CG_AT_7                                         0x748
+
+#define CG_BSP_0                                        0x750
+#       define BSP(x)                                   ((x) << 0)
+#       define BSP_MASK                                 (0xffff << 0)
+#       define BSP_SHIFT                                0
+#       define BSU(x)                                   ((x) << 16)
+#       define BSU_MASK                                 (0xf << 16)
+#       define BSU_SHIFT                                16
+
+#define CG_CG_VOLTAGE_CNTL                              0x770
+#       define REQ                                      (1 << 0)
+#       define LEVEL(x)                                 ((x) << 1)
+#       define LEVEL_MASK                               (0x3 << 1)
+#       define LEVEL_SHIFT                              1
+#       define CG_VOLTAGE_EN                            (1 << 3)
+#       define FORCE                                    (1 << 4)
+#       define PERIOD(x)                                ((x) << 8)
+#       define PERIOD_MASK                              (0xffff << 8)
+#       define PERIOD_SHIFT                             8
+#       define UNIT(x)                                  ((x) << 24)
+#       define UNIT_MASK                                (0xf << 24)
+#       define UNIT_SHIFT                               24
+
+#define CG_ACPI_VOLTAGE_CNTL                            0x780
+#       define ACPI_VOLTAGE_EN                          (1 << 8)
+
+#define CG_DPM_VOLTAGE_CNTL                             0x788
+#       define DPM_STATE0_LEVEL_MASK                    (0x3 << 0)
+#       define DPM_STATE0_LEVEL_SHIFT                   0
+#       define DPM_VOLTAGE_EN                           (1 << 16)
+
+#define CG_PWR_GATING_CNTL                              0x7ac
+#       define DYN_PWR_DOWN_EN                          (1 << 0)
+#       define ACPI_PWR_DOWN_EN                         (1 << 1)
+#       define GFX_CLK_OFF_PWR_DOWN_EN                  (1 << 2)
+#       define IOC_DISGPU_PWR_DOWN_EN                   (1 << 3)
+#       define FORCE_POWR_ON                            (1 << 4)
+#       define PGP(x)                                   ((x) << 8)
+#       define PGP_MASK                                 (0xffff << 8)
+#       define PGP_SHIFT                                8
+#       define PGU(x)                                   ((x) << 24)
+#       define PGU_MASK                                 (0xf << 24)
+#       define PGU_SHIFT                                24
+
+#define CG_CGTT_LOCAL_0                                 0x7d0
+#define CG_CGTT_LOCAL_1                                 0x7d4
+
+#define DEEP_SLEEP_CNTL                                 0x818
+#       define R_DIS                                    (1 << 3)
+#       define HS(x)                                    ((x) << 4)
+#       define HS_MASK                                  (0xfff << 4)
+#       define HS_SHIFT                                 4
+#       define ENABLE_DS                                (1 << 31)
+#define DEEP_SLEEP_CNTL2                                0x81c
+#       define LB_UFP_EN                                (1 << 0)
+#       define INOUT_C(x)                               ((x) << 4)
+#       define INOUT_C_MASK                             (0xff << 4)
+#       define INOUT_C_SHIFT                            4
+
+#define CG_SCRATCH2                                     0x824
+
+#define CG_SCLK_DPM_CTRL_11                             0x830
+
+#define HW_REV   					0x5564
+#       define ATI_REV_ID_MASK                          (0xf << 28)
+#       define ATI_REV_ID_SHIFT                         28
+/* 0 = A0, 1 = A1, 2 = B0, 3 = C0, etc. */
+
+#define DOUT_SCRATCH3   				0x611c
+
+#define GB_ADDR_CONFIG  				0x98f8
+
+#endif
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 081/165] drm/radeon/kms: add dpm support for trinity asics
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (80 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 080/165] drm/radeon/kms: add dpm support for sumo asics alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 082/165] drm/radeon/dpm: let atom control display phy powergating alexdeucher
                   ` (31 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

This adds dpm support for trinity asics.  This includes:
- clockgating
- powergating
- dynamic engine clock scaling
- dynamic voltage scaling

set radeon.dpm=1 to enable it.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/Makefile      |    3 +-
 drivers/gpu/drm/radeon/evergreen.c   |   13 +-
 drivers/gpu/drm/radeon/evergreend.h  |   10 +
 drivers/gpu/drm/radeon/ppsmc.h       |   10 +-
 drivers/gpu/drm/radeon/radeon_asic.c |   12 +
 drivers/gpu/drm/radeon/radeon_asic.h |   12 +
 drivers/gpu/drm/radeon/radeon_pm.c   |    1 +
 drivers/gpu/drm/radeon/sumo_dpm.c    |   90 +-
 drivers/gpu/drm/radeon/sumo_dpm.h    |   21 +-
 drivers/gpu/drm/radeon/sumo_smc.c    |    2 -
 drivers/gpu/drm/radeon/trinity_dpm.c | 1613 ++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/radeon/trinity_dpm.h |  110 +++
 drivers/gpu/drm/radeon/trinity_smc.c |  110 +++
 drivers/gpu/drm/radeon/trinityd.h    |  223 +++++
 14 files changed, 2179 insertions(+), 51 deletions(-)
 create mode 100644 drivers/gpu/drm/radeon/trinity_dpm.c
 create mode 100644 drivers/gpu/drm/radeon/trinity_dpm.h
 create mode 100644 drivers/gpu/drm/radeon/trinity_smc.c
 create mode 100644 drivers/gpu/drm/radeon/trinityd.h

diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile
index 7c77e1d..2239ec2 100644
--- a/drivers/gpu/drm/radeon/Makefile
+++ b/drivers/gpu/drm/radeon/Makefile
@@ -78,7 +78,8 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \
 	atombios_encoders.o radeon_semaphore.o radeon_sa.o atombios_i2c.o si.o \
 	si_blit_shaders.o radeon_prime.o radeon_uvd.o cik.o cik_blit_shaders.o \
 	r600_dpm.o rs780_dpm.o rv6xx_dpm.o rv770_dpm.o rv730_dpm.o rv740_dpm.o \
-	rv770_smc.o cypress_dpm.o btc_dpm.o sumo_dpm.o sumo_smc.o
+	rv770_smc.o cypress_dpm.o btc_dpm.o sumo_dpm.o sumo_smc.o trinity_dpm.o \
+	trinity_smc.o
 
 radeon-$(CONFIG_COMPAT) += radeon_ioc32.o
 radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
index c91b1e5..6449953 100644
--- a/drivers/gpu/drm/radeon/evergreen.c
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -4187,8 +4187,12 @@ int evergreen_irq_set(struct radeon_device *rdev)
 	hpd4 = RREG32(DC_HPD4_INT_CONTROL) & ~DC_HPDx_INT_EN;
 	hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~DC_HPDx_INT_EN;
 	hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~DC_HPDx_INT_EN;
-	thermal_int = RREG32(CG_THERMAL_INT) &
-		~(THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW);
+	if (rdev->family == CHIP_ARUBA)
+		thermal_int = RREG32(TN_CG_THERMAL_INT_CTRL) &
+			~(THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW);
+	else
+		thermal_int = RREG32(CG_THERMAL_INT) &
+			~(THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW);
 
 	afmt1 = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET) & ~AFMT_AZ_FORMAT_WTRIG_MASK;
 	afmt2 = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET) & ~AFMT_AZ_FORMAT_WTRIG_MASK;
@@ -4360,7 +4364,10 @@ int evergreen_irq_set(struct radeon_device *rdev)
 	WREG32(DC_HPD4_INT_CONTROL, hpd4);
 	WREG32(DC_HPD5_INT_CONTROL, hpd5);
 	WREG32(DC_HPD6_INT_CONTROL, hpd6);
-	WREG32(CG_THERMAL_INT, thermal_int);
+	if (rdev->family == CHIP_ARUBA)
+		WREG32(TN_CG_THERMAL_INT_CTRL, thermal_int);
+	else
+		WREG32(CG_THERMAL_INT, thermal_int);
 
 	WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, afmt1);
 	WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, afmt2);
diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h
index 93b91a3..35e6153 100644
--- a/drivers/gpu/drm/radeon/evergreend.h
+++ b/drivers/gpu/drm/radeon/evergreend.h
@@ -823,6 +823,16 @@
 #define 	THERM_INT_MASK_HIGH			(1 << 24)
 #define 	THERM_INT_MASK_LOW			(1 << 25)
 
+#define	TN_CG_THERMAL_INT_CTRL				0x738
+#define		TN_DIG_THERM_INTH(x)			((x) << 0)
+#define		TN_DIG_THERM_INTH_MASK			0x000000FF
+#define		TN_DIG_THERM_INTH_SHIFT			0
+#define		TN_DIG_THERM_INTL(x)			((x) << 8)
+#define		TN_DIG_THERM_INTL_MASK			0x0000FF00
+#define		TN_DIG_THERM_INTL_SHIFT			8
+#define 	TN_THERM_INT_MASK_HIGH			(1 << 24)
+#define 	TN_THERM_INT_MASK_LOW			(1 << 25)
+
 #define	CG_MULT_THERMAL_STATUS				0x740
 #define		ASIC_T(x)			        ((x) << 16)
 #define		ASIC_T_MASK			        0x07FF0000
diff --git a/drivers/gpu/drm/radeon/ppsmc.h b/drivers/gpu/drm/radeon/ppsmc.h
index 638de17..8ef479a 100644
--- a/drivers/gpu/drm/radeon/ppsmc.h
+++ b/drivers/gpu/drm/radeon/ppsmc.h
@@ -69,7 +69,15 @@ typedef uint8_t PPSMC_Result;
 #define PPSMC_MSG_ExitULV                   ((uint8_t)0x65)
 #define PPSMC_MSG_ResetToDefaults           ((uint8_t)0x84)
 
-typedef uint8_t PPSMC_Msg;
+/* TN */
+#define PPSMC_MSG_DPM_Config                ((uint32_t) 0x102)
+#define PPSMC_MSG_DPM_ForceState            ((uint32_t) 0x104)
+#define PPSMC_MSG_PG_SIMD_Config            ((uint32_t) 0x108)
+#define PPSMC_MSG_DCE_RemoveVoltageAdjustment   ((uint32_t) 0x11d)
+#define PPSMC_MSG_DCE_AllowVoltageAdjustment    ((uint32_t) 0x11e)
+
+
+typedef uint16_t PPSMC_Msg;
 
 #pragma pack(pop)
 
diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c
index 8b541b4..5dcbb28 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.c
+++ b/drivers/gpu/drm/radeon/radeon_asic.c
@@ -1944,6 +1944,18 @@ static struct radeon_asic trinity_asic = {
 		.set_uvd_clocks = &sumo_set_uvd_clocks,
 		.get_temperature = &tn_get_temp,
 	},
+	.dpm = {
+		.init = &trinity_dpm_init,
+		.setup_asic = &trinity_dpm_setup_asic,
+		.enable = &trinity_dpm_enable,
+		.disable = &trinity_dpm_disable,
+		.set_power_state = &trinity_dpm_set_power_state,
+		.display_configuration_changed = &trinity_dpm_display_configuration_changed,
+		.fini = &trinity_dpm_fini,
+		.get_sclk = &trinity_dpm_get_sclk,
+		.get_mclk = &trinity_dpm_get_mclk,
+		.print_power_state = &trinity_dpm_print_power_state,
+	},
 	.pflip = {
 		.pre_page_flip = &evergreen_pre_page_flip,
 		.page_flip = &evergreen_page_flip,
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index f6c0984..4d3f93d 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -581,6 +581,18 @@ bool cayman_gfx_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring);
 bool cayman_dma_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring);
 void cayman_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm);
 
+int trinity_dpm_init(struct radeon_device *rdev);
+int trinity_dpm_enable(struct radeon_device *rdev);
+void trinity_dpm_disable(struct radeon_device *rdev);
+int trinity_dpm_set_power_state(struct radeon_device *rdev);
+void trinity_dpm_setup_asic(struct radeon_device *rdev);
+void trinity_dpm_display_configuration_changed(struct radeon_device *rdev);
+void trinity_dpm_fini(struct radeon_device *rdev);
+u32 trinity_dpm_get_sclk(struct radeon_device *rdev, bool low);
+u32 trinity_dpm_get_mclk(struct radeon_device *rdev, bool low);
+void trinity_dpm_print_power_state(struct radeon_device *rdev,
+				   struct radeon_ps *ps);
+
 /* DCE6 - SI */
 void dce6_bandwidth_update(struct radeon_device *rdev);
 
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
index b924bcc1..e6fce0b 100644
--- a/drivers/gpu/drm/radeon/radeon_pm.c
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
@@ -1055,6 +1055,7 @@ int radeon_pm_init(struct radeon_device *rdev)
 	case CHIP_BARTS:
 	case CHIP_TURKS:
 	case CHIP_CAICOS:
+	case CHIP_ARUBA:
 		if (radeon_dpm == 1)
 			rdev->pm.pm_method = PM_METHOD_DPM;
 		else
diff --git a/drivers/gpu/drm/radeon/sumo_dpm.c b/drivers/gpu/drm/radeon/sumo_dpm.c
index 4f49450..67c85c7 100644
--- a/drivers/gpu/drm/radeon/sumo_dpm.c
+++ b/drivers/gpu/drm/radeon/sumo_dpm.c
@@ -27,7 +27,6 @@
 #include "r600_dpm.h"
 #include "cypress_dpm.h"
 #include "sumo_dpm.h"
-#include "atom.h"
 
 #define SUMO_MAX_DEEPSLEEP_DIVIDER_ID 5
 #define SUMO_MINIMUM_ENGINE_CLOCK 800
@@ -144,7 +143,7 @@ static void sumo_program_grsd(struct radeon_device *rdev)
 	WREG32(CG_GCOOR, PHC(grs) | SDC(p) | SU(u));
 }
 
-static void sumo_gfx_clockgating_initialize(struct radeon_device *rdev)
+void sumo_gfx_clockgating_initialize(struct radeon_device *rdev)
 {
 	sumo_program_git(rdev);
 	sumo_program_grsd(rdev);
@@ -452,17 +451,17 @@ static void sumo_program_tp(struct radeon_device *rdev)
 		WREG32_P(SCLK_PWRMGT_CNTL, FIR_TREND_MODE, ~FIR_TREND_MODE);
 }
 
-static void sumo_program_vc(struct radeon_device *rdev)
+void sumo_program_vc(struct radeon_device *rdev, u32 vrc)
 {
-	WREG32(CG_FTV, SUMO_VRC_DFLT);
+	WREG32(CG_FTV, vrc);
 }
 
-static void sumo_clear_vc(struct radeon_device *rdev)
+void sumo_clear_vc(struct radeon_device *rdev)
 {
 	WREG32(CG_FTV, 0);
 }
 
-static void sumo_program_sstp(struct radeon_device *rdev)
+void sumo_program_sstp(struct radeon_device *rdev)
 {
 	u32 p, u;
 	u32 xclk = sumo_get_xclk(rdev);
@@ -812,7 +811,7 @@ static void sumo_program_bootup_state(struct radeon_device *rdev)
 		sumo_power_level_enable(rdev, i, false);
 }
 
-static void sumo_take_smu_control(struct radeon_device *rdev, bool enable)
+void sumo_take_smu_control(struct radeon_device *rdev, bool enable)
 {
 	u32 v = RREG32(DOUT_SCRATCH3);
 
@@ -933,14 +932,14 @@ static void sumo_force_nbp_state(struct radeon_device *rdev)
 	}
 }
 
-static u32 sumo_get_sleep_divider_from_id(u32 id)
+u32 sumo_get_sleep_divider_from_id(u32 id)
 {
 	return 1 << id;
 }
 
-static u32 sumo_get_sleep_divider_id_from_clock(struct radeon_device *rdev,
-						u32 sclk,
-						u32 min_sclk_in_sr)
+u32 sumo_get_sleep_divider_id_from_clock(struct radeon_device *rdev,
+					 u32 sclk,
+					 u32 min_sclk_in_sr)
 {
 	struct sumo_power_info *pi = sumo_get_pi(rdev);
 	u32 i;
@@ -1136,7 +1135,7 @@ int sumo_dpm_enable(struct radeon_device *rdev)
 	sumo_program_power_level_enter_state(rdev);
 	sumo_enable_voltage_scaling(rdev, true);
 	sumo_program_sstp(rdev);
-	sumo_program_vc(rdev);
+	sumo_program_vc(rdev, SUMO_VRC_DFLT);
 	sumo_override_cnb_thermal_events(rdev);
 	sumo_start_dpm(rdev);
 	sumo_wait_for_level_0(rdev);
@@ -1393,23 +1392,25 @@ static int sumo_parse_power_table(struct radeon_device *rdev)
 	return 0;
 }
 
-static u32 sumo_convert_vid2_to_vid7(struct radeon_device *rdev, u32 vid_2bit)
+u32 sumo_convert_vid2_to_vid7(struct radeon_device *rdev,
+			      struct sumo_vid_mapping_table *vid_mapping_table,
+			      u32 vid_2bit)
 {
-	struct sumo_power_info *pi = sumo_get_pi(rdev);
 	u32 i;
 
-	for (i = 0; i < pi->sys_info.vid_mapping_table.num_entries; i++) {
-		if (pi->sys_info.vid_mapping_table.entries[i].vid_2bit == vid_2bit)
-			return pi->sys_info.vid_mapping_table.entries[i].vid_7bit;
+	for (i = 0; i < vid_mapping_table->num_entries; i++) {
+		if (vid_mapping_table->entries[i].vid_2bit == vid_2bit)
+			return vid_mapping_table->entries[i].vid_7bit;
 	}
 
-	return pi->sys_info.vid_mapping_table.entries[pi->sys_info.vid_mapping_table.num_entries - 1].vid_7bit;
+	return vid_mapping_table->entries[vid_mapping_table->num_entries - 1].vid_7bit;
 }
 
 static u16 sumo_convert_voltage_index_to_value(struct radeon_device *rdev,
 					       u32 vid_2bit)
 {
-	u32 vid_7bit = sumo_convert_vid2_to_vid7(rdev, vid_2bit);
+	struct sumo_power_info *pi = sumo_get_pi(rdev);
+	u32 vid_7bit = sumo_convert_vid2_to_vid7(rdev, &pi->sys_info.vid_mapping_table, vid_2bit);
 
 	if (vid_7bit > 0x7C)
 		return 0;
@@ -1418,71 +1419,71 @@ static u16 sumo_convert_voltage_index_to_value(struct radeon_device *rdev,
 }
 
 static void sumo_construct_display_voltage_mapping_table(struct radeon_device *rdev,
+							 struct sumo_disp_clock_voltage_mapping_table *disp_clk_voltage_mapping_table,
 							 ATOM_CLK_VOLT_CAPABILITY *table)
 {
-	struct sumo_power_info *pi = sumo_get_pi(rdev);
 	u32 i;
 
 	for (i = 0; i < SUMO_MAX_NUMBER_VOLTAGES; i++) {
 		if (table[i].ulMaximumSupportedCLK == 0)
 			break;
 
-		pi->sys_info.disp_clk_voltage_mapping_table.display_clock_frequency[i] =
+		disp_clk_voltage_mapping_table->display_clock_frequency[i] =
 			table[i].ulMaximumSupportedCLK;
 	}
 
-	pi->sys_info.disp_clk_voltage_mapping_table.num_max_voltage_levels = i;
+	disp_clk_voltage_mapping_table->num_max_voltage_levels = i;
 
-	if (pi->sys_info.disp_clk_voltage_mapping_table.num_max_voltage_levels == 0) {
-		pi->sys_info.disp_clk_voltage_mapping_table.display_clock_frequency[0] = 80000;
-		pi->sys_info.disp_clk_voltage_mapping_table.num_max_voltage_levels = 1;
+	if (disp_clk_voltage_mapping_table->num_max_voltage_levels == 0) {
+		disp_clk_voltage_mapping_table->display_clock_frequency[0] = 80000;
+		disp_clk_voltage_mapping_table->num_max_voltage_levels = 1;
 	}
 }
 
-static void sumo_construct_sclk_voltage_mapping_table(struct radeon_device *rdev,
-						      ATOM_AVAILABLE_SCLK_LIST *table)
+void sumo_construct_sclk_voltage_mapping_table(struct radeon_device *rdev,
+					       struct sumo_sclk_voltage_mapping_table *sclk_voltage_mapping_table,
+					       ATOM_AVAILABLE_SCLK_LIST *table)
 {
-	struct sumo_power_info *pi = sumo_get_pi(rdev);
 	u32 i;
 	u32 n = 0;
 	u32 prev_sclk = 0;
 
 	for (i = 0; i < SUMO_MAX_HARDWARE_POWERLEVELS; i++) {
 		if (table[i].ulSupportedSCLK > prev_sclk) {
-			pi->sys_info.sclk_voltage_mapping_table.entries[n].sclk_frequency =
+			sclk_voltage_mapping_table->entries[n].sclk_frequency =
 				table[i].ulSupportedSCLK;
-			pi->sys_info.sclk_voltage_mapping_table.entries[n].vid_2bit =
+			sclk_voltage_mapping_table->entries[n].vid_2bit =
 				table[i].usVoltageIndex;
 			prev_sclk = table[i].ulSupportedSCLK;
 			n++;
 		}
 	}
 
-	pi->sys_info.sclk_voltage_mapping_table.num_max_dpm_entries = n;
+	sclk_voltage_mapping_table->num_max_dpm_entries = n;
 }
 
-static void sumo_construct_vid_mapping_table(struct radeon_device *rdev,
-					     ATOM_AVAILABLE_SCLK_LIST *table)
+void sumo_construct_vid_mapping_table(struct radeon_device *rdev,
+				      struct sumo_vid_mapping_table *vid_mapping_table,
+				      ATOM_AVAILABLE_SCLK_LIST *table)
 {
-	struct sumo_power_info *pi = sumo_get_pi(rdev);
 	u32 i, j;
 
 	for (i = 0; i < SUMO_MAX_HARDWARE_POWERLEVELS; i++) {
 		if (table[i].ulSupportedSCLK != 0) {
-			pi->sys_info.vid_mapping_table.entries[table[i].usVoltageIndex].vid_7bit =
+			vid_mapping_table->entries[table[i].usVoltageIndex].vid_7bit =
 				table[i].usVoltageID;
-			pi->sys_info.vid_mapping_table.entries[table[i].usVoltageIndex].vid_2bit =
+			vid_mapping_table->entries[table[i].usVoltageIndex].vid_2bit =
 				table[i].usVoltageIndex;
 		}
 	}
 
 	for (i = 0; i < SUMO_MAX_NUMBER_VOLTAGES; i++) {
-		if (pi->sys_info.vid_mapping_table.entries[i].vid_7bit == 0) {
+		if (vid_mapping_table->entries[i].vid_7bit == 0) {
 			for (j = i + 1; j < SUMO_MAX_NUMBER_VOLTAGES; j++) {
-				if (pi->sys_info.vid_mapping_table.entries[j].vid_7bit != 0) {
-					pi->sys_info.vid_mapping_table.entries[i] =
-						pi->sys_info.vid_mapping_table.entries[j];
-					pi->sys_info.vid_mapping_table.entries[j].vid_7bit = 0;
+				if (vid_mapping_table->entries[j].vid_7bit != 0) {
+					vid_mapping_table->entries[i] =
+						vid_mapping_table->entries[j];
+					vid_mapping_table->entries[j].vid_7bit = 0;
 					break;
 				}
 			}
@@ -1492,7 +1493,7 @@ static void sumo_construct_vid_mapping_table(struct radeon_device *rdev,
 		}
 	}
 
-	pi->sys_info.vid_mapping_table.num_entries = i;
+	vid_mapping_table->num_entries = i;
 }
 
 union igp_info {
@@ -1561,10 +1562,13 @@ static int sumo_parse_sys_info_table(struct radeon_device *rdev)
 		else
 			pi->sys_info.enable_boost = false;
 		sumo_construct_display_voltage_mapping_table(rdev,
+							     &pi->sys_info.disp_clk_voltage_mapping_table,
 							     igp_info->info_6.sDISPCLK_Voltage);
 		sumo_construct_sclk_voltage_mapping_table(rdev,
+							  &pi->sys_info.sclk_voltage_mapping_table,
 							  igp_info->info_6.sAvail_SCLK);
-		sumo_construct_vid_mapping_table(rdev, igp_info->info_6.sAvail_SCLK);
+		sumo_construct_vid_mapping_table(rdev, &pi->sys_info.vid_mapping_table,
+						 igp_info->info_6.sAvail_SCLK);
 
 	}
 	return 0;
diff --git a/drivers/gpu/drm/radeon/sumo_dpm.h b/drivers/gpu/drm/radeon/sumo_dpm.h
index 561bee1..d041a6c 100644
--- a/drivers/gpu/drm/radeon/sumo_dpm.h
+++ b/drivers/gpu/drm/radeon/sumo_dpm.h
@@ -23,6 +23,8 @@
 #ifndef __SUMO_DPM_H__
 #define __SUMO_DPM_H__
 
+#include "atom.h"
+
 #define SUMO_MAX_HARDWARE_POWERLEVELS 5
 #define SUMO_PM_NUMBER_OF_TC 15
 
@@ -184,7 +186,24 @@ struct sumo_power_info {
 
 /* sumo_dpm.c */
 u32 sumo_get_xclk(struct radeon_device *rdev);
-
+void sumo_gfx_clockgating_initialize(struct radeon_device *rdev);
+void sumo_program_vc(struct radeon_device *rdev, u32 vrc);
+void sumo_clear_vc(struct radeon_device *rdev);
+void sumo_program_sstp(struct radeon_device *rdev);
+void sumo_take_smu_control(struct radeon_device *rdev, bool enable);
+void sumo_construct_sclk_voltage_mapping_table(struct radeon_device *rdev,
+					       struct sumo_sclk_voltage_mapping_table *sclk_voltage_mapping_table,
+					       ATOM_AVAILABLE_SCLK_LIST *table);
+void sumo_construct_vid_mapping_table(struct radeon_device *rdev,
+				      struct sumo_vid_mapping_table *vid_mapping_table,
+				      ATOM_AVAILABLE_SCLK_LIST *table);
+u32 sumo_convert_vid2_to_vid7(struct radeon_device *rdev,
+			      struct sumo_vid_mapping_table *vid_mapping_table,
+			      u32 vid_2bit);
+u32 sumo_get_sleep_divider_from_id(u32 id);
+u32 sumo_get_sleep_divider_id_from_clock(struct radeon_device *rdev,
+					 u32 sclk,
+					 u32 min_sclk_in_sr);
 
 /* sumo_smc.c */
 void sumo_initialize_m3_arb(struct radeon_device *rdev);
diff --git a/drivers/gpu/drm/radeon/sumo_smc.c b/drivers/gpu/drm/radeon/sumo_smc.c
index 9d0ae9b..bc1a510 100644
--- a/drivers/gpu/drm/radeon/sumo_smc.c
+++ b/drivers/gpu/drm/radeon/sumo_smc.c
@@ -21,13 +21,11 @@
  *
  */
 
-#include <linux/firmware.h>
 #include "drmP.h"
 #include "radeon.h"
 #include "sumod.h"
 #include "sumo_dpm.h"
 #include "ppsmc.h"
-#include "radeon_ucode.h"
 
 #define SUMO_SMU_SERVICE_ROUTINE_PG_INIT        1
 #define SUMO_SMU_SERVICE_ROUTINE_ALTVDDNB_NOTIFY  27
diff --git a/drivers/gpu/drm/radeon/trinity_dpm.c b/drivers/gpu/drm/radeon/trinity_dpm.c
new file mode 100644
index 0000000..c4779a6
--- /dev/null
+++ b/drivers/gpu/drm/radeon/trinity_dpm.c
@@ -0,0 +1,1613 @@
+/*
+ * Copyright 2012 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "drmP.h"
+#include "radeon.h"
+#include "trinityd.h"
+#include "r600_dpm.h"
+#include "trinity_dpm.h"
+
+#define TRINITY_MAX_DEEPSLEEP_DIVIDER_ID 5
+#define TRINITY_MINIMUM_ENGINE_CLOCK 800
+#define SCLK_MIN_DIV_INTV_SHIFT     12
+#define TRINITY_DISPCLK_BYPASS_THRESHOLD 10000
+
+#ifndef TRINITY_MGCG_SEQUENCE
+#define TRINITY_MGCG_SEQUENCE  100
+
+static const u32 trinity_mgcg_shls_default[] =
+{
+	/* Register, Value, Mask */
+	0x0000802c, 0xc0000000, 0xffffffff,
+	0x00003fc4, 0xc0000000, 0xffffffff,
+	0x00005448, 0x00000100, 0xffffffff,
+	0x000055e4, 0x00000100, 0xffffffff,
+	0x0000160c, 0x00000100, 0xffffffff,
+	0x00008984, 0x06000100, 0xffffffff,
+	0x0000c164, 0x00000100, 0xffffffff,
+	0x00008a18, 0x00000100, 0xffffffff,
+	0x0000897c, 0x06000100, 0xffffffff,
+	0x00008b28, 0x00000100, 0xffffffff,
+	0x00009144, 0x00800200, 0xffffffff,
+	0x00009a60, 0x00000100, 0xffffffff,
+	0x00009868, 0x00000100, 0xffffffff,
+	0x00008d58, 0x00000100, 0xffffffff,
+	0x00009510, 0x00000100, 0xffffffff,
+	0x0000949c, 0x00000100, 0xffffffff,
+	0x00009654, 0x00000100, 0xffffffff,
+	0x00009030, 0x00000100, 0xffffffff,
+	0x00009034, 0x00000100, 0xffffffff,
+	0x00009038, 0x00000100, 0xffffffff,
+	0x0000903c, 0x00000100, 0xffffffff,
+	0x00009040, 0x00000100, 0xffffffff,
+	0x0000a200, 0x00000100, 0xffffffff,
+	0x0000a204, 0x00000100, 0xffffffff,
+	0x0000a208, 0x00000100, 0xffffffff,
+	0x0000a20c, 0x00000100, 0xffffffff,
+	0x00009744, 0x00000100, 0xffffffff,
+	0x00003f80, 0x00000100, 0xffffffff,
+	0x0000a210, 0x00000100, 0xffffffff,
+	0x0000a214, 0x00000100, 0xffffffff,
+	0x000004d8, 0x00000100, 0xffffffff,
+	0x00009664, 0x00000100, 0xffffffff,
+	0x00009698, 0x00000100, 0xffffffff,
+	0x000004d4, 0x00000200, 0xffffffff,
+	0x000004d0, 0x00000000, 0xffffffff,
+	0x000030cc, 0x00000104, 0xffffffff,
+	0x0000d0c0, 0x00000100, 0xffffffff,
+	0x0000d8c0, 0x00000100, 0xffffffff,
+	0x0000951c, 0x00010000, 0xffffffff,
+	0x00009160, 0x00030002, 0xffffffff,
+	0x00009164, 0x00050004, 0xffffffff,
+	0x00009168, 0x00070006, 0xffffffff,
+	0x00009178, 0x00070000, 0xffffffff,
+	0x0000917c, 0x00030002, 0xffffffff,
+	0x00009180, 0x00050004, 0xffffffff,
+	0x0000918c, 0x00010006, 0xffffffff,
+	0x00009190, 0x00090008, 0xffffffff,
+	0x00009194, 0x00070000, 0xffffffff,
+	0x00009198, 0x00030002, 0xffffffff,
+	0x0000919c, 0x00050004, 0xffffffff,
+	0x000091a8, 0x00010006, 0xffffffff,
+	0x000091ac, 0x00090008, 0xffffffff,
+	0x000091b0, 0x00070000, 0xffffffff,
+	0x000091b4, 0x00030002, 0xffffffff,
+	0x000091b8, 0x00050004, 0xffffffff,
+	0x000091c4, 0x00010006, 0xffffffff,
+	0x000091c8, 0x00090008, 0xffffffff,
+	0x000091cc, 0x00070000, 0xffffffff,
+	0x000091d0, 0x00030002, 0xffffffff,
+	0x000091d4, 0x00050004, 0xffffffff,
+	0x000091e0, 0x00010006, 0xffffffff,
+	0x000091e4, 0x00090008, 0xffffffff,
+	0x000091e8, 0x00000000, 0xffffffff,
+	0x000091ec, 0x00070000, 0xffffffff,
+	0x000091f0, 0x00030002, 0xffffffff,
+	0x000091f4, 0x00050004, 0xffffffff,
+	0x00009200, 0x00010006, 0xffffffff,
+	0x00009204, 0x00090008, 0xffffffff,
+	0x00009208, 0x00070000, 0xffffffff,
+	0x0000920c, 0x00030002, 0xffffffff,
+	0x00009210, 0x00050004, 0xffffffff,
+	0x0000921c, 0x00010006, 0xffffffff,
+	0x00009220, 0x00090008, 0xffffffff,
+	0x00009294, 0x00000000, 0xffffffff
+};
+
+static const u32 trinity_mgcg_shls_enable[] =
+{
+	/* Register, Value, Mask */
+	0x0000802c, 0xc0000000, 0xffffffff,
+	0x000008f8, 0x00000000, 0xffffffff,
+	0x000008fc, 0x00000000, 0x000133FF,
+	0x000008f8, 0x00000001, 0xffffffff,
+	0x000008fc, 0x00000000, 0xE00B03FC,
+	0x00009150, 0x96944200, 0xffffffff
+};
+
+static const u32 trinity_mgcg_shls_disable[] =
+{
+	/* Register, Value, Mask */
+	0x0000802c, 0xc0000000, 0xffffffff,
+	0x00009150, 0x00600000, 0xffffffff,
+	0x000008f8, 0x00000000, 0xffffffff,
+	0x000008fc, 0xffffffff, 0x000133FF,
+	0x000008f8, 0x00000001, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xE00B03FC
+};
+#endif
+
+#ifndef TRINITY_SYSLS_SEQUENCE
+#define TRINITY_SYSLS_SEQUENCE  100
+
+static const u32 trinity_sysls_default[] =
+{
+	/* Register, Value, Mask */
+	0x000055e8, 0x00000000, 0xffffffff,
+	0x0000d0bc, 0x00000000, 0xffffffff,
+	0x0000d8bc, 0x00000000, 0xffffffff,
+	0x000015c0, 0x000c1401, 0xffffffff,
+	0x0000264c, 0x000c0400, 0xffffffff,
+	0x00002648, 0x000c0400, 0xffffffff,
+	0x00002650, 0x000c0400, 0xffffffff,
+	0x000020b8, 0x000c0400, 0xffffffff,
+	0x000020bc, 0x000c0400, 0xffffffff,
+	0x000020c0, 0x000c0c80, 0xffffffff,
+	0x0000f4a0, 0x000000c0, 0xffffffff,
+	0x0000f4a4, 0x00680fff, 0xffffffff,
+	0x00002f50, 0x00000404, 0xffffffff,
+	0x000004c8, 0x00000001, 0xffffffff,
+	0x0000641c, 0x00000000, 0xffffffff,
+	0x00000c7c, 0x00000000, 0xffffffff,
+	0x00006dfc, 0x00000000, 0xffffffff
+};
+
+static const u32 trinity_sysls_disable[] =
+{
+	/* Register, Value, Mask */
+	0x0000d0c0, 0x00000000, 0xffffffff,
+	0x0000d8c0, 0x00000000, 0xffffffff,
+	0x000055e8, 0x00000000, 0xffffffff,
+	0x0000d0bc, 0x00000000, 0xffffffff,
+	0x0000d8bc, 0x00000000, 0xffffffff,
+	0x000015c0, 0x00041401, 0xffffffff,
+	0x0000264c, 0x00040400, 0xffffffff,
+	0x00002648, 0x00040400, 0xffffffff,
+	0x00002650, 0x00040400, 0xffffffff,
+	0x000020b8, 0x00040400, 0xffffffff,
+	0x000020bc, 0x00040400, 0xffffffff,
+	0x000020c0, 0x00040c80, 0xffffffff,
+	0x0000f4a0, 0x000000c0, 0xffffffff,
+	0x0000f4a4, 0x00680000, 0xffffffff,
+	0x00002f50, 0x00000404, 0xffffffff,
+	0x000004c8, 0x00000001, 0xffffffff,
+	0x0000641c, 0x00007ffd, 0xffffffff,
+	0x00000c7c, 0x0000ff00, 0xffffffff,
+	0x00006dfc, 0x0000007f, 0xffffffff
+};
+
+static const u32 trinity_sysls_enable[] =
+{
+	/* Register, Value, Mask */
+	0x000055e8, 0x00000001, 0xffffffff,
+	0x0000d0bc, 0x00000100, 0xffffffff,
+	0x0000d8bc, 0x00000100, 0xffffffff,
+	0x000015c0, 0x000c1401, 0xffffffff,
+	0x0000264c, 0x000c0400, 0xffffffff,
+	0x00002648, 0x000c0400, 0xffffffff,
+	0x00002650, 0x000c0400, 0xffffffff,
+	0x000020b8, 0x000c0400, 0xffffffff,
+	0x000020bc, 0x000c0400, 0xffffffff,
+	0x000020c0, 0x000c0c80, 0xffffffff,
+	0x0000f4a0, 0x000000c0, 0xffffffff,
+	0x0000f4a4, 0x00680fff, 0xffffffff,
+	0x00002f50, 0x00000903, 0xffffffff,
+	0x000004c8, 0x00000000, 0xffffffff,
+	0x0000641c, 0x00000000, 0xffffffff,
+	0x00000c7c, 0x00000000, 0xffffffff,
+	0x00006dfc, 0x00000000, 0xffffffff
+};
+#endif
+
+static const u32 trinity_override_mgpg_sequences[] =
+{
+	/* Register, Value */
+	0x00000200, 0xE030032C,
+	0x00000204, 0x00000FFF,
+	0x00000200, 0xE0300058,
+	0x00000204, 0x00030301,
+	0x00000200, 0xE0300054,
+	0x00000204, 0x500010FF,
+	0x00000200, 0xE0300074,
+	0x00000204, 0x00030301,
+	0x00000200, 0xE0300070,
+	0x00000204, 0x500010FF,
+	0x00000200, 0xE0300090,
+	0x00000204, 0x00030301,
+	0x00000200, 0xE030008C,
+	0x00000204, 0x500010FF,
+	0x00000200, 0xE03000AC,
+	0x00000204, 0x00030301,
+	0x00000200, 0xE03000A8,
+	0x00000204, 0x500010FF,
+	0x00000200, 0xE03000C8,
+	0x00000204, 0x00030301,
+	0x00000200, 0xE03000C4,
+	0x00000204, 0x500010FF,
+	0x00000200, 0xE03000E4,
+	0x00000204, 0x00030301,
+	0x00000200, 0xE03000E0,
+	0x00000204, 0x500010FF,
+	0x00000200, 0xE0300100,
+	0x00000204, 0x00030301,
+	0x00000200, 0xE03000FC,
+	0x00000204, 0x500010FF,
+	0x00000200, 0xE0300058,
+	0x00000204, 0x00030303,
+	0x00000200, 0xE0300054,
+	0x00000204, 0x600010FF,
+	0x00000200, 0xE0300074,
+	0x00000204, 0x00030303,
+	0x00000200, 0xE0300070,
+	0x00000204, 0x600010FF,
+	0x00000200, 0xE0300090,
+	0x00000204, 0x00030303,
+	0x00000200, 0xE030008C,
+	0x00000204, 0x600010FF,
+	0x00000200, 0xE03000AC,
+	0x00000204, 0x00030303,
+	0x00000200, 0xE03000A8,
+	0x00000204, 0x600010FF,
+	0x00000200, 0xE03000C8,
+	0x00000204, 0x00030303,
+	0x00000200, 0xE03000C4,
+	0x00000204, 0x600010FF,
+	0x00000200, 0xE03000E4,
+	0x00000204, 0x00030303,
+	0x00000200, 0xE03000E0,
+	0x00000204, 0x600010FF,
+	0x00000200, 0xE0300100,
+	0x00000204, 0x00030303,
+	0x00000200, 0xE03000FC,
+	0x00000204, 0x600010FF,
+	0x00000200, 0xE0300058,
+	0x00000204, 0x00030303,
+	0x00000200, 0xE0300054,
+	0x00000204, 0x700010FF,
+	0x00000200, 0xE0300074,
+	0x00000204, 0x00030303,
+	0x00000200, 0xE0300070,
+	0x00000204, 0x700010FF,
+	0x00000200, 0xE0300090,
+	0x00000204, 0x00030303,
+	0x00000200, 0xE030008C,
+	0x00000204, 0x700010FF,
+	0x00000200, 0xE03000AC,
+	0x00000204, 0x00030303,
+	0x00000200, 0xE03000A8,
+	0x00000204, 0x700010FF,
+	0x00000200, 0xE03000C8,
+	0x00000204, 0x00030303,
+	0x00000200, 0xE03000C4,
+	0x00000204, 0x700010FF,
+	0x00000200, 0xE03000E4,
+	0x00000204, 0x00030303,
+	0x00000200, 0xE03000E0,
+	0x00000204, 0x700010FF,
+	0x00000200, 0xE0300100,
+	0x00000204, 0x00030303,
+	0x00000200, 0xE03000FC,
+	0x00000204, 0x700010FF,
+	0x00000200, 0xE0300058,
+	0x00000204, 0x00010303,
+	0x00000200, 0xE0300054,
+	0x00000204, 0x800010FF,
+	0x00000200, 0xE0300074,
+	0x00000204, 0x00010303,
+	0x00000200, 0xE0300070,
+	0x00000204, 0x800010FF,
+	0x00000200, 0xE0300090,
+	0x00000204, 0x00010303,
+	0x00000200, 0xE030008C,
+	0x00000204, 0x800010FF,
+	0x00000200, 0xE03000AC,
+	0x00000204, 0x00010303,
+	0x00000200, 0xE03000A8,
+	0x00000204, 0x800010FF,
+	0x00000200, 0xE03000C4,
+	0x00000204, 0x800010FF,
+	0x00000200, 0xE03000C8,
+	0x00000204, 0x00010303,
+	0x00000200, 0xE03000E4,
+	0x00000204, 0x00010303,
+	0x00000200, 0xE03000E0,
+	0x00000204, 0x800010FF,
+	0x00000200, 0xE0300100,
+	0x00000204, 0x00010303,
+	0x00000200, 0xE03000FC,
+	0x00000204, 0x800010FF,
+	0x00000200, 0x0001f198,
+	0x00000204, 0x0003ffff,
+	0x00000200, 0x0001f19C,
+	0x00000204, 0x3fffffff,
+	0x00000200, 0xE030032C,
+	0x00000204, 0x00000000,
+};
+
+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);
+static void trinity_apply_state_adjust_rules(struct radeon_device *rdev);
+
+struct trinity_ps *trinity_get_ps(struct radeon_ps *rps)
+{
+	struct trinity_ps *ps = rps->ps_priv;
+
+	return ps;
+}
+
+struct trinity_power_info *trinity_get_pi(struct radeon_device *rdev)
+{
+	struct trinity_power_info *pi = rdev->pm.dpm.priv;
+
+	return pi;
+}
+
+static void trinity_gfx_powergating_initialize(struct radeon_device *rdev)
+{
+	struct trinity_power_info *pi = trinity_get_pi(rdev);
+	u32 p, u;
+	u32 value;
+	struct atom_clock_dividers dividers;
+	u32 xclk = sumo_get_xclk(rdev);
+	u32 sssd = 1;
+	int ret;
+	u32 hw_rev = (RREG32(HW_REV) & ATI_REV_ID_MASK) >> ATI_REV_ID_SHIFT;
+
+        ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
+                                             25000, false, &dividers);
+	if (ret)
+		return;
+
+	value = RREG32_SMC(GFX_POWER_GATING_CNTL);
+	value &= ~(SSSD_MASK | PDS_DIV_MASK);
+	if (sssd)
+		value |= SSSD(1);
+	value |= PDS_DIV(dividers.post_div);
+	WREG32_SMC(GFX_POWER_GATING_CNTL, value);
+
+	r600_calculate_u_and_p(500, xclk, 16, &p, &u);
+
+	WREG32(CG_PG_CTRL, SP(p) | SU(u));
+
+	WREG32_P(CG_GIPOTS, CG_GIPOT(p), ~CG_GIPOT_MASK);
+
+	/* XXX double check hw_rev */
+	if (pi->override_dynamic_mgpg && (hw_rev == 0))
+		trinity_override_dynamic_mg_powergating(rdev);
+
+}
+
+#define CGCG_CGTT_LOCAL0_MASK       0xFFFF33FF
+#define CGCG_CGTT_LOCAL1_MASK       0xFFFB0FFE
+#define CGTS_SM_CTRL_REG_DISABLE    0x00600000
+#define CGTS_SM_CTRL_REG_ENABLE     0x96944200
+
+static void trinity_mg_clockgating_enable(struct radeon_device *rdev,
+					  bool enable)
+{
+	u32 local0;
+	u32 local1;
+
+	if (enable) {
+		local0 = RREG32_CG(CG_CGTT_LOCAL_0);
+		local1 = RREG32_CG(CG_CGTT_LOCAL_1);
+
+		WREG32_CG(CG_CGTT_LOCAL_0,
+			  (0x00380000 & CGCG_CGTT_LOCAL0_MASK) | (local0 & ~CGCG_CGTT_LOCAL0_MASK) );
+		WREG32_CG(CG_CGTT_LOCAL_1,
+			  (0x0E000000 & CGCG_CGTT_LOCAL1_MASK) | (local1 & ~CGCG_CGTT_LOCAL1_MASK) );
+
+		WREG32(CGTS_SM_CTRL_REG, CGTS_SM_CTRL_REG_ENABLE);
+	} else {
+		WREG32(CGTS_SM_CTRL_REG, CGTS_SM_CTRL_REG_DISABLE);
+
+		local0 = RREG32_CG(CG_CGTT_LOCAL_0);
+		local1 = RREG32_CG(CG_CGTT_LOCAL_1);
+
+		WREG32_CG(CG_CGTT_LOCAL_0,
+			  CGCG_CGTT_LOCAL0_MASK | (local0 & ~CGCG_CGTT_LOCAL0_MASK) );
+		WREG32_CG(CG_CGTT_LOCAL_1,
+			  CGCG_CGTT_LOCAL1_MASK | (local1 & ~CGCG_CGTT_LOCAL1_MASK) );
+	}
+}
+
+static void trinity_mg_clockgating_initialize(struct radeon_device *rdev)
+{
+	u32 count;
+	const u32 *seq = NULL;
+
+	seq = &trinity_mgcg_shls_default[0];
+	count = sizeof(trinity_mgcg_shls_default) / (3 * sizeof(u32));
+
+	trinity_program_clk_gating_hw_sequence(rdev, seq, count);
+}
+
+static void trinity_gfx_clockgating_enable(struct radeon_device *rdev,
+					   bool enable)
+{
+	if (enable) {
+		WREG32_P(SCLK_PWRMGT_CNTL, DYN_GFX_CLK_OFF_EN, ~DYN_GFX_CLK_OFF_EN);
+	} else {
+		WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_GFX_CLK_OFF_EN);
+		WREG32_P(SCLK_PWRMGT_CNTL, GFX_CLK_FORCE_ON, ~GFX_CLK_FORCE_ON);
+		WREG32_P(SCLK_PWRMGT_CNTL, 0, ~GFX_CLK_FORCE_ON);
+		RREG32(GB_ADDR_CONFIG);
+	}
+}
+
+static void trinity_program_clk_gating_hw_sequence(struct radeon_device *rdev,
+						   const u32 *seq, u32 count)
+{
+	u32 i, length = count * 3;
+
+	for (i = 0; i < length; i += 3)
+		WREG32_P(seq[i], seq[i+1], ~seq[i+2]);
+}
+
+static void trinity_program_override_mgpg_sequences(struct radeon_device *rdev,
+						    const u32 *seq, u32 count)
+{
+	u32  i, length = count * 2;
+
+	for (i = 0; i < length; i += 2)
+		WREG32(seq[i], seq[i+1]);
+
+}
+
+static void trinity_override_dynamic_mg_powergating(struct radeon_device *rdev)
+{
+	u32 count;
+	const u32 *seq = NULL;
+
+	seq = &trinity_override_mgpg_sequences[0];
+	count = sizeof(trinity_override_mgpg_sequences) / (2 * sizeof(u32));
+
+	trinity_program_override_mgpg_sequences(rdev, seq, count);
+}
+
+static void trinity_ls_clockgating_enable(struct radeon_device *rdev,
+					  bool enable)
+{
+	u32 count;
+	const u32 *seq = NULL;
+
+	if (enable) {
+		seq = &trinity_sysls_enable[0];
+		count = sizeof(trinity_sysls_enable) / (3 * sizeof(u32));
+	} else {
+		seq = &trinity_sysls_disable[0];
+		count = sizeof(trinity_sysls_disable) / (3 * sizeof(u32));
+	}
+
+	trinity_program_clk_gating_hw_sequence(rdev, seq, count);
+}
+
+static void trinity_gfx_powergating_enable(struct radeon_device *rdev,
+					   bool enable)
+{
+	if (enable) {
+		if (RREG32_SMC(CC_SMU_TST_EFUSE1_MISC) & RB_BACKEND_DISABLE_MASK)
+			WREG32_SMC(SMU_SCRATCH_A, (RREG32_SMC(SMU_SCRATCH_A) | 0x01));
+
+		WREG32_P(SCLK_PWRMGT_CNTL, DYN_PWR_DOWN_EN, ~DYN_PWR_DOWN_EN);
+	} else {
+		WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_PWR_DOWN_EN);
+		RREG32(GB_ADDR_CONFIG);
+	}
+}
+
+static void trinity_gfx_dynamic_mgpg_enable(struct radeon_device *rdev,
+					    bool enable)
+{
+	u32 value;
+
+	if (enable) {
+		value = RREG32_SMC(PM_I_CNTL_1);
+		value &= ~DS_PG_CNTL_MASK;
+		value |= DS_PG_CNTL(1);
+		WREG32_SMC(PM_I_CNTL_1, value);
+
+		value = RREG32_SMC(SMU_S_PG_CNTL);
+		value &= ~DS_PG_EN_MASK;
+		value |= DS_PG_EN(1);
+		WREG32_SMC(SMU_S_PG_CNTL, value);
+	} else {
+		value = RREG32_SMC(SMU_S_PG_CNTL);
+		value &= ~DS_PG_EN_MASK;
+		WREG32_SMC(SMU_S_PG_CNTL, value);
+
+		value = RREG32_SMC(PM_I_CNTL_1);
+		value &= ~DS_PG_CNTL_MASK;
+		WREG32_SMC(PM_I_CNTL_1, value);
+	}
+
+	trinity_gfx_dynamic_mgpg_config(rdev);
+
+}
+
+static void trinity_enable_clock_power_gating(struct radeon_device *rdev)
+{
+	struct trinity_power_info *pi = trinity_get_pi(rdev);
+
+	if (pi->enable_gfx_clock_gating)
+		sumo_gfx_clockgating_initialize(rdev);
+	if (pi->enable_mg_clock_gating)
+		trinity_mg_clockgating_initialize(rdev);
+	if (pi->enable_gfx_power_gating)
+		trinity_gfx_powergating_initialize(rdev);
+	if (pi->enable_mg_clock_gating) {
+		trinity_ls_clockgating_enable(rdev, true);
+		trinity_mg_clockgating_enable(rdev, true);
+	}
+	if (pi->enable_gfx_clock_gating)
+		trinity_gfx_clockgating_enable(rdev, true);
+	if (pi->enable_gfx_dynamic_mgpg)
+		trinity_gfx_dynamic_mgpg_enable(rdev, true);
+	if (pi->enable_gfx_power_gating)
+		trinity_gfx_powergating_enable(rdev, true);
+}
+
+static void trinity_disable_clock_power_gating(struct radeon_device *rdev)
+{
+	struct trinity_power_info *pi = trinity_get_pi(rdev);
+
+	if (pi->enable_gfx_power_gating)
+		trinity_gfx_powergating_enable(rdev, false);
+	if (pi->enable_gfx_dynamic_mgpg)
+		trinity_gfx_dynamic_mgpg_enable(rdev, false);
+	if (pi->enable_gfx_clock_gating)
+		trinity_gfx_clockgating_enable(rdev, false);
+	if (pi->enable_mg_clock_gating) {
+		trinity_mg_clockgating_enable(rdev, false);
+		trinity_ls_clockgating_enable(rdev, false);
+	}
+}
+
+static void trinity_set_divider_value(struct radeon_device *rdev,
+				      u32 index, u32 sclk)
+{
+	struct atom_clock_dividers  dividers;
+	int ret;
+	u32 value;
+	u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
+
+        ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
+                                             sclk, false, &dividers);
+	if (ret)
+		return;
+
+	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix);
+	value &= ~CLK_DIVIDER_MASK;
+	value |= CLK_DIVIDER(dividers.post_div);
+	WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix, value);
+
+        ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
+                                             sclk/2, false, &dividers);
+	if (ret)
+		return;
+
+	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_PG_CNTL + ix);
+	value &= ~PD_SCLK_DIVIDER_MASK;
+	value |= PD_SCLK_DIVIDER(dividers.post_div);
+	WREG32_SMC(SMU_SCLK_DPM_STATE_0_PG_CNTL + ix, value);
+}
+
+static void trinity_set_ds_dividers(struct radeon_device *rdev,
+				    u32 index, u32 divider)
+{
+	u32 value;
+	u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
+
+	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix);
+	value &= ~DS_DIV_MASK;
+	value |= DS_DIV(divider);
+	WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix, value);
+}
+
+static void trinity_set_ss_dividers(struct radeon_device *rdev,
+				    u32 index, u32 divider)
+{
+	u32 value;
+	u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
+
+	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix);
+	value &= ~DS_SH_DIV_MASK;
+	value |= DS_SH_DIV(divider);
+	WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix, value);
+}
+
+static void trinity_set_vid(struct radeon_device *rdev, u32 index, u32 vid)
+{
+	struct trinity_power_info *pi = trinity_get_pi(rdev);
+	u32 vid_7bit = sumo_convert_vid2_to_vid7(rdev, &pi->sys_info.vid_mapping_table, vid);
+	u32 value;
+	u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
+
+	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix);
+	value &= ~VID_MASK;
+	value |= VID(vid_7bit);
+	WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix, value);
+
+	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix);
+	value &= ~LVRT_MASK;
+	value |= LVRT(0);
+	WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix, value);
+}
+
+static void trinity_set_allos_gnb_slow(struct radeon_device *rdev,
+				       u32 index, u32 gnb_slow)
+{
+	u32 value;
+	u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
+
+	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_3 + ix);
+	value &= ~GNB_SLOW_MASK;
+	value |= GNB_SLOW(gnb_slow);
+	WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_3 + ix, value);
+}
+
+static void trinity_set_force_nbp_state(struct radeon_device *rdev,
+					u32 index, u32 force_nbp_state)
+{
+	u32 value;
+	u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
+
+	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_3 + ix);
+	value &= ~FORCE_NBPS1_MASK;
+	value |= FORCE_NBPS1(force_nbp_state);
+	WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_3 + ix, value);
+}
+
+static void trinity_set_display_wm(struct radeon_device *rdev,
+				   u32 index, u32 wm)
+{
+	u32 value;
+	u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
+
+	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix);
+	value &= ~DISPLAY_WM_MASK;
+	value |= DISPLAY_WM(wm);
+	WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix, value);
+}
+
+static void trinity_set_vce_wm(struct radeon_device *rdev,
+			       u32 index, u32 wm)
+{
+	u32 value;
+	u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
+
+	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix);
+	value &= ~VCE_WM_MASK;
+	value |= VCE_WM(wm);
+	WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix, value);
+}
+
+static void trinity_set_at(struct radeon_device *rdev,
+			   u32 index, u32 at)
+{
+	u32 value;
+	u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
+
+	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_AT + ix);
+	value &= ~AT_MASK;
+	value |= AT(at);
+	WREG32_SMC(SMU_SCLK_DPM_STATE_0_AT + ix, value);
+}
+
+static void trinity_program_power_level(struct radeon_device *rdev,
+					struct trinity_pl *pl, u32 index)
+{
+	struct trinity_power_info *pi = trinity_get_pi(rdev);
+
+	if (index >= SUMO_MAX_HARDWARE_POWERLEVELS)
+		return;
+
+	trinity_set_divider_value(rdev, index, pl->sclk);
+	trinity_set_vid(rdev, index, pl->vddc_index);
+	trinity_set_ss_dividers(rdev, index, pl->ss_divider_index);
+	trinity_set_ds_dividers(rdev, index, pl->ds_divider_index);
+	trinity_set_allos_gnb_slow(rdev, index, pl->allow_gnb_slow);
+	trinity_set_force_nbp_state(rdev, index, pl->force_nbp_state);
+	trinity_set_display_wm(rdev, index, pl->display_wm);
+	trinity_set_vce_wm(rdev, index, pl->vce_wm);
+	trinity_set_at(rdev, index, pi->at[index]);
+}
+
+static void trinity_power_level_enable_disable(struct radeon_device *rdev,
+					       u32 index, bool enable)
+{
+	u32 value;
+	u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
+
+	value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix);
+	value &= ~STATE_VALID_MASK;
+	if (enable)
+		value |= STATE_VALID(1);
+	WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix, value);
+}
+
+static bool trinity_dpm_enabled(struct radeon_device *rdev)
+{
+	if (RREG32_SMC(SMU_SCLK_DPM_CNTL) & SCLK_DPM_EN(1))
+		return true;
+	else
+		return false;
+}
+
+static void trinity_start_dpm(struct radeon_device *rdev)
+{
+	u32 value = RREG32_SMC(SMU_SCLK_DPM_CNTL);
+
+	value &= ~(SCLK_DPM_EN_MASK | SCLK_DPM_BOOT_STATE_MASK | VOLTAGE_CHG_EN_MASK);
+	value |= SCLK_DPM_EN(1) | SCLK_DPM_BOOT_STATE(0) | VOLTAGE_CHG_EN(1);
+	WREG32_SMC(SMU_SCLK_DPM_CNTL, value);
+
+	WREG32_P(GENERAL_PWRMGT, GLOBAL_PWRMGT_EN, ~GLOBAL_PWRMGT_EN);
+	WREG32_P(CG_CG_VOLTAGE_CNTL, 0, ~EN);
+
+	trinity_dpm_config(rdev, true);
+}
+
+static void trinity_wait_for_dpm_enabled(struct radeon_device *rdev)
+{
+	int i;
+
+	for (i = 0; i < rdev->usec_timeout; i++) {
+		if (RREG32(SCLK_PWRMGT_CNTL) & DYNAMIC_PM_EN)
+			break;
+		udelay(1);
+	}
+	for (i = 0; i < rdev->usec_timeout; i++) {
+		if ((RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & TARGET_STATE_MASK) == 0)
+			break;
+		udelay(1);
+	}
+	for (i = 0; i < rdev->usec_timeout; i++) {
+		if ((RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_MASK) == 0)
+			break;
+		udelay(1);
+	}
+}
+
+static void trinity_stop_dpm(struct radeon_device *rdev)
+{
+	u32 sclk_dpm_cntl;
+
+	WREG32_P(CG_CG_VOLTAGE_CNTL, EN, ~EN);
+
+	sclk_dpm_cntl = RREG32_SMC(SMU_SCLK_DPM_CNTL);
+	sclk_dpm_cntl &= ~(SCLK_DPM_EN_MASK | VOLTAGE_CHG_EN_MASK);
+	WREG32_SMC(SMU_SCLK_DPM_CNTL, sclk_dpm_cntl);
+
+	trinity_dpm_config(rdev, false);
+}
+
+static void trinity_start_am(struct radeon_device *rdev)
+{
+	WREG32_P(SCLK_PWRMGT_CNTL, 0, ~(RESET_SCLK_CNT | RESET_BUSY_CNT));
+}
+
+static void trinity_reset_am(struct radeon_device *rdev)
+{
+	WREG32_P(SCLK_PWRMGT_CNTL, RESET_SCLK_CNT | RESET_BUSY_CNT,
+		 ~(RESET_SCLK_CNT | RESET_BUSY_CNT));
+}
+
+static void trinity_wait_for_level_0(struct radeon_device *rdev)
+{
+	int i;
+
+	for (i = 0; i < rdev->usec_timeout; i++) {
+		if ((RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_MASK) == 0)
+			break;
+		udelay(1);
+	}
+}
+
+static void trinity_enable_power_level_0(struct radeon_device *rdev)
+{
+	trinity_power_level_enable_disable(rdev, 0, true);
+}
+
+static void trinity_force_level_0(struct radeon_device *rdev)
+{
+	trinity_dpm_force_state(rdev, 0);
+}
+
+static void trinity_unforce_levels(struct radeon_device *rdev)
+{
+	trinity_dpm_no_forced_level(rdev);
+}
+
+static void trinity_update_current_power_levels(struct radeon_device *rdev)
+{
+	struct trinity_ps *new_ps = trinity_get_ps(rdev->pm.dpm.requested_ps);
+	struct trinity_power_info *pi = trinity_get_pi(rdev);
+
+	pi->current_ps = *new_ps;
+}
+
+static void trinity_program_power_levels_0_to_n(struct radeon_device *rdev)
+{
+	struct trinity_ps *new_ps = trinity_get_ps(rdev->pm.dpm.requested_ps);
+	struct trinity_ps *old_ps = trinity_get_ps(rdev->pm.dpm.current_ps);
+	u32 i;
+	u32 n_current_state_levels = (old_ps == NULL) ? 1 : old_ps->num_levels;
+
+	for (i = 0; i < new_ps->num_levels; i++) {
+		trinity_program_power_level(rdev, &new_ps->levels[i], i);
+		trinity_power_level_enable_disable(rdev, i, true);
+	}
+
+	for (i = new_ps->num_levels; i < n_current_state_levels; i++)
+		trinity_power_level_enable_disable(rdev, i, false);
+}
+
+static void trinity_program_bootup_state(struct radeon_device *rdev)
+{
+	struct trinity_power_info *pi = trinity_get_pi(rdev);
+	u32 i;
+
+	trinity_program_power_level(rdev, &pi->boot_pl, 0);
+	trinity_power_level_enable_disable(rdev, 0, true);
+
+	for (i = 1; i < 8; i++)
+		trinity_power_level_enable_disable(rdev, i, false);
+}
+
+static void trinity_program_ttt(struct radeon_device *rdev)
+{
+	struct trinity_power_info *pi = trinity_get_pi(rdev);
+	u32 value = RREG32_SMC(SMU_SCLK_DPM_TTT);
+
+	value &= ~(HT_MASK | LT_MASK);
+	value |= HT((pi->thermal_auto_throttling + 49) * 8);
+	value |= LT((pi->thermal_auto_throttling + 49 - pi->sys_info.htc_hyst_lmt) * 8);
+	WREG32_SMC(SMU_SCLK_DPM_TTT, value);
+}
+
+static void trinity_enable_att(struct radeon_device *rdev)
+{
+	u32 value = RREG32_SMC(SMU_SCLK_DPM_TT_CNTL);
+
+	value &= ~SCLK_TT_EN_MASK;
+	value |= SCLK_TT_EN(1);
+	WREG32_SMC(SMU_SCLK_DPM_TT_CNTL, value);
+}
+
+static void trinity_program_sclk_dpm(struct radeon_device *rdev)
+{
+	u32 p, u;
+	u32 tp = RREG32_SMC(PM_TP);
+	u32 ni;
+	u32 xclk = sumo_get_xclk(rdev);
+	u32 value;
+
+	r600_calculate_u_and_p(400, xclk, 16, &p, &u);
+
+	ni = (p + tp - 1) / tp;
+
+	value = RREG32_SMC(PM_I_CNTL_1);
+	value &= ~SCLK_DPM_MASK;
+	value |= SCLK_DPM(ni);
+	WREG32_SMC(PM_I_CNTL_1, value);
+}
+
+static int trinity_set_thermal_temperature_range(struct radeon_device *rdev,
+						 int min_temp, int max_temp)
+{
+	int low_temp = 0 * 1000;
+	int high_temp = 255 * 1000;
+
+        if (low_temp < min_temp)
+		low_temp = min_temp;
+        if (high_temp > max_temp)
+		high_temp = max_temp;
+        if (high_temp < low_temp) {
+		DRM_ERROR("invalid thermal range: %d - %d\n", low_temp, high_temp);
+                return -EINVAL;
+        }
+
+	WREG32_P(CG_THERMAL_INT_CTRL, DIG_THERM_INTH(49 + (high_temp / 1000)), ~DIG_THERM_INTH_MASK);
+	WREG32_P(CG_THERMAL_INT_CTRL, DIG_THERM_INTL(49 + (low_temp / 1000)), ~DIG_THERM_INTL_MASK);
+
+	rdev->pm.dpm.thermal.min_temp = low_temp;
+	rdev->pm.dpm.thermal.max_temp = high_temp;
+
+	return 0;
+}
+
+int trinity_dpm_enable(struct radeon_device *rdev)
+{
+	struct trinity_power_info *pi = trinity_get_pi(rdev);
+
+	trinity_acquire_mutex(rdev);
+
+	if (trinity_dpm_enabled(rdev)) {
+		trinity_release_mutex(rdev);
+		return -EINVAL;
+	}
+
+	trinity_enable_clock_power_gating(rdev);
+	trinity_program_bootup_state(rdev);
+	sumo_program_vc(rdev, 0x00C00033);
+	trinity_start_am(rdev);
+	if (pi->enable_auto_thermal_throttling) {
+		trinity_program_ttt(rdev);
+		trinity_enable_att(rdev);
+	}
+	trinity_program_sclk_dpm(rdev);
+	trinity_start_dpm(rdev);
+	trinity_wait_for_dpm_enabled(rdev);
+	trinity_release_mutex(rdev);
+
+	if (rdev->irq.installed &&
+	    r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
+		trinity_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
+		rdev->irq.dpm_thermal = true;
+		radeon_irq_set(rdev);
+	}
+
+	return 0;
+}
+
+void trinity_dpm_disable(struct radeon_device *rdev)
+{
+	trinity_acquire_mutex(rdev);
+	if (!trinity_dpm_enabled(rdev)) {
+		trinity_release_mutex(rdev);
+		return;
+	}
+	trinity_disable_clock_power_gating(rdev);
+	sumo_clear_vc(rdev);
+	trinity_wait_for_level_0(rdev);
+	trinity_stop_dpm(rdev);
+	trinity_reset_am(rdev);
+	trinity_release_mutex(rdev);
+
+	if (rdev->irq.installed &&
+	    r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
+		rdev->irq.dpm_thermal = false;
+		radeon_irq_set(rdev);
+	}
+}
+
+static void trinity_get_min_sclk_divider(struct radeon_device *rdev)
+{
+	struct trinity_power_info *pi = trinity_get_pi(rdev);
+
+	pi->min_sclk_did =
+		(RREG32_SMC(CC_SMU_MISC_FUSES) & MinSClkDid_MASK) >> MinSClkDid_SHIFT;
+}
+
+static void trinity_setup_nbp_sim(struct radeon_device *rdev)
+{
+	struct trinity_power_info *pi = trinity_get_pi(rdev);
+	struct trinity_ps *new_ps = trinity_get_ps(rdev->pm.dpm.requested_ps);
+	u32 nbpsconfig;
+
+	if (pi->sys_info.nb_dpm_enable) {
+		nbpsconfig = RREG32_SMC(NB_PSTATE_CONFIG);
+		nbpsconfig &= ~(Dpm0PgNbPsLo_MASK | Dpm0PgNbPsHi_MASK | DpmXNbPsLo_MASK | DpmXNbPsHi_MASK);
+		nbpsconfig |= (Dpm0PgNbPsLo(new_ps->Dpm0PgNbPsLo) |
+			       Dpm0PgNbPsHi(new_ps->Dpm0PgNbPsHi) |
+			       DpmXNbPsLo(new_ps->DpmXNbPsLo) |
+			       DpmXNbPsHi(new_ps->DpmXNbPsHi));
+		WREG32_SMC(NB_PSTATE_CONFIG, nbpsconfig);
+	}
+}
+
+int trinity_dpm_set_power_state(struct radeon_device *rdev)
+{
+	struct trinity_power_info *pi = trinity_get_pi(rdev);
+
+	trinity_apply_state_adjust_rules(rdev);
+	trinity_update_current_power_levels(rdev);
+
+	trinity_acquire_mutex(rdev);
+	if (pi->enable_dpm) {
+		trinity_enable_power_level_0(rdev);
+		trinity_force_level_0(rdev);
+		trinity_wait_for_level_0(rdev);
+		trinity_setup_nbp_sim(rdev);
+		trinity_program_power_levels_0_to_n(rdev);
+		trinity_force_level_0(rdev);
+		trinity_unforce_levels(rdev);
+	}
+	trinity_release_mutex(rdev);
+
+	return 0;
+}
+
+void trinity_dpm_setup_asic(struct radeon_device *rdev)
+{
+	trinity_acquire_mutex(rdev);
+	sumo_program_sstp(rdev);
+	sumo_take_smu_control(rdev, true);
+	trinity_get_min_sclk_divider(rdev);
+	trinity_release_mutex(rdev);
+}
+
+void trinity_dpm_reset_asic(struct radeon_device *rdev)
+{
+	struct trinity_power_info *pi = trinity_get_pi(rdev);
+
+	trinity_acquire_mutex(rdev);
+	if (pi->enable_dpm) {
+		trinity_enable_power_level_0(rdev);
+		trinity_force_level_0(rdev);
+		trinity_wait_for_level_0(rdev);
+		trinity_program_bootup_state(rdev);
+		trinity_force_level_0(rdev);
+		trinity_unforce_levels(rdev);
+	}
+	trinity_release_mutex(rdev);
+}
+
+static u16 trinity_convert_voltage_index_to_value(struct radeon_device *rdev,
+						  u32 vid_2bit)
+{
+	struct trinity_power_info *pi = trinity_get_pi(rdev);
+	u32 vid_7bit = sumo_convert_vid2_to_vid7(rdev, &pi->sys_info.vid_mapping_table, vid_2bit);
+	u32 svi_mode = (RREG32_SMC(PM_CONFIG) & SVI_Mode) ? 1 : 0;
+	u32 step = (svi_mode == 0) ? 1250 : 625;
+	u32 delta = vid_7bit * step + 50;
+
+	if (delta > 155000)
+		return 0;
+
+	return (155000 - delta) / 100;
+}
+
+static void trinity_patch_boot_state(struct radeon_device *rdev,
+				     struct trinity_ps *ps)
+{
+	struct trinity_power_info *pi = trinity_get_pi(rdev);
+
+	ps->num_levels = 1;
+	ps->nbps_flags = 0;
+	ps->bapm_flags = 0;
+	ps->levels[0] = pi->boot_pl;
+}
+
+static u8 trinity_calculate_vce_wm(struct radeon_device *rdev, u32 sclk)
+{
+	if (sclk < 20000)
+		return 1;
+	return 0;
+}
+
+static void trinity_construct_boot_state(struct radeon_device *rdev)
+{
+	struct trinity_power_info *pi = trinity_get_pi(rdev);
+
+	pi->boot_pl.sclk = pi->sys_info.bootup_sclk;
+	pi->boot_pl.vddc_index = pi->sys_info.bootup_nb_voltage_index;
+	pi->boot_pl.ds_divider_index = 0;
+	pi->boot_pl.ss_divider_index = 0;
+	pi->boot_pl.allow_gnb_slow = 1;
+	pi->boot_pl.force_nbp_state = 0;
+	pi->boot_pl.display_wm = 0;
+	pi->boot_pl.vce_wm = 0;
+	pi->current_ps.num_levels = 1;
+	pi->current_ps.levels[0] = pi->boot_pl;
+}
+
+static u8 trinity_get_sleep_divider_id_from_clock(struct radeon_device *rdev,
+						  u32 sclk, u32 min_sclk_in_sr)
+{
+	struct trinity_power_info *pi = trinity_get_pi(rdev);
+	u32 i;
+	u32 temp;
+	u32 min = (min_sclk_in_sr > TRINITY_MINIMUM_ENGINE_CLOCK) ?
+		min_sclk_in_sr : TRINITY_MINIMUM_ENGINE_CLOCK;
+
+	if (sclk < min)
+		return 0;
+
+	if (!pi->enable_sclk_ds)
+		return 0;
+
+	for (i = TRINITY_MAX_DEEPSLEEP_DIVIDER_ID;  ; i--) {
+		temp = sclk / sumo_get_sleep_divider_from_id(i);
+		if (temp >= min || i == 0)
+			break;
+	}
+
+	return (u8)i;
+}
+
+static u32 trinity_get_valid_engine_clock(struct radeon_device *rdev,
+					  u32 lower_limit)
+{
+	struct trinity_power_info *pi = trinity_get_pi(rdev);
+	u32 i;
+
+	for (i = 0; i < pi->sys_info.sclk_voltage_mapping_table.num_max_dpm_entries; i++) {
+		if (pi->sys_info.sclk_voltage_mapping_table.entries[i].sclk_frequency >= lower_limit)
+			return pi->sys_info.sclk_voltage_mapping_table.entries[i].sclk_frequency;
+	}
+
+	if (i == pi->sys_info.sclk_voltage_mapping_table.num_max_dpm_entries)
+		DRM_ERROR("engine clock out of range!");
+
+	return 0;
+}
+
+static void trinity_patch_thermal_state(struct radeon_device *rdev,
+					struct trinity_ps *ps,
+					struct trinity_ps *current_ps)
+{
+	struct trinity_power_info *pi = trinity_get_pi(rdev);
+	u32 sclk_in_sr = pi->sys_info.min_sclk; /* ??? */
+	u32 current_vddc;
+	u32 current_sclk;
+	u32 current_index = 0;
+
+	if (current_ps) {
+		current_vddc = current_ps->levels[current_index].vddc_index;
+		current_sclk = current_ps->levels[current_index].sclk;
+	} else {
+		current_vddc = pi->boot_pl.vddc_index;
+		current_sclk = pi->boot_pl.sclk;
+	}
+
+	ps->levels[0].vddc_index = current_vddc;
+
+	if (ps->levels[0].sclk > current_sclk)
+		ps->levels[0].sclk = current_sclk;
+
+	ps->levels[0].ds_divider_index =
+		trinity_get_sleep_divider_id_from_clock(rdev, ps->levels[0].sclk, sclk_in_sr);
+	ps->levels[0].ss_divider_index = ps->levels[0].ds_divider_index;
+	ps->levels[0].allow_gnb_slow = 1;
+	ps->levels[0].force_nbp_state = 0;
+	ps->levels[0].display_wm = 0;
+	ps->levels[0].vce_wm =
+		trinity_calculate_vce_wm(rdev, ps->levels[0].sclk);
+}
+
+static u8 trinity_calculate_display_wm(struct radeon_device *rdev,
+				       struct trinity_ps *ps, u32 index)
+{
+	if (ps == NULL || ps->num_levels <= 1)
+		return 0;
+	else if (ps->num_levels == 2) {
+		if (index == 0)
+			return 0;
+		else
+			return 1;
+	} else {
+		if (index == 0)
+			return 0;
+		else if (ps->levels[index].sclk < 30000)
+			return 0;
+		else
+			return 1;
+	}
+}
+
+static void trinity_apply_state_adjust_rules(struct radeon_device *rdev)
+{
+	struct radeon_ps *rps = rdev->pm.dpm.requested_ps;
+	struct trinity_ps *ps = trinity_get_ps(rps);
+	struct trinity_ps *current_ps = trinity_get_ps(rdev->pm.dpm.current_ps);
+	struct trinity_power_info *pi = trinity_get_pi(rdev);
+	u32 min_voltage = 0; /* ??? */
+	u32 min_sclk = pi->sys_info.min_sclk; /* XXX check against disp reqs */
+	u32 sclk_in_sr = pi->sys_info.min_sclk; /* ??? */
+	u32 i;
+	bool force_high;
+	u32 num_active_displays = rdev->pm.dpm.new_active_crtc_count;
+
+	if (rps->class & ATOM_PPLIB_CLASSIFICATION_THERMAL)
+		return trinity_patch_thermal_state(rdev, ps, current_ps);
+
+	for (i = 0; i < ps->num_levels; i++) {
+		if (ps->levels[i].vddc_index < min_voltage)
+			ps->levels[i].vddc_index = min_voltage;
+
+		if (ps->levels[i].sclk < min_sclk)
+			ps->levels[i].sclk =
+				trinity_get_valid_engine_clock(rdev, min_sclk);
+
+		ps->levels[i].ds_divider_index =
+			sumo_get_sleep_divider_id_from_clock(rdev, ps->levels[i].sclk, sclk_in_sr);
+
+		ps->levels[i].ss_divider_index = ps->levels[i].ds_divider_index;
+
+		ps->levels[i].allow_gnb_slow = 1;
+		ps->levels[i].force_nbp_state = 0;
+		ps->levels[i].display_wm =
+			trinity_calculate_display_wm(rdev, ps, i);
+		ps->levels[i].vce_wm =
+			trinity_calculate_vce_wm(rdev, ps->levels[0].sclk);
+	}
+
+	if ((rps->class & (ATOM_PPLIB_CLASSIFICATION_HDSTATE | ATOM_PPLIB_CLASSIFICATION_SDSTATE)) ||
+	    ((rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) == ATOM_PPLIB_CLASSIFICATION_UI_BATTERY))
+		ps->bapm_flags |= TRINITY_POWERSTATE_FLAGS_BAPM_DISABLE;
+
+	if (pi->sys_info.nb_dpm_enable) {
+		ps->Dpm0PgNbPsLo = 0x1;
+		ps->Dpm0PgNbPsHi = 0x0;
+		ps->DpmXNbPsLo = 0x2;
+		ps->DpmXNbPsHi = 0x1;
+
+		if ((rps->class & (ATOM_PPLIB_CLASSIFICATION_HDSTATE | ATOM_PPLIB_CLASSIFICATION_SDSTATE)) ||
+		    ((rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) == ATOM_PPLIB_CLASSIFICATION_UI_BATTERY)) {
+			force_high = ((rps->class & ATOM_PPLIB_CLASSIFICATION_HDSTATE) ||
+				      ((rps->class & ATOM_PPLIB_CLASSIFICATION_SDSTATE) &&
+				       (pi->sys_info.uma_channel_number == 1)));
+			force_high = (num_active_displays >= 3) || force_high;
+			ps->Dpm0PgNbPsLo = force_high ? 0x2 : 0x3;
+			ps->Dpm0PgNbPsHi = 0x1;
+			ps->DpmXNbPsLo = force_high ? 0x2 : 0x3;
+			ps->DpmXNbPsHi = 0x2;
+			ps->levels[ps->num_levels - 1].allow_gnb_slow = 0;
+		}
+	}
+}
+
+static void trinity_cleanup_asic(struct radeon_device *rdev)
+{
+	sumo_take_smu_control(rdev, false);
+}
+
+#if 0
+static void trinity_pre_display_configuration_change(struct radeon_device *rdev)
+{
+	struct trinity_power_info *pi = trinity_get_pi(rdev);
+
+	if (pi->voltage_drop_in_dce)
+		trinity_dce_enable_voltage_adjustment(rdev, false);
+}
+#endif
+
+static void trinity_add_dccac_value(struct radeon_device *rdev)
+{
+	u32 gpu_cac_avrg_cntl_window_size;
+	u32 num_active_displays = rdev->pm.dpm.new_active_crtc_count;
+	u64 disp_clk = rdev->clock.default_dispclk / 100;
+	u32 dc_cac_value;
+
+	gpu_cac_avrg_cntl_window_size =
+		(RREG32_SMC(GPU_CAC_AVRG_CNTL) & WINDOW_SIZE_MASK) >> WINDOW_SIZE_SHIFT;
+
+	dc_cac_value = (u32)((14213 * disp_clk * disp_clk * (u64)num_active_displays) >>
+			     (32 - gpu_cac_avrg_cntl_window_size));
+
+	WREG32_SMC(DC_CAC_VALUE, dc_cac_value);
+}
+
+void trinity_dpm_display_configuration_changed(struct radeon_device *rdev)
+{
+	struct trinity_power_info *pi = trinity_get_pi(rdev);
+
+	if (pi->voltage_drop_in_dce)
+		trinity_dce_enable_voltage_adjustment(rdev, true);
+	trinity_add_dccac_value(rdev);
+}
+
+union power_info {
+	struct _ATOM_POWERPLAY_INFO info;
+	struct _ATOM_POWERPLAY_INFO_V2 info_2;
+	struct _ATOM_POWERPLAY_INFO_V3 info_3;
+	struct _ATOM_PPLIB_POWERPLAYTABLE pplib;
+	struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2;
+	struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3;
+};
+
+union pplib_clock_info {
+	struct _ATOM_PPLIB_R600_CLOCK_INFO r600;
+	struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780;
+	struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen;
+	struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo;
+};
+
+union pplib_power_state {
+	struct _ATOM_PPLIB_STATE v1;
+	struct _ATOM_PPLIB_STATE_V2 v2;
+};
+
+static void trinity_parse_pplib_non_clock_info(struct radeon_device *rdev,
+					       struct radeon_ps *rps,
+					       struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info,
+					       u8 table_rev)
+{
+	struct trinity_ps *ps = trinity_get_ps(rps);
+
+	rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings);
+	rps->class = le16_to_cpu(non_clock_info->usClassification);
+	rps->class2 = le16_to_cpu(non_clock_info->usClassification2);
+
+	if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) {
+		rps->vclk = le32_to_cpu(non_clock_info->ulVCLK);
+		rps->dclk = le32_to_cpu(non_clock_info->ulDCLK);
+	} else {
+		rps->vclk = 0;
+		rps->dclk = 0;
+	}
+
+	if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) {
+		rdev->pm.dpm.boot_ps = rps;
+		trinity_patch_boot_state(rdev, ps);
+	}
+	if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
+		rdev->pm.dpm.uvd_ps = rps;
+}
+
+static void trinity_parse_pplib_clock_info(struct radeon_device *rdev,
+					   struct radeon_ps *rps, int index,
+					   union pplib_clock_info *clock_info)
+{
+	struct trinity_power_info *pi = trinity_get_pi(rdev);
+	struct trinity_ps *ps = trinity_get_ps(rps);
+	struct trinity_pl *pl = &ps->levels[index];
+	u32 sclk;
+
+	sclk = le16_to_cpu(clock_info->sumo.usEngineClockLow);
+	sclk |= clock_info->sumo.ucEngineClockHigh << 16;
+	pl->sclk = sclk;
+	pl->vddc_index = clock_info->sumo.vddcIndex;
+
+	ps->num_levels = index + 1;
+
+	if (pi->enable_sclk_ds) {
+		pl->ds_divider_index = 5;
+		pl->ss_divider_index = 5;
+	}
+}
+
+static int trinity_parse_power_table(struct radeon_device *rdev)
+{
+	struct radeon_mode_info *mode_info = &rdev->mode_info;
+	struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
+	union pplib_power_state *power_state;
+	int i, j, k, non_clock_array_index, clock_array_index;
+	union pplib_clock_info *clock_info;
+	struct _StateArray *state_array;
+	struct _ClockInfoArray *clock_info_array;
+	struct _NonClockInfoArray *non_clock_info_array;
+	union power_info *power_info;
+	int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
+        u16 data_offset;
+	u8 frev, crev;
+	u8 *power_state_offset;
+	struct sumo_ps *ps;
+
+	if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
+				   &frev, &crev, &data_offset))
+		return -EINVAL;
+	power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
+
+	state_array = (struct _StateArray *)
+		(mode_info->atom_context->bios + data_offset +
+		 le16_to_cpu(power_info->pplib.usStateArrayOffset));
+	clock_info_array = (struct _ClockInfoArray *)
+		(mode_info->atom_context->bios + data_offset +
+		 le16_to_cpu(power_info->pplib.usClockInfoArrayOffset));
+	non_clock_info_array = (struct _NonClockInfoArray *)
+		(mode_info->atom_context->bios + data_offset +
+		 le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset));
+
+	rdev->pm.dpm.ps = kzalloc(sizeof(struct radeon_ps) *
+				  state_array->ucNumEntries, GFP_KERNEL);
+	if (!rdev->pm.dpm.ps)
+		return -ENOMEM;
+	power_state_offset = (u8 *)state_array->states;
+	rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps);
+	rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime);
+	rdev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime);
+	for (i = 0; i < state_array->ucNumEntries; i++) {
+		power_state = (union pplib_power_state *)power_state_offset;
+		non_clock_array_index = power_state->v2.nonClockInfoIndex;
+		non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
+			&non_clock_info_array->nonClockInfo[non_clock_array_index];
+		if (!rdev->pm.power_state[i].clock_info)
+			return -EINVAL;
+		ps = kzalloc(sizeof(struct sumo_ps), GFP_KERNEL);
+		if (ps == NULL) {
+			kfree(rdev->pm.dpm.ps);
+			return -ENOMEM;
+		}
+		rdev->pm.dpm.ps[i].ps_priv = ps;
+		k = 0;
+		for (j = 0; j < power_state->v2.ucNumDPMLevels; j++) {
+			clock_array_index = power_state->v2.clockInfoIndex[j];
+			if (clock_array_index >= clock_info_array->ucNumEntries)
+				continue;
+			if (k >= SUMO_MAX_HARDWARE_POWERLEVELS)
+				break;
+			clock_info = (union pplib_clock_info *)
+				&clock_info_array->clockInfo[clock_array_index * clock_info_array->ucEntrySize];
+			trinity_parse_pplib_clock_info(rdev,
+						       &rdev->pm.dpm.ps[i], k,
+						       clock_info);
+			k++;
+		}
+		trinity_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i],
+						   non_clock_info,
+						   non_clock_info_array->ucEntrySize);
+		power_state_offset += 2 + power_state->v2.ucNumDPMLevels;
+	}
+	rdev->pm.dpm.num_ps = state_array->ucNumEntries;
+	return 0;
+}
+
+union igp_info {
+	struct _ATOM_INTEGRATED_SYSTEM_INFO info;
+	struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2;
+	struct _ATOM_INTEGRATED_SYSTEM_INFO_V5 info_5;
+	struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 info_6;
+	struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7 info_7;
+};
+
+static int trinity_parse_sys_info_table(struct radeon_device *rdev)
+{
+	struct trinity_power_info *pi = trinity_get_pi(rdev);
+	struct radeon_mode_info *mode_info = &rdev->mode_info;
+	int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);
+	union igp_info *igp_info;
+	u8 frev, crev;
+	u16 data_offset;
+	int i;
+
+	if (atom_parse_data_header(mode_info->atom_context, index, NULL,
+				   &frev, &crev, &data_offset)) {
+		igp_info = (union igp_info *)(mode_info->atom_context->bios +
+					      data_offset);
+
+		if (crev != 7) {
+			DRM_ERROR("Unsupported IGP table: %d %d\n", frev, crev);
+			return -EINVAL;
+		}
+		pi->sys_info.bootup_sclk = le32_to_cpu(igp_info->info_7.ulBootUpEngineClock);
+		pi->sys_info.min_sclk = le32_to_cpu(igp_info->info_7.ulMinEngineClock);
+		pi->sys_info.bootup_uma_clk = le32_to_cpu(igp_info->info_7.ulBootUpUMAClock);
+		pi->sys_info.bootup_nb_voltage_index =
+			le16_to_cpu(igp_info->info_7.usBootUpNBVoltage);
+		if (igp_info->info_7.ucHtcTmpLmt == 0)
+			pi->sys_info.htc_tmp_lmt = 203;
+		else
+			pi->sys_info.htc_tmp_lmt = igp_info->info_7.ucHtcTmpLmt;
+		if (igp_info->info_7.ucHtcHystLmt == 0)
+			pi->sys_info.htc_hyst_lmt = 5;
+		else
+			pi->sys_info.htc_hyst_lmt = igp_info->info_7.ucHtcHystLmt;
+		if (pi->sys_info.htc_tmp_lmt <= pi->sys_info.htc_hyst_lmt) {
+			DRM_ERROR("The htcTmpLmt should be larger than htcHystLmt.\n");
+		}
+
+		if (pi->enable_nbps_policy)
+			pi->sys_info.nb_dpm_enable = igp_info->info_7.ucNBDPMEnable;
+		else
+			pi->sys_info.nb_dpm_enable = 0;
+
+		for (i = 0; i < TRINITY_NUM_NBPSTATES; i++) {
+			pi->sys_info.nbp_mclk[i] = le32_to_cpu(igp_info->info_7.ulNbpStateMemclkFreq[i]);
+			pi->sys_info.nbp_nclk[i] = le32_to_cpu(igp_info->info_7.ulNbpStateNClkFreq[i]);
+		}
+
+		pi->sys_info.nbp_voltage_index[0] = le16_to_cpu(igp_info->info_7.usNBP0Voltage);
+		pi->sys_info.nbp_voltage_index[1] = le16_to_cpu(igp_info->info_7.usNBP1Voltage);
+		pi->sys_info.nbp_voltage_index[2] = le16_to_cpu(igp_info->info_7.usNBP2Voltage);
+		pi->sys_info.nbp_voltage_index[3] = le16_to_cpu(igp_info->info_7.usNBP3Voltage);
+
+		if (!pi->sys_info.nb_dpm_enable) {
+			for (i = 1; i < TRINITY_NUM_NBPSTATES; i++) {
+				pi->sys_info.nbp_mclk[i] = pi->sys_info.nbp_mclk[0];
+				pi->sys_info.nbp_nclk[i] = pi->sys_info.nbp_nclk[0];
+				pi->sys_info.nbp_voltage_index[i] = pi->sys_info.nbp_voltage_index[0];
+			}
+		}
+
+		pi->sys_info.uma_channel_number = igp_info->info_7.ucUMAChannelNumber;
+
+		sumo_construct_sclk_voltage_mapping_table(rdev,
+							  &pi->sys_info.sclk_voltage_mapping_table,
+							  igp_info->info_7.sAvail_SCLK);
+		sumo_construct_vid_mapping_table(rdev, &pi->sys_info.vid_mapping_table,
+						 igp_info->info_7.sAvail_SCLK);
+
+	}
+	return 0;
+}
+
+int trinity_dpm_init(struct radeon_device *rdev)
+{
+	struct trinity_power_info *pi;
+	int ret, i;
+
+	pi = kzalloc(sizeof(struct trinity_power_info), GFP_KERNEL);
+	if (pi == NULL)
+		return -ENOMEM;
+	rdev->pm.dpm.priv = pi;
+
+	for (i = 0; i < SUMO_MAX_HARDWARE_POWERLEVELS; i++)
+		pi->at[i] = TRINITY_AT_DFLT;
+
+	pi->enable_nbps_policy = true;
+	pi->enable_sclk_ds = true;
+	pi->enable_gfx_power_gating = true;
+	pi->enable_gfx_clock_gating = true;
+	pi->enable_mg_clock_gating = true;
+	pi->enable_gfx_dynamic_mgpg = true; /* ??? */
+	pi->override_dynamic_mgpg = true;
+	pi->enable_auto_thermal_throttling = true;
+	pi->voltage_drop_in_dce = false; /* need to restructure dpm/modeset interaction */
+
+	ret = trinity_parse_sys_info_table(rdev);
+	if (ret)
+		return ret;
+
+	trinity_construct_boot_state(rdev);
+
+	ret = trinity_parse_power_table(rdev);
+	if (ret)
+		return ret;
+
+	pi->thermal_auto_throttling = pi->sys_info.htc_tmp_lmt;
+	pi->enable_dpm = true;
+
+	return 0;
+}
+
+void trinity_dpm_print_power_state(struct radeon_device *rdev,
+				   struct radeon_ps *rps)
+{
+	int i;
+	struct trinity_ps *ps = trinity_get_ps(rps);
+
+	r600_dpm_print_class_info(rps->class, rps->class2);
+	r600_dpm_print_cap_info(rps->caps);
+	printk("\tuvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
+	for (i = 0; i < ps->num_levels; i++) {
+		struct trinity_pl *pl = &ps->levels[i];
+		printk("\t\tpower level %d    sclk: %u vddc: %u\n",
+		       i, pl->sclk,
+		       trinity_convert_voltage_index_to_value(rdev, pl->vddc_index));
+	}
+	r600_dpm_print_ps_status(rdev, rps);
+}
+
+void trinity_dpm_fini(struct radeon_device *rdev)
+{
+	int i;
+
+	trinity_cleanup_asic(rdev); /* ??? */
+
+	for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
+		kfree(rdev->pm.dpm.ps[i].ps_priv);
+	}
+	kfree(rdev->pm.dpm.ps);
+	kfree(rdev->pm.dpm.priv);
+}
+
+u32 trinity_dpm_get_sclk(struct radeon_device *rdev, bool low)
+{
+	struct trinity_ps *requested_state = trinity_get_ps(rdev->pm.dpm.requested_ps);
+
+	if (low)
+		return requested_state->levels[0].sclk;
+	else
+		return requested_state->levels[requested_state->num_levels - 1].sclk;
+}
+
+u32 trinity_dpm_get_mclk(struct radeon_device *rdev, bool low)
+{
+	struct trinity_power_info *pi = trinity_get_pi(rdev);
+
+	return pi->sys_info.bootup_uma_clk;
+}
diff --git a/drivers/gpu/drm/radeon/trinity_dpm.h b/drivers/gpu/drm/radeon/trinity_dpm.h
new file mode 100644
index 0000000..15e050f
--- /dev/null
+++ b/drivers/gpu/drm/radeon/trinity_dpm.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2012 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef __TRINITY_DPM_H__
+#define __TRINITY_DPM_H__
+
+#include "sumo_dpm.h"
+
+#define TRINITY_SIZEOF_DPM_STATE_TABLE (SMU_SCLK_DPM_STATE_1_CNTL_0 - SMU_SCLK_DPM_STATE_0_CNTL_0)
+
+struct trinity_pl {
+	u32 sclk;
+	u8 vddc_index;
+	u8 ds_divider_index;
+	u8 ss_divider_index;
+	u8 allow_gnb_slow;
+	u8 force_nbp_state;
+	u8 display_wm;
+	u8 vce_wm;
+};
+
+#define TRINITY_POWERSTATE_FLAGS_NBPS_FORCEHIGH  (1 << 0)
+#define TRINITY_POWERSTATE_FLAGS_NBPS_LOCKTOHIGH (1 << 1)
+#define TRINITY_POWERSTATE_FLAGS_NBPS_LOCKTOLOW  (1 << 2)
+
+#define TRINITY_POWERSTATE_FLAGS_BAPM_DISABLE    (1 << 0)
+
+struct trinity_ps {
+	u32 num_levels;
+	struct trinity_pl levels[SUMO_MAX_HARDWARE_POWERLEVELS];
+
+	u32 nbps_flags;
+	u32 bapm_flags;
+
+	u8 Dpm0PgNbPsLo;
+	u8 Dpm0PgNbPsHi;
+	u8 DpmXNbPsLo;
+	u8 DpmXNbPsHi;
+};
+
+#define TRINITY_NUM_NBPSTATES   4
+
+struct trinity_sys_info {
+	u32 bootup_uma_clk;
+	u32 bootup_sclk;
+	u32 min_sclk;
+	u32 nb_dpm_enable;
+	u32 nbp_mclk[TRINITY_NUM_NBPSTATES];
+	u32 nbp_nclk[TRINITY_NUM_NBPSTATES];
+	u16 nbp_voltage_index[TRINITY_NUM_NBPSTATES];
+	u16 bootup_nb_voltage_index;
+	u8 htc_tmp_lmt;
+	u8 htc_hyst_lmt;
+	struct sumo_sclk_voltage_mapping_table sclk_voltage_mapping_table;
+	struct sumo_vid_mapping_table vid_mapping_table;
+	u32 uma_channel_number;
+};
+
+struct trinity_power_info {
+	u32 at[SUMO_MAX_HARDWARE_POWERLEVELS];
+	u32 dpm_interval;
+	u32 thermal_auto_throttling;
+	struct trinity_sys_info sys_info;
+	struct trinity_pl boot_pl;
+	struct trinity_ps current_ps;
+	u32 min_sclk_did;
+	bool enable_nbps_policy;
+	bool voltage_drop_in_dce;
+	bool override_dynamic_mgpg;
+	bool enable_gfx_clock_gating;
+	bool enable_gfx_power_gating;
+	bool enable_mg_clock_gating;
+	bool enable_gfx_dynamic_mgpg;
+	bool enable_auto_thermal_throttling;
+	bool enable_dpm;
+	bool enable_sclk_ds;
+};
+
+#define TRINITY_AT_DFLT            30
+
+/* trinity_smc.c */
+int trinity_dpm_config(struct radeon_device *rdev, bool enable);
+int trinity_dpm_force_state(struct radeon_device *rdev, u32 n);
+int trinity_dpm_no_forced_level(struct radeon_device *rdev);
+int trinity_dce_enable_voltage_adjustment(struct radeon_device *rdev,
+					  bool enable);
+int trinity_gfx_dynamic_mgpg_config(struct radeon_device *rdev);
+void trinity_acquire_mutex(struct radeon_device *rdev);
+void trinity_release_mutex(struct radeon_device *rdev);
+
+#endif
diff --git a/drivers/gpu/drm/radeon/trinity_smc.c b/drivers/gpu/drm/radeon/trinity_smc.c
new file mode 100644
index 0000000..60ffc1e
--- /dev/null
+++ b/drivers/gpu/drm/radeon/trinity_smc.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2012 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "drmP.h"
+#include "radeon.h"
+#include "trinityd.h"
+#include "trinity_dpm.h"
+#include "ppsmc.h"
+
+struct trinity_ps *trinity_get_ps(struct radeon_ps *rps);
+struct trinity_power_info *trinity_get_pi(struct radeon_device *rdev);
+
+static int trinity_notify_message_to_smu(struct radeon_device *rdev, u32 id)
+{
+	int i;
+	u32 v = 0;
+
+	WREG32(SMC_MESSAGE_0, id);
+	for (i = 0; i < rdev->usec_timeout; i++) {
+		if (RREG32(SMC_RESP_0) != 0)
+			break;
+		udelay(1);
+	}
+	v = RREG32(SMC_RESP_0);
+
+	if (v != 1) {
+		if (v == 0xFF) {
+			DRM_ERROR("SMC failed to handle the message!\n");
+			return -EINVAL;
+		} else if (v == 0xFE) {
+			DRM_ERROR("Unknown SMC message!\n");
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+int trinity_dpm_config(struct radeon_device *rdev, bool enable)
+{
+	if (enable)
+		WREG32_SMC(SMU_SCRATCH0, 1);
+	else
+		WREG32_SMC(SMU_SCRATCH0, 0);
+
+	return trinity_notify_message_to_smu(rdev, PPSMC_MSG_DPM_Config);
+}
+
+int trinity_dpm_force_state(struct radeon_device *rdev, u32 n)
+{
+	WREG32_SMC(SMU_SCRATCH0, n);
+
+	return trinity_notify_message_to_smu(rdev, PPSMC_MSG_DPM_ForceState);
+}
+
+int trinity_dpm_no_forced_level(struct radeon_device *rdev)
+{
+	return trinity_notify_message_to_smu(rdev, PPSMC_MSG_NoForcedLevel);
+}
+
+int trinity_dce_enable_voltage_adjustment(struct radeon_device *rdev,
+					  bool enable)
+{
+	if (enable)
+		return trinity_notify_message_to_smu(rdev, PPSMC_MSG_DCE_AllowVoltageAdjustment);
+	else
+		return trinity_notify_message_to_smu(rdev, PPSMC_MSG_DCE_RemoveVoltageAdjustment);
+}
+
+int trinity_gfx_dynamic_mgpg_config(struct radeon_device *rdev)
+{
+	return trinity_notify_message_to_smu(rdev, PPSMC_MSG_PG_SIMD_Config);
+}
+
+void trinity_acquire_mutex(struct radeon_device *rdev)
+{
+	int i;
+
+	WREG32(SMC_INT_REQ, 1);
+	for (i = 0; i < rdev->usec_timeout; i++) {
+		if ((RREG32(SMC_INT_REQ) & 0xffff) == 1)
+			break;
+		udelay(1);
+	}
+}
+
+void trinity_release_mutex(struct radeon_device *rdev)
+{
+	WREG32(SMC_INT_REQ, 0);
+}
diff --git a/drivers/gpu/drm/radeon/trinityd.h b/drivers/gpu/drm/radeon/trinityd.h
new file mode 100644
index 0000000..b234d36
--- /dev/null
+++ b/drivers/gpu/drm/radeon/trinityd.h
@@ -0,0 +1,223 @@
+/*
+ * Copyright 2012 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Alex Deucher
+ */
+#ifndef _TRINITYD_H_
+#define _TRINITYD_H_
+
+/* pm registers */
+
+/* cg */
+#define CG_CGTT_LOCAL_0                                 0x0
+#define CG_CGTT_LOCAL_1                                 0x1
+
+/* smc */
+#define SMU_SCLK_DPM_STATE_0_CNTL_0                     0x1f000
+#       define STATE_VALID(x)                           ((x) << 0)
+#       define STATE_VALID_MASK                         (0xff << 0)
+#       define STATE_VALID_SHIFT                        0
+#       define CLK_DIVIDER(x)                           ((x) << 8)
+#       define CLK_DIVIDER_MASK                         (0xff << 8)
+#       define CLK_DIVIDER_SHIFT                        8
+#       define VID(x)                                   ((x) << 16)
+#       define VID_MASK                                 (0xff << 16)
+#       define VID_SHIFT                                16
+#       define LVRT(x)                                  ((x) << 24)
+#       define LVRT_MASK                                (0xff << 24)
+#       define LVRT_SHIFT                               24
+#define SMU_SCLK_DPM_STATE_0_CNTL_1                     0x1f004
+#       define DS_DIV(x)                                ((x) << 0)
+#       define DS_DIV_MASK                              (0xff << 0)
+#       define DS_DIV_SHIFT                             0
+#       define DS_SH_DIV(x)                             ((x) << 8)
+#       define DS_SH_DIV_MASK                           (0xff << 8)
+#       define DS_SH_DIV_SHIFT                          8
+#       define DISPLAY_WM(x)                            ((x) << 16)
+#       define DISPLAY_WM_MASK                          (0xff << 16)
+#       define DISPLAY_WM_SHIFT                         16
+#       define VCE_WM(x)                                ((x) << 24)
+#       define VCE_WM_MASK                              (0xff << 24)
+#       define VCE_WM_SHIFT                             24
+
+#define SMU_SCLK_DPM_STATE_0_CNTL_3                     0x1f00c
+#       define GNB_SLOW(x)                              ((x) << 0)
+#       define GNB_SLOW_MASK                            (0xff << 0)
+#       define GNB_SLOW_SHIFT                           0
+#       define FORCE_NBPS1(x)                           ((x) << 8)
+#       define FORCE_NBPS1_MASK                         (0xff << 8)
+#       define FORCE_NBPS1_SHIFT                        8
+#define SMU_SCLK_DPM_STATE_0_AT                         0x1f010
+#       define AT(x)                                    ((x) << 0)
+#       define AT_MASK                                  (0xff << 0)
+#       define AT_SHIFT                                 0
+
+#define SMU_SCLK_DPM_STATE_0_PG_CNTL                    0x1f014
+#       define PD_SCLK_DIVIDER(x)                       ((x) << 16)
+#       define PD_SCLK_DIVIDER_MASK                     (0xff << 16)
+#       define PD_SCLK_DIVIDER_SHIFT                    16
+
+#define SMU_SCLK_DPM_STATE_1_CNTL_0                     0x1f020
+
+#define SMU_SCLK_DPM_CNTL                               0x1f100
+#       define SCLK_DPM_EN(x)                           ((x) << 0)
+#       define SCLK_DPM_EN_MASK                         (0xff << 0)
+#       define SCLK_DPM_EN_SHIFT                        0
+#       define SCLK_DPM_BOOT_STATE(x)                   ((x) << 16)
+#       define SCLK_DPM_BOOT_STATE_MASK                 (0xff << 16)
+#       define SCLK_DPM_BOOT_STATE_SHIFT                16
+#       define VOLTAGE_CHG_EN(x)                        ((x) << 24)
+#       define VOLTAGE_CHG_EN_MASK                      (0xff << 24)
+#       define VOLTAGE_CHG_EN_SHIFT                     24
+
+#define SMU_SCLK_DPM_TT_CNTL                            0x1f108
+#       define SCLK_TT_EN(x)                            ((x) << 0)
+#       define SCLK_TT_EN_MASK                          (0xff << 0)
+#       define SCLK_TT_EN_SHIFT                         0
+#define SMU_SCLK_DPM_TTT                                0x1f10c
+#       define LT(x)                                    ((x) << 0)
+#       define LT_MASK                                  (0xffff << 0)
+#       define LT_SHIFT                                 0
+#       define HT(x)                                    ((x) << 16)
+#       define HT_MASK                                  (0xffff << 16)
+#       define HT_SHIFT                                 16
+
+#define SMU_S_PG_CNTL                                   0x1f118
+#       define DS_PG_EN(x)                              ((x) << 16)
+#       define DS_PG_EN_MASK                            (0xff << 16)
+#       define DS_PG_EN_SHIFT                           16
+
+#define GFX_POWER_GATING_CNTL                           0x1f38c
+#       define PDS_DIV(x)                               ((x) << 0)
+#       define PDS_DIV_MASK                             (0xff << 0)
+#       define PDS_DIV_SHIFT                            0
+#       define SSSD(x)                                  ((x) << 8)
+#       define SSSD_MASK                                (0xff << 8)
+#       define SSSD_SHIFT                               8
+
+#define PM_CONFIG                                       0x1f428
+#       define SVI_Mode                                 (1 << 29)
+
+#define PM_I_CNTL_1                                     0x1f464
+#       define SCLK_DPM(x)                              ((x) << 0)
+#       define SCLK_DPM_MASK                            (0xff << 0)
+#       define SCLK_DPM_SHIFT                           0
+#       define DS_PG_CNTL(x)                            ((x) << 16)
+#       define DS_PG_CNTL_MASK                          (0xff << 16)
+#       define DS_PG_CNTL_SHIFT                         16
+#define PM_TP                                           0x1f468
+
+#define NB_PSTATE_CONFIG                                0x1f5f8
+#       define Dpm0PgNbPsLo(x)                          ((x) << 0)
+#       define Dpm0PgNbPsLo_MASK                        (3 << 0)
+#       define Dpm0PgNbPsLo_SHIFT                       0
+#       define Dpm0PgNbPsHi(x)                          ((x) << 2)
+#       define Dpm0PgNbPsHi_MASK                        (3 << 2)
+#       define Dpm0PgNbPsHi_SHIFT                       2
+#       define DpmXNbPsLo(x)                            ((x) << 4)
+#       define DpmXNbPsLo_MASK                          (3 << 4)
+#       define DpmXNbPsLo_SHIFT                         4
+#       define DpmXNbPsHi(x)                            ((x) << 6)
+#       define DpmXNbPsHi_MASK                          (3 << 6)
+#       define DpmXNbPsHi_SHIFT                         6
+
+#define DC_CAC_VALUE                                    0x1f908
+
+#define GPU_CAC_AVRG_CNTL                               0x1f920
+#       define WINDOW_SIZE(x)                           ((x) << 0)
+#       define WINDOW_SIZE_MASK                         (0xff << 0)
+#       define WINDOW_SIZE_SHIFT                        0
+
+#define CC_SMU_MISC_FUSES                               0xe0001004
+#       define MinSClkDid(x)                   ((x) << 2)
+#       define MinSClkDid_MASK                 (0x7f << 2)
+#       define MinSClkDid_SHIFT                2
+
+#define CC_SMU_TST_EFUSE1_MISC                          0xe000101c
+#       define RB_BACKEND_DISABLE(x)                    ((x) << 16)
+#       define RB_BACKEND_DISABLE_MASK                  (3 << 16)
+#       define RB_BACKEND_DISABLE_SHIFT                 16
+
+#define SMU_SCRATCH_A                                   0xe0003024
+
+#define SMU_SCRATCH0                                    0xe0003040
+
+/* mmio */
+#define SMC_INT_REQ                                     0x220
+
+#define SMC_MESSAGE_0                                   0x22c
+#define SMC_RESP_0                                      0x230
+
+#define GENERAL_PWRMGT                                  0x670
+#       define GLOBAL_PWRMGT_EN                         (1 << 0)
+
+#define SCLK_PWRMGT_CNTL                                0x678
+#       define DYN_PWR_DOWN_EN                          (1 << 2)
+#       define RESET_BUSY_CNT                           (1 << 4)
+#       define RESET_SCLK_CNT                           (1 << 5)
+#       define DYN_GFX_CLK_OFF_EN                       (1 << 7)
+#       define GFX_CLK_FORCE_ON                         (1 << 8)
+#       define DYNAMIC_PM_EN                            (1 << 21)
+
+#define TARGET_AND_CURRENT_PROFILE_INDEX                0x684
+#       define TARGET_STATE(x)                          ((x) << 0)
+#       define TARGET_STATE_MASK                        (0xf << 0)
+#       define TARGET_STATE_SHIFT                       0
+#       define CURRENT_STATE(x)                         ((x) << 4)
+#       define CURRENT_STATE_MASK                       (0xf << 4)
+#       define CURRENT_STATE_SHIFT                      4
+
+#define CG_GIPOTS                                       0x6d8
+#       define CG_GIPOT(x)                              ((x) << 16)
+#       define CG_GIPOT_MASK                            (0xffff << 16)
+#       define CG_GIPOT_SHIFT                           16
+
+#define CG_PG_CTRL                                      0x6e0
+#       define SP(x)                                    ((x) << 0)
+#       define SP_MASK                                  (0xffff << 0)
+#       define SP_SHIFT                                 0
+#       define SU(x)                                    ((x) << 16)
+#       define SU_MASK                                  (0xffff << 16)
+#       define SU_SHIFT                                 16
+
+#define CG_THERMAL_INT_CTRL                             0x738
+#       define DIG_THERM_INTH(x)                        ((x) << 0)
+#       define DIG_THERM_INTH_MASK                      (0xff << 0)
+#       define DIG_THERM_INTH_SHIFT                     0
+#       define DIG_THERM_INTL(x)                        ((x) << 8)
+#       define DIG_THERM_INTL_MASK                      (0xff << 8)
+#       define DIG_THERM_INTL_SHIFT                     8
+#       define THERM_INTH_MASK                          (1 << 24)
+#       define THERM_INTL_MASK                          (1 << 25)
+
+#define CG_CG_VOLTAGE_CNTL                              0x770
+#       define EN                                       (1 << 9)
+
+#define HW_REV   					0x5564
+#       define ATI_REV_ID_MASK                          (0xf << 28)
+#       define ATI_REV_ID_SHIFT                         28
+/* 0 = A0, 1 = A1, 2 = B0, 3 = C0, etc. */
+
+#define CGTS_SM_CTRL_REG                                0x9150
+
+#define GB_ADDR_CONFIG                                  0x98f8
+
+#endif
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 082/165] drm/radeon/dpm: let atom control display phy powergating
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (81 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 081/165] drm/radeon/kms: add dpm support for trinity asics alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 083/165] drm/radeon: add dpm UVD handling for r7xx asics alexdeucher
                   ` (30 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/sumo_dpm.c |    7 +++++++
 1 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/radeon/sumo_dpm.c b/drivers/gpu/drm/radeon/sumo_dpm.c
index 67c85c7..f103880 100644
--- a/drivers/gpu/drm/radeon/sumo_dpm.c
+++ b/drivers/gpu/drm/radeon/sumo_dpm.c
@@ -813,6 +813,12 @@ static void sumo_program_bootup_state(struct radeon_device *rdev)
 
 void sumo_take_smu_control(struct radeon_device *rdev, bool enable)
 {
+/* This bit selects who handles display phy powergating.
+ * Clear the bit to let atom handle it.
+ * Set it to let the driver handle it.
+ * For now we just let atom handle it.
+ */
+#if 0
 	u32 v = RREG32(DOUT_SCRATCH3);
 
 	if (enable)
@@ -821,6 +827,7 @@ void sumo_take_smu_control(struct radeon_device *rdev, bool enable)
 		v &= 0xFFFFFFFB;
 
 	WREG32(DOUT_SCRATCH3, v);
+#endif
 }
 
 static void sumo_enable_sclk_ds(struct radeon_device *rdev, bool enable)
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 083/165] drm/radeon: add dpm UVD handling for r7xx asics
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (82 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 082/165] drm/radeon/dpm: let atom control display phy powergating alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 084/165] drm/radeon: add dpm UVD handling for evergreen/btc asics alexdeucher
                   ` (29 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/rv770_dpm.c |   34 ++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/radeon/rv770_dpm.h |    2 ++
 2 files changed, 36 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/radeon/rv770_dpm.c b/drivers/gpu/drm/radeon/rv770_dpm.c
index 8ea6d69..42f559a 100644
--- a/drivers/gpu/drm/radeon/rv770_dpm.c
+++ b/drivers/gpu/drm/radeon/rv770_dpm.c
@@ -1427,6 +1427,38 @@ int rv770_set_boot_state(struct radeon_device *rdev)
 	return 0;
 }
 
+void rv770_set_uvd_clock_before_set_eng_clock(struct radeon_device *rdev)
+{
+	struct rv7xx_ps *new_state = rv770_get_ps(rdev->pm.dpm.requested_ps);
+	struct rv7xx_ps *current_state = rv770_get_ps(rdev->pm.dpm.current_ps);
+
+	if ((rdev->pm.dpm.requested_ps->vclk == rdev->pm.dpm.current_ps->vclk) &&
+	    (rdev->pm.dpm.requested_ps->dclk == rdev->pm.dpm.current_ps->dclk))
+		return;
+
+	if (new_state->high.sclk >= current_state->high.sclk)
+		return;
+
+	radeon_set_uvd_clocks(rdev, rdev->pm.dpm.requested_ps->vclk,
+			      rdev->pm.dpm.requested_ps->dclk);
+}
+
+void rv770_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev)
+{
+	struct rv7xx_ps *new_state = rv770_get_ps(rdev->pm.dpm.requested_ps);
+	struct rv7xx_ps *current_state = rv770_get_ps(rdev->pm.dpm.current_ps);
+
+	if ((rdev->pm.dpm.requested_ps->vclk == rdev->pm.dpm.current_ps->vclk) &&
+	    (rdev->pm.dpm.requested_ps->dclk == rdev->pm.dpm.current_ps->dclk))
+		return;
+
+	if (new_state->high.sclk < current_state->high.sclk)
+		return;
+
+	radeon_set_uvd_clocks(rdev, rdev->pm.dpm.requested_ps->vclk,
+			      rdev->pm.dpm.requested_ps->dclk);
+}
+
 int rv770_restrict_performance_levels_before_switch(struct radeon_device *rdev)
 {
 	if (rv770_send_msg_to_smc(rdev, (PPSMC_Msg)(PPSMC_MSG_NoForcedLevel)) != PPSMC_Result_OK)
@@ -1950,6 +1982,7 @@ int rv770_dpm_set_power_state(struct radeon_device *rdev)
 	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
 
 	rv770_restrict_performance_levels_before_switch(rdev);
+	rv770_set_uvd_clock_before_set_eng_clock(rdev);
 	rv770_halt_smc(rdev);
 	rv770_upload_sw_state(rdev);
 	r7xx_program_memory_timing_parameters(rdev);
@@ -1959,6 +1992,7 @@ int rv770_dpm_set_power_state(struct radeon_device *rdev)
 	rv770_set_sw_state(rdev);
 	if (pi->dcodt)
 		rv770_program_dcodt_after_state_switch(rdev);
+	rv770_set_uvd_clock_after_set_eng_clock(rdev);
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/radeon/rv770_dpm.h b/drivers/gpu/drm/radeon/rv770_dpm.h
index bd6ea7b..e42c064 100644
--- a/drivers/gpu/drm/radeon/rv770_dpm.h
+++ b/drivers/gpu/drm/radeon/rv770_dpm.h
@@ -262,6 +262,8 @@ int rv770_resume_smc(struct radeon_device *rdev);
 int rv770_set_sw_state(struct radeon_device *rdev);
 int rv770_set_boot_state(struct radeon_device *rdev);
 int rv7xx_parse_power_table(struct radeon_device *rdev);
+void rv770_set_uvd_clock_before_set_eng_clock(struct radeon_device *rdev);
+void rv770_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev);
 
 /* smc */
 int rv770_read_smc_soft_register(struct radeon_device *rdev,
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 084/165] drm/radeon: add dpm UVD handling for evergreen/btc asics
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (83 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 083/165] drm/radeon: add dpm UVD handling for r7xx asics alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 085/165] drm/radeon: add dpm UVD handling for sumo asics alexdeucher
                   ` (28 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/btc_dpm.c     |   62 ++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/radeon/btc_dpm.h     |    4 ++
 drivers/gpu/drm/radeon/cypress_dpm.c |   10 +++++-
 drivers/gpu/drm/radeon/cypress_dpm.h |   10 +++++
 drivers/gpu/drm/radeon/rv770_dpm.c   |   30 +++++++++-------
 drivers/gpu/drm/radeon/rv770_dpm.h   |    4 ++
 drivers/gpu/drm/radeon/rv770_smc.h   |    1 +
 7 files changed, 107 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/radeon/btc_dpm.c b/drivers/gpu/drm/radeon/btc_dpm.c
index 6780120..2662ef0 100644
--- a/drivers/gpu/drm/radeon/btc_dpm.c
+++ b/drivers/gpu/drm/radeon/btc_dpm.c
@@ -1510,6 +1510,46 @@ static int btc_init_smc_table(struct radeon_device *rdev)
 				       pi->sram_end);
 }
 
+static void btc_set_at_for_uvd(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	struct radeon_ps *radeon_new_state = rdev->pm.dpm.requested_ps;
+	int idx = 0;
+
+	if (r600_is_uvd_state(radeon_new_state->class, radeon_new_state->class2))
+		idx = 1;
+
+	if ((idx == 1) && !eg_pi->smu_uvd_hs) {
+		pi->rlp = 10;
+		pi->rmp = 100;
+		pi->lhp = 100;
+		pi->lmp = 10;
+	} else {
+		pi->rlp = eg_pi->ats[idx].rlp;
+		pi->rmp = eg_pi->ats[idx].rmp;
+		pi->lhp = eg_pi->ats[idx].lhp;
+		pi->lmp = eg_pi->ats[idx].lmp;
+	}
+
+}
+
+static void btc_notify_uvd_to_smc(struct radeon_device *rdev)
+{
+	struct radeon_ps *radeon_new_state = rdev->pm.dpm.requested_ps;
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+
+	if (r600_is_uvd_state(radeon_new_state->class, radeon_new_state->class2)) {
+		rv770_write_smc_soft_register(rdev,
+					      RV770_SMC_SOFT_REGISTER_uvd_enabled, 1);
+		eg_pi->uvd_enabled = true;
+	} else {
+		rv770_write_smc_soft_register(rdev,
+					      RV770_SMC_SOFT_REGISTER_uvd_enabled, 0);
+		eg_pi->uvd_enabled = false;
+	}
+}
+
 static int btc_reset_to_default(struct radeon_device *rdev)
 {
 	if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_ResetToDefaults) != PPSMC_Result_OK)
@@ -1880,7 +1920,11 @@ int btc_dpm_set_power_state(struct radeon_device *rdev)
 	if (eg_pi->pcie_performance_request)
 		cypress_notify_link_speed_change_before_state_change(rdev);
 
+	rv770_set_uvd_clock_before_set_eng_clock(rdev);
 	rv770_halt_smc(rdev);
+	btc_set_at_for_uvd(rdev);
+	if (eg_pi->smu_uvd_hs)
+		btc_notify_uvd_to_smc(rdev);
 	cypress_upload_sw_state(rdev);
 
 	if (eg_pi->dynamic_ac_timing)
@@ -1890,6 +1934,7 @@ int btc_dpm_set_power_state(struct radeon_device *rdev)
 
 	rv770_resume_smc(rdev);
 	rv770_set_sw_state(rdev);
+	rv770_set_uvd_clock_after_set_eng_clock(rdev);
 
 	if (eg_pi->pcie_performance_request)
 		cypress_notify_link_speed_change_after_state_change(rdev);
@@ -2093,6 +2138,23 @@ int btc_dpm_init(struct radeon_device *rdev)
 	pi->mclk_edc_enable_threshold = 40000;
 	eg_pi->mclk_edc_wr_enable_threshold = 40000;
 
+	pi->rlp = RV770_RLP_DFLT;
+	pi->rmp = RV770_RMP_DFLT;
+	pi->lhp = RV770_LHP_DFLT;
+	pi->lmp = RV770_LMP_DFLT;
+
+	eg_pi->ats[0].rlp = RV770_RLP_DFLT;
+	eg_pi->ats[0].rmp = RV770_RMP_DFLT;
+	eg_pi->ats[0].lhp = RV770_LHP_DFLT;
+	eg_pi->ats[0].lmp = RV770_LMP_DFLT;
+
+	eg_pi->ats[1].rlp = BTC_RLP_UVD_DFLT;
+	eg_pi->ats[1].rmp = BTC_RMP_UVD_DFLT;
+	eg_pi->ats[1].lhp = BTC_LHP_UVD_DFLT;
+	eg_pi->ats[1].lmp = BTC_LMP_UVD_DFLT;
+
+	eg_pi->smu_uvd_hs = true;
+
 	pi->voltage_control =
 		radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC);
 
diff --git a/drivers/gpu/drm/radeon/btc_dpm.h b/drivers/gpu/drm/radeon/btc_dpm.h
index a095d40..56b1957 100644
--- a/drivers/gpu/drm/radeon/btc_dpm.h
+++ b/drivers/gpu/drm/radeon/btc_dpm.h
@@ -23,6 +23,10 @@
 #ifndef __BTC_DPM_H__
 #define __BTC_DPM_H__
 
+#define BTC_RLP_UVD_DFLT                              20
+#define BTC_RMP_UVD_DFLT                              50
+#define BTC_LHP_UVD_DFLT                              50
+#define BTC_LMP_UVD_DFLT                              20
 #define BARTS_MGCGCGTSSMCTRL_DFLT                     0x81944000
 #define TURKS_MGCGCGTSSMCTRL_DFLT                     0x6e944000
 #define CAICOS_MGCGCGTSSMCTRL_DFLT                    0x46944040
diff --git a/drivers/gpu/drm/radeon/cypress_dpm.c b/drivers/gpu/drm/radeon/cypress_dpm.c
index 2345c81..403ee15 100644
--- a/drivers/gpu/drm/radeon/cypress_dpm.c
+++ b/drivers/gpu/drm/radeon/cypress_dpm.c
@@ -690,7 +690,8 @@ int cypress_convert_power_level_to_smc(struct radeon_device *rdev,
 
 	level->mcFlags =  0;
 	if (pi->mclk_stutter_mode_threshold &&
-	    (pl->mclk <= pi->mclk_stutter_mode_threshold)) {
+	    (pl->mclk <= pi->mclk_stutter_mode_threshold) &&
+	    !eg_pi->uvd_enabled) {
 		level->mcFlags |= SMC_MC_STUTTER_EN;
 		if (eg_pi->sclk_deep_sleep)
 			level->stateFlags |= PPSMC_STATEFLAG_AUTO_PULSE_SKIP;
@@ -1938,6 +1939,7 @@ int cypress_dpm_set_power_state(struct radeon_device *rdev)
 	if (eg_pi->pcie_performance_request)
 		cypress_notify_link_speed_change_before_state_change(rdev);
 
+	rv770_set_uvd_clock_before_set_eng_clock(rdev);
 	rv770_halt_smc(rdev);
 	cypress_upload_sw_state(rdev);
 
@@ -1948,6 +1950,7 @@ int cypress_dpm_set_power_state(struct radeon_device *rdev)
 
 	rv770_resume_smc(rdev);
 	rv770_set_sw_state(rdev);
+	rv770_set_uvd_clock_after_set_eng_clock(rdev);
 
 	if (eg_pi->pcie_performance_request)
 		cypress_notify_link_speed_change_after_state_change(rdev);
@@ -2010,6 +2013,11 @@ int cypress_dpm_init(struct radeon_device *rdev)
 	pi->mclk_edc_enable_threshold = 40000;
 	eg_pi->mclk_edc_wr_enable_threshold = 40000;
 
+	pi->rlp = RV770_RLP_DFLT;
+	pi->rmp = RV770_RMP_DFLT;
+	pi->lhp = RV770_LHP_DFLT;
+	pi->lmp = RV770_LMP_DFLT;
+
 	pi->voltage_control =
 		radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC);
 
diff --git a/drivers/gpu/drm/radeon/cypress_dpm.h b/drivers/gpu/drm/radeon/cypress_dpm.h
index 6cc3d3f..029bc9d 100644
--- a/drivers/gpu/drm/radeon/cypress_dpm.h
+++ b/drivers/gpu/drm/radeon/cypress_dpm.h
@@ -51,6 +51,13 @@ struct evergreen_arb_registers {
 	u32 mc_arb_burst_time;
 };
 
+struct at {
+	u32 rlp;
+	u32 rmp;
+	u32 lhp;
+	u32 lmp;
+};
+
 struct evergreen_power_info {
 	/* must be first! */
 	struct rv7xx_power_info rv7xx;
@@ -66,6 +73,8 @@ struct evergreen_power_info {
 	bool sclk_deep_sleep;
 	bool dll_default_on;
 	bool ls_clock_gating;
+	bool smu_uvd_hs;
+	bool uvd_enabled;
 	/* stored values */
 	u16 acpi_vddci;
 	u8 mvdd_high_index;
@@ -76,6 +85,7 @@ struct evergreen_power_info {
 	struct atom_voltage_table vddci_voltage_table;
 	struct evergreen_arb_registers bootup_arb_registers;
 	struct evergreen_ulv_param ulv;
+	struct at ats[2];
 	/* smc offsets */
 	u16 mc_reg_table_start;
 };
diff --git a/drivers/gpu/drm/radeon/rv770_dpm.c b/drivers/gpu/drm/radeon/rv770_dpm.c
index 42f559a..55e5126 100644
--- a/drivers/gpu/drm/radeon/rv770_dpm.c
+++ b/drivers/gpu/drm/radeon/rv770_dpm.c
@@ -265,22 +265,21 @@ int rv770_populate_smc_t(struct radeon_device *rdev,
 	l[0] = 0;
 	r[2] = 100;
 
-	a_n = (int)state->medium.sclk * RV770_LMP_DFLT +
-		(int)state->low.sclk * (R600_AH_DFLT - RV770_RLP_DFLT);
-	a_d = (int)state->low.sclk * (100 - (int)RV770_RLP_DFLT) +
-		(int)state->medium.sclk * RV770_LMP_DFLT;
+	a_n = (int)state->medium.sclk * pi->lmp +
+		(int)state->low.sclk * (R600_AH_DFLT - pi->rlp);
+	a_d = (int)state->low.sclk * (100 - (int)pi->rlp) +
+		(int)state->medium.sclk * pi->lmp;
 
-	l[1] = (u8)(RV770_LMP_DFLT - (int)RV770_LMP_DFLT * a_n / a_d);
-	r[0] = (u8)(RV770_RLP_DFLT + (100 - (int)RV770_RLP_DFLT) * a_n / a_d);
+	l[1] = (u8)(pi->lmp - (int)pi->lmp * a_n / a_d);
+	r[0] = (u8)(pi->rlp + (100 - (int)pi->rlp) * a_n / a_d);
 
-	a_n = (int)state->high.sclk * RV770_LHP_DFLT +
-		(int)state->medium.sclk *
-		(R600_AH_DFLT - RV770_RMP_DFLT);
-	a_d = (int)state->medium.sclk * (100 - (int)RV770_RMP_DFLT) +
-		(int)state->high.sclk * RV770_LHP_DFLT;
+	a_n = (int)state->high.sclk * pi->lhp + (int)state->medium.sclk *
+		(R600_AH_DFLT - pi->rmp);
+	a_d = (int)state->medium.sclk * (100 - (int)pi->rmp) +
+		(int)state->high.sclk * pi->lhp;
 
-	l[2] = (u8)(RV770_LHP_DFLT - (int)RV770_LHP_DFLT * a_n / a_d);
-	r[1] = (u8)(RV770_RMP_DFLT + (100 - (int)RV770_RMP_DFLT) * a_n / a_d);
+	l[2] = (u8)(pi->lhp - (int)pi->lhp * a_n / a_d);
+	r[1] = (u8)(pi->rmp + (100 - (int)pi->rmp) * a_n / a_d);
 
 	for (i = 0; i < (RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE - 1); i++) {
 		a_t = CG_R(r[i] * pi->bsp / 200) | CG_L(l[i] * pi->bsp / 200);
@@ -2269,6 +2268,11 @@ int rv770_dpm_init(struct radeon_device *rdev)
 	pi->mclk_strobe_mode_threshold = 30000;
 	pi->mclk_edc_enable_threshold = 30000;
 
+	pi->rlp = RV770_RLP_DFLT;
+	pi->rmp = RV770_RMP_DFLT;
+	pi->lhp = RV770_LHP_DFLT;
+	pi->lmp = RV770_LMP_DFLT;
+
 	pi->voltage_control =
 		radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC);
 
diff --git a/drivers/gpu/drm/radeon/rv770_dpm.h b/drivers/gpu/drm/radeon/rv770_dpm.h
index e42c064..dfb133f 100644
--- a/drivers/gpu/drm/radeon/rv770_dpm.h
+++ b/drivers/gpu/drm/radeon/rv770_dpm.h
@@ -126,6 +126,10 @@ struct rv7xx_power_info {
 	u32 pasi;
 	u32 vrc;
 	u32 restricted_levels;
+	u32 rlp;
+	u32 rmp;
+	u32 lhp;
+	u32 lmp;
 	/* smc offsets */
 	u16 state_table_start;
 	u16 soft_regs_start;
diff --git a/drivers/gpu/drm/radeon/rv770_smc.h b/drivers/gpu/drm/radeon/rv770_smc.h
index bdb652c..f78d92a 100644
--- a/drivers/gpu/drm/radeon/rv770_smc.h
+++ b/drivers/gpu/drm/radeon/rv770_smc.h
@@ -184,6 +184,7 @@ typedef struct RV770_SMC_STATETABLE RV770_SMC_STATETABLE;
 #define RV770_SMC_SOFT_REGISTER_mvdd_chg_time           0x68
 #define RV770_SMC_SOFT_REGISTER_mclk_switch_lim         0x78
 #define RV770_SMC_SOFT_REGISTER_mc_block_delay          0x90
+#define RV770_SMC_SOFT_REGISTER_uvd_enabled             0x9C
 #define RV770_SMC_SOFT_REGISTER_is_asic_lombok          0xA0
 
 int rv770_set_smc_sram_address(struct radeon_device *rdev,
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 085/165] drm/radeon: add dpm UVD handling for sumo asics
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (84 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 084/165] drm/radeon: add dpm UVD handling for evergreen/btc asics alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 086/165] drm/radeon: add dpm UVD handling for TN asics (v2) alexdeucher
                   ` (27 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/sumo_dpm.c |   55 +++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/radeon/sumod.h    |   10 +++++++
 2 files changed, 65 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/radeon/sumo_dpm.c b/drivers/gpu/drm/radeon/sumo_dpm.c
index f103880..cef25c4 100644
--- a/drivers/gpu/drm/radeon/sumo_dpm.c
+++ b/drivers/gpu/drm/radeon/sumo_dpm.c
@@ -811,6 +811,40 @@ static void sumo_program_bootup_state(struct radeon_device *rdev)
 		sumo_power_level_enable(rdev, i, false);
 }
 
+static void sumo_set_uvd_clock_before_set_eng_clock(struct radeon_device *rdev)
+{
+	struct sumo_ps *new_ps = sumo_get_ps(rdev->pm.dpm.requested_ps);
+	struct sumo_ps *current_ps = sumo_get_ps(rdev->pm.dpm.current_ps);
+
+	if ((rdev->pm.dpm.requested_ps->vclk == rdev->pm.dpm.current_ps->vclk) &&
+	    (rdev->pm.dpm.requested_ps->dclk == rdev->pm.dpm.current_ps->dclk))
+		return;
+
+	if (new_ps->levels[new_ps->num_levels - 1].sclk >=
+	    current_ps->levels[current_ps->num_levels - 1].sclk)
+		return;
+
+	radeon_set_uvd_clocks(rdev, rdev->pm.dpm.requested_ps->vclk,
+			      rdev->pm.dpm.requested_ps->dclk);
+}
+
+static void sumo_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev)
+{
+	struct sumo_ps *new_ps = sumo_get_ps(rdev->pm.dpm.requested_ps);
+	struct sumo_ps *current_ps = sumo_get_ps(rdev->pm.dpm.current_ps);
+
+	if ((rdev->pm.dpm.requested_ps->vclk == rdev->pm.dpm.current_ps->vclk) &&
+	    (rdev->pm.dpm.requested_ps->dclk == rdev->pm.dpm.current_ps->dclk))
+		return;
+
+	if (new_ps->levels[new_ps->num_levels - 1].sclk <
+	    current_ps->levels[current_ps->num_levels - 1].sclk)
+		return;
+
+	radeon_set_uvd_clocks(rdev, rdev->pm.dpm.requested_ps->vclk,
+			      rdev->pm.dpm.requested_ps->dclk);
+}
+
 void sumo_take_smu_control(struct radeon_device *rdev, bool enable)
 {
 /* This bit selects who handles display phy powergating.
@@ -1096,6 +1130,22 @@ static void sumo_cleanup_asic(struct radeon_device *rdev)
 	sumo_take_smu_control(rdev, false);
 }
 
+static void sumo_uvd_init(struct radeon_device *rdev)
+{
+	u32 tmp;
+
+	tmp = RREG32(CG_VCLK_CNTL);
+	tmp &= ~VCLK_DIR_CNTL_EN;
+	WREG32(CG_VCLK_CNTL, tmp);
+
+	tmp = RREG32(CG_DCLK_CNTL);
+	tmp &= ~DCLK_DIR_CNTL_EN;
+	WREG32(CG_DCLK_CNTL, tmp);
+
+	/* 100 Mhz */
+	radeon_set_uvd_clocks(rdev, 10000, 10000);
+}
+
 static int sumo_set_thermal_temperature_range(struct radeon_device *rdev,
 					      int min_temp, int max_temp)
 {
@@ -1188,6 +1238,8 @@ int sumo_dpm_set_power_state(struct radeon_device *rdev)
 
 	if (pi->enable_dynamic_patch_ps)
 		sumo_apply_state_adjust_rules(rdev);
+	if (pi->enable_dpm)
+		sumo_set_uvd_clock_before_set_eng_clock(rdev);
 	sumo_update_current_power_levels(rdev);
 	if (pi->enable_boost) {
 		sumo_enable_boost(rdev, false);
@@ -1211,6 +1263,8 @@ int sumo_dpm_set_power_state(struct radeon_device *rdev)
 	}
 	if (pi->enable_boost)
 		sumo_enable_boost(rdev, true);
+	if (pi->enable_dpm)
+		sumo_set_uvd_clock_after_set_eng_clock(rdev);
 
 	return 0;
 }
@@ -1237,6 +1291,7 @@ void sumo_dpm_setup_asic(struct radeon_device *rdev)
 	sumo_program_acpi_power_level(rdev);
 	sumo_enable_acpi_pm(rdev);
 	sumo_take_smu_control(rdev, true);
+	sumo_uvd_init(rdev);
 }
 
 void sumo_dpm_display_configuration_changed(struct radeon_device *rdev)
diff --git a/drivers/gpu/drm/radeon/sumod.h b/drivers/gpu/drm/radeon/sumod.h
index a5deba6..7c9c2d4 100644
--- a/drivers/gpu/drm/radeon/sumod.h
+++ b/drivers/gpu/drm/radeon/sumod.h
@@ -136,6 +136,16 @@
 #define CG_SCLK_STATUS                                  0x604
 #       define SCLK_OVERCLK_DETECT                      (1 << 2)
 
+#define CG_DCLK_CNTL                                    0x610
+#       define DCLK_DIVIDER_MASK                        0x7f
+#       define DCLK_DIR_CNTL_EN                         (1 << 8)
+#define CG_DCLK_STATUS                                  0x614
+#       define DCLK_STATUS                              (1 << 0)
+#define CG_VCLK_CNTL                                    0x618
+#       define VCLK_DIVIDER_MASK                        0x7f
+#       define VCLK_DIR_CNTL_EN                         (1 << 8)
+#define CG_VCLK_STATUS                                  0x61c
+
 #define GENERAL_PWRMGT                                  0x63c
 #       define STATIC_PM_EN                             (1 << 1)
 
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 086/165] drm/radeon: add dpm UVD handling for TN asics (v2)
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (85 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 085/165] drm/radeon: add dpm UVD handling for sumo asics alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 087/165] drm/radeon/kms: enable UVD as needed (v9) alexdeucher
                   ` (26 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

v2: fix typo noticed by Dan Carpenter

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/ppsmc.h       |    1 +
 drivers/gpu/drm/radeon/trinity_dpm.c |  220 ++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/radeon/trinity_dpm.h |   18 +++
 drivers/gpu/drm/radeon/trinity_smc.c |    5 +
 drivers/gpu/drm/radeon/trinityd.h    |    5 +
 5 files changed, 249 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/radeon/ppsmc.h b/drivers/gpu/drm/radeon/ppsmc.h
index 8ef479a..3d0786f 100644
--- a/drivers/gpu/drm/radeon/ppsmc.h
+++ b/drivers/gpu/drm/radeon/ppsmc.h
@@ -75,6 +75,7 @@ typedef uint8_t PPSMC_Result;
 #define PPSMC_MSG_PG_SIMD_Config            ((uint32_t) 0x108)
 #define PPSMC_MSG_DCE_RemoveVoltageAdjustment   ((uint32_t) 0x11d)
 #define PPSMC_MSG_DCE_AllowVoltageAdjustment    ((uint32_t) 0x11e)
+#define PPSMC_MSG_UVD_DPM_Config            ((uint32_t) 0x124)
 
 
 typedef uint16_t PPSMC_Msg;
diff --git a/drivers/gpu/drm/radeon/trinity_dpm.c b/drivers/gpu/drm/radeon/trinity_dpm.c
index c4779a6..1b3822f 100644
--- a/drivers/gpu/drm/radeon/trinity_dpm.c
+++ b/drivers/gpu/drm/radeon/trinity_dpm.c
@@ -866,6 +866,117 @@ static void trinity_program_bootup_state(struct radeon_device *rdev)
 		trinity_power_level_enable_disable(rdev, i, false);
 }
 
+static void trinity_setup_uvd_clock_table(struct radeon_device *rdev,
+					  struct radeon_ps *rps)
+{
+	struct trinity_ps *ps = trinity_get_ps(rps);
+	u32 uvdstates = (ps->vclk_low_divider |
+			 ps->vclk_high_divider << 8 |
+			 ps->dclk_low_divider << 16 |
+			 ps->dclk_high_divider << 24);
+
+	WREG32_SMC(SMU_UVD_DPM_STATES, uvdstates);
+}
+
+static void trinity_setup_uvd_dpm_interval(struct radeon_device *rdev,
+					   u32 interval)
+{
+	u32 p, u;
+	u32 tp = RREG32_SMC(PM_TP);
+	u32 val;
+	u32 xclk = sumo_get_xclk(rdev);
+
+	r600_calculate_u_and_p(interval, xclk, 16, &p, &u);
+
+	val = (p + tp - 1) / tp;
+
+	WREG32_SMC(SMU_UVD_DPM_CNTL, val);
+}
+
+static bool trinity_uvd_clocks_zero(struct radeon_ps *rps)
+{
+	if ((rps->vclk == 0) && (rps->dclk == 0))
+		return true;
+	else
+		return false;
+}
+
+static bool trinity_uvd_clocks_equal(struct radeon_ps *rps1,
+				     struct radeon_ps *rps2)
+{
+	struct trinity_ps *ps1 = trinity_get_ps(rps1);
+	struct trinity_ps *ps2 = trinity_get_ps(rps2);
+
+	if ((rps1->vclk == rps2->vclk) &&
+	    (rps1->dclk == rps2->dclk) &&
+	    (ps1->vclk_low_divider == ps2->vclk_low_divider) &&
+	    (ps1->vclk_high_divider == ps2->vclk_high_divider) &&
+	    (ps1->dclk_low_divider == ps2->dclk_low_divider) &&
+	    (ps1->dclk_high_divider == ps2->dclk_high_divider))
+		return true;
+	else
+		return false;
+}
+
+static void trinity_setup_uvd_clocks(struct radeon_device *rdev,
+				     struct radeon_ps *current_rps,
+				     struct radeon_ps *new_rps)
+{
+	struct trinity_power_info *pi = trinity_get_pi(rdev);
+
+	if (pi->uvd_dpm) {
+		if (trinity_uvd_clocks_zero(new_rps) &&
+		    !trinity_uvd_clocks_zero(current_rps)) {
+			trinity_setup_uvd_dpm_interval(rdev, 0);
+		} else if (!trinity_uvd_clocks_zero(new_rps)) {
+			trinity_setup_uvd_clock_table(rdev, new_rps);
+
+			if (trinity_uvd_clocks_zero(current_rps)) {
+				u32 tmp = RREG32(CG_MISC_REG);
+				tmp &= 0xfffffffd;
+				WREG32(CG_MISC_REG, tmp);
+
+				radeon_set_uvd_clocks(rdev, new_rps->vclk, new_rps->dclk);
+
+				trinity_setup_uvd_dpm_interval(rdev, 3000);
+			}
+		}
+		trinity_uvd_dpm_config(rdev);
+	} else {
+		if (trinity_uvd_clocks_zero(new_rps) ||
+		    trinity_uvd_clocks_equal(new_rps, current_rps))
+			return;
+
+		radeon_set_uvd_clocks(rdev, new_rps->vclk, new_rps->dclk);
+	}
+}
+
+static void trinity_set_uvd_clock_before_set_eng_clock(struct radeon_device *rdev)
+{
+	struct trinity_ps *new_ps = trinity_get_ps(rdev->pm.dpm.requested_ps);
+	struct trinity_ps *current_ps = trinity_get_ps(rdev->pm.dpm.current_ps);
+
+	if (new_ps->levels[new_ps->num_levels - 1].sclk >=
+	    current_ps->levels[current_ps->num_levels - 1].sclk)
+		return;
+
+	trinity_setup_uvd_clocks(rdev, rdev->pm.dpm.current_ps,
+				 rdev->pm.dpm.requested_ps);
+}
+
+static void trinity_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev)
+{
+	struct trinity_ps *new_ps = trinity_get_ps(rdev->pm.dpm.requested_ps);
+	struct trinity_ps *current_ps = trinity_get_ps(rdev->pm.dpm.current_ps);
+
+	if (new_ps->levels[new_ps->num_levels - 1].sclk <
+	    current_ps->levels[current_ps->num_levels - 1].sclk)
+		return;
+
+	trinity_setup_uvd_clocks(rdev, rdev->pm.dpm.current_ps,
+				 rdev->pm.dpm.requested_ps);
+}
+
 static void trinity_program_ttt(struct radeon_device *rdev)
 {
 	struct trinity_power_info *pi = trinity_get_pi(rdev);
@@ -1017,6 +1128,7 @@ int trinity_dpm_set_power_state(struct radeon_device *rdev)
 
 	trinity_acquire_mutex(rdev);
 	if (pi->enable_dpm) {
+		trinity_set_uvd_clock_before_set_eng_clock(rdev);
 		trinity_enable_power_level_0(rdev);
 		trinity_force_level_0(rdev);
 		trinity_wait_for_level_0(rdev);
@@ -1024,6 +1136,7 @@ int trinity_dpm_set_power_state(struct radeon_device *rdev)
 		trinity_program_power_levels_0_to_n(rdev);
 		trinity_force_level_0(rdev);
 		trinity_unforce_levels(rdev);
+		trinity_set_uvd_clock_after_set_eng_clock(rdev);
 	}
 	trinity_release_mutex(rdev);
 
@@ -1198,6 +1311,61 @@ static u8 trinity_calculate_display_wm(struct radeon_device *rdev,
 	}
 }
 
+static u32 trinity_get_uvd_clock_index(struct radeon_device *rdev,
+				       struct radeon_ps *rps)
+{
+	struct trinity_power_info *pi = trinity_get_pi(rdev);
+	u32 i = 0;
+
+	for (i = 0; i < 4; i++) {
+		if ((rps->vclk == pi->sys_info.uvd_clock_table_entries[i].vclk) &&
+		    (rps->dclk == pi->sys_info.uvd_clock_table_entries[i].dclk))
+		    break;
+	}
+
+	if (i >= 4) {
+		DRM_ERROR("UVD clock index not found!\n");
+		i = 3;
+	}
+	return i;
+}
+
+static void trinity_adjust_uvd_state(struct radeon_device *rdev,
+				     struct radeon_ps *rps)
+{
+	struct trinity_ps *ps = trinity_get_ps(rps);
+	struct trinity_power_info *pi = trinity_get_pi(rdev);
+	u32 high_index = 0;
+	u32 low_index = 0;
+
+	if (pi->uvd_dpm && r600_is_uvd_state(rps->class, rps->class2)) {
+		high_index = trinity_get_uvd_clock_index(rdev, rps);
+
+		switch(high_index) {
+		case 3:
+		case 2:
+			low_index = 1;
+			break;
+		case 1:
+		case 0:
+		default:
+			low_index = 0;
+			break;
+		}
+
+		ps->vclk_low_divider =
+			pi->sys_info.uvd_clock_table_entries[high_index].vclk_did;
+		ps->dclk_low_divider =
+			pi->sys_info.uvd_clock_table_entries[high_index].dclk_did;
+		ps->vclk_high_divider =
+			pi->sys_info.uvd_clock_table_entries[low_index].vclk_did;
+		ps->dclk_high_divider =
+			pi->sys_info.uvd_clock_table_entries[low_index].dclk_did;
+	}
+}
+
+
+
 static void trinity_apply_state_adjust_rules(struct radeon_device *rdev)
 {
 	struct radeon_ps *rps = rdev->pm.dpm.requested_ps;
@@ -1214,6 +1382,8 @@ static void trinity_apply_state_adjust_rules(struct radeon_device *rdev)
 	if (rps->class & ATOM_PPLIB_CLASSIFICATION_THERMAL)
 		return trinity_patch_thermal_state(rdev, ps, current_ps);
 
+	trinity_adjust_uvd_state(rdev, rps);
+
 	for (i = 0; i < ps->num_levels; i++) {
 		if (ps->levels[i].vddc_index < min_voltage)
 			ps->levels[i].vddc_index = min_voltage;
@@ -1454,6 +1624,25 @@ union igp_info {
 	struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7 info_7;
 };
 
+static u32 trinity_convert_did_to_freq(struct radeon_device *rdev, u8 did)
+{
+	struct trinity_power_info *pi = trinity_get_pi(rdev);
+	u32 divider;
+
+	if (did >= 8 && did <= 0x3f)
+		divider = did * 25;
+	else if (did > 0x3f && did <= 0x5f)
+		divider = (did - 64) * 50 + 1600;
+	else if (did > 0x5f && did <= 0x7e)
+		divider = (did - 96) * 100 + 3200;
+	else if (did == 0x7f)
+		divider = 128 * 100;
+	else
+		return 10000;
+
+	return ((pi->sys_info.dentist_vco_freq * 100) + (divider - 1)) / divider;
+}
+
 static int trinity_parse_sys_info_table(struct radeon_device *rdev)
 {
 	struct trinity_power_info *pi = trinity_get_pi(rdev);
@@ -1476,6 +1665,7 @@ static int trinity_parse_sys_info_table(struct radeon_device *rdev)
 		pi->sys_info.bootup_sclk = le32_to_cpu(igp_info->info_7.ulBootUpEngineClock);
 		pi->sys_info.min_sclk = le32_to_cpu(igp_info->info_7.ulMinEngineClock);
 		pi->sys_info.bootup_uma_clk = le32_to_cpu(igp_info->info_7.ulBootUpUMAClock);
+		pi->sys_info.dentist_vco_freq = le32_to_cpu(igp_info->info_7.ulDentistVCOFreq);
 		pi->sys_info.bootup_nb_voltage_index =
 			le16_to_cpu(igp_info->info_7.usBootUpNBVoltage);
 		if (igp_info->info_7.ucHtcTmpLmt == 0)
@@ -1521,6 +1711,35 @@ static int trinity_parse_sys_info_table(struct radeon_device *rdev)
 		sumo_construct_vid_mapping_table(rdev, &pi->sys_info.vid_mapping_table,
 						 igp_info->info_7.sAvail_SCLK);
 
+		pi->sys_info.uvd_clock_table_entries[0].vclk_did =
+			igp_info->info_7.ucDPMState0VclkFid;
+		pi->sys_info.uvd_clock_table_entries[1].vclk_did =
+			igp_info->info_7.ucDPMState1VclkFid;
+		pi->sys_info.uvd_clock_table_entries[2].vclk_did =
+			igp_info->info_7.ucDPMState2VclkFid;
+		pi->sys_info.uvd_clock_table_entries[3].vclk_did =
+			igp_info->info_7.ucDPMState3VclkFid;
+
+		pi->sys_info.uvd_clock_table_entries[0].dclk_did =
+			igp_info->info_7.ucDPMState0DclkFid;
+		pi->sys_info.uvd_clock_table_entries[1].dclk_did =
+			igp_info->info_7.ucDPMState1DclkFid;
+		pi->sys_info.uvd_clock_table_entries[2].dclk_did =
+			igp_info->info_7.ucDPMState2DclkFid;
+		pi->sys_info.uvd_clock_table_entries[3].dclk_did =
+			igp_info->info_7.ucDPMState3DclkFid;
+
+		for (i = 0; i < 4; i++) {
+			pi->sys_info.uvd_clock_table_entries[i].vclk =
+				trinity_convert_did_to_freq(rdev,
+							    pi->sys_info.uvd_clock_table_entries[i].vclk_did);
+			pi->sys_info.uvd_clock_table_entries[i].dclk =
+				trinity_convert_did_to_freq(rdev,
+							    pi->sys_info.uvd_clock_table_entries[i].dclk_did);
+		}
+
+
+
 	}
 	return 0;
 }
@@ -1547,6 +1766,7 @@ int trinity_dpm_init(struct radeon_device *rdev)
 	pi->override_dynamic_mgpg = true;
 	pi->enable_auto_thermal_throttling = true;
 	pi->voltage_drop_in_dce = false; /* need to restructure dpm/modeset interaction */
+	pi->uvd_dpm = true; /* ??? */
 
 	ret = trinity_parse_sys_info_table(rdev);
 	if (ret)
diff --git a/drivers/gpu/drm/radeon/trinity_dpm.h b/drivers/gpu/drm/radeon/trinity_dpm.h
index 15e050f..31100ac 100644
--- a/drivers/gpu/drm/radeon/trinity_dpm.h
+++ b/drivers/gpu/drm/radeon/trinity_dpm.h
@@ -55,14 +55,29 @@ struct trinity_ps {
 	u8 Dpm0PgNbPsHi;
 	u8 DpmXNbPsLo;
 	u8 DpmXNbPsHi;
+
+	u32 vclk_low_divider;
+	u32 vclk_high_divider;
+	u32 dclk_low_divider;
+	u32 dclk_high_divider;
 };
 
 #define TRINITY_NUM_NBPSTATES   4
 
+struct trinity_uvd_clock_table_entry
+{
+	u32 vclk;
+	u32 dclk;
+	u8 vclk_did;
+	u8 dclk_did;
+	u8 rsv[2];
+};
+
 struct trinity_sys_info {
 	u32 bootup_uma_clk;
 	u32 bootup_sclk;
 	u32 min_sclk;
+	u32 dentist_vco_freq;
 	u32 nb_dpm_enable;
 	u32 nbp_mclk[TRINITY_NUM_NBPSTATES];
 	u32 nbp_nclk[TRINITY_NUM_NBPSTATES];
@@ -73,6 +88,7 @@ struct trinity_sys_info {
 	struct sumo_sclk_voltage_mapping_table sclk_voltage_mapping_table;
 	struct sumo_vid_mapping_table vid_mapping_table;
 	u32 uma_channel_number;
+	struct trinity_uvd_clock_table_entry uvd_clock_table_entries[4];
 };
 
 struct trinity_power_info {
@@ -93,12 +109,14 @@ struct trinity_power_info {
 	bool enable_auto_thermal_throttling;
 	bool enable_dpm;
 	bool enable_sclk_ds;
+	bool uvd_dpm;
 };
 
 #define TRINITY_AT_DFLT            30
 
 /* trinity_smc.c */
 int trinity_dpm_config(struct radeon_device *rdev, bool enable);
+int trinity_uvd_dpm_config(struct radeon_device *rdev);
 int trinity_dpm_force_state(struct radeon_device *rdev, u32 n);
 int trinity_dpm_no_forced_level(struct radeon_device *rdev);
 int trinity_dce_enable_voltage_adjustment(struct radeon_device *rdev,
diff --git a/drivers/gpu/drm/radeon/trinity_smc.c b/drivers/gpu/drm/radeon/trinity_smc.c
index 60ffc1e..85f86a2 100644
--- a/drivers/gpu/drm/radeon/trinity_smc.c
+++ b/drivers/gpu/drm/radeon/trinity_smc.c
@@ -73,6 +73,11 @@ int trinity_dpm_force_state(struct radeon_device *rdev, u32 n)
 	return trinity_notify_message_to_smu(rdev, PPSMC_MSG_DPM_ForceState);
 }
 
+int trinity_uvd_dpm_config(struct radeon_device *rdev)
+{
+	return trinity_notify_message_to_smu(rdev, PPSMC_MSG_UVD_DPM_Config);
+}
+
 int trinity_dpm_no_forced_level(struct radeon_device *rdev)
 {
 	return trinity_notify_message_to_smu(rdev, PPSMC_MSG_NoForcedLevel);
diff --git a/drivers/gpu/drm/radeon/trinityd.h b/drivers/gpu/drm/radeon/trinityd.h
index b234d36..fd32e27 100644
--- a/drivers/gpu/drm/radeon/trinityd.h
+++ b/drivers/gpu/drm/radeon/trinityd.h
@@ -100,6 +100,9 @@
 #       define HT_MASK                                  (0xffff << 16)
 #       define HT_SHIFT                                 16
 
+#define SMU_UVD_DPM_STATES                              0x1f1a0
+#define SMU_UVD_DPM_CNTL                                0x1f1a4
+
 #define SMU_S_PG_CNTL                                   0x1f118
 #       define DS_PG_EN(x)                              ((x) << 16)
 #       define DS_PG_EN_MASK                            (0xff << 16)
@@ -198,6 +201,8 @@
 #       define SU_MASK                                  (0xffff << 16)
 #       define SU_SHIFT                                 16
 
+#define CG_MISC_REG                                     0x708
+
 #define CG_THERMAL_INT_CTRL                             0x738
 #       define DIG_THERM_INTH(x)                        ((x) << 0)
 #       define DIG_THERM_INTH_MASK                      (0xff << 0)
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 087/165] drm/radeon/kms: enable UVD as needed (v9)
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (86 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 086/165] drm/radeon: add dpm UVD handling for TN asics (v2) alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 088/165] drm/radeon/dpm: add helpers for extended power tables (v2) alexdeucher
                   ` (25 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

When using UVD, the driver must switch to a special UVD power
state.  In the CS ioctl, switch to the power state and schedule
work to change the power state back, when the work comes up,
check if uvd is still busy and if not, switch back to the user
state, otherwise, reschedule the work.

Note:  We really need some better way to decide when to
switch out of the uvd power state.  Switching power states
while playback is active make uvd angry.

V2: fix locking.

V3: switch from timer to delayed work

V4: check fence driver for UVD jobs, reduce timeout to
    1 second and rearm timeout on activity

v5: rebase on new dpm tree

v6: rebase on interim uvd on demand changes

v7: fix UVD when DPM is disabled

v8: unify non-DPM and DPM UVD handling

v9: remove leftover idle work struct

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Christian König <deathsimple@vodafone.de>
---
 drivers/gpu/drm/radeon/radeon.h     |    1 +
 drivers/gpu/drm/radeon/radeon_cs.c  |    1 +
 drivers/gpu/drm/radeon/radeon_pm.c  |   12 +++++++++++-
 drivers/gpu/drm/radeon/radeon_uvd.c |   24 +++++++++++++++++++-----
 4 files changed, 32 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 037773d..3b345cc 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -1246,6 +1246,7 @@ struct radeon_dpm {
 	int			current_active_crtc_count;
 	/* special states active */
 	bool                    thermal_active;
+	bool                    uvd_active;
 	/* thermal handling */
 	struct radeon_dpm_thermal thermal;
 };
diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c
index 7e265a5..4f6b22b 100644
--- a/drivers/gpu/drm/radeon/radeon_cs.c
+++ b/drivers/gpu/drm/radeon/radeon_cs.c
@@ -550,6 +550,7 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
 		return r;
 	}
 
+	/* XXX pick SD/HD/MVC */
 	if (parser.ring == R600_RING_TYPE_UVD_INDEX)
 		radeon_uvd_note_usage(rdev);
 
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
index e6fce0b..5987580 100644
--- a/drivers/gpu/drm/radeon/radeon_pm.c
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
@@ -699,7 +699,8 @@ static void radeon_dpm_change_power_state_locked(struct radeon_device *rdev)
 
 	if (rdev->pm.dpm.user_state != rdev->pm.dpm.state) {
 		/* add other state override checks here */
-		if (!rdev->pm.dpm.thermal_active)
+		if ((!rdev->pm.dpm.thermal_active) &&
+		    (!rdev->pm.dpm.uvd_active))
 			rdev->pm.dpm.state = rdev->pm.dpm.user_state;
 	}
 	dpm_state = rdev->pm.dpm.state;
@@ -769,8 +770,16 @@ void radeon_dpm_enable_power_state(struct radeon_device *rdev,
 	case POWER_STATE_TYPE_INTERNAL_THERMAL:
 		rdev->pm.dpm.thermal_active = true;
 		break;
+	case POWER_STATE_TYPE_INTERNAL_UVD:
+	case POWER_STATE_TYPE_INTERNAL_UVD_SD:
+	case POWER_STATE_TYPE_INTERNAL_UVD_HD:
+	case POWER_STATE_TYPE_INTERNAL_UVD_HD2:
+	case POWER_STATE_TYPE_INTERNAL_UVD_MVC:
+		rdev->pm.dpm.uvd_active = true;
+		break;
 	default:
 		rdev->pm.dpm.thermal_active = false;
+		rdev->pm.dpm.uvd_active = false;
 		break;
 	}
 	rdev->pm.dpm.state = dpm_state;
@@ -1223,6 +1232,7 @@ static void radeon_pm_compute_clocks_dpm(struct radeon_device *rdev)
 	radeon_dpm_change_power_state_locked(rdev);
 
 	mutex_unlock(&rdev->pm.mutex);
+
 }
 
 void radeon_pm_compute_clocks(struct radeon_device *rdev)
diff --git a/drivers/gpu/drm/radeon/radeon_uvd.c b/drivers/gpu/drm/radeon/radeon_uvd.c
index fdc77d1..ce5a10c 100644
--- a/drivers/gpu/drm/radeon/radeon_uvd.c
+++ b/drivers/gpu/drm/radeon/radeon_uvd.c
@@ -699,11 +699,19 @@ static void radeon_uvd_idle_work_handler(struct work_struct *work)
 	struct radeon_device *rdev =
 		container_of(work, struct radeon_device, uvd.idle_work.work);
 
-	if (radeon_fence_count_emitted(rdev, R600_RING_TYPE_UVD_INDEX) == 0)
-		radeon_set_uvd_clocks(rdev, 0, 0);
-	else
+	if (radeon_fence_count_emitted(rdev, R600_RING_TYPE_UVD_INDEX) == 0) {
+		if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) {
+			mutex_lock(&rdev->pm.mutex);
+			rdev->pm.dpm.uvd_active = false;
+			mutex_unlock(&rdev->pm.mutex);
+			radeon_pm_compute_clocks(rdev);
+		} else {
+			radeon_set_uvd_clocks(rdev, 0, 0);
+		}
+	} else {
 		schedule_delayed_work(&rdev->uvd.idle_work,
 				      msecs_to_jiffies(UVD_IDLE_TIMEOUT_MS));
+	}
 }
 
 void radeon_uvd_note_usage(struct radeon_device *rdev)
@@ -711,8 +719,14 @@ void radeon_uvd_note_usage(struct radeon_device *rdev)
 	bool set_clocks = !cancel_delayed_work_sync(&rdev->uvd.idle_work);
 	set_clocks &= schedule_delayed_work(&rdev->uvd.idle_work,
 					    msecs_to_jiffies(UVD_IDLE_TIMEOUT_MS));
-	if (set_clocks)
-		radeon_set_uvd_clocks(rdev, 53300, 40000);
+	if (set_clocks) {
+		if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) {
+			/* XXX pick SD/HD/MVC */
+			radeon_dpm_enable_power_state(rdev, POWER_STATE_TYPE_INTERNAL_UVD);
+		} else {
+			radeon_set_uvd_clocks(rdev, 53300, 40000);
+		}
+	}
 }
 
 static unsigned radeon_uvd_calc_upll_post_div(unsigned vco_freq,
-- 
1.7.7.5

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 088/165] drm/radeon/dpm: add helpers for extended power tables (v2)
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (87 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 087/165] drm/radeon/kms: enable UVD as needed (v9) alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 089/165] drm/radeon/dpm: track whether we are on AC or battery alexdeucher
                   ` (24 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

This data will be needed for dpm on newer asics.

v2: fix typo in rebase

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/r600_dpm.c |  179 +++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/radeon/r600_dpm.h |    3 +
 drivers/gpu/drm/radeon/radeon.h   |   70 ++++++++++++++
 3 files changed, 252 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/radeon/r600_dpm.c b/drivers/gpu/drm/radeon/r600_dpm.c
index bf396a0..c9f9647 100644
--- a/drivers/gpu/drm/radeon/r600_dpm.c
+++ b/drivers/gpu/drm/radeon/r600_dpm.c
@@ -721,3 +721,182 @@ bool r600_is_internal_thermal_sensor(enum radeon_int_thermal_type sensor)
 		return false;
 	}
 }
+
+union power_info {
+	struct _ATOM_POWERPLAY_INFO info;
+	struct _ATOM_POWERPLAY_INFO_V2 info_2;
+	struct _ATOM_POWERPLAY_INFO_V3 info_3;
+	struct _ATOM_PPLIB_POWERPLAYTABLE pplib;
+	struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2;
+	struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3;
+	struct _ATOM_PPLIB_POWERPLAYTABLE4 pplib4;
+	struct _ATOM_PPLIB_POWERPLAYTABLE5 pplib5;
+};
+
+union fan_info {
+	struct _ATOM_PPLIB_FANTABLE fan;
+	struct _ATOM_PPLIB_FANTABLE2 fan2;
+};
+
+static int r600_parse_clk_voltage_dep_table(struct radeon_clock_voltage_dependency_table *radeon_table,
+					    ATOM_PPLIB_Clock_Voltage_Dependency_Table *atom_table)
+{
+	u32 size = atom_table->ucNumEntries *
+		sizeof(struct radeon_clock_voltage_dependency_entry);
+	int i;
+
+	radeon_table->entries = kzalloc(size, GFP_KERNEL);
+	if (!radeon_table->entries)
+		return -ENOMEM;
+
+	for (i = 0; i < atom_table->ucNumEntries; i++) {
+		radeon_table->entries[i].clk = le16_to_cpu(atom_table->entries[i].usClockLow) |
+			(atom_table->entries[i].ucClockHigh << 16);
+		radeon_table->entries[i].v = le16_to_cpu(atom_table->entries[i].usVoltage);
+	}
+	radeon_table->count = atom_table->ucNumEntries;
+
+	return 0;
+}
+
+int r600_parse_extended_power_table(struct radeon_device *rdev)
+{
+	struct radeon_mode_info *mode_info = &rdev->mode_info;
+	union power_info *power_info;
+	union fan_info *fan_info;
+	ATOM_PPLIB_Clock_Voltage_Dependency_Table *dep_table;
+	int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
+        u16 data_offset;
+	u8 frev, crev;
+	int ret, i;
+
+	if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
+				   &frev, &crev, &data_offset))
+		return -EINVAL;
+	power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
+
+	/* fan table */
+	if (power_info->pplib.usTableSize >= sizeof(struct _ATOM_PPLIB_POWERPLAYTABLE3)) {
+		if (power_info->pplib3.usFanTableOffset) {
+			fan_info = (union fan_info *)(mode_info->atom_context->bios + data_offset +
+						      le16_to_cpu(power_info->pplib3.usFanTableOffset));
+			rdev->pm.dpm.fan.t_hyst = fan_info->fan.ucTHyst;
+			rdev->pm.dpm.fan.t_min = le16_to_cpu(fan_info->fan.usTMin);
+			rdev->pm.dpm.fan.t_med = le16_to_cpu(fan_info->fan.usTMed);
+			rdev->pm.dpm.fan.t_high = le16_to_cpu(fan_info->fan.usTHigh);
+			rdev->pm.dpm.fan.pwm_min = le16_to_cpu(fan_info->fan.usPWMMin);
+			rdev->pm.dpm.fan.pwm_med = le16_to_cpu(fan_info->fan.usPWMMed);
+			rdev->pm.dpm.fan.pwm_high = le16_to_cpu(fan_info->fan.usPWMHigh);
+			if (fan_info->fan.ucFanTableFormat >= 2)
+				rdev->pm.dpm.fan.t_max = le16_to_cpu(fan_info->fan2.usTMax);
+			else
+				rdev->pm.dpm.fan.t_max = 10900;
+			rdev->pm.dpm.fan.cycle_delay = 100000;
+			rdev->pm.dpm.fan.ucode_fan_control = true;
+		}
+	}
+
+	/* clock dependancy tables */
+	if (power_info->pplib.usTableSize >= sizeof(struct _ATOM_PPLIB_POWERPLAYTABLE4)) {
+		if (power_info->pplib4.usVddcDependencyOnSCLKOffset) {
+			dep_table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
+				(mode_info->atom_context->bios + data_offset +
+				 le16_to_cpu(power_info->pplib4.usVddcDependencyOnSCLKOffset));
+			ret = r600_parse_clk_voltage_dep_table(&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk,
+							       dep_table);
+			if (ret)
+				return ret;
+		}
+		if (power_info->pplib4.usVddciDependencyOnMCLKOffset) {
+			dep_table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
+				(mode_info->atom_context->bios + data_offset +
+				 le16_to_cpu(power_info->pplib4.usVddciDependencyOnMCLKOffset));
+			ret = r600_parse_clk_voltage_dep_table(&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk,
+							       dep_table);
+			if (ret) {
+				kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries);
+				return ret;
+			}
+		}
+		if (power_info->pplib4.usVddcDependencyOnMCLKOffset) {
+			dep_table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
+				(mode_info->atom_context->bios + data_offset +
+				 le16_to_cpu(power_info->pplib4.usVddcDependencyOnMCLKOffset));
+			ret = r600_parse_clk_voltage_dep_table(&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk,
+							       dep_table);
+			if (ret) {
+				kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries);
+				kfree(rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk.entries);
+				return ret;
+			}
+		}
+		if (power_info->pplib4.usMaxClockVoltageOnDCOffset) {
+			ATOM_PPLIB_Clock_Voltage_Limit_Table *clk_v =
+				(ATOM_PPLIB_Clock_Voltage_Limit_Table *)
+				(mode_info->atom_context->bios + data_offset +
+				 le16_to_cpu(power_info->pplib4.usMaxClockVoltageOnDCOffset));
+			if (clk_v->ucNumEntries) {
+				rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc.sclk =
+					le16_to_cpu(clk_v->entries[0].usSclkLow) |
+					(clk_v->entries[0].ucSclkHigh << 16);
+				rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc.mclk =
+					le16_to_cpu(clk_v->entries[0].usMclkLow) |
+					(clk_v->entries[0].ucMclkHigh << 16);
+				rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc.vddc =
+					le16_to_cpu(clk_v->entries[0].usVddc);
+				rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc.vddci =
+					le16_to_cpu(clk_v->entries[0].usVddci);
+			}
+		}
+	}
+
+	/* cac data */
+	if (power_info->pplib.usTableSize >= sizeof(struct _ATOM_PPLIB_POWERPLAYTABLE5)) {
+		rdev->pm.dpm.tdp_limit = le32_to_cpu(power_info->pplib5.ulTDPLimit);
+		rdev->pm.dpm.near_tdp_limit = le32_to_cpu(power_info->pplib5.ulNearTDPLimit);
+		rdev->pm.dpm.tdp_od_limit = le16_to_cpu(power_info->pplib5.usTDPODLimit);
+		if (rdev->pm.dpm.tdp_od_limit)
+			rdev->pm.dpm.power_control = true;
+		else
+			rdev->pm.dpm.power_control = false;
+		rdev->pm.dpm.tdp_adjustment = 0;
+		rdev->pm.dpm.sq_ramping_threshold = le32_to_cpu(power_info->pplib5.ulSQRampingThreshold);
+		rdev->pm.dpm.cac_leakage = le32_to_cpu(power_info->pplib5.ulCACLeakage);
+		rdev->pm.dpm.load_line_slope = le16_to_cpu(power_info->pplib5.usLoadLineSlope);
+		if (power_info->pplib5.usCACLeakageTableOffset) {
+			ATOM_PPLIB_CAC_Leakage_Table *cac_table =
+				(ATOM_PPLIB_CAC_Leakage_Table *)
+				(mode_info->atom_context->bios + data_offset +
+				 le16_to_cpu(power_info->pplib5.usCACLeakageTableOffset));
+			u32 size = cac_table->ucNumEntries * sizeof(struct radeon_cac_leakage_table);
+			rdev->pm.dpm.dyn_state.cac_leakage_table.entries = kzalloc(size, GFP_KERNEL);
+			if (!rdev->pm.dpm.dyn_state.cac_leakage_table.entries) {
+				kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries);
+				kfree(rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk.entries);
+				kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk.entries);
+				return -ENOMEM;
+			}
+			for (i = 0; i < cac_table->ucNumEntries; i++) {
+				rdev->pm.dpm.dyn_state.cac_leakage_table.entries[i].vddc =
+					le16_to_cpu(cac_table->entries[i].usVddc);
+				rdev->pm.dpm.dyn_state.cac_leakage_table.entries[i].leakage =
+					le32_to_cpu(cac_table->entries[i].ulLeakageValue);
+			}
+			rdev->pm.dpm.dyn_state.cac_leakage_table.count = cac_table->ucNumEntries;
+		}
+	}
+
+	return 0;
+}
+
+void r600_free_extended_power_table(struct radeon_device *rdev)
+{
+	if (rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries)
+		kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries);
+	if (rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk.entries)
+		kfree(rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk.entries);
+	if (rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk.entries)
+		kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk.entries);
+	if (rdev->pm.dpm.dyn_state.cac_leakage_table.entries)
+		kfree(rdev->pm.dpm.dyn_state.cac_leakage_table.entries);
+}
diff --git a/drivers/gpu/drm/radeon/r600_dpm.h b/drivers/gpu/drm/radeon/r600_dpm.h
index bd33aa1..c6b9e30 100644
--- a/drivers/gpu/drm/radeon/r600_dpm.h
+++ b/drivers/gpu/drm/radeon/r600_dpm.h
@@ -215,4 +215,7 @@ int r600_set_thermal_temperature_range(struct radeon_device *rdev,
 				       int min_temp, int max_temp);
 bool r600_is_internal_thermal_sensor(enum radeon_int_thermal_type sensor);
 
+int r600_parse_extended_power_table(struct radeon_device *rdev);
+void r600_free_extended_power_table(struct radeon_device *rdev);
+
 #endif
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 3b345cc..5bdb0bd 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -1222,6 +1222,66 @@ struct radeon_dpm_thermal {
 	bool               high_to_low;
 };
 
+struct radeon_clock_and_voltage_limits {
+	u32 sclk;
+	u32 mclk;
+	u32 vddc;
+	u32 vddci;
+};
+
+struct radeon_clock_array {
+	u32 count;
+	u32 *values;
+};
+
+struct radeon_clock_voltage_dependency_entry {
+	u32 clk;
+	u16 v;
+};
+
+struct radeon_clock_voltage_dependency_table {
+	u32 count;
+	struct radeon_clock_voltage_dependency_entry *entries;
+};
+
+struct radeon_cac_leakage_entry {
+	u16 vddc;
+	u32 leakage;
+};
+
+struct radeon_cac_leakage_table {
+	u32 count;
+	struct radeon_cac_leakage_entry *entries;
+};
+
+struct radeon_dpm_dynamic_state {
+	struct radeon_clock_voltage_dependency_table vddc_dependency_on_sclk;
+	struct radeon_clock_voltage_dependency_table vddci_dependency_on_mclk;
+	struct radeon_clock_voltage_dependency_table vddc_dependency_on_mclk;
+	struct radeon_clock_array valid_sclk_values;
+	struct radeon_clock_array valid_mclk_values;
+	struct radeon_clock_and_voltage_limits max_clock_voltage_on_dc;
+	struct radeon_clock_and_voltage_limits max_clock_voltage_on_ac;
+	u32 mclk_sclk_ratio;
+	u32 sclk_mclk_delta;
+	u16 vddc_vddci_delta;
+	u16 min_vddc_for_pcie_gen2;
+	struct radeon_cac_leakage_table cac_leakage_table;
+};
+
+struct radeon_dpm_fan {
+	u16 t_min;
+	u16 t_med;
+	u16 t_high;
+	u16 pwm_min;
+	u16 pwm_med;
+	u16 pwm_high;
+	u8 t_hyst;
+	u32 cycle_delay;
+	u16 t_max;
+	bool ucode_fan_control;
+};
+
 struct radeon_dpm {
 	struct radeon_ps        *ps;
 	/* number of valid power states */
@@ -1244,6 +1304,16 @@ struct radeon_dpm {
 	int			new_active_crtc_count;
 	u32			current_active_crtcs;
 	int			current_active_crtc_count;
+	struct radeon_dpm_dynamic_state dyn_state;
+	struct radeon_dpm_fan fan;
+	u32 tdp_limit;
+	u32 near_tdp_limit;
+	u32 sq_ramping_threshold;
+	u32 cac_leakage;
+	u16 tdp_od_limit;
+	u32 tdp_adjustment;
+	u16 load_line_slope;
+	bool power_control;
 	/* special states active */
 	bool                    thermal_active;
 	bool                    uvd_active;
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 089/165] drm/radeon/dpm: track whether we are on AC or battery
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (88 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 088/165] drm/radeon/dpm: add helpers for extended power tables (v2) alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 090/165] drm/radeon/dpm: fixup dynamic state adjust for sumo alexdeucher
                   ` (23 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Driver needs this information to validate power states.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/radeon.h    |    1 +
 drivers/gpu/drm/radeon/radeon_pm.c |    7 +++++++
 2 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 5bdb0bd..53aba4f 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -1314,6 +1314,7 @@ struct radeon_dpm {
 	u32 tdp_adjustment;
 	u16 load_line_slope;
 	bool power_control;
+	bool ac_power;
 	/* special states active */
 	bool                    thermal_active;
 	bool                    uvd_active;
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
index 5987580..9ac261f 100644
--- a/drivers/gpu/drm/radeon/radeon_pm.c
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
@@ -1218,6 +1218,7 @@ static void radeon_pm_compute_clocks_dpm(struct radeon_device *rdev)
 
 	mutex_lock(&rdev->pm.mutex);
 
+	/* update active crtc counts */
 	rdev->pm.dpm.new_active_crtcs = 0;
 	rdev->pm.dpm.new_active_crtc_count = 0;
 	list_for_each_entry(crtc,
@@ -1229,6 +1230,12 @@ static void radeon_pm_compute_clocks_dpm(struct radeon_device *rdev)
 		}
 	}
 
+	/* update battery/ac status */
+	if (power_supply_is_system_supplied() > 0)
+		rdev->pm.dpm.ac_power = true;
+	else
+		rdev->pm.dpm.ac_power = false;
+
 	radeon_dpm_change_power_state_locked(rdev);
 
 	mutex_unlock(&rdev->pm.mutex);
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 090/165] drm/radeon/dpm: fixup dynamic state adjust for sumo
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (89 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 089/165] drm/radeon/dpm: track whether we are on AC or battery alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 091/165] drm/radeon/dpm: fixup dynamic state adjust for TN alexdeucher
                   ` (22 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Use a dedicated copy of the current power state since
we may have to adjust it on the fly.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/radeon.h    |    1 +
 drivers/gpu/drm/radeon/radeon_pm.c |   13 ++++++++++++-
 drivers/gpu/drm/radeon/sumo_dpm.c  |    5 +++++
 drivers/gpu/drm/radeon/sumo_dpm.h  |    1 +
 4 files changed, 19 insertions(+), 1 deletions(-)

diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 53aba4f..a4d8d97 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -1294,6 +1294,7 @@ struct radeon_dpm {
 	struct radeon_ps        *boot_ps;
 	/* default uvd power state */
 	struct radeon_ps        *uvd_ps;
+	struct radeon_ps        hw_ps;
 	enum radeon_pm_state_type state;
 	enum radeon_pm_state_type user_state;
 	u32                     platform_caps;
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
index 9ac261f..7ee8cf6 100644
--- a/drivers/gpu/drm/radeon/radeon_pm.c
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
@@ -687,6 +687,17 @@ restart_search:
 	return NULL;
 }
 
+static void radeon_dpm_update_requested_ps(struct radeon_device *rdev,
+					   struct radeon_ps *ps)
+{
+	/* copy the ps to the hw ps and point the requested ps
+	 * at the hw state in case the driver wants to modify
+	 * the state dynamically.
+	 */
+	rdev->pm.dpm.hw_ps = *ps;
+	rdev->pm.dpm.requested_ps = &rdev->pm.dpm.hw_ps;
+}
+
 static void radeon_dpm_change_power_state_locked(struct radeon_device *rdev)
 {
 	int i;
@@ -707,7 +718,7 @@ static void radeon_dpm_change_power_state_locked(struct radeon_device *rdev)
 
 	ps = radeon_dpm_pick_power_state(rdev, dpm_state);
 	if (ps)
-		rdev->pm.dpm.requested_ps = ps;
+		radeon_dpm_update_requested_ps(rdev, ps);
 	else
 		return;
 
diff --git a/drivers/gpu/drm/radeon/sumo_dpm.c b/drivers/gpu/drm/radeon/sumo_dpm.c
index cef25c4..3805302 100644
--- a/drivers/gpu/drm/radeon/sumo_dpm.c
+++ b/drivers/gpu/drm/radeon/sumo_dpm.c
@@ -1072,6 +1072,11 @@ static void sumo_apply_state_adjust_rules(struct radeon_device *rdev)
 	u32 sclk_in_sr = pi->sys_info.min_sclk; /* ??? */
 	u32 i;
 
+	/* point to the hw copy since this function will modify the ps */
+	pi->hw_ps = *ps;
+	rdev->pm.dpm.hw_ps.ps_priv = &pi->hw_ps;
+	ps = &pi->hw_ps;
+
 	if (rps->class & ATOM_PPLIB_CLASSIFICATION_THERMAL)
 		return sumo_patch_thermal_state(rdev, ps, current_ps);
 
diff --git a/drivers/gpu/drm/radeon/sumo_dpm.h b/drivers/gpu/drm/radeon/sumo_dpm.h
index d041a6c..a40b62a 100644
--- a/drivers/gpu/drm/radeon/sumo_dpm.h
+++ b/drivers/gpu/drm/radeon/sumo_dpm.h
@@ -129,6 +129,7 @@ struct sumo_power_info {
 	bool enable_dynamic_patch_ps;
 	bool enable_dpm;
 	bool enable_boost;
+	struct sumo_ps hw_ps;
 };
 
 #define SUMO_UTC_DFLT_00                     0x48
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 091/165] drm/radeon/dpm: fixup dynamic state adjust for TN
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (90 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 090/165] drm/radeon/dpm: fixup dynamic state adjust for sumo alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 092/165] drm/radeon/dpm: fixup dynamic state adjust for btc (v2) alexdeucher
                   ` (21 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Use a dedicated copy of the current power state since
we may have to adjust it on the fly.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/trinity_dpm.c |    5 +++++
 drivers/gpu/drm/radeon/trinity_dpm.h |    1 +
 2 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/radeon/trinity_dpm.c b/drivers/gpu/drm/radeon/trinity_dpm.c
index 1b3822f..0c1b50a 100644
--- a/drivers/gpu/drm/radeon/trinity_dpm.c
+++ b/drivers/gpu/drm/radeon/trinity_dpm.c
@@ -1379,6 +1379,11 @@ static void trinity_apply_state_adjust_rules(struct radeon_device *rdev)
 	bool force_high;
 	u32 num_active_displays = rdev->pm.dpm.new_active_crtc_count;
 
+	/* point to the hw copy since this function will modify the ps */
+	pi->hw_ps = *ps;
+	rdev->pm.dpm.hw_ps.ps_priv = &pi->hw_ps;
+	ps = &pi->hw_ps;
+
 	if (rps->class & ATOM_PPLIB_CLASSIFICATION_THERMAL)
 		return trinity_patch_thermal_state(rdev, ps, current_ps);
 
diff --git a/drivers/gpu/drm/radeon/trinity_dpm.h b/drivers/gpu/drm/radeon/trinity_dpm.h
index 31100ac..c663aed 100644
--- a/drivers/gpu/drm/radeon/trinity_dpm.h
+++ b/drivers/gpu/drm/radeon/trinity_dpm.h
@@ -110,6 +110,7 @@ struct trinity_power_info {
 	bool enable_dpm;
 	bool enable_sclk_ds;
 	bool uvd_dpm;
+	struct trinity_ps hw_ps;
 };
 
 #define TRINITY_AT_DFLT            30
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 092/165] drm/radeon/dpm: fixup dynamic state adjust for btc (v2)
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (91 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 091/165] drm/radeon/dpm: fixup dynamic state adjust for TN alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 093/165] drm/radeon/kms: add dpm support for cayman alexdeucher
                   ` (20 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Use a dedicated copy of the current power state since
we may have to adjust it on the fly.

v2: fix up redundant state sets

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/btc_dpm.c     |  340 ++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/radeon/btc_dpm.h     |    2 +
 drivers/gpu/drm/radeon/cypress_dpm.h |    1 +
 drivers/gpu/drm/radeon/radeon.h      |   13 ++
 drivers/gpu/drm/radeon/radeon_pm.c   |   43 ++++-
 drivers/gpu/drm/radeon/rv770_dpm.c   |   10 +
 6 files changed, 400 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/radeon/btc_dpm.c b/drivers/gpu/drm/radeon/btc_dpm.c
index 2662ef0..989592e 100644
--- a/drivers/gpu/drm/radeon/btc_dpm.c
+++ b/drivers/gpu/drm/radeon/btc_dpm.c
@@ -1152,6 +1152,164 @@ static const u32 turks_sysls_enable[] =
 
 #endif
 
+u32 btc_valid_sclk[] =
+{
+	5000,   10000,  15000,  20000,  25000,  30000,  35000,  40000,  45000,  50000,
+	55000,  60000,  65000,  70000,  75000,  80000,  85000,  90000,  95000,  100000,
+	105000, 110000, 11500,  120000, 125000, 130000, 135000, 140000, 145000, 150000,
+	155000, 160000, 165000, 170000, 175000, 180000, 185000, 190000, 195000, 200000
+};
+
+static const struct radeon_blacklist_clocks btc_blacklist_clocks[] =
+{
+        { 10000, 30000, RADEON_SCLK_UP },
+        { 15000, 30000, RADEON_SCLK_UP },
+        { 20000, 30000, RADEON_SCLK_UP },
+        { 25000, 30000, RADEON_SCLK_UP }
+};
+
+static void btc_apply_voltage_dependency_rules(struct radeon_clock_voltage_dependency_table *table,
+					       u32 clock, u16 max_voltage, u16 *voltage)
+{
+	u32 i;
+
+	if ((table == NULL) || (table->count == 0))
+		return;
+
+	for (i= 0; i < table->count; i++) {
+		if (clock <= table->entries[i].clk) {
+			if (*voltage < table->entries[i].v)
+				*voltage = (u16)((table->entries[i].v < max_voltage) ?
+						  table->entries[i].v : max_voltage);
+			return;
+		}
+	}
+
+	*voltage = (*voltage > max_voltage) ? *voltage : max_voltage;
+}
+
+static u32 btc_find_valid_clock(struct radeon_clock_array *clocks,
+				u32 max_clock, u32 requested_clock)
+{
+	unsigned int i;
+
+	if ((clocks == NULL) || (clocks->count == 0))
+		return (requested_clock < max_clock) ? requested_clock : max_clock;
+
+	for (i = 0; i < clocks->count; i++) {
+		if (clocks->values[i] >= requested_clock)
+			return (clocks->values[i] < max_clock) ? clocks->values[i] : max_clock;
+	}
+
+	return (clocks->values[clocks->count - 1] < max_clock) ?
+		clocks->values[clocks->count - 1] : max_clock;
+}
+
+static u32 btc_get_valid_mclk(struct radeon_device *rdev,
+			      u32 max_mclk, u32 requested_mclk)
+{
+	return btc_find_valid_clock(&rdev->pm.dpm.dyn_state.valid_mclk_values,
+				    max_mclk, requested_mclk);
+}
+
+static u32 btc_get_valid_sclk(struct radeon_device *rdev,
+			      u32 max_sclk, u32 requested_sclk)
+{
+	return btc_find_valid_clock(&rdev->pm.dpm.dyn_state.valid_sclk_values,
+				    max_sclk, requested_sclk);
+}
+
+static void btc_skip_blacklist_clocks(struct radeon_device *rdev,
+				      const u32 max_sclk, const u32 max_mclk,
+				      u32 *sclk, u32 *mclk)
+{
+	int i, num_blacklist_clocks;
+
+	if ((sclk == NULL) || (mclk == NULL))
+		return;
+
+	num_blacklist_clocks = ARRAY_SIZE(btc_blacklist_clocks);
+
+	for (i = 0; i < num_blacklist_clocks; i++) {
+		if ((btc_blacklist_clocks[i].sclk == *sclk) &&
+		    (btc_blacklist_clocks[i].mclk == *mclk))
+			break;
+	}
+
+	if (i < num_blacklist_clocks) {
+		if (btc_blacklist_clocks[i].action == RADEON_SCLK_UP) {
+			*sclk = btc_get_valid_sclk(rdev, max_sclk, *sclk + 1);
+
+			if (*sclk < max_sclk)
+				btc_skip_blacklist_clocks(rdev, max_sclk, max_mclk, sclk, mclk);
+		}
+	}
+}
+
+static void btc_adjust_clock_combinations(struct radeon_device *rdev,
+					  const struct radeon_clock_and_voltage_limits *max_limits,
+					  struct rv7xx_pl *pl)
+{
+
+	if ((pl->mclk == 0) || (pl->sclk == 0))
+		return;
+
+	if (pl->mclk == pl->sclk)
+		return;
+
+	if (pl->mclk > pl->sclk) {
+		if (((pl->mclk + (pl->sclk - 1)) / pl->sclk) > rdev->pm.dpm.dyn_state.mclk_sclk_ratio)
+			pl->sclk = btc_get_valid_sclk(rdev,
+						      max_limits->sclk,
+						      (pl->mclk +
+						       (rdev->pm.dpm.dyn_state.mclk_sclk_ratio - 1)) /
+						      rdev->pm.dpm.dyn_state.mclk_sclk_ratio);
+	} else {
+		if ((pl->sclk - pl->mclk) > rdev->pm.dpm.dyn_state.sclk_mclk_delta)
+			pl->mclk = btc_get_valid_mclk(rdev,
+						      max_limits->mclk,
+						      pl->sclk -
+						      rdev->pm.dpm.dyn_state.sclk_mclk_delta);
+	}
+}
+
+static u16 btc_find_voltage(struct atom_voltage_table *table, u16 voltage)
+{
+	unsigned int i;
+
+	for (i = 0; i < table->count; i++) {
+		if (voltage <= table->entries[i].value)
+			return table->entries[i].value;
+	}
+
+	return table->entries[table->count - 1].value;
+}
+
+static void btc_apply_voltage_delta_rules(struct radeon_device *rdev,
+					  u16 max_vddc, u16 max_vddci,
+					  u16 *vddc, u16 *vddci)
+{
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	u16 new_voltage;
+
+	if ((0 == *vddc) || (0 == *vddci))
+		return;
+
+	if (*vddc > *vddci) {
+		if ((*vddc - *vddci) > rdev->pm.dpm.dyn_state.vddc_vddci_delta) {
+			new_voltage = btc_find_voltage(&eg_pi->vddci_voltage_table,
+						       (*vddc - rdev->pm.dpm.dyn_state.vddc_vddci_delta));
+			*vddci = (new_voltage < max_vddci) ? new_voltage : max_vddci;
+		}
+	} else {
+		if ((*vddci - *vddc) > rdev->pm.dpm.dyn_state.vddc_vddci_delta) {
+			new_voltage = btc_find_voltage(&eg_pi->vddc_voltage_table,
+						       (*vddci - rdev->pm.dpm.dyn_state.vddc_vddci_delta));
+			*vddc = (new_voltage < max_vddc) ? new_voltage : max_vddc;
+		}
+	}
+}
+
 static void btc_enable_bif_dynamic_pcie_gen2(struct radeon_device *rdev,
 					     bool enable)
 {
@@ -1901,6 +2059,169 @@ static void btc_init_stutter_mode(struct radeon_device *rdev)
 	}
 }
 
+static void btc_apply_state_adjust_rules(struct radeon_device *rdev)
+{
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	struct radeon_ps *rps = rdev->pm.dpm.requested_ps;
+	struct rv7xx_ps *ps = rv770_get_ps(rps);
+	struct radeon_clock_and_voltage_limits *max_limits;
+	bool disable_mclk_switching;
+	u32 mclk, sclk;
+	u16 vddc, vddci;
+
+	/* point to the hw copy since this function will modify the ps */
+	eg_pi->hw_ps = *ps;
+	rdev->pm.dpm.hw_ps.ps_priv = &eg_pi->hw_ps;
+	ps = &eg_pi->hw_ps;
+
+	if (rdev->pm.dpm.new_active_crtc_count > 1)
+		disable_mclk_switching = true;
+	else
+		disable_mclk_switching = false;
+
+	if (rdev->pm.dpm.ac_power)
+		max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
+	else
+		max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc;
+
+	if (rdev->pm.dpm.ac_power == false) {
+		if (ps->high.mclk > max_limits->mclk)
+			ps->high.mclk = max_limits->mclk;
+		if (ps->high.sclk > max_limits->sclk)
+			ps->high.sclk = max_limits->sclk;
+		if (ps->high.vddc > max_limits->vddc)
+			ps->high.vddc = max_limits->vddc;
+		if (ps->high.vddci > max_limits->vddci)
+			ps->high.vddci = max_limits->vddci;
+
+		if (ps->medium.mclk > max_limits->mclk)
+			ps->medium.mclk = max_limits->mclk;
+		if (ps->medium.sclk > max_limits->sclk)
+			ps->medium.sclk = max_limits->sclk;
+		if (ps->medium.vddc > max_limits->vddc)
+			ps->medium.vddc = max_limits->vddc;
+		if (ps->medium.vddci > max_limits->vddci)
+			ps->medium.vddci = max_limits->vddci;
+
+		if (ps->low.mclk > max_limits->mclk)
+			ps->low.mclk = max_limits->mclk;
+		if (ps->low.sclk > max_limits->sclk)
+			ps->low.sclk = max_limits->sclk;
+		if (ps->low.vddc > max_limits->vddc)
+			ps->low.vddc = max_limits->vddc;
+		if (ps->low.vddci > max_limits->vddci)
+			ps->low.vddci = max_limits->vddci;
+	}
+
+	/* XXX validate the min clocks required for display */
+
+	if (disable_mclk_switching) {
+		sclk = ps->low.sclk;
+		mclk = ps->high.mclk;
+		vddc = ps->low.vddc;
+		vddci = ps->high.vddci;
+	} else {
+		sclk = ps->low.sclk;
+		mclk = ps->low.mclk;
+		vddc = ps->low.vddc;
+		vddci = ps->low.vddci;
+	}
+
+	/* adjusted low state */
+	ps->low.sclk = sclk;
+	ps->low.mclk = mclk;
+	ps->low.vddc = vddc;
+	ps->low.vddci = vddci;
+
+	btc_skip_blacklist_clocks(rdev, max_limits->sclk, max_limits->mclk,
+				  &ps->low.sclk, &ps->low.mclk);
+
+	/* adjusted medium, high states */
+	if (ps->medium.sclk < ps->low.sclk)
+		ps->medium.sclk = ps->low.sclk;
+	if (ps->medium.vddc < ps->low.vddc)
+		ps->medium.vddc = ps->low.vddc;
+	if (ps->high.sclk < ps->medium.sclk)
+		ps->high.sclk = ps->medium.sclk;
+	if (ps->high.vddc < ps->medium.vddc)
+		ps->high.vddc = ps->medium.vddc;
+
+	if (disable_mclk_switching) {
+		mclk = ps->low.mclk;
+		if (mclk < ps->medium.mclk)
+			mclk = ps->medium.mclk;
+		if (mclk < ps->high.mclk)
+			mclk = ps->high.mclk;
+		ps->low.mclk = mclk;
+		ps->low.vddci = vddci;
+		ps->medium.mclk = mclk;
+		ps->medium.vddci = vddci;
+		ps->high.mclk = mclk;
+		ps->high.vddci = vddci;
+	} else {
+		if (ps->medium.mclk < ps->low.mclk)
+			ps->medium.mclk = ps->low.mclk;
+		if (ps->medium.vddci < ps->low.vddci)
+			ps->medium.vddci = ps->low.vddci;
+		if (ps->high.mclk < ps->medium.mclk)
+			ps->high.mclk = ps->medium.mclk;
+		if (ps->high.vddci < ps->medium.vddci)
+			ps->high.vddci = ps->medium.vddci;
+	}
+
+	btc_skip_blacklist_clocks(rdev, max_limits->sclk, max_limits->mclk,
+				  &ps->medium.sclk, &ps->medium.mclk);
+	btc_skip_blacklist_clocks(rdev, max_limits->sclk, max_limits->mclk,
+				  &ps->high.sclk, &ps->high.mclk);
+
+	btc_adjust_clock_combinations(rdev, max_limits, &ps->low);
+	btc_adjust_clock_combinations(rdev, max_limits, &ps->medium);
+	btc_adjust_clock_combinations(rdev, max_limits, &ps->high);
+
+	btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk,
+					   ps->low.sclk, max_limits->vddc, &ps->low.vddc);
+	btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk,
+					   ps->low.mclk, max_limits->vddci, &ps->low.vddci);
+	btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk,
+					   ps->low.mclk, max_limits->vddc, &ps->low.vddc);
+	/* XXX validate the voltage required for display */
+	btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk,
+					   ps->medium.sclk, max_limits->vddc, &ps->medium.vddc);
+	btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk,
+					   ps->medium.mclk, max_limits->vddci, &ps->medium.vddci);
+	btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk,
+					   ps->medium.mclk, max_limits->vddc, &ps->medium.vddc);
+	/* XXX validate the voltage required for display */
+	btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk,
+					   ps->high.sclk, max_limits->vddc, &ps->high.vddc);
+	btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk,
+					   ps->high.mclk, max_limits->vddci, &ps->high.vddci);
+	btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk,
+					   ps->high.mclk, max_limits->vddc, &ps->high.vddc);
+	/* XXX validate the voltage required for display */
+
+	btc_apply_voltage_delta_rules(rdev, max_limits->vddc, max_limits->vddci,
+				      &ps->low.vddc, &ps->low.vddci);
+	btc_apply_voltage_delta_rules(rdev, max_limits->vddc, max_limits->vddci,
+				      &ps->medium.vddc, &ps->medium.vddci);
+	btc_apply_voltage_delta_rules(rdev, max_limits->vddc, max_limits->vddci,
+				      &ps->high.vddc, &ps->high.vddci);
+
+	if ((ps->high.vddc <= rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc.vddc) &&
+	    (ps->medium.vddc <= rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc.vddc) &&
+	    (ps->low.vddc <= rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc.vddc))
+		ps->dc_compatible = true;
+	else
+		ps->dc_compatible = false;
+
+	if (ps->low.vddc < rdev->pm.dpm.dyn_state.min_vddc_for_pcie_gen2)
+		ps->low.flags &= ~ATOM_PPLIB_R600_FLAGS_PCIEGEN2;
+	if (ps->medium.vddc < rdev->pm.dpm.dyn_state.min_vddc_for_pcie_gen2)
+		ps->medium.flags &= ~ATOM_PPLIB_R600_FLAGS_PCIEGEN2;
+	if (ps->high.vddc < rdev->pm.dpm.dyn_state.min_vddc_for_pcie_gen2)
+		ps->high.flags &= ~ATOM_PPLIB_R600_FLAGS_PCIEGEN2;
+}
+
 void btc_dpm_reset_asic(struct radeon_device *rdev)
 {
 	rv770_restrict_performance_levels_before_switch(rdev);
@@ -1913,6 +2234,8 @@ int btc_dpm_set_power_state(struct radeon_device *rdev)
 {
 	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
 
+	btc_apply_state_adjust_rules(rdev);
+
 	btc_disable_ulv(rdev);
 	btc_set_boot_state_timing(rdev);
 	rv770_restrict_performance_levels_before_switch(rdev);
@@ -2121,6 +2444,9 @@ int btc_dpm_init(struct radeon_device *rdev)
 	ret = rv7xx_parse_power_table(rdev);
 	if (ret)
 		return ret;
+	ret = r600_parse_extended_power_table(rdev);
+	if (ret)
+		return ret;
 
 	if (rdev->pm.dpm.voltage_response_time == 0)
 		rdev->pm.dpm.voltage_response_time = R600_VOLTAGERESPONSETIME_DFLT;
@@ -2230,6 +2556,19 @@ int btc_dpm_init(struct radeon_device *rdev)
 
 	pi->sram_end = SMC_RAM_END;
 
+	rdev->pm.dpm.dyn_state.mclk_sclk_ratio = 4;
+	rdev->pm.dpm.dyn_state.vddc_vddci_delta = 200;
+	rdev->pm.dpm.dyn_state.min_vddc_for_pcie_gen2 = 900;
+	rdev->pm.dpm.dyn_state.valid_sclk_values.count = ARRAY_SIZE(btc_valid_sclk);
+	rdev->pm.dpm.dyn_state.valid_sclk_values.values = btc_valid_sclk;
+	rdev->pm.dpm.dyn_state.valid_mclk_values.count = 0;
+	rdev->pm.dpm.dyn_state.valid_mclk_values.values = NULL;
+
+	if (rdev->family == CHIP_TURKS)
+		rdev->pm.dpm.dyn_state.sclk_mclk_delta = 15000;
+	else
+		rdev->pm.dpm.dyn_state.sclk_mclk_delta = 10000;
+
 	return 0;
 }
 
@@ -2242,4 +2581,5 @@ void btc_dpm_fini(struct radeon_device *rdev)
 	}
 	kfree(rdev->pm.dpm.ps);
 	kfree(rdev->pm.dpm.priv);
+	r600_free_extended_power_table(rdev);
 }
diff --git a/drivers/gpu/drm/radeon/btc_dpm.h b/drivers/gpu/drm/radeon/btc_dpm.h
index 56b1957..807024d 100644
--- a/drivers/gpu/drm/radeon/btc_dpm.h
+++ b/drivers/gpu/drm/radeon/btc_dpm.h
@@ -33,4 +33,6 @@
 #define BTC_CGULVPARAMETER_DFLT                       0x00040035
 #define BTC_CGULVCONTROL_DFLT                         0x00001450
 
+extern u32 btc_valid_sclk[];
+
 #endif
diff --git a/drivers/gpu/drm/radeon/cypress_dpm.h b/drivers/gpu/drm/radeon/cypress_dpm.h
index 029bc9d..9e24d7a 100644
--- a/drivers/gpu/drm/radeon/cypress_dpm.h
+++ b/drivers/gpu/drm/radeon/cypress_dpm.h
@@ -88,6 +88,7 @@ struct evergreen_power_info {
 	struct at ats[2];
 	/* smc offsets */
 	u16 mc_reg_table_start;
+	struct rv7xx_ps hw_ps;
 };
 
 #define CYPRESS_HASI_DFLT                               400000
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index a4d8d97..16c7d52 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -1222,6 +1222,19 @@ struct radeon_dpm_thermal {
 	bool               high_to_low;
 };
 
+enum radeon_clk_action
+{
+	RADEON_SCLK_UP = 1,
+	RADEON_SCLK_DOWN
+};
+
+struct radeon_blacklist_clocks
+{
+	u32 sclk;
+	u32 mclk;
+	enum radeon_clk_action action;
+};
+
 struct radeon_clock_and_voltage_limits {
 	u32 sclk;
 	u32 mclk;
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
index 7ee8cf6..2eb41be 100644
--- a/drivers/gpu/drm/radeon/radeon_pm.c
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
@@ -722,17 +722,42 @@ static void radeon_dpm_change_power_state_locked(struct radeon_device *rdev)
 	else
 		return;
 
-	/* no need to reprogram if nothing changed */
+	/* no need to reprogram if nothing changed unless we are on BTC+ */
 	if (rdev->pm.dpm.current_ps == rdev->pm.dpm.requested_ps) {
-		/* update display watermarks based on new power state */
-		if (rdev->pm.dpm.new_active_crtcs != rdev->pm.dpm.current_active_crtcs) {
-			radeon_bandwidth_update(rdev);
-			/* update displays */
-			radeon_dpm_display_configuration_changed(rdev);
-			rdev->pm.dpm.current_active_crtcs = rdev->pm.dpm.new_active_crtcs;
-			rdev->pm.dpm.current_active_crtc_count = rdev->pm.dpm.new_active_crtc_count;
+		if ((rdev->family < CHIP_BARTS) || (rdev->flags & RADEON_IS_IGP)) {
+			/* for pre-BTC and APUs if the num crtcs changed but state is the same,
+			 * all we need to do is update the display configuration.
+			 */
+			if (rdev->pm.dpm.new_active_crtcs != rdev->pm.dpm.current_active_crtcs) {
+				/* update display watermarks based on new power state */
+				radeon_bandwidth_update(rdev);
+				/* update displays */
+				radeon_dpm_display_configuration_changed(rdev);
+				rdev->pm.dpm.current_active_crtcs = rdev->pm.dpm.new_active_crtcs;
+				rdev->pm.dpm.current_active_crtc_count = rdev->pm.dpm.new_active_crtc_count;
+			}
+			return;
+		} else {
+			/* for BTC+ if the num crtcs hasn't changed and state is the same,
+			 * nothing to do, if the num crtcs is > 1 and state is the same,
+			 * update display configuration.
+			 */
+			if (rdev->pm.dpm.new_active_crtcs ==
+			    rdev->pm.dpm.current_active_crtcs) {
+				return;
+			} else {
+				if ((rdev->pm.dpm.current_active_crtc_count > 1) &&
+				    (rdev->pm.dpm.new_active_crtc_count > 1)) {
+					/* update display watermarks based on new power state */
+					radeon_bandwidth_update(rdev);
+					/* update displays */
+					radeon_dpm_display_configuration_changed(rdev);
+					rdev->pm.dpm.current_active_crtcs = rdev->pm.dpm.new_active_crtcs;
+					rdev->pm.dpm.current_active_crtc_count = rdev->pm.dpm.new_active_crtc_count;
+					return;
+				}
+			}
 		}
-		return;
 	}
 
 	printk("switching from power state:\n");
diff --git a/drivers/gpu/drm/radeon/rv770_dpm.c b/drivers/gpu/drm/radeon/rv770_dpm.c
index 55e5126..f5efa4c 100644
--- a/drivers/gpu/drm/radeon/rv770_dpm.c
+++ b/drivers/gpu/drm/radeon/rv770_dpm.c
@@ -2165,6 +2165,16 @@ static void rv7xx_parse_pplib_clock_info(struct radeon_device *rdev,
 		pl->vddc = vddc;
 		pl->vddci = vddci;
 	}
+
+	if (rdev->family >= CHIP_BARTS) {
+		if ((rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) ==
+		    ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE) {
+			rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.sclk = pl->sclk;
+			rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.mclk = pl->mclk;
+			rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.vddc = pl->vddc;
+			rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.vddci = pl->vddci;
+		}
+	}
 }
 
 int rv7xx_parse_power_table(struct radeon_device *rdev)
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 093/165] drm/radeon/kms: add dpm support for cayman
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (92 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 092/165] drm/radeon/dpm: fixup dynamic state adjust for btc (v2) alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 11:29   ` Jerome Glisse
  2013-06-26 13:22 ` [PATCH 094/165] drm/radeon/cayman: update tdp limits in set_power_state alexdeucher
                   ` (19 subsequent siblings)
  113 siblings, 1 reply; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

This adds dpm support for cayman asics.  This includes:
- clockgating
- dynamic engine clock scaling
- dynamic memory clock scaling
- dynamic voltage scaling
- dynamic pcie gen1/gen2 switching (requires additional acpi support)
- power containment
- shader power scaling

Set radeon.dpm=1 to enable.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/Makefile       |    2 +-
 drivers/gpu/drm/radeon/btc_dpm.c      |   36 +-
 drivers/gpu/drm/radeon/btc_dpm.h      |   20 +-
 drivers/gpu/drm/radeon/cypress_dpm.c  |   11 +-
 drivers/gpu/drm/radeon/cypress_dpm.h  |    4 +
 drivers/gpu/drm/radeon/ni.c           |    4 +-
 drivers/gpu/drm/radeon/ni_dpm.c       | 4093 +++++++++++++++++++++++++++++++++
 drivers/gpu/drm/radeon/ni_dpm.h       |  233 ++
 drivers/gpu/drm/radeon/nid.h          |  552 +++++
 drivers/gpu/drm/radeon/nislands_smc.h |  329 +++
 drivers/gpu/drm/radeon/ppsmc.h        |   12 +
 drivers/gpu/drm/radeon/radeon_asic.c  |   12 +
 drivers/gpu/drm/radeon/radeon_asic.h  |   10 +
 drivers/gpu/drm/radeon/radeon_pm.c    |    1 +
 drivers/gpu/drm/radeon/radeon_ucode.h |    5 +
 drivers/gpu/drm/radeon/rv770_smc.c    |   27 +
 16 files changed, 5323 insertions(+), 28 deletions(-)
 create mode 100644 drivers/gpu/drm/radeon/ni_dpm.c
 create mode 100644 drivers/gpu/drm/radeon/ni_dpm.h
 create mode 100644 drivers/gpu/drm/radeon/nislands_smc.h

diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile
index 2239ec2..32d1c7f 100644
--- a/drivers/gpu/drm/radeon/Makefile
+++ b/drivers/gpu/drm/radeon/Makefile
@@ -79,7 +79,7 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \
 	si_blit_shaders.o radeon_prime.o radeon_uvd.o cik.o cik_blit_shaders.o \
 	r600_dpm.o rs780_dpm.o rv6xx_dpm.o rv770_dpm.o rv730_dpm.o rv740_dpm.o \
 	rv770_smc.o cypress_dpm.o btc_dpm.o sumo_dpm.o sumo_smc.o trinity_dpm.o \
-	trinity_smc.o
+	trinity_smc.o ni_dpm.o
 
 radeon-$(CONFIG_COMPAT) += radeon_ioc32.o
 radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o
diff --git a/drivers/gpu/drm/radeon/btc_dpm.c b/drivers/gpu/drm/radeon/btc_dpm.c
index 989592e..79f5ed4 100644
--- a/drivers/gpu/drm/radeon/btc_dpm.c
+++ b/drivers/gpu/drm/radeon/btc_dpm.c
@@ -1152,7 +1152,7 @@ static const u32 turks_sysls_enable[] =
 
 #endif
 
-u32 btc_valid_sclk[] =
+u32 btc_valid_sclk[40] =
 {
 	5000,   10000,  15000,  20000,  25000,  30000,  35000,  40000,  45000,  50000,
 	55000,  60000,  65000,  70000,  75000,  80000,  85000,  90000,  95000,  100000,
@@ -1168,8 +1168,8 @@ static const struct radeon_blacklist_clocks btc_blacklist_clocks[] =
         { 25000, 30000, RADEON_SCLK_UP }
 };
 
-static void btc_apply_voltage_dependency_rules(struct radeon_clock_voltage_dependency_table *table,
-					       u32 clock, u16 max_voltage, u16 *voltage)
+void btc_apply_voltage_dependency_rules(struct radeon_clock_voltage_dependency_table *table,
+					u32 clock, u16 max_voltage, u16 *voltage)
 {
 	u32 i;
 
@@ -1219,9 +1219,9 @@ static u32 btc_get_valid_sclk(struct radeon_device *rdev,
 				    max_sclk, requested_sclk);
 }
 
-static void btc_skip_blacklist_clocks(struct radeon_device *rdev,
-				      const u32 max_sclk, const u32 max_mclk,
-				      u32 *sclk, u32 *mclk)
+void btc_skip_blacklist_clocks(struct radeon_device *rdev,
+			       const u32 max_sclk, const u32 max_mclk,
+			       u32 *sclk, u32 *mclk)
 {
 	int i, num_blacklist_clocks;
 
@@ -1246,9 +1246,9 @@ static void btc_skip_blacklist_clocks(struct radeon_device *rdev,
 	}
 }
 
-static void btc_adjust_clock_combinations(struct radeon_device *rdev,
-					  const struct radeon_clock_and_voltage_limits *max_limits,
-					  struct rv7xx_pl *pl)
+void btc_adjust_clock_combinations(struct radeon_device *rdev,
+				   const struct radeon_clock_and_voltage_limits *max_limits,
+				   struct rv7xx_pl *pl)
 {
 
 	if ((pl->mclk == 0) || (pl->sclk == 0))
@@ -1285,9 +1285,9 @@ static u16 btc_find_voltage(struct atom_voltage_table *table, u16 voltage)
 	return table->entries[table->count - 1].value;
 }
 
-static void btc_apply_voltage_delta_rules(struct radeon_device *rdev,
-					  u16 max_vddc, u16 max_vddci,
-					  u16 *vddc, u16 *vddci)
+void btc_apply_voltage_delta_rules(struct radeon_device *rdev,
+				   u16 max_vddc, u16 max_vddci,
+				   u16 *vddc, u16 *vddci)
 {
 	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
 	u16 new_voltage;
@@ -1417,8 +1417,8 @@ static int btc_populate_smc_acpi_state(struct radeon_device *rdev,
 	return ret;
 }
 
-static void btc_program_mgcg_hw_sequence(struct radeon_device *rdev,
-					 const u32 *sequence, u32 count)
+void btc_program_mgcg_hw_sequence(struct radeon_device *rdev,
+				  const u32 *sequence, u32 count)
 {
 	u32 i, length = count * 3;
 	u32 tmp;
@@ -1596,7 +1596,7 @@ static void btc_ls_clock_gating_enable(struct radeon_device *rdev,
 	btc_program_mgcg_hw_sequence(rdev, p, count);
 }
 
-static bool btc_dpm_enabled(struct radeon_device *rdev)
+bool btc_dpm_enabled(struct radeon_device *rdev)
 {
 	if (rv770_is_smc_running(rdev))
 		return true;
@@ -1692,7 +1692,7 @@ static void btc_set_at_for_uvd(struct radeon_device *rdev)
 
 }
 
-static void btc_notify_uvd_to_smc(struct radeon_device *rdev)
+void btc_notify_uvd_to_smc(struct radeon_device *rdev)
 {
 	struct radeon_ps *radeon_new_state = rdev->pm.dpm.requested_ps;
 	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
@@ -1708,7 +1708,7 @@ static void btc_notify_uvd_to_smc(struct radeon_device *rdev)
 	}
 }
 
-static int btc_reset_to_default(struct radeon_device *rdev)
+int btc_reset_to_default(struct radeon_device *rdev)
 {
 	if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_ResetToDefaults) != PPSMC_Result_OK)
 		return -EINVAL;
@@ -1730,7 +1730,7 @@ static void btc_stop_smc(struct radeon_device *rdev)
 	r7xx_stop_smc(rdev);
 }
 
-static void btc_read_arb_registers(struct radeon_device *rdev)
+void btc_read_arb_registers(struct radeon_device *rdev)
 {
 	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
 	struct evergreen_arb_registers *arb_registers =
diff --git a/drivers/gpu/drm/radeon/btc_dpm.h b/drivers/gpu/drm/radeon/btc_dpm.h
index 807024d..c22d39f 100644
--- a/drivers/gpu/drm/radeon/btc_dpm.h
+++ b/drivers/gpu/drm/radeon/btc_dpm.h
@@ -33,6 +33,24 @@
 #define BTC_CGULVPARAMETER_DFLT                       0x00040035
 #define BTC_CGULVCONTROL_DFLT                         0x00001450
 
-extern u32 btc_valid_sclk[];
+extern u32 btc_valid_sclk[40];
+
+void btc_read_arb_registers(struct radeon_device *rdev);
+void btc_program_mgcg_hw_sequence(struct radeon_device *rdev,
+				  const u32 *sequence, u32 count);
+void btc_skip_blacklist_clocks(struct radeon_device *rdev,
+			       const u32 max_sclk, const u32 max_mclk,
+			       u32 *sclk, u32 *mclk);
+void btc_adjust_clock_combinations(struct radeon_device *rdev,
+				   const struct radeon_clock_and_voltage_limits *max_limits,
+				   struct rv7xx_pl *pl);
+void btc_apply_voltage_dependency_rules(struct radeon_clock_voltage_dependency_table *table,
+					u32 clock, u16 max_voltage, u16 *voltage);
+void btc_apply_voltage_delta_rules(struct radeon_device *rdev,
+				   u16 max_vddc, u16 max_vddci,
+				   u16 *vddc, u16 *vddci);
+bool btc_dpm_enabled(struct radeon_device *rdev);
+int btc_reset_to_default(struct radeon_device *rdev);
+void btc_notify_uvd_to_smc(struct radeon_device *rdev);
 
 #endif
diff --git a/drivers/gpu/drm/radeon/cypress_dpm.c b/drivers/gpu/drm/radeon/cypress_dpm.c
index 403ee15..22297b1 100644
--- a/drivers/gpu/drm/radeon/cypress_dpm.c
+++ b/drivers/gpu/drm/radeon/cypress_dpm.c
@@ -45,9 +45,6 @@ struct rv7xx_ps *rv770_get_ps(struct radeon_ps *rps);
 struct rv7xx_power_info *rv770_get_pi(struct radeon_device *rdev);
 struct evergreen_power_info *evergreen_get_pi(struct radeon_device *rdev);
 
-static u8 cypress_get_mclk_frequency_ratio(struct radeon_device *rdev,
-					   u32 memory_clock, bool strobe_mode);
-
 static void cypress_enable_bif_dynamic_pcie_gen2(struct radeon_device *rdev,
 						 bool enable)
 {
@@ -416,7 +413,7 @@ static int cypress_populate_voltage_value(struct radeon_device *rdev,
 	return 0;
 }
 
-static u8 cypress_get_strobe_mode_settings(struct radeon_device *rdev, u32 mclk)
+u8 cypress_get_strobe_mode_settings(struct radeon_device *rdev, u32 mclk)
 {
 	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
 	u8 result = 0;
@@ -434,7 +431,7 @@ static u8 cypress_get_strobe_mode_settings(struct radeon_device *rdev, u32 mclk)
 	return result;
 }
 
-static u32 cypress_map_clkf_to_ibias(struct radeon_device *rdev, u32 clkf)
+u32 cypress_map_clkf_to_ibias(struct radeon_device *rdev, u32 clkf)
 {
 	u32 ref_clk = rdev->clock.mpll.reference_freq;
 	u32 vco = clkf * ref_clk;
@@ -603,8 +600,8 @@ static int cypress_populate_mclk_value(struct radeon_device *rdev,
 	return 0;
 }
 
-static u8 cypress_get_mclk_frequency_ratio(struct radeon_device *rdev,
-					   u32 memory_clock, bool strobe_mode)
+u8 cypress_get_mclk_frequency_ratio(struct radeon_device *rdev,
+				    u32 memory_clock, bool strobe_mode)
 {
 	u8 mc_para_index;
 
diff --git a/drivers/gpu/drm/radeon/cypress_dpm.h b/drivers/gpu/drm/radeon/cypress_dpm.h
index 9e24d7a..9b6198e 100644
--- a/drivers/gpu/drm/radeon/cypress_dpm.h
+++ b/drivers/gpu/drm/radeon/cypress_dpm.h
@@ -141,5 +141,9 @@ void cypress_enable_mclk_control(struct radeon_device *rdev,
 				 bool enable);
 void cypress_start_dpm(struct radeon_device *rdev);
 void cypress_advertise_gen2_capability(struct radeon_device *rdev);
+u32 cypress_map_clkf_to_ibias(struct radeon_device *rdev, u32 clkf);
+u8 cypress_get_mclk_frequency_ratio(struct radeon_device *rdev,
+				    u32 memory_clock, bool strobe_mode);
+u8 cypress_get_strobe_mode_settings(struct radeon_device *rdev, u32 mclk);
 
 #endif
diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c
index 7407762..ad65143 100644
--- a/drivers/gpu/drm/radeon/ni.c
+++ b/drivers/gpu/drm/radeon/ni.c
@@ -194,6 +194,7 @@ MODULE_FIRMWARE("radeon/CAYMAN_pfp.bin");
 MODULE_FIRMWARE("radeon/CAYMAN_me.bin");
 MODULE_FIRMWARE("radeon/CAYMAN_mc.bin");
 MODULE_FIRMWARE("radeon/CAYMAN_rlc.bin");
+MODULE_FIRMWARE("radeon/CAYMAN_smc.bin");
 MODULE_FIRMWARE("radeon/ARUBA_pfp.bin");
 MODULE_FIRMWARE("radeon/ARUBA_me.bin");
 MODULE_FIRMWARE("radeon/ARUBA_rlc.bin");
@@ -734,6 +735,7 @@ int ni_init_microcode(struct radeon_device *rdev)
 		me_req_size = CAYMAN_PM4_UCODE_SIZE * 4;
 		rlc_req_size = CAYMAN_RLC_UCODE_SIZE * 4;
 		mc_req_size = CAYMAN_MC_UCODE_SIZE * 4;
+		smc_req_size = ALIGN(CAYMAN_SMC_UCODE_SIZE, 4);
 		break;
 	case CHIP_ARUBA:
 		chip_name = "ARUBA";
@@ -797,7 +799,7 @@ int ni_init_microcode(struct radeon_device *rdev)
 		}
 	}
 
-	if ((rdev->family >= CHIP_BARTS) && (rdev->family <= CHIP_CAICOS)) {
+	if ((rdev->family >= CHIP_BARTS) && (rdev->family <= CHIP_CAYMAN)) {
 		snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", chip_name);
 		err = request_firmware(&rdev->smc_fw, fw_name, &pdev->dev);
 		if (err)
diff --git a/drivers/gpu/drm/radeon/ni_dpm.c b/drivers/gpu/drm/radeon/ni_dpm.c
new file mode 100644
index 0000000..635bf04
--- /dev/null
+++ b/drivers/gpu/drm/radeon/ni_dpm.c
@@ -0,0 +1,4093 @@
+/*
+ * Copyright 2012 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "drmP.h"
+#include "radeon.h"
+#include "nid.h"
+#include "r600_dpm.h"
+#include "ni_dpm.h"
+#include "atom.h"
+
+#define MC_CG_ARB_FREQ_F0           0x0a
+#define MC_CG_ARB_FREQ_F1           0x0b
+#define MC_CG_ARB_FREQ_F2           0x0c
+#define MC_CG_ARB_FREQ_F3           0x0d
+
+#define SMC_RAM_END 0xC000
+
+static const struct ni_cac_weights cac_weights_cayman_xt =
+{
+	0x15,
+	0x2,
+	0x19,
+	0x2,
+	0x8,
+	0x14,
+	0x2,
+	0x16,
+	0xE,
+	0x17,
+	0x13,
+	0x2B,
+	0x10,
+	0x7,
+	0x5,
+	0x5,
+	0x5,
+	0x2,
+	0x3,
+	0x9,
+	0x10,
+	0x10,
+	0x2B,
+	0xA,
+	0x9,
+	0x4,
+	0xD,
+	0xD,
+	0x3E,
+	0x18,
+	0x14,
+	0,
+	0x3,
+	0x3,
+	0x5,
+	0,
+	0x2,
+	0,
+	0,
+	0,
+	0,
+	0,
+	0,
+	0,
+	0,
+	0,
+	0x1CC,
+	0,
+	0x164,
+	1,
+	1,
+	1,
+	1,
+	12,
+	12,
+	12,
+	0x12,
+	0x1F,
+	132,
+	5,
+	7,
+	0,
+	{ 0, 0, 0, 0, 0, 0, 0, 0 },
+	{ 0, 0, 0, 0 },
+	true
+};
+
+static const struct ni_cac_weights cac_weights_cayman_pro =
+{
+	0x16,
+	0x4,
+	0x10,
+	0x2,
+	0xA,
+	0x16,
+	0x2,
+	0x18,
+	0x10,
+	0x1A,
+	0x16,
+	0x2D,
+	0x12,
+	0xA,
+	0x6,
+	0x6,
+	0x6,
+	0x2,
+	0x4,
+	0xB,
+	0x11,
+	0x11,
+	0x2D,
+	0xC,
+	0xC,
+	0x7,
+	0x10,
+	0x10,
+	0x3F,
+	0x1A,
+	0x16,
+	0,
+	0x7,
+	0x4,
+	0x6,
+	1,
+	0x2,
+	0x1,
+	0,
+	0,
+	0,
+	0,
+	0,
+	0,
+	0x30,
+	0,
+	0x1CF,
+	0,
+	0x166,
+	1,
+	1,
+	1,
+	1,
+	12,
+	12,
+	12,
+	0x15,
+	0x1F,
+	132,
+	6,
+	6,
+	0,
+	{ 0, 0, 0, 0, 0, 0, 0, 0 },
+	{ 0, 0, 0, 0 },
+	true
+};
+
+static const struct ni_cac_weights cac_weights_cayman_le =
+{
+	0x7,
+	0xE,
+	0x1,
+	0xA,
+	0x1,
+	0x3F,
+	0x2,
+	0x18,
+	0x10,
+	0x1A,
+	0x1,
+	0x3F,
+	0x1,
+	0xE,
+	0x6,
+	0x6,
+	0x6,
+	0x2,
+	0x4,
+	0x9,
+	0x1A,
+	0x1A,
+	0x2C,
+	0xA,
+	0x11,
+	0x8,
+	0x19,
+	0x19,
+	0x1,
+	0x1,
+	0x1A,
+	0,
+	0x8,
+	0x5,
+	0x8,
+	0x1,
+	0x3,
+	0x1,
+	0,
+	0,
+	0,
+	0,
+	0,
+	0,
+	0x38,
+	0x38,
+	0x239,
+	0x3,
+	0x18A,
+	1,
+	1,
+	1,
+	1,
+	12,
+	12,
+	12,
+	0x15,
+	0x22,
+	132,
+	6,
+	6,
+	0,
+	{ 0, 0, 0, 0, 0, 0, 0, 0 },
+	{ 0, 0, 0, 0 },
+	true
+};
+
+#define NISLANDS_MGCG_SEQUENCE  300
+
+static const u32 cayman_cgcg_cgls_default[] =
+{
+	0x000008f8, 0x00000010, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000011, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000012, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000013, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000014, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000015, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000016, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000017, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000018, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000019, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x0000001a, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x0000001b, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000020, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000021, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000022, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000023, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000024, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000025, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000026, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000027, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000028, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000029, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x0000002a, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x0000002b, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff
+};
+#define CAYMAN_CGCG_CGLS_DEFAULT_LENGTH sizeof(cayman_cgcg_cgls_default) / (3 * sizeof(u32))
+
+static const u32 cayman_cgcg_cgls_disable[] =
+{
+	0x000008f8, 0x00000010, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000011, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000012, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000013, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000014, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000015, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000016, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000017, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000018, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000019, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x0000001a, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x0000001b, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000020, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000021, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000022, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000023, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000024, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000025, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000026, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000027, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000028, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000029, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x0000002a, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x0000002b, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x00000644, 0x000f7902, 0x001f4180,
+	0x00000644, 0x000f3802, 0x001f4180
+};
+#define CAYMAN_CGCG_CGLS_DISABLE_LENGTH sizeof(cayman_cgcg_cgls_disable) / (3 * sizeof(u32))
+
+static const u32 cayman_cgcg_cgls_enable[] =
+{
+	0x00000644, 0x000f7882, 0x001f4080,
+	0x000008f8, 0x00000010, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000011, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000012, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000013, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000014, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000015, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000016, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000017, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000018, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000019, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x0000001a, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x0000001b, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000020, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000021, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000022, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000023, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000024, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000025, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000026, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000027, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000028, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000029, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x0000002a, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x0000002b, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff
+};
+#define CAYMAN_CGCG_CGLS_ENABLE_LENGTH  sizeof(cayman_cgcg_cgls_enable) / (3 * sizeof(u32))
+
+static const u32 cayman_mgcg_default[] =
+{
+	0x0000802c, 0xc0000000, 0xffffffff,
+	0x00003fc4, 0xc0000000, 0xffffffff,
+	0x00005448, 0x00000100, 0xffffffff,
+	0x000055e4, 0x00000100, 0xffffffff,
+	0x0000160c, 0x00000100, 0xffffffff,
+	0x00008984, 0x06000100, 0xffffffff,
+	0x0000c164, 0x00000100, 0xffffffff,
+	0x00008a18, 0x00000100, 0xffffffff,
+	0x0000897c, 0x06000100, 0xffffffff,
+	0x00008b28, 0x00000100, 0xffffffff,
+	0x00009144, 0x00800200, 0xffffffff,
+	0x00009a60, 0x00000100, 0xffffffff,
+	0x00009868, 0x00000100, 0xffffffff,
+	0x00008d58, 0x00000100, 0xffffffff,
+	0x00009510, 0x00000100, 0xffffffff,
+	0x0000949c, 0x00000100, 0xffffffff,
+	0x00009654, 0x00000100, 0xffffffff,
+	0x00009030, 0x00000100, 0xffffffff,
+	0x00009034, 0x00000100, 0xffffffff,
+	0x00009038, 0x00000100, 0xffffffff,
+	0x0000903c, 0x00000100, 0xffffffff,
+	0x00009040, 0x00000100, 0xffffffff,
+	0x0000a200, 0x00000100, 0xffffffff,
+	0x0000a204, 0x00000100, 0xffffffff,
+	0x0000a208, 0x00000100, 0xffffffff,
+	0x0000a20c, 0x00000100, 0xffffffff,
+	0x00009744, 0x00000100, 0xffffffff,
+	0x00003f80, 0x00000100, 0xffffffff,
+	0x0000a210, 0x00000100, 0xffffffff,
+	0x0000a214, 0x00000100, 0xffffffff,
+	0x000004d8, 0x00000100, 0xffffffff,
+	0x00009664, 0x00000100, 0xffffffff,
+	0x00009698, 0x00000100, 0xffffffff,
+	0x000004d4, 0x00000200, 0xffffffff,
+	0x000004d0, 0x00000000, 0xffffffff,
+	0x000030cc, 0x00000104, 0xffffffff,
+	0x0000d0c0, 0x00000100, 0xffffffff,
+	0x0000d8c0, 0x00000100, 0xffffffff,
+	0x0000802c, 0x40000000, 0xffffffff,
+	0x00003fc4, 0x40000000, 0xffffffff,
+	0x0000915c, 0x00010000, 0xffffffff,
+	0x00009160, 0x00030002, 0xffffffff,
+	0x00009164, 0x00050004, 0xffffffff,
+	0x00009168, 0x00070006, 0xffffffff,
+	0x00009178, 0x00070000, 0xffffffff,
+	0x0000917c, 0x00030002, 0xffffffff,
+	0x00009180, 0x00050004, 0xffffffff,
+	0x0000918c, 0x00010006, 0xffffffff,
+	0x00009190, 0x00090008, 0xffffffff,
+	0x00009194, 0x00070000, 0xffffffff,
+	0x00009198, 0x00030002, 0xffffffff,
+	0x0000919c, 0x00050004, 0xffffffff,
+	0x000091a8, 0x00010006, 0xffffffff,
+	0x000091ac, 0x00090008, 0xffffffff,
+	0x000091b0, 0x00070000, 0xffffffff,
+	0x000091b4, 0x00030002, 0xffffffff,
+	0x000091b8, 0x00050004, 0xffffffff,
+	0x000091c4, 0x00010006, 0xffffffff,
+	0x000091c8, 0x00090008, 0xffffffff,
+	0x000091cc, 0x00070000, 0xffffffff,
+	0x000091d0, 0x00030002, 0xffffffff,
+	0x000091d4, 0x00050004, 0xffffffff,
+	0x000091e0, 0x00010006, 0xffffffff,
+	0x000091e4, 0x00090008, 0xffffffff,
+	0x000091e8, 0x00000000, 0xffffffff,
+	0x000091ec, 0x00070000, 0xffffffff,
+	0x000091f0, 0x00030002, 0xffffffff,
+	0x000091f4, 0x00050004, 0xffffffff,
+	0x00009200, 0x00010006, 0xffffffff,
+	0x00009204, 0x00090008, 0xffffffff,
+	0x00009208, 0x00070000, 0xffffffff,
+	0x0000920c, 0x00030002, 0xffffffff,
+	0x00009210, 0x00050004, 0xffffffff,
+	0x0000921c, 0x00010006, 0xffffffff,
+	0x00009220, 0x00090008, 0xffffffff,
+	0x00009224, 0x00070000, 0xffffffff,
+	0x00009228, 0x00030002, 0xffffffff,
+	0x0000922c, 0x00050004, 0xffffffff,
+	0x00009238, 0x00010006, 0xffffffff,
+	0x0000923c, 0x00090008, 0xffffffff,
+	0x00009240, 0x00070000, 0xffffffff,
+	0x00009244, 0x00030002, 0xffffffff,
+	0x00009248, 0x00050004, 0xffffffff,
+	0x00009254, 0x00010006, 0xffffffff,
+	0x00009258, 0x00090008, 0xffffffff,
+	0x0000925c, 0x00070000, 0xffffffff,
+	0x00009260, 0x00030002, 0xffffffff,
+	0x00009264, 0x00050004, 0xffffffff,
+	0x00009270, 0x00010006, 0xffffffff,
+	0x00009274, 0x00090008, 0xffffffff,
+	0x00009278, 0x00070000, 0xffffffff,
+	0x0000927c, 0x00030002, 0xffffffff,
+	0x00009280, 0x00050004, 0xffffffff,
+	0x0000928c, 0x00010006, 0xffffffff,
+	0x00009290, 0x00090008, 0xffffffff,
+	0x000092a8, 0x00070000, 0xffffffff,
+	0x000092ac, 0x00030002, 0xffffffff,
+	0x000092b0, 0x00050004, 0xffffffff,
+	0x000092bc, 0x00010006, 0xffffffff,
+	0x000092c0, 0x00090008, 0xffffffff,
+	0x000092c4, 0x00070000, 0xffffffff,
+	0x000092c8, 0x00030002, 0xffffffff,
+	0x000092cc, 0x00050004, 0xffffffff,
+	0x000092d8, 0x00010006, 0xffffffff,
+	0x000092dc, 0x00090008, 0xffffffff,
+	0x00009294, 0x00000000, 0xffffffff,
+	0x0000802c, 0x40010000, 0xffffffff,
+	0x00003fc4, 0x40010000, 0xffffffff,
+	0x0000915c, 0x00010000, 0xffffffff,
+	0x00009160, 0x00030002, 0xffffffff,
+	0x00009164, 0x00050004, 0xffffffff,
+	0x00009168, 0x00070006, 0xffffffff,
+	0x00009178, 0x00070000, 0xffffffff,
+	0x0000917c, 0x00030002, 0xffffffff,
+	0x00009180, 0x00050004, 0xffffffff,
+	0x0000918c, 0x00010006, 0xffffffff,
+	0x00009190, 0x00090008, 0xffffffff,
+	0x00009194, 0x00070000, 0xffffffff,
+	0x00009198, 0x00030002, 0xffffffff,
+	0x0000919c, 0x00050004, 0xffffffff,
+	0x000091a8, 0x00010006, 0xffffffff,
+	0x000091ac, 0x00090008, 0xffffffff,
+	0x000091b0, 0x00070000, 0xffffffff,
+	0x000091b4, 0x00030002, 0xffffffff,
+	0x000091b8, 0x00050004, 0xffffffff,
+	0x000091c4, 0x00010006, 0xffffffff,
+	0x000091c8, 0x00090008, 0xffffffff,
+	0x000091cc, 0x00070000, 0xffffffff,
+	0x000091d0, 0x00030002, 0xffffffff,
+	0x000091d4, 0x00050004, 0xffffffff,
+	0x000091e0, 0x00010006, 0xffffffff,
+	0x000091e4, 0x00090008, 0xffffffff,
+	0x000091e8, 0x00000000, 0xffffffff,
+	0x000091ec, 0x00070000, 0xffffffff,
+	0x000091f0, 0x00030002, 0xffffffff,
+	0x000091f4, 0x00050004, 0xffffffff,
+	0x00009200, 0x00010006, 0xffffffff,
+	0x00009204, 0x00090008, 0xffffffff,
+	0x00009208, 0x00070000, 0xffffffff,
+	0x0000920c, 0x00030002, 0xffffffff,
+	0x00009210, 0x00050004, 0xffffffff,
+	0x0000921c, 0x00010006, 0xffffffff,
+	0x00009220, 0x00090008, 0xffffffff,
+	0x00009224, 0x00070000, 0xffffffff,
+	0x00009228, 0x00030002, 0xffffffff,
+	0x0000922c, 0x00050004, 0xffffffff,
+	0x00009238, 0x00010006, 0xffffffff,
+	0x0000923c, 0x00090008, 0xffffffff,
+	0x00009240, 0x00070000, 0xffffffff,
+	0x00009244, 0x00030002, 0xffffffff,
+	0x00009248, 0x00050004, 0xffffffff,
+	0x00009254, 0x00010006, 0xffffffff,
+	0x00009258, 0x00090008, 0xffffffff,
+	0x0000925c, 0x00070000, 0xffffffff,
+	0x00009260, 0x00030002, 0xffffffff,
+	0x00009264, 0x00050004, 0xffffffff,
+	0x00009270, 0x00010006, 0xffffffff,
+	0x00009274, 0x00090008, 0xffffffff,
+	0x00009278, 0x00070000, 0xffffffff,
+	0x0000927c, 0x00030002, 0xffffffff,
+	0x00009280, 0x00050004, 0xffffffff,
+	0x0000928c, 0x00010006, 0xffffffff,
+	0x00009290, 0x00090008, 0xffffffff,
+	0x000092a8, 0x00070000, 0xffffffff,
+	0x000092ac, 0x00030002, 0xffffffff,
+	0x000092b0, 0x00050004, 0xffffffff,
+	0x000092bc, 0x00010006, 0xffffffff,
+	0x000092c0, 0x00090008, 0xffffffff,
+	0x000092c4, 0x00070000, 0xffffffff,
+	0x000092c8, 0x00030002, 0xffffffff,
+	0x000092cc, 0x00050004, 0xffffffff,
+	0x000092d8, 0x00010006, 0xffffffff,
+	0x000092dc, 0x00090008, 0xffffffff,
+	0x00009294, 0x00000000, 0xffffffff,
+	0x0000802c, 0xc0000000, 0xffffffff,
+	0x00003fc4, 0xc0000000, 0xffffffff,
+	0x000008f8, 0x00000010, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000011, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000012, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000013, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000014, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000015, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000016, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000017, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000018, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000019, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x0000001a, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x0000001b, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff
+};
+#define CAYMAN_MGCG_DEFAULT_LENGTH sizeof(cayman_mgcg_default) / (3 * sizeof(u32))
+
+static const u32 cayman_mgcg_disable[] =
+{
+	0x0000802c, 0xc0000000, 0xffffffff,
+	0x000008f8, 0x00000000, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000001, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000002, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x000008f8, 0x00000003, 0xffffffff,
+	0x000008fc, 0xffffffff, 0xffffffff,
+	0x00009150, 0x00600000, 0xffffffff
+};
+#define CAYMAN_MGCG_DISABLE_LENGTH   sizeof(cayman_mgcg_disable) / (3 * sizeof(u32))
+
+static const u32 cayman_mgcg_enable[] =
+{
+	0x0000802c, 0xc0000000, 0xffffffff,
+	0x000008f8, 0x00000000, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000001, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x000008f8, 0x00000002, 0xffffffff,
+	0x000008fc, 0x00600000, 0xffffffff,
+	0x000008f8, 0x00000003, 0xffffffff,
+	0x000008fc, 0x00000000, 0xffffffff,
+	0x00009150, 0x96944200, 0xffffffff
+};
+
+#define CAYMAN_MGCG_ENABLE_LENGTH   sizeof(cayman_mgcg_enable) / (3 * sizeof(u32))
+
+#define NISLANDS_SYSLS_SEQUENCE  100
+
+static const u32 cayman_sysls_default[] =
+{
+	/* Register,   Value,     Mask bits */
+	0x000055e8, 0x00000000, 0xffffffff,
+	0x0000d0bc, 0x00000000, 0xffffffff,
+	0x0000d8bc, 0x00000000, 0xffffffff,
+	0x000015c0, 0x000c1401, 0xffffffff,
+	0x0000264c, 0x000c0400, 0xffffffff,
+	0x00002648, 0x000c0400, 0xffffffff,
+	0x00002650, 0x000c0400, 0xffffffff,
+	0x000020b8, 0x000c0400, 0xffffffff,
+	0x000020bc, 0x000c0400, 0xffffffff,
+	0x000020c0, 0x000c0c80, 0xffffffff,
+	0x0000f4a0, 0x000000c0, 0xffffffff,
+	0x0000f4a4, 0x00680fff, 0xffffffff,
+	0x00002f50, 0x00000404, 0xffffffff,
+	0x000004c8, 0x00000001, 0xffffffff,
+	0x000064ec, 0x00000000, 0xffffffff,
+	0x00000c7c, 0x00000000, 0xffffffff,
+	0x00008dfc, 0x00000000, 0xffffffff
+};
+#define CAYMAN_SYSLS_DEFAULT_LENGTH sizeof(cayman_sysls_default) / (3 * sizeof(u32))
+
+static const u32 cayman_sysls_disable[] =
+{
+	/* Register,   Value,     Mask bits */
+	0x0000d0c0, 0x00000000, 0xffffffff,
+	0x0000d8c0, 0x00000000, 0xffffffff,
+	0x000055e8, 0x00000000, 0xffffffff,
+	0x0000d0bc, 0x00000000, 0xffffffff,
+	0x0000d8bc, 0x00000000, 0xffffffff,
+	0x000015c0, 0x00041401, 0xffffffff,
+	0x0000264c, 0x00040400, 0xffffffff,
+	0x00002648, 0x00040400, 0xffffffff,
+	0x00002650, 0x00040400, 0xffffffff,
+	0x000020b8, 0x00040400, 0xffffffff,
+	0x000020bc, 0x00040400, 0xffffffff,
+	0x000020c0, 0x00040c80, 0xffffffff,
+	0x0000f4a0, 0x000000c0, 0xffffffff,
+	0x0000f4a4, 0x00680000, 0xffffffff,
+	0x00002f50, 0x00000404, 0xffffffff,
+	0x000004c8, 0x00000001, 0xffffffff,
+	0x000064ec, 0x00007ffd, 0xffffffff,
+	0x00000c7c, 0x0000ff00, 0xffffffff,
+	0x00008dfc, 0x0000007f, 0xffffffff
+};
+#define CAYMAN_SYSLS_DISABLE_LENGTH sizeof(cayman_sysls_disable) / (3 * sizeof(u32))
+
+static const u32 cayman_sysls_enable[] =
+{
+	/* Register,   Value,     Mask bits */
+	0x000055e8, 0x00000001, 0xffffffff,
+	0x0000d0bc, 0x00000100, 0xffffffff,
+	0x0000d8bc, 0x00000100, 0xffffffff,
+	0x000015c0, 0x000c1401, 0xffffffff,
+	0x0000264c, 0x000c0400, 0xffffffff,
+	0x00002648, 0x000c0400, 0xffffffff,
+	0x00002650, 0x000c0400, 0xffffffff,
+	0x000020b8, 0x000c0400, 0xffffffff,
+	0x000020bc, 0x000c0400, 0xffffffff,
+	0x000020c0, 0x000c0c80, 0xffffffff,
+	0x0000f4a0, 0x000000c0, 0xffffffff,
+	0x0000f4a4, 0x00680fff, 0xffffffff,
+	0x00002f50, 0x00000903, 0xffffffff,
+	0x000004c8, 0x00000000, 0xffffffff,
+	0x000064ec, 0x00000000, 0xffffffff,
+	0x00000c7c, 0x00000000, 0xffffffff,
+	0x00008dfc, 0x00000000, 0xffffffff
+};
+#define CAYMAN_SYSLS_ENABLE_LENGTH sizeof(cayman_sysls_enable) / (3 * sizeof(u32))
+
+struct rv7xx_power_info *rv770_get_pi(struct radeon_device *rdev);
+struct evergreen_power_info *evergreen_get_pi(struct radeon_device *rdev);
+
+static struct ni_power_info *ni_get_pi(struct radeon_device *rdev)
+{
+        struct ni_power_info *pi = rdev->pm.dpm.priv;
+
+        return pi;
+}
+
+struct ni_ps *ni_get_ps(struct radeon_ps *rps)
+{
+	struct ni_ps *ps = rps->ps_priv;
+
+	return ps;
+}
+
+/* XXX: fix for kernel use  */
+#if 0
+static double ni_exp(double x)
+{
+	int count = 1;
+	double sum = 1.0, term, tolerance = 0.000000001, y = x;
+
+	if (x < 0)
+		y = -1 * x;
+	term  = y;
+
+	while (term >= tolerance) {
+		sum = sum + term;
+		count = count + 1;
+		term  = term * (y / count);
+	}
+
+	if (x < 0)
+		sum = 1.0 / sum;
+
+	return sum;
+}
+#endif
+
+static void ni_calculate_leakage_for_v_and_t_formula(const struct ni_leakage_coeffients *coeff,
+						     u16 v, s32 t,
+						     u32 ileakage,
+						     u32 *leakage)
+{
+/* XXX: fix for kernel use  */
+#if 0
+	double kt, kv, leakage_w, i_leakage, vddc, temperature;
+
+	i_leakage   = ((double)ileakage) / 1000;
+	vddc        = ((double)v) / 1000;
+	temperature = ((double)t) / 1000;
+
+	kt = (((double)(coeff->at)) / 1000) * ni_exp((((double)(coeff->bt)) / 1000) * temperature);
+	kv = (((double)(coeff->av)) / 1000) * ni_exp((((double)(coeff->bv)) / 1000) * vddc);
+
+	leakage_w = i_leakage * kt * kv * vddc;
+
+	*leakage = (u32)(leakage_w * 1000);
+#endif
+}
+
+static void ni_calculate_leakage_for_v_and_t(struct radeon_device *rdev,
+					     const struct ni_leakage_coeffients *coeff,
+					     u16 v,
+					     s32 t,
+					     u32 i_leakage,
+					     u32 *leakage)
+{
+	ni_calculate_leakage_for_v_and_t_formula(coeff, v, t, i_leakage, leakage);
+}
+
+static void ni_apply_state_adjust_rules(struct radeon_device *rdev)
+{
+	struct ni_power_info *ni_pi = ni_get_pi(rdev);
+	struct radeon_ps *rps = rdev->pm.dpm.requested_ps;
+	struct ni_ps *ps = ni_get_ps(rps);
+	struct radeon_clock_and_voltage_limits *max_limits;
+	bool disable_mclk_switching;
+	u32 mclk, sclk;
+	u16 vddc, vddci;
+	int i;
+
+	/* point to the hw copy since this function will modify the ps */
+	ni_pi->hw_ps = *ps;
+	rdev->pm.dpm.hw_ps.ps_priv = &ni_pi->hw_ps;
+	ps = &ni_pi->hw_ps;
+
+	if (rdev->pm.dpm.new_active_crtc_count > 1)
+		disable_mclk_switching = true;
+	else
+		disable_mclk_switching = false;
+
+	if (rdev->pm.dpm.ac_power)
+		max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
+	else
+		max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc;
+
+	if (rdev->pm.dpm.ac_power == false) {
+		for (i = 0; i < ps->performance_level_count; i++) {
+			if (ps->performance_levels[i].mclk > max_limits->mclk)
+				ps->performance_levels[i].mclk = max_limits->mclk;
+			if (ps->performance_levels[i].sclk > max_limits->sclk)
+				ps->performance_levels[i].sclk = max_limits->sclk;
+			if (ps->performance_levels[i].vddc > max_limits->vddc)
+				ps->performance_levels[i].vddc = max_limits->vddc;
+			if (ps->performance_levels[i].vddci > max_limits->vddci)
+				ps->performance_levels[i].vddci = max_limits->vddci;
+		}
+	}
+
+	/* XXX validate the min clocks required for display */
+
+	if (disable_mclk_switching) {
+		mclk  = ps->performance_levels[ps->performance_level_count - 1].mclk;
+		sclk = ps->performance_levels[0].sclk;
+		vddc = ps->performance_levels[0].vddc;
+		vddci = ps->performance_levels[ps->performance_level_count - 1].vddci;
+	} else {
+		sclk = ps->performance_levels[0].sclk;
+		mclk = ps->performance_levels[0].mclk;
+		vddc = ps->performance_levels[0].vddc;
+		vddci = ps->performance_levels[0].vddci;
+	}
+
+	/* adjusted low state */
+	ps->performance_levels[0].sclk = sclk;
+	ps->performance_levels[0].mclk = mclk;
+	ps->performance_levels[0].vddc = vddc;
+	ps->performance_levels[0].vddci = vddci;
+
+	btc_skip_blacklist_clocks(rdev, max_limits->sclk, max_limits->mclk,
+				  &ps->performance_levels[0].sclk,
+				  &ps->performance_levels[0].mclk);
+
+	for (i = 1; i < ps->performance_level_count; i++) {
+		if (ps->performance_levels[i].sclk < ps->performance_levels[i - 1].sclk)
+			ps->performance_levels[i].sclk = ps->performance_levels[i - 1].sclk;
+		if (ps->performance_levels[i].vddc < ps->performance_levels[i - 1].vddc)
+			ps->performance_levels[i].vddc = ps->performance_levels[i - 1].vddc;
+	}
+
+	if (disable_mclk_switching) {
+		mclk = ps->performance_levels[0].mclk;
+		for (i = 1; i < ps->performance_level_count; i++) {
+			if (mclk < ps->performance_levels[i].mclk)
+				mclk = ps->performance_levels[i].mclk;
+		}
+		for (i = 0; i < ps->performance_level_count; i++) {
+			ps->performance_levels[i].mclk = mclk;
+			ps->performance_levels[i].vddci = vddci;
+		}
+	} else {
+		for (i = 1; i < ps->performance_level_count; i++) {
+			if (ps->performance_levels[i].mclk < ps->performance_levels[i - 1].mclk)
+				ps->performance_levels[i].mclk = ps->performance_levels[i - 1].mclk;
+			if (ps->performance_levels[i].vddci < ps->performance_levels[i - 1].vddci)
+				ps->performance_levels[i].vddci = ps->performance_levels[i - 1].vddci;
+		}
+	}
+
+	for (i = 1; i < ps->performance_level_count; i++)
+		btc_skip_blacklist_clocks(rdev, max_limits->sclk, max_limits->mclk,
+					  &ps->performance_levels[i].sclk,
+					  &ps->performance_levels[i].mclk);
+
+	for (i = 0; i < ps->performance_level_count; i++)
+		btc_adjust_clock_combinations(rdev, max_limits,
+					      &ps->performance_levels[i]);
+
+	for (i = 0; i < ps->performance_level_count; i++) {
+		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);
+		btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk,
+						   ps->performance_levels[i].mclk,
+						   max_limits->vddci, &ps->performance_levels[i].vddci);
+		btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk,
+						   ps->performance_levels[i].mclk,
+						   max_limits->vddc,  &ps->performance_levels[i].vddc);
+		/* XXX validate the voltage required for display */
+	}
+
+	for (i = 0; i < ps->performance_level_count; i++) {
+		btc_apply_voltage_delta_rules(rdev,
+					      max_limits->vddc, max_limits->vddci,
+					      &ps->performance_levels[i].vddc,
+					      &ps->performance_levels[i].vddci);
+	}
+
+	ps->dc_compatible = true;
+	for (i = 0; i < ps->performance_level_count; i++) {
+		if (ps->performance_levels[i].vddc > rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc.vddc)
+			ps->dc_compatible = false;
+
+		if (ps->performance_levels[i].vddc < rdev->pm.dpm.dyn_state.min_vddc_for_pcie_gen2)
+			ps->performance_levels[i].flags &= ~ATOM_PPLIB_R600_FLAGS_PCIEGEN2;
+	}
+}
+
+static void ni_cg_clockgating_default(struct radeon_device *rdev)
+{
+	u32 count;
+	const u32 *ps = NULL;
+
+	ps = (const u32 *)&cayman_cgcg_cgls_default;
+	count = CAYMAN_CGCG_CGLS_DEFAULT_LENGTH;
+
+	btc_program_mgcg_hw_sequence(rdev, ps, count);
+}
+
+static void ni_gfx_clockgating_enable(struct radeon_device *rdev,
+				      bool enable)
+{
+	u32 count;
+	const u32 *ps = NULL;
+
+	if (enable) {
+		ps = (const u32 *)&cayman_cgcg_cgls_enable;
+		count = CAYMAN_CGCG_CGLS_ENABLE_LENGTH;
+	} else {
+		ps = (const u32 *)&cayman_cgcg_cgls_disable;
+		count = CAYMAN_CGCG_CGLS_DISABLE_LENGTH;
+	}
+
+	btc_program_mgcg_hw_sequence(rdev, ps, count);
+}
+
+static void ni_mg_clockgating_default(struct radeon_device *rdev)
+{
+	u32 count;
+	const u32 *ps = NULL;
+
+	ps = (const u32 *)&cayman_mgcg_default;
+	count = CAYMAN_MGCG_DEFAULT_LENGTH;
+
+	btc_program_mgcg_hw_sequence(rdev, ps, count);
+}
+
+static void ni_mg_clockgating_enable(struct radeon_device *rdev,
+				     bool enable)
+{
+	u32 count;
+	const u32 *ps = NULL;
+
+	if (enable) {
+		ps = (const u32 *)&cayman_mgcg_enable;
+		count = CAYMAN_MGCG_ENABLE_LENGTH;
+	} else {
+		ps = (const u32 *)&cayman_mgcg_disable;
+		count = CAYMAN_MGCG_DISABLE_LENGTH;
+	}
+
+	btc_program_mgcg_hw_sequence(rdev, ps, count);
+}
+
+static void ni_ls_clockgating_default(struct radeon_device *rdev)
+{
+	u32 count;
+	const u32 *ps = NULL;
+
+	ps = (const u32 *)&cayman_sysls_default;
+	count = CAYMAN_SYSLS_DEFAULT_LENGTH;
+
+	btc_program_mgcg_hw_sequence(rdev, ps, count);
+}
+
+static void ni_ls_clockgating_enable(struct radeon_device *rdev,
+				     bool enable)
+{
+	u32 count;
+	const u32 *ps = NULL;
+
+	if (enable) {
+		ps = (const u32 *)&cayman_sysls_enable;
+		count = CAYMAN_SYSLS_ENABLE_LENGTH;
+	} else {
+		ps = (const u32 *)&cayman_sysls_disable;
+		count = CAYMAN_SYSLS_DISABLE_LENGTH;
+	}
+
+	btc_program_mgcg_hw_sequence(rdev, ps, count);
+
+}
+
+static int ni_patch_single_dependency_table_based_on_leakage(struct radeon_device *rdev,
+							     struct radeon_clock_voltage_dependency_table *table)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	u32 i;
+
+	if (table) {
+		for (i = 0; i < table->count; i++) {
+			if (0xff01 == table->entries[i].v) {
+				if (pi->max_vddc == 0)
+					return -EINVAL;
+				table->entries[i].v = pi->max_vddc;
+			}
+		}
+	}
+	return 0;
+}
+
+static int ni_patch_dependency_tables_based_on_leakage(struct radeon_device *rdev)
+{
+	int ret = 0;
+
+	ret = ni_patch_single_dependency_table_based_on_leakage(rdev,
+								&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk);
+
+	ret = ni_patch_single_dependency_table_based_on_leakage(rdev,
+								&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk);
+	return ret;
+}
+
+static void ni_stop_dpm(struct radeon_device *rdev)
+{
+	WREG32_P(GENERAL_PWRMGT, 0, ~GLOBAL_PWRMGT_EN);
+}
+
+#if 0
+static int ni_notify_hw_of_power_source(struct radeon_device *rdev,
+					bool ac_power)
+{
+	if (ac_power)
+		return (rv770_send_msg_to_smc(rdev, PPSMC_MSG_RunningOnAC) == PPSMC_Result_OK) ?
+			0 : -EINVAL;
+
+	return 0;
+}
+#endif
+
+static PPSMC_Result ni_send_msg_to_smc_with_parameter(struct radeon_device *rdev,
+						      PPSMC_Msg msg, u32 parameter)
+{
+	WREG32(SMC_SCRATCH0, parameter);
+	return rv770_send_msg_to_smc(rdev, msg);
+}
+
+static int ni_restrict_performance_levels_before_switch(struct radeon_device *rdev)
+{
+	if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_NoForcedLevel) != PPSMC_Result_OK)
+		return -EINVAL;
+
+	return (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 1) == PPSMC_Result_OK) ?
+		0 : -EINVAL;
+}
+
+static void ni_stop_smc(struct radeon_device *rdev)
+{
+	u32 tmp;
+	int i;
+
+	for (i = 0; i < rdev->usec_timeout; i++) {
+		tmp = RREG32(LB_SYNC_RESET_SEL) & LB_SYNC_RESET_SEL_MASK;
+		if (tmp != 1)
+			break;
+		udelay(1);
+	}
+
+	udelay(100);
+
+	r7xx_stop_smc(rdev);
+}
+
+static int ni_process_firmware_header(struct radeon_device *rdev)
+{
+        struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+        struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+        struct ni_power_info *ni_pi = ni_get_pi(rdev);
+	u32 tmp;
+	int ret;
+
+	ret = rv770_read_smc_sram_dword(rdev,
+					NISLANDS_SMC_FIRMWARE_HEADER_LOCATION +
+					NISLANDS_SMC_FIRMWARE_HEADER_stateTable,
+					&tmp, pi->sram_end);
+
+	if (ret)
+		return ret;
+
+	pi->state_table_start = (u16)tmp;
+
+	ret = rv770_read_smc_sram_dword(rdev,
+					NISLANDS_SMC_FIRMWARE_HEADER_LOCATION +
+					NISLANDS_SMC_FIRMWARE_HEADER_softRegisters,
+					&tmp, pi->sram_end);
+
+	if (ret)
+		return ret;
+
+	pi->soft_regs_start = (u16)tmp;
+
+	ret = rv770_read_smc_sram_dword(rdev,
+					NISLANDS_SMC_FIRMWARE_HEADER_LOCATION +
+					NISLANDS_SMC_FIRMWARE_HEADER_mcRegisterTable,
+					&tmp, pi->sram_end);
+
+	if (ret)
+		return ret;
+
+	eg_pi->mc_reg_table_start = (u16)tmp;
+
+	ret = rv770_read_smc_sram_dword(rdev,
+					NISLANDS_SMC_FIRMWARE_HEADER_LOCATION +
+					NISLANDS_SMC_FIRMWARE_HEADER_fanTable,
+					&tmp, pi->sram_end);
+
+	if (ret)
+		return ret;
+
+	ni_pi->fan_table_start = (u16)tmp;
+
+	ret = rv770_read_smc_sram_dword(rdev,
+					NISLANDS_SMC_FIRMWARE_HEADER_LOCATION +
+					NISLANDS_SMC_FIRMWARE_HEADER_mcArbDramAutoRefreshTable,
+					&tmp, pi->sram_end);
+
+	if (ret)
+		return ret;
+
+	ni_pi->arb_table_start = (u16)tmp;
+
+	ret = rv770_read_smc_sram_dword(rdev,
+					NISLANDS_SMC_FIRMWARE_HEADER_LOCATION +
+					NISLANDS_SMC_FIRMWARE_HEADER_cacTable,
+					&tmp, pi->sram_end);
+
+	if (ret)
+		return ret;
+
+	ni_pi->cac_table_start = (u16)tmp;
+
+	ret = rv770_read_smc_sram_dword(rdev,
+					NISLANDS_SMC_FIRMWARE_HEADER_LOCATION +
+					NISLANDS_SMC_FIRMWARE_HEADER_spllTable,
+					&tmp, pi->sram_end);
+
+	if (ret)
+		return ret;
+
+	ni_pi->spll_table_start = (u16)tmp;
+
+
+	return ret;
+}
+
+static void ni_read_clock_registers(struct radeon_device *rdev)
+{
+	struct ni_power_info *ni_pi = ni_get_pi(rdev);
+
+	ni_pi->clock_registers.cg_spll_func_cntl = RREG32(CG_SPLL_FUNC_CNTL);
+	ni_pi->clock_registers.cg_spll_func_cntl_2 = RREG32(CG_SPLL_FUNC_CNTL_2);
+	ni_pi->clock_registers.cg_spll_func_cntl_3 = RREG32(CG_SPLL_FUNC_CNTL_3);
+	ni_pi->clock_registers.cg_spll_func_cntl_4 = RREG32(CG_SPLL_FUNC_CNTL_4);
+	ni_pi->clock_registers.cg_spll_spread_spectrum = RREG32(CG_SPLL_SPREAD_SPECTRUM);
+	ni_pi->clock_registers.cg_spll_spread_spectrum_2 = RREG32(CG_SPLL_SPREAD_SPECTRUM_2);
+	ni_pi->clock_registers.mpll_ad_func_cntl = RREG32(MPLL_AD_FUNC_CNTL);
+	ni_pi->clock_registers.mpll_ad_func_cntl_2 = RREG32(MPLL_AD_FUNC_CNTL_2);
+	ni_pi->clock_registers.mpll_dq_func_cntl = RREG32(MPLL_DQ_FUNC_CNTL);
+	ni_pi->clock_registers.mpll_dq_func_cntl_2 = RREG32(MPLL_DQ_FUNC_CNTL_2);
+	ni_pi->clock_registers.mclk_pwrmgt_cntl = RREG32(MCLK_PWRMGT_CNTL);
+	ni_pi->clock_registers.dll_cntl = RREG32(DLL_CNTL);
+	ni_pi->clock_registers.mpll_ss1 = RREG32(MPLL_SS1);
+	ni_pi->clock_registers.mpll_ss2 = RREG32(MPLL_SS2);
+}
+
+#if 0
+static int ni_enter_ulp_state(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+	if (pi->gfx_clock_gating) {
+                WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_GFX_CLK_OFF_EN);
+		WREG32_P(SCLK_PWRMGT_CNTL, GFX_CLK_FORCE_ON, ~GFX_CLK_FORCE_ON);
+                WREG32_P(SCLK_PWRMGT_CNTL, 0, ~GFX_CLK_FORCE_ON);
+		RREG32(GB_ADDR_CONFIG);
+        }
+
+	WREG32_P(SMC_MSG, HOST_SMC_MSG(PPSMC_MSG_SwitchToMinimumPower),
+                 ~HOST_SMC_MSG_MASK);
+
+	udelay(25000);
+
+	return 0;
+}
+#endif
+
+static void ni_program_response_times(struct radeon_device *rdev)
+{
+	u32 voltage_response_time, backbias_response_time, acpi_delay_time, vbi_time_out;
+	u32 vddc_dly, bb_dly, acpi_dly, vbi_dly, mclk_switch_limit;
+	u32 reference_clock;
+
+	rv770_write_smc_soft_register(rdev, NI_SMC_SOFT_REGISTER_mvdd_chg_time, 1);
+
+        voltage_response_time = (u32)rdev->pm.dpm.voltage_response_time;
+        backbias_response_time = (u32)rdev->pm.dpm.backbias_response_time;
+
+        if (voltage_response_time == 0)
+                voltage_response_time = 1000;
+
+        if (backbias_response_time == 0)
+                backbias_response_time = 1000;
+
+	acpi_delay_time = 15000;
+	vbi_time_out = 100000;
+
+	reference_clock = radeon_get_xclk(rdev);
+
+	vddc_dly = (voltage_response_time  * reference_clock) / 1600;
+	bb_dly   = (backbias_response_time * reference_clock) / 1600;
+	acpi_dly = (acpi_delay_time * reference_clock) / 1600;
+	vbi_dly  = (vbi_time_out * reference_clock) / 1600;
+
+	mclk_switch_limit = (460 * reference_clock) / 100;
+
+	rv770_write_smc_soft_register(rdev, NI_SMC_SOFT_REGISTER_delay_vreg,  vddc_dly);
+	rv770_write_smc_soft_register(rdev, NI_SMC_SOFT_REGISTER_delay_bbias, bb_dly);
+	rv770_write_smc_soft_register(rdev, NI_SMC_SOFT_REGISTER_delay_acpi,  acpi_dly);
+	rv770_write_smc_soft_register(rdev, NI_SMC_SOFT_REGISTER_mclk_chg_timeout, vbi_dly);
+	rv770_write_smc_soft_register(rdev, NI_SMC_SOFT_REGISTER_mc_block_delay, 0xAA);
+	rv770_write_smc_soft_register(rdev, NI_SMC_SOFT_REGISTER_mclk_switch_lim, mclk_switch_limit);
+}
+
+static void ni_populate_smc_voltage_table(struct radeon_device *rdev,
+					  struct atom_voltage_table *voltage_table,
+					  NISLANDS_SMC_STATETABLE *table)
+{
+	unsigned int i;
+
+	for (i = 0; i < voltage_table->count; i++) {
+		table->highSMIO[i] = 0;
+		table->lowSMIO[i] |= cpu_to_be32(voltage_table->entries[i].smio_low);
+	}
+}
+
+static void ni_populate_smc_voltage_tables(struct radeon_device *rdev,
+					   NISLANDS_SMC_STATETABLE *table)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+        struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	unsigned char i;
+
+	if (eg_pi->vddc_voltage_table.count) {
+		ni_populate_smc_voltage_table(rdev, &eg_pi->vddc_voltage_table, table);
+		table->voltageMaskTable.highMask[NISLANDS_SMC_VOLTAGEMASK_VDDC] = 0;
+		table->voltageMaskTable.lowMask[NISLANDS_SMC_VOLTAGEMASK_VDDC] =
+			cpu_to_be32(eg_pi->vddc_voltage_table.mask_low);
+
+		for (i = 0; i < eg_pi->vddc_voltage_table.count; i++) {
+			if (pi->max_vddc_in_table <= eg_pi->vddc_voltage_table.entries[i].value) {
+				table->maxVDDCIndexInPPTable = i;
+				break;
+			}
+		}
+	}
+
+	if (eg_pi->vddci_voltage_table.count) {
+		ni_populate_smc_voltage_table(rdev, &eg_pi->vddci_voltage_table, table);
+
+		table->voltageMaskTable.highMask[NISLANDS_SMC_VOLTAGEMASK_VDDCI] = 0;
+		table->voltageMaskTable.lowMask[NISLANDS_SMC_VOLTAGEMASK_VDDCI] =
+			cpu_to_be32(eg_pi->vddc_voltage_table.mask_low);
+	}
+}
+
+static int ni_populate_voltage_value(struct radeon_device *rdev,
+				     struct atom_voltage_table *table,
+				     u16 value,
+				     NISLANDS_SMC_VOLTAGE_VALUE *voltage)
+{
+	unsigned int i;
+
+	for (i = 0; i < table->count; i++) {
+		if (value <= table->entries[i].value) {
+			voltage->index = (u8)i;
+			voltage->value = cpu_to_be16(table->entries[i].value);
+			break;
+		}
+	}
+
+	if (i >= table->count)
+		return -EINVAL;
+
+	return 0;
+}
+
+static void ni_populate_mvdd_value(struct radeon_device *rdev,
+				   u32 mclk,
+				   NISLANDS_SMC_VOLTAGE_VALUE *voltage)
+{
+        struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+        struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+
+	if (!pi->mvdd_control) {
+		voltage->index = eg_pi->mvdd_high_index;
+                voltage->value = cpu_to_be16(MVDD_HIGH_VALUE);
+		return;
+        }
+
+        if (mclk <= pi->mvdd_split_frequency) {
+                voltage->index = eg_pi->mvdd_low_index;
+                voltage->value = cpu_to_be16(MVDD_LOW_VALUE);
+	} else {
+		voltage->index = eg_pi->mvdd_high_index;
+		voltage->value = cpu_to_be16(MVDD_HIGH_VALUE);
+        }
+}
+
+static int ni_get_std_voltage_value(struct radeon_device *rdev,
+				    NISLANDS_SMC_VOLTAGE_VALUE *voltage,
+				    u16 *std_voltage)
+{
+	if (rdev->pm.dpm.dyn_state.cac_leakage_table.entries &&
+	    ((u32)voltage->index < rdev->pm.dpm.dyn_state.cac_leakage_table.count))
+		*std_voltage = rdev->pm.dpm.dyn_state.cac_leakage_table.entries[voltage->index].vddc;
+	else
+		*std_voltage = be16_to_cpu(voltage->value);
+
+	return 0;
+}
+
+static void ni_populate_std_voltage_value(struct radeon_device *rdev,
+					  u16 value, u8 index,
+					  NISLANDS_SMC_VOLTAGE_VALUE *voltage)
+{
+	voltage->index = index;
+	voltage->value = cpu_to_be16(value);
+}
+
+static u32 ni_get_smc_power_scaling_factor(struct radeon_device *rdev)
+{
+	u32 xclk_period;
+	u32 xclk = radeon_get_xclk(rdev);
+	u32 tmp = RREG32(CG_CAC_CTRL) & TID_CNT_MASK;
+
+	xclk_period = (1000000000UL / xclk);
+	xclk_period /= 10000UL;
+
+	return tmp * xclk_period;
+}
+
+static u32 ni_scale_power_for_smc(u32 power_in_watts, u32 scaling_factor)
+{
+	return (power_in_watts * scaling_factor) << 2;
+}
+
+static u32 ni_calculate_power_boost_limit(struct radeon_device *rdev,
+					  struct radeon_ps *radeon_state,
+					  u32 near_tdp_limit)
+{
+	struct ni_ps *state = ni_get_ps(radeon_state);
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	struct ni_power_info *ni_pi = ni_get_pi(rdev);
+	u32 power_boost_limit = 0;
+	int ret;
+
+	if (ni_pi->enable_power_containment &&
+	    ni_pi->use_power_boost_limit) {
+		NISLANDS_SMC_VOLTAGE_VALUE vddc;
+		u16 std_vddc_med;
+		u16 std_vddc_high;
+		u64 tmp;
+
+		if (state->performance_level_count < 3)
+			return 0;
+
+		ret = ni_populate_voltage_value(rdev, &eg_pi->vddc_voltage_table,
+						state->performance_levels[state->performance_level_count - 2].vddc,
+						&vddc);
+		if (ret)
+			return 0;
+
+		ret = ni_get_std_voltage_value(rdev, &vddc, &std_vddc_med);
+		if (ret)
+			return 0;
+
+		ret = ni_populate_voltage_value(rdev, &eg_pi->vddc_voltage_table,
+						state->performance_levels[state->performance_level_count - 1].vddc,
+						&vddc);
+		if (ret)
+			return 0;
+
+		ret = ni_get_std_voltage_value(rdev, &vddc, &std_vddc_high);
+		if (ret)
+			return 0;
+
+		tmp = ((u64)near_tdp_limit * ((u64)std_vddc_med * (u64)std_vddc_med) * 90) /
+			((u64)std_vddc_high * (u64)std_vddc_high * 100);
+		if (tmp >> 32)
+			return 0;
+		power_boost_limit = (u32)tmp;
+	}
+
+	return power_boost_limit;
+}
+
+static int ni_calculate_adjusted_tdp_limits(struct radeon_device *rdev,
+					    bool adjust_polarity,
+					    u32 tdp_adjustment,
+					    u32 *tdp_limit,
+					    u32 *near_tdp_limit)
+{
+	if (tdp_adjustment > (u32)rdev->pm.dpm.tdp_od_limit)
+		return -EINVAL;
+
+	if (adjust_polarity) {
+		*tdp_limit = ((100 + tdp_adjustment) * rdev->pm.dpm.tdp_limit) / 100;
+		*near_tdp_limit = rdev->pm.dpm.near_tdp_limit + (*tdp_limit - rdev->pm.dpm.tdp_limit);
+	} else {
+		*tdp_limit = ((100 - tdp_adjustment) * rdev->pm.dpm.tdp_limit) / 100;
+		*near_tdp_limit = rdev->pm.dpm.near_tdp_limit - (rdev->pm.dpm.tdp_limit - *tdp_limit);
+	}
+
+	return 0;
+}
+
+static int ni_populate_smc_tdp_limits(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	struct ni_power_info *ni_pi = ni_get_pi(rdev);
+
+	if (ni_pi->enable_power_containment) {
+		struct radeon_ps *radeon_state = rdev->pm.dpm.requested_ps;
+		NISLANDS_SMC_STATETABLE *smc_table = &ni_pi->smc_statetable;
+		u32 scaling_factor = ni_get_smc_power_scaling_factor(rdev);
+		u32 tdp_limit;
+		u32 near_tdp_limit;
+		u32 power_boost_limit;
+		int ret;
+
+		if (scaling_factor == 0)
+			return -EINVAL;
+
+		memset(smc_table, 0, sizeof(NISLANDS_SMC_STATETABLE));
+
+		ret = ni_calculate_adjusted_tdp_limits(rdev,
+						       false, /* ??? */
+						       rdev->pm.dpm.tdp_adjustment,
+						       &tdp_limit,
+						       &near_tdp_limit);
+		if (ret)
+			return ret;
+
+		power_boost_limit = ni_calculate_power_boost_limit(rdev, radeon_state,
+								   near_tdp_limit);
+
+		smc_table->dpm2Params.TDPLimit =
+			cpu_to_be32(ni_scale_power_for_smc(tdp_limit, scaling_factor));
+		smc_table->dpm2Params.NearTDPLimit =
+			cpu_to_be32(ni_scale_power_for_smc(near_tdp_limit, scaling_factor));
+		smc_table->dpm2Params.SafePowerLimit =
+			cpu_to_be32(ni_scale_power_for_smc((near_tdp_limit * NISLANDS_DPM2_TDP_SAFE_LIMIT_PERCENT) / 100,
+							   scaling_factor));
+		smc_table->dpm2Params.PowerBoostLimit =
+			cpu_to_be32(ni_scale_power_for_smc(power_boost_limit, scaling_factor));
+
+		ret = rv770_copy_bytes_to_smc(rdev,
+					      (u16)(pi->state_table_start + offsetof(NISLANDS_SMC_STATETABLE, dpm2Params) +
+						    offsetof(PP_NIslands_DPM2Parameters, TDPLimit)),
+					      (u8 *)(&smc_table->dpm2Params.TDPLimit),
+					      sizeof(u32) * 4, pi->sram_end);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int ni_copy_and_switch_arb_sets(struct radeon_device *rdev,
+				       u32 arb_freq_src, u32 arb_freq_dest)
+{
+	u32 mc_arb_dram_timing;
+	u32 mc_arb_dram_timing2;
+	u32 burst_time;
+	u32 mc_cg_config;
+
+	switch (arb_freq_src) {
+        case MC_CG_ARB_FREQ_F0:
+		mc_arb_dram_timing  = RREG32(MC_ARB_DRAM_TIMING);
+		mc_arb_dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2);
+		burst_time = (RREG32(MC_ARB_BURST_TIME) & STATE0_MASK) >> STATE0_SHIFT;
+		break;
+        case MC_CG_ARB_FREQ_F1:
+		mc_arb_dram_timing  = RREG32(MC_ARB_DRAM_TIMING_1);
+		mc_arb_dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2_1);
+		burst_time = (RREG32(MC_ARB_BURST_TIME) & STATE1_MASK) >> STATE1_SHIFT;
+		break;
+        case MC_CG_ARB_FREQ_F2:
+		mc_arb_dram_timing  = RREG32(MC_ARB_DRAM_TIMING_2);
+		mc_arb_dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2_2);
+		burst_time = (RREG32(MC_ARB_BURST_TIME) & STATE2_MASK) >> STATE2_SHIFT;
+		break;
+        case MC_CG_ARB_FREQ_F3:
+		mc_arb_dram_timing  = RREG32(MC_ARB_DRAM_TIMING_3);
+		mc_arb_dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2_3);
+		burst_time = (RREG32(MC_ARB_BURST_TIME) & STATE3_MASK) >> STATE3_SHIFT;
+		break;
+        default:
+		return -EINVAL;
+	}
+
+	switch (arb_freq_dest) {
+        case MC_CG_ARB_FREQ_F0:
+		WREG32(MC_ARB_DRAM_TIMING, mc_arb_dram_timing);
+		WREG32(MC_ARB_DRAM_TIMING2, mc_arb_dram_timing2);
+		WREG32_P(MC_ARB_BURST_TIME, STATE0(burst_time), ~STATE0_MASK);
+		break;
+        case MC_CG_ARB_FREQ_F1:
+		WREG32(MC_ARB_DRAM_TIMING_1, mc_arb_dram_timing);
+		WREG32(MC_ARB_DRAM_TIMING2_1, mc_arb_dram_timing2);
+		WREG32_P(MC_ARB_BURST_TIME, STATE1(burst_time), ~STATE1_MASK);
+		break;
+        case MC_CG_ARB_FREQ_F2:
+		WREG32(MC_ARB_DRAM_TIMING_2, mc_arb_dram_timing);
+		WREG32(MC_ARB_DRAM_TIMING2_2, mc_arb_dram_timing2);
+		WREG32_P(MC_ARB_BURST_TIME, STATE2(burst_time), ~STATE2_MASK);
+		break;
+        case MC_CG_ARB_FREQ_F3:
+		WREG32(MC_ARB_DRAM_TIMING_3, mc_arb_dram_timing);
+		WREG32(MC_ARB_DRAM_TIMING2_3, mc_arb_dram_timing2);
+		WREG32_P(MC_ARB_BURST_TIME, STATE3(burst_time), ~STATE3_MASK);
+		break;
+        default:
+		return -EINVAL;
+	}
+
+	mc_cg_config = RREG32(MC_CG_CONFIG) | 0x0000000F;
+	WREG32(MC_CG_CONFIG, mc_cg_config);
+	WREG32_P(MC_ARB_CG, CG_ARB_REQ(arb_freq_dest), ~CG_ARB_REQ_MASK);
+
+	return 0;
+}
+
+static int ni_init_arb_table_index(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	struct ni_power_info *ni_pi = ni_get_pi(rdev);
+	u32 tmp;
+	int ret;
+
+	ret = rv770_read_smc_sram_dword(rdev, ni_pi->arb_table_start,
+					&tmp, pi->sram_end);
+	if (ret)
+		return ret;
+
+	tmp &= 0x00FFFFFF;
+	tmp |= ((u32)MC_CG_ARB_FREQ_F1) << 24;
+
+	return rv770_write_smc_sram_dword(rdev, ni_pi->arb_table_start,
+					  tmp, pi->sram_end);
+}
+
+static int ni_initial_switch_from_arb_f0_to_f1(struct radeon_device *rdev)
+{
+	return ni_copy_and_switch_arb_sets(rdev, MC_CG_ARB_FREQ_F0, MC_CG_ARB_FREQ_F1);
+}
+
+static int ni_force_switch_to_arb_f0(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	struct ni_power_info *ni_pi = ni_get_pi(rdev);
+	u32 tmp;
+	int ret;
+
+	ret = rv770_read_smc_sram_dword(rdev, ni_pi->arb_table_start,
+					&tmp, pi->sram_end);
+	if (ret)
+		return ret;
+
+	tmp = (tmp >> 24) & 0xff;
+
+	if (tmp == MC_CG_ARB_FREQ_F0)
+		return 0;
+
+	return ni_copy_and_switch_arb_sets(rdev, tmp, MC_CG_ARB_FREQ_F0);
+}
+
+static int ni_populate_memory_timing_parameters(struct radeon_device *rdev,
+						struct rv7xx_pl *pl,
+						SMC_NIslands_MCArbDramTimingRegisterSet *arb_regs)
+{
+	u32 dram_timing;
+	u32 dram_timing2;
+
+	arb_regs->mc_arb_rfsh_rate =
+		(u8)rv770_calculate_memory_refresh_rate(rdev, pl->sclk);
+
+
+	radeon_atom_set_engine_dram_timings(rdev,
+                                            pl->sclk,
+                                            pl->mclk);
+
+	dram_timing = RREG32(MC_ARB_DRAM_TIMING);
+	dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2);
+
+	arb_regs->mc_arb_dram_timing  = cpu_to_be32(dram_timing);
+	arb_regs->mc_arb_dram_timing2 = cpu_to_be32(dram_timing2);
+
+	return 0;
+}
+
+static int ni_do_program_memory_timing_parameters(struct radeon_device *rdev,
+						  struct radeon_ps *radeon_state,
+						  unsigned int first_arb_set)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	struct ni_power_info *ni_pi = ni_get_pi(rdev);
+	struct ni_ps *state = ni_get_ps(radeon_state);
+	SMC_NIslands_MCArbDramTimingRegisterSet arb_regs = { 0 };
+	int i, ret = 0;
+
+	for (i = 0; i < state->performance_level_count; i++) {
+		ret = ni_populate_memory_timing_parameters(rdev, &state->performance_levels[i], &arb_regs);
+		if (ret)
+			break;
+
+		ret = rv770_copy_bytes_to_smc(rdev,
+					      (u16)(ni_pi->arb_table_start +
+						    offsetof(SMC_NIslands_MCArbDramTimingRegisters, data) +
+						    sizeof(SMC_NIslands_MCArbDramTimingRegisterSet) * (first_arb_set + i)),
+					      (u8 *)&arb_regs,
+					      (u16)sizeof(SMC_NIslands_MCArbDramTimingRegisterSet),
+					      pi->sram_end);
+		if (ret)
+			break;
+	}
+	return ret;
+}
+
+static int ni_program_memory_timing_parameters(struct radeon_device *rdev)
+{
+	struct radeon_ps *radeon_new_state = rdev->pm.dpm.requested_ps;
+
+	return ni_do_program_memory_timing_parameters(rdev, radeon_new_state,
+						      NISLANDS_DRIVER_STATE_ARB_INDEX);
+}
+
+static void ni_populate_initial_mvdd_value(struct radeon_device *rdev,
+					   struct NISLANDS_SMC_VOLTAGE_VALUE *voltage)
+{
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+
+	voltage->index = eg_pi->mvdd_high_index;
+	voltage->value = cpu_to_be16(MVDD_HIGH_VALUE);
+}
+
+static int ni_populate_smc_initial_state(struct radeon_device *rdev,
+					 struct radeon_ps *radeon_initial_state,
+					 NISLANDS_SMC_STATETABLE *table)
+{
+	struct ni_ps *initial_state = ni_get_ps(radeon_initial_state);
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	struct ni_power_info *ni_pi = ni_get_pi(rdev);
+	u32 reg;
+	int ret;
+
+	table->initialState.levels[0].mclk.vMPLL_AD_FUNC_CNTL =
+		cpu_to_be32(ni_pi->clock_registers.mpll_ad_func_cntl);
+	table->initialState.levels[0].mclk.vMPLL_AD_FUNC_CNTL_2 =
+		cpu_to_be32(ni_pi->clock_registers.mpll_ad_func_cntl_2);
+	table->initialState.levels[0].mclk.vMPLL_DQ_FUNC_CNTL =
+		cpu_to_be32(ni_pi->clock_registers.mpll_dq_func_cntl);
+	table->initialState.levels[0].mclk.vMPLL_DQ_FUNC_CNTL_2 =
+		cpu_to_be32(ni_pi->clock_registers.mpll_dq_func_cntl_2);
+	table->initialState.levels[0].mclk.vMCLK_PWRMGT_CNTL =
+		cpu_to_be32(ni_pi->clock_registers.mclk_pwrmgt_cntl);
+	table->initialState.levels[0].mclk.vDLL_CNTL =
+		cpu_to_be32(ni_pi->clock_registers.dll_cntl);
+	table->initialState.levels[0].mclk.vMPLL_SS =
+		cpu_to_be32(ni_pi->clock_registers.mpll_ss1);
+	table->initialState.levels[0].mclk.vMPLL_SS2 =
+		cpu_to_be32(ni_pi->clock_registers.mpll_ss2);
+	table->initialState.levels[0].mclk.mclk_value =
+		cpu_to_be32(initial_state->performance_levels[0].mclk);
+
+	table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL =
+		cpu_to_be32(ni_pi->clock_registers.cg_spll_func_cntl);
+	table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_2 =
+		cpu_to_be32(ni_pi->clock_registers.cg_spll_func_cntl_2);
+	table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_3 =
+		cpu_to_be32(ni_pi->clock_registers.cg_spll_func_cntl_3);
+	table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_4 =
+		cpu_to_be32(ni_pi->clock_registers.cg_spll_func_cntl_4);
+	table->initialState.levels[0].sclk.vCG_SPLL_SPREAD_SPECTRUM =
+		cpu_to_be32(ni_pi->clock_registers.cg_spll_spread_spectrum);
+	table->initialState.levels[0].sclk.vCG_SPLL_SPREAD_SPECTRUM_2 =
+		cpu_to_be32(ni_pi->clock_registers.cg_spll_spread_spectrum_2);
+	table->initialState.levels[0].sclk.sclk_value =
+		cpu_to_be32(initial_state->performance_levels[0].sclk);
+	table->initialState.levels[0].arbRefreshState =
+		NISLANDS_INITIAL_STATE_ARB_INDEX;
+
+	table->initialState.levels[0].ACIndex = 0;
+
+	ret = ni_populate_voltage_value(rdev, &eg_pi->vddc_voltage_table,
+					initial_state->performance_levels[0].vddc,
+					&table->initialState.levels[0].vddc);
+	if (!ret) {
+		u16 std_vddc;
+
+		ret = ni_get_std_voltage_value(rdev,
+					       &table->initialState.levels[0].vddc,
+					       &std_vddc);
+		if (!ret)
+			ni_populate_std_voltage_value(rdev, std_vddc,
+						      table->initialState.levels[0].vddc.index,
+						      &table->initialState.levels[0].std_vddc);
+	}
+
+	if (eg_pi->vddci_control)
+		ni_populate_voltage_value(rdev,
+					  &eg_pi->vddci_voltage_table,
+					  initial_state->performance_levels[0].vddci,
+					  &table->initialState.levels[0].vddci);
+
+	ni_populate_initial_mvdd_value(rdev, &table->initialState.levels[0].mvdd);
+
+	reg = CG_R(0xffff) | CG_L(0);
+	table->initialState.levels[0].aT = cpu_to_be32(reg);
+
+	table->initialState.levels[0].bSP = cpu_to_be32(pi->dsp);
+
+	if (pi->boot_in_gen2)
+		table->initialState.levels[0].gen2PCIE = 1;
+	else
+		table->initialState.levels[0].gen2PCIE = 0;
+
+	if (pi->mem_gddr5) {
+		table->initialState.levels[0].strobeMode =
+			cypress_get_strobe_mode_settings(rdev,
+							 initial_state->performance_levels[0].mclk);
+
+		if (initial_state->performance_levels[0].mclk > pi->mclk_edc_enable_threshold)
+			table->initialState.levels[0].mcFlags = NISLANDS_SMC_MC_EDC_RD_FLAG | NISLANDS_SMC_MC_EDC_WR_FLAG;
+		else
+			table->initialState.levels[0].mcFlags =  0;
+	}
+
+	table->initialState.levelCount = 1;
+
+	table->initialState.flags |= PPSMC_SWSTATE_FLAG_DC;
+
+	table->initialState.levels[0].dpm2.MaxPS = 0;
+	table->initialState.levels[0].dpm2.NearTDPDec = 0;
+	table->initialState.levels[0].dpm2.AboveSafeInc = 0;
+	table->initialState.levels[0].dpm2.BelowSafeInc = 0;
+
+	reg = MIN_POWER_MASK | MAX_POWER_MASK;
+	table->initialState.levels[0].SQPowerThrottle = cpu_to_be32(reg);
+
+	reg = MAX_POWER_DELTA_MASK | STI_SIZE_MASK | LTI_RATIO_MASK;
+	table->initialState.levels[0].SQPowerThrottle_2 = cpu_to_be32(reg);
+
+	return 0;
+}
+
+static int ni_populate_smc_acpi_state(struct radeon_device *rdev,
+				      NISLANDS_SMC_STATETABLE *table)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	struct ni_power_info *ni_pi = ni_get_pi(rdev);
+	u32 mpll_ad_func_cntl   = ni_pi->clock_registers.mpll_ad_func_cntl;
+	u32 mpll_ad_func_cntl_2 = ni_pi->clock_registers.mpll_ad_func_cntl_2;
+	u32 mpll_dq_func_cntl   = ni_pi->clock_registers.mpll_dq_func_cntl;
+	u32 mpll_dq_func_cntl_2 = ni_pi->clock_registers.mpll_dq_func_cntl_2;
+	u32 spll_func_cntl      = ni_pi->clock_registers.cg_spll_func_cntl;
+	u32 spll_func_cntl_2    = ni_pi->clock_registers.cg_spll_func_cntl_2;
+	u32 spll_func_cntl_3    = ni_pi->clock_registers.cg_spll_func_cntl_3;
+	u32 spll_func_cntl_4    = ni_pi->clock_registers.cg_spll_func_cntl_4;
+	u32 mclk_pwrmgt_cntl    = ni_pi->clock_registers.mclk_pwrmgt_cntl;
+	u32 dll_cntl            = ni_pi->clock_registers.dll_cntl;
+	u32 reg;
+	int ret;
+
+	table->ACPIState = table->initialState;
+
+	table->ACPIState.flags &= ~PPSMC_SWSTATE_FLAG_DC;
+
+	if (pi->acpi_vddc) {
+		ret = ni_populate_voltage_value(rdev,
+						&eg_pi->vddc_voltage_table,
+						pi->acpi_vddc, &table->ACPIState.levels[0].vddc);
+		if (!ret) {
+			u16 std_vddc;
+
+			ret = ni_get_std_voltage_value(rdev,
+						       &table->ACPIState.levels[0].vddc, &std_vddc);
+			if (!ret)
+				ni_populate_std_voltage_value(rdev, std_vddc,
+							      table->ACPIState.levels[0].vddc.index,
+							      &table->ACPIState.levels[0].std_vddc);
+		}
+
+		if (pi->pcie_gen2) {
+			if (pi->acpi_pcie_gen2)
+				table->ACPIState.levels[0].gen2PCIE = 1;
+			else
+				table->ACPIState.levels[0].gen2PCIE = 0;
+		} else {
+			table->ACPIState.levels[0].gen2PCIE = 0;
+		}
+	} else {
+		ret = ni_populate_voltage_value(rdev,
+						&eg_pi->vddc_voltage_table,
+						pi->min_vddc_in_table,
+						&table->ACPIState.levels[0].vddc);
+		if (!ret) {
+			u16 std_vddc;
+
+			ret = ni_get_std_voltage_value(rdev,
+						       &table->ACPIState.levels[0].vddc,
+						       &std_vddc);
+			if (!ret)
+				ni_populate_std_voltage_value(rdev, std_vddc,
+							      table->ACPIState.levels[0].vddc.index,
+							      &table->ACPIState.levels[0].std_vddc);
+		}
+		table->ACPIState.levels[0].gen2PCIE = 0;
+	}
+
+	if (eg_pi->acpi_vddci) {
+		if (eg_pi->vddci_control)
+			ni_populate_voltage_value(rdev,
+						  &eg_pi->vddci_voltage_table,
+						  eg_pi->acpi_vddci,
+						  &table->ACPIState.levels[0].vddci);
+	}
+
+
+	mpll_ad_func_cntl &= ~PDNB;
+
+	mpll_ad_func_cntl_2 |= BIAS_GEN_PDNB | RESET_EN;
+
+        if (pi->mem_gddr5)
+                mpll_dq_func_cntl &= ~PDNB;
+        mpll_dq_func_cntl_2 |= BIAS_GEN_PDNB | RESET_EN | BYPASS;
+
+
+        mclk_pwrmgt_cntl |= (MRDCKA0_RESET |
+                             MRDCKA1_RESET |
+                             MRDCKB0_RESET |
+                             MRDCKB1_RESET |
+                             MRDCKC0_RESET |
+                             MRDCKC1_RESET |
+                             MRDCKD0_RESET |
+                             MRDCKD1_RESET);
+
+        mclk_pwrmgt_cntl &= ~(MRDCKA0_PDNB |
+                              MRDCKA1_PDNB |
+			      MRDCKB0_PDNB |
+                              MRDCKB1_PDNB |
+			      MRDCKC0_PDNB |
+                              MRDCKC1_PDNB |
+                              MRDCKD0_PDNB |
+                              MRDCKD1_PDNB);
+
+	dll_cntl |= (MRDCKA0_BYPASS |
+                     MRDCKA1_BYPASS |
+                     MRDCKB0_BYPASS |
+                     MRDCKB1_BYPASS |
+                     MRDCKC0_BYPASS |
+                     MRDCKC1_BYPASS |
+                     MRDCKD0_BYPASS |
+                     MRDCKD1_BYPASS);
+
+        spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK;
+	spll_func_cntl_2 |= SCLK_MUX_SEL(4);
+
+	table->ACPIState.levels[0].mclk.vMPLL_AD_FUNC_CNTL = cpu_to_be32(mpll_ad_func_cntl);
+	table->ACPIState.levels[0].mclk.vMPLL_AD_FUNC_CNTL_2 = cpu_to_be32(mpll_ad_func_cntl_2);
+	table->ACPIState.levels[0].mclk.vMPLL_DQ_FUNC_CNTL = cpu_to_be32(mpll_dq_func_cntl);
+	table->ACPIState.levels[0].mclk.vMPLL_DQ_FUNC_CNTL_2 = cpu_to_be32(mpll_dq_func_cntl_2);
+	table->ACPIState.levels[0].mclk.vMCLK_PWRMGT_CNTL = cpu_to_be32(mclk_pwrmgt_cntl);
+	table->ACPIState.levels[0].mclk.vDLL_CNTL = cpu_to_be32(dll_cntl);
+
+	table->ACPIState.levels[0].mclk.mclk_value = 0;
+
+	table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL = cpu_to_be32(spll_func_cntl);
+	table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_2 = cpu_to_be32(spll_func_cntl_2);
+	table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_3 = cpu_to_be32(spll_func_cntl_3);
+	table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_4 = cpu_to_be32(spll_func_cntl_4);
+
+	table->ACPIState.levels[0].sclk.sclk_value = 0;
+
+	ni_populate_mvdd_value(rdev, 0, &table->ACPIState.levels[0].mvdd);
+
+	if (eg_pi->dynamic_ac_timing)
+		table->ACPIState.levels[0].ACIndex = 1;
+
+	table->ACPIState.levels[0].dpm2.MaxPS = 0;
+	table->ACPIState.levels[0].dpm2.NearTDPDec = 0;
+	table->ACPIState.levels[0].dpm2.AboveSafeInc = 0;
+	table->ACPIState.levels[0].dpm2.BelowSafeInc = 0;
+
+	reg = MIN_POWER_MASK | MAX_POWER_MASK;
+	table->ACPIState.levels[0].SQPowerThrottle = cpu_to_be32(reg);
+
+	reg = MAX_POWER_DELTA_MASK | STI_SIZE_MASK | LTI_RATIO_MASK;
+	table->ACPIState.levels[0].SQPowerThrottle_2 = cpu_to_be32(reg);
+
+	return 0;
+}
+
+static int ni_init_smc_table(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	struct ni_power_info *ni_pi = ni_get_pi(rdev);
+	int ret;
+	struct radeon_ps *radeon_boot_state = rdev->pm.dpm.boot_ps;
+	NISLANDS_SMC_STATETABLE *table = &ni_pi->smc_statetable;
+
+	memset(table, 0, sizeof(NISLANDS_SMC_STATETABLE));
+
+	ni_populate_smc_voltage_tables(rdev, table);
+
+        switch (rdev->pm.int_thermal_type) {
+        case THERMAL_TYPE_NI:
+        case THERMAL_TYPE_EMC2103_WITH_INTERNAL:
+                table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_INTERNAL;
+                break;
+        case THERMAL_TYPE_NONE:
+                table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_NONE;
+		break;
+        default:
+                table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_EXTERNAL;
+                break;
+        }
+
+	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_HARDWAREDC)
+		table->systemFlags |= PPSMC_SYSTEMFLAG_GPIO_DC;
+
+	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_REGULATOR_HOT)
+		table->systemFlags |= PPSMC_SYSTEMFLAG_REGULATOR_HOT;
+
+	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC)
+		table->systemFlags |= PPSMC_SYSTEMFLAG_STEPVDDC;
+
+	if (pi->mem_gddr5)
+		table->systemFlags |= PPSMC_SYSTEMFLAG_GDDR5;
+
+	ret = ni_populate_smc_initial_state(rdev, radeon_boot_state, table);
+	if (ret)
+		return ret;
+
+	ret = ni_populate_smc_acpi_state(rdev, table);
+	if (ret)
+		return ret;
+
+	table->driverState = table->initialState;
+
+	table->ULVState = table->initialState;
+
+	ret = ni_do_program_memory_timing_parameters(rdev, radeon_boot_state,
+						     NISLANDS_INITIAL_STATE_ARB_INDEX);
+	if (ret)
+		return ret;
+
+	return rv770_copy_bytes_to_smc(rdev, pi->state_table_start, (u8 *)table,
+				       sizeof(NISLANDS_SMC_STATETABLE), pi->sram_end);
+}
+
+static int ni_calculate_sclk_params(struct radeon_device *rdev,
+				    u32 engine_clock,
+				    NISLANDS_SMC_SCLK_VALUE *sclk)
+{
+        struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	struct ni_power_info *ni_pi = ni_get_pi(rdev);
+	struct atom_clock_dividers dividers;
+	u32 spll_func_cntl = ni_pi->clock_registers.cg_spll_func_cntl;
+	u32 spll_func_cntl_2 = ni_pi->clock_registers.cg_spll_func_cntl_2;
+	u32 spll_func_cntl_3 = ni_pi->clock_registers.cg_spll_func_cntl_3;
+	u32 spll_func_cntl_4 = ni_pi->clock_registers.cg_spll_func_cntl_4;
+	u32 cg_spll_spread_spectrum = ni_pi->clock_registers.cg_spll_spread_spectrum;
+	u32 cg_spll_spread_spectrum_2 = ni_pi->clock_registers.cg_spll_spread_spectrum_2;
+	u64 tmp;
+	u32 reference_clock = rdev->clock.spll.reference_freq;
+	u32 reference_divider;
+	u32 fbdiv;
+	int ret;
+
+        ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
+                                             engine_clock, false, &dividers);
+	if (ret)
+		return ret;
+
+	reference_divider = 1 + dividers.ref_div;
+
+	tmp = (u64) engine_clock * reference_divider * dividers.post_div;
+
+	fbdiv = (u32) ((16384 * tmp) / reference_clock);
+
+        spll_func_cntl &= ~(SPLL_PDIV_A_MASK | SPLL_REF_DIV_MASK);
+        spll_func_cntl |= SPLL_REF_DIV(dividers.ref_div);
+        spll_func_cntl |= SPLL_PDIV_A(dividers.post_div);
+
+        spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK;
+        spll_func_cntl_2 |= SCLK_MUX_SEL(2);
+
+	spll_func_cntl_3 &= ~SPLL_FB_DIV_MASK;
+        spll_func_cntl_3 |= SPLL_FB_DIV(fbdiv);
+        spll_func_cntl_3 |= SPLL_DITHEN;
+
+	if (pi->sclk_ss) {
+                struct radeon_atom_ss ss;
+                u32 vco_freq = engine_clock * dividers.post_div;
+
+                if (radeon_atombios_get_asic_ss_info(rdev, &ss,
+                                                     ASIC_INTERNAL_ENGINE_SS, vco_freq)) {
+                        u32 clk_s = reference_clock * 5 / (reference_divider * ss.rate);
+                        u32 clk_v = 4 * ss.percentage * fbdiv / (clk_s * 10000);
+
+                        cg_spll_spread_spectrum &= ~CLK_S_MASK;
+			cg_spll_spread_spectrum |= CLK_S(clk_s);
+                        cg_spll_spread_spectrum |= SSEN;
+
+                        cg_spll_spread_spectrum_2 &= ~CLK_V_MASK;
+                        cg_spll_spread_spectrum_2 |= CLK_V(clk_v);
+		}
+	}
+
+	sclk->sclk_value = engine_clock;
+	sclk->vCG_SPLL_FUNC_CNTL = spll_func_cntl;
+	sclk->vCG_SPLL_FUNC_CNTL_2 = spll_func_cntl_2;
+	sclk->vCG_SPLL_FUNC_CNTL_3 = spll_func_cntl_3;
+	sclk->vCG_SPLL_FUNC_CNTL_4 = spll_func_cntl_4;
+	sclk->vCG_SPLL_SPREAD_SPECTRUM = cg_spll_spread_spectrum;
+	sclk->vCG_SPLL_SPREAD_SPECTRUM_2 = cg_spll_spread_spectrum_2;
+
+	return 0;
+}
+
+static int ni_populate_sclk_value(struct radeon_device *rdev,
+				  u32 engine_clock,
+				  NISLANDS_SMC_SCLK_VALUE *sclk)
+{
+	NISLANDS_SMC_SCLK_VALUE sclk_tmp;
+	int ret;
+
+	ret = ni_calculate_sclk_params(rdev, engine_clock, &sclk_tmp);
+	if (!ret) {
+		sclk->sclk_value = cpu_to_be32(sclk_tmp.sclk_value);
+		sclk->vCG_SPLL_FUNC_CNTL = cpu_to_be32(sclk_tmp.vCG_SPLL_FUNC_CNTL);
+		sclk->vCG_SPLL_FUNC_CNTL_2 = cpu_to_be32(sclk_tmp.vCG_SPLL_FUNC_CNTL_2);
+		sclk->vCG_SPLL_FUNC_CNTL_3 = cpu_to_be32(sclk_tmp.vCG_SPLL_FUNC_CNTL_3);
+		sclk->vCG_SPLL_FUNC_CNTL_4 = cpu_to_be32(sclk_tmp.vCG_SPLL_FUNC_CNTL_4);
+		sclk->vCG_SPLL_SPREAD_SPECTRUM = cpu_to_be32(sclk_tmp.vCG_SPLL_SPREAD_SPECTRUM);
+		sclk->vCG_SPLL_SPREAD_SPECTRUM_2 = cpu_to_be32(sclk_tmp.vCG_SPLL_SPREAD_SPECTRUM_2);
+	}
+
+	return ret;
+}
+
+static int ni_init_smc_spll_table(struct radeon_device *rdev)
+{
+        struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	struct ni_power_info *ni_pi = ni_get_pi(rdev);
+	SMC_NISLANDS_SPLL_DIV_TABLE *spll_table;
+	NISLANDS_SMC_SCLK_VALUE sclk_params;
+	u32 fb_div;
+	u32 p_div;
+	u32 clk_s;
+	u32 clk_v;
+	u32 sclk = 0;
+	int i, ret;
+	u32 tmp;
+
+	if (ni_pi->spll_table_start == 0)
+		return -EINVAL;
+
+	spll_table = kzalloc(sizeof(SMC_NISLANDS_SPLL_DIV_TABLE), GFP_KERNEL);
+	if (spll_table == NULL)
+		return -ENOMEM;
+
+	for (i = 0; i < 256; i++) {
+		ret = ni_calculate_sclk_params(rdev, sclk, &sclk_params);
+		if (ret)
+			break;
+
+		p_div = (sclk_params.vCG_SPLL_FUNC_CNTL & SPLL_PDIV_A_MASK) >> SPLL_PDIV_A_SHIFT;
+		fb_div = (sclk_params.vCG_SPLL_FUNC_CNTL_3 & SPLL_FB_DIV_MASK) >> SPLL_FB_DIV_SHIFT;
+		clk_s = (sclk_params.vCG_SPLL_SPREAD_SPECTRUM & CLK_S_MASK) >> CLK_S_SHIFT;
+		clk_v = (sclk_params.vCG_SPLL_SPREAD_SPECTRUM_2 & CLK_V_MASK) >> CLK_V_SHIFT;
+
+		fb_div &= ~0x00001FFF;
+		fb_div >>= 1;
+		clk_v >>= 6;
+
+		if (p_div & ~(SMC_NISLANDS_SPLL_DIV_TABLE_PDIV_MASK >> SMC_NISLANDS_SPLL_DIV_TABLE_PDIV_SHIFT))
+			ret = -EINVAL;
+
+		if (clk_s & ~(SMC_NISLANDS_SPLL_DIV_TABLE_CLKS_MASK >> SMC_NISLANDS_SPLL_DIV_TABLE_CLKS_SHIFT))
+			ret = -EINVAL;
+
+		if (clk_s & ~(SMC_NISLANDS_SPLL_DIV_TABLE_CLKS_MASK >> SMC_NISLANDS_SPLL_DIV_TABLE_CLKS_SHIFT))
+			ret = -EINVAL;
+
+		if (clk_v & ~(SMC_NISLANDS_SPLL_DIV_TABLE_CLKV_MASK >> SMC_NISLANDS_SPLL_DIV_TABLE_CLKV_SHIFT))
+			ret = -EINVAL;
+
+		if (ret)
+			break;
+
+		tmp = ((fb_div << SMC_NISLANDS_SPLL_DIV_TABLE_FBDIV_SHIFT) & SMC_NISLANDS_SPLL_DIV_TABLE_FBDIV_MASK) |
+			((p_div << SMC_NISLANDS_SPLL_DIV_TABLE_PDIV_SHIFT) & SMC_NISLANDS_SPLL_DIV_TABLE_PDIV_MASK);
+		spll_table->freq[i] = cpu_to_be32(tmp);
+
+		tmp = ((clk_v << SMC_NISLANDS_SPLL_DIV_TABLE_CLKV_SHIFT) & SMC_NISLANDS_SPLL_DIV_TABLE_CLKV_MASK) |
+			((clk_s << SMC_NISLANDS_SPLL_DIV_TABLE_CLKS_SHIFT) & SMC_NISLANDS_SPLL_DIV_TABLE_CLKS_MASK);
+		spll_table->ss[i] = cpu_to_be32(tmp);
+
+		sclk += 512;
+	}
+
+	if (!ret)
+		ret = rv770_copy_bytes_to_smc(rdev, ni_pi->spll_table_start, (u8 *)spll_table,
+					      sizeof(SMC_NISLANDS_SPLL_DIV_TABLE), pi->sram_end);
+
+	kfree(spll_table);
+
+	return ret;
+}
+
+static int ni_populate_mclk_value(struct radeon_device *rdev,
+				  u32 engine_clock,
+				  u32 memory_clock,
+				  NISLANDS_SMC_MCLK_VALUE *mclk,
+				  bool strobe_mode,
+				  bool dll_state_on)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	struct ni_power_info *ni_pi = ni_get_pi(rdev);
+	u32 mpll_ad_func_cntl = ni_pi->clock_registers.mpll_ad_func_cntl;
+	u32 mpll_ad_func_cntl_2 = ni_pi->clock_registers.mpll_ad_func_cntl_2;
+	u32 mpll_dq_func_cntl = ni_pi->clock_registers.mpll_dq_func_cntl;
+	u32 mpll_dq_func_cntl_2 = ni_pi->clock_registers.mpll_dq_func_cntl_2;
+	u32 mclk_pwrmgt_cntl = ni_pi->clock_registers.mclk_pwrmgt_cntl;
+	u32 dll_cntl = ni_pi->clock_registers.dll_cntl;
+	u32 mpll_ss1 = ni_pi->clock_registers.mpll_ss1;
+	u32 mpll_ss2 = ni_pi->clock_registers.mpll_ss2;
+	struct atom_clock_dividers dividers;
+	u32 ibias;
+	u32 dll_speed;
+	int ret;
+	u32 mc_seq_misc7;
+
+        ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_MEMORY_PLL_PARAM,
+                                             memory_clock, strobe_mode, &dividers);
+	if (ret)
+		return ret;
+
+	if (!strobe_mode) {
+		mc_seq_misc7 = RREG32(MC_SEQ_MISC7);
+
+		if (mc_seq_misc7 & 0x8000000)
+			dividers.post_div = 1;
+	}
+
+	ibias = cypress_map_clkf_to_ibias(rdev, dividers.whole_fb_div);
+
+        mpll_ad_func_cntl &= ~(CLKR_MASK |
+                               YCLK_POST_DIV_MASK |
+                               CLKF_MASK |
+                               CLKFRAC_MASK |
+                               IBIAS_MASK);
+        mpll_ad_func_cntl |= CLKR(dividers.ref_div);
+        mpll_ad_func_cntl |= YCLK_POST_DIV(dividers.post_div);
+        mpll_ad_func_cntl |= CLKF(dividers.whole_fb_div);
+        mpll_ad_func_cntl |= CLKFRAC(dividers.frac_fb_div);
+	mpll_ad_func_cntl |= IBIAS(ibias);
+
+        if (dividers.vco_mode)
+		mpll_ad_func_cntl_2 |= VCO_MODE;
+	else
+		mpll_ad_func_cntl_2 &= ~VCO_MODE;
+
+	if (pi->mem_gddr5) {
+                mpll_dq_func_cntl &= ~(CLKR_MASK |
+                                       YCLK_POST_DIV_MASK |
+                                       CLKF_MASK |
+                                       CLKFRAC_MASK |
+                                       IBIAS_MASK);
+                mpll_dq_func_cntl |= CLKR(dividers.ref_div);
+                mpll_dq_func_cntl |= YCLK_POST_DIV(dividers.post_div);
+                mpll_dq_func_cntl |= CLKF(dividers.whole_fb_div);
+                mpll_dq_func_cntl |= CLKFRAC(dividers.frac_fb_div);
+                mpll_dq_func_cntl |= IBIAS(ibias);
+
+		if (strobe_mode)
+			mpll_dq_func_cntl &= ~PDNB;
+                else
+			mpll_dq_func_cntl |= PDNB;
+
+		if (dividers.vco_mode)
+			mpll_dq_func_cntl_2 |= VCO_MODE;
+		else
+                        mpll_dq_func_cntl_2 &= ~VCO_MODE;
+	}
+
+	if (pi->mclk_ss) {
+                struct radeon_atom_ss ss;
+                u32 vco_freq = memory_clock * dividers.post_div;
+
+                if (radeon_atombios_get_asic_ss_info(rdev, &ss,
+						     ASIC_INTERNAL_MEMORY_SS, vco_freq)) {
+			u32 reference_clock = rdev->clock.mpll.reference_freq;
+                        u32 decoded_ref = rv740_get_decoded_reference_divider(dividers.ref_div);
+			u32 clk_s = reference_clock * 5 / (decoded_ref * ss.rate);
+                        u32 clk_v = ss.percentage *
+                                (0x4000 * dividers.whole_fb_div + 0x800 * dividers.frac_fb_div) / (clk_s * 625);
+
+                        mpll_ss1 &= ~CLKV_MASK;
+                        mpll_ss1 |= CLKV(clk_v);
+
+                        mpll_ss2 &= ~CLKS_MASK;
+                        mpll_ss2 |= CLKS(clk_s);
+		}
+	}
+
+        dll_speed = rv740_get_dll_speed(pi->mem_gddr5,
+                                        memory_clock);
+
+        mclk_pwrmgt_cntl &= ~DLL_SPEED_MASK;
+        mclk_pwrmgt_cntl |= DLL_SPEED(dll_speed);
+        if (dll_state_on)
+                mclk_pwrmgt_cntl |= (MRDCKA0_PDNB |
+                                     MRDCKA1_PDNB |
+                                     MRDCKB0_PDNB |
+                                     MRDCKB1_PDNB |
+                                     MRDCKC0_PDNB |
+                                     MRDCKC1_PDNB |
+                                     MRDCKD0_PDNB |
+                                     MRDCKD1_PDNB);
+        else
+                mclk_pwrmgt_cntl &= ~(MRDCKA0_PDNB |
+                                      MRDCKA1_PDNB |
+                                      MRDCKB0_PDNB |
+                                      MRDCKB1_PDNB |
+                                      MRDCKC0_PDNB |
+                                      MRDCKC1_PDNB |
+                                      MRDCKD0_PDNB |
+                                      MRDCKD1_PDNB);
+
+
+	mclk->mclk_value = cpu_to_be32(memory_clock);
+	mclk->vMPLL_AD_FUNC_CNTL = cpu_to_be32(mpll_ad_func_cntl);
+	mclk->vMPLL_AD_FUNC_CNTL_2 = cpu_to_be32(mpll_ad_func_cntl_2);
+	mclk->vMPLL_DQ_FUNC_CNTL = cpu_to_be32(mpll_dq_func_cntl);
+	mclk->vMPLL_DQ_FUNC_CNTL_2 = cpu_to_be32(mpll_dq_func_cntl_2);
+	mclk->vMCLK_PWRMGT_CNTL = cpu_to_be32(mclk_pwrmgt_cntl);
+	mclk->vDLL_CNTL = cpu_to_be32(dll_cntl);
+	mclk->vMPLL_SS = cpu_to_be32(mpll_ss1);
+	mclk->vMPLL_SS2 = cpu_to_be32(mpll_ss2);
+
+	return 0;
+}
+
+static void ni_populate_smc_sp(struct radeon_device *rdev,
+			       struct radeon_ps *radeon_state,
+			       NISLANDS_SMC_SWSTATE *smc_state)
+{
+	struct ni_ps *ps = ni_get_ps(radeon_state);
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	int i;
+
+	for (i = 0; i < ps->performance_level_count - 1; i++)
+		smc_state->levels[i].bSP = cpu_to_be32(pi->dsp);
+
+	smc_state->levels[ps->performance_level_count - 1].bSP =
+		cpu_to_be32(pi->psp);
+}
+
+static int ni_convert_power_level_to_smc(struct radeon_device *rdev,
+					 struct rv7xx_pl *pl,
+					 NISLANDS_SMC_HW_PERFORMANCE_LEVEL *level)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+        struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+        struct ni_power_info *ni_pi = ni_get_pi(rdev);
+	int ret;
+	bool dll_state_on;
+	u16 std_vddc;
+	u32 tmp = RREG32(DC_STUTTER_CNTL);
+
+	level->gen2PCIE = pi->pcie_gen2 ?
+		((pl->flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) ? 1 : 0) : 0;
+
+	ret = ni_populate_sclk_value(rdev, pl->sclk, &level->sclk);
+	if (ret)
+		return ret;
+
+	level->mcFlags =  0;
+	if (pi->mclk_stutter_mode_threshold &&
+	    (pl->mclk <= pi->mclk_stutter_mode_threshold) &&
+	    !eg_pi->uvd_enabled &&
+	    (tmp & DC_STUTTER_ENABLE_A) &&
+	    (tmp & DC_STUTTER_ENABLE_B))
+		level->mcFlags |= NISLANDS_SMC_MC_STUTTER_EN;
+
+	if (pi->mem_gddr5) {
+		if (pl->mclk > pi->mclk_edc_enable_threshold)
+			level->mcFlags |= NISLANDS_SMC_MC_EDC_RD_FLAG;
+		if (pl->mclk > eg_pi->mclk_edc_wr_enable_threshold)
+			level->mcFlags |= NISLANDS_SMC_MC_EDC_WR_FLAG;
+
+		level->strobeMode = cypress_get_strobe_mode_settings(rdev, pl->mclk);
+
+		if (level->strobeMode & NISLANDS_SMC_STROBE_ENABLE) {
+			if (cypress_get_mclk_frequency_ratio(rdev, pl->mclk, true) >=
+			    ((RREG32(MC_SEQ_MISC7) >> 16) & 0xf))
+				dll_state_on = ((RREG32(MC_SEQ_MISC5) >> 1) & 0x1) ? true : false;
+			else
+				dll_state_on = ((RREG32(MC_SEQ_MISC6) >> 1) & 0x1) ? true : false;
+		} else {
+			dll_state_on = false;
+			if (pl->mclk > ni_pi->mclk_rtt_mode_threshold)
+				level->mcFlags |= NISLANDS_SMC_MC_RTT_ENABLE;
+		}
+
+		ret = ni_populate_mclk_value(rdev, pl->sclk, pl->mclk,
+					     &level->mclk,
+					     (level->strobeMode & NISLANDS_SMC_STROBE_ENABLE) != 0,
+					     dll_state_on);
+	} else
+		ret = ni_populate_mclk_value(rdev, pl->sclk, pl->mclk, &level->mclk, 1, 1);
+
+	if (ret)
+		return ret;
+
+	ret = ni_populate_voltage_value(rdev, &eg_pi->vddc_voltage_table,
+					pl->vddc, &level->vddc);
+	if (ret)
+		return ret;
+
+	ret = ni_get_std_voltage_value(rdev, &level->vddc, &std_vddc);
+	if (ret)
+		return ret;
+
+	ni_populate_std_voltage_value(rdev, std_vddc,
+				      level->vddc.index, &level->std_vddc);
+
+	if (eg_pi->vddci_control) {
+		ret = ni_populate_voltage_value(rdev, &eg_pi->vddci_voltage_table,
+						pl->vddci, &level->vddci);
+		if (ret)
+			return ret;
+	}
+
+	ni_populate_mvdd_value(rdev, pl->mclk, &level->mvdd);
+
+	return ret;
+}
+
+static int ni_populate_smc_t(struct radeon_device *rdev,
+			     struct radeon_ps *radeon_state,
+			     NISLANDS_SMC_SWSTATE *smc_state)
+{
+        struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+        struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	struct ni_ps *state = ni_get_ps(radeon_state);
+	u32 a_t;
+	u32 t_l, t_h;
+	u32 high_bsp;
+	int i, ret;
+
+	if (state->performance_level_count >= 9)
+		return -EINVAL;
+
+	if (state->performance_level_count < 2) {
+		a_t = CG_R(0xffff) | CG_L(0);
+		smc_state->levels[0].aT = cpu_to_be32(a_t);
+		return 0;
+	}
+
+	smc_state->levels[0].aT = cpu_to_be32(0);
+
+	for (i = 0; i <= state->performance_level_count - 2; i++) {
+		if (eg_pi->uvd_enabled)
+			ret = r600_calculate_at(
+				1000 * (i * (eg_pi->smu_uvd_hs ? 2 : 8) + 2),
+				100 * R600_AH_DFLT,
+				state->performance_levels[i + 1].sclk,
+				state->performance_levels[i].sclk,
+				&t_l,
+				&t_h);
+		else
+			ret = r600_calculate_at(
+				1000 * (i + 1),
+				100 * R600_AH_DFLT,
+				state->performance_levels[i + 1].sclk,
+				state->performance_levels[i].sclk,
+				&t_l,
+				&t_h);
+
+		if (ret) {
+			t_h = (i + 1) * 1000 - 50 * R600_AH_DFLT;
+			t_l = (i + 1) * 1000 + 50 * R600_AH_DFLT;
+		}
+
+		a_t = be32_to_cpu(smc_state->levels[i].aT) & ~CG_R_MASK;
+		a_t |= CG_R(t_l * pi->bsp / 20000);
+		smc_state->levels[i].aT = cpu_to_be32(a_t);
+
+		high_bsp = (i == state->performance_level_count - 2) ?
+			pi->pbsp : pi->bsp;
+
+		a_t = CG_R(0xffff) | CG_L(t_h * high_bsp / 20000);
+		smc_state->levels[i + 1].aT = cpu_to_be32(a_t);
+	}
+
+	return 0;
+}
+
+static int ni_populate_power_containment_values(struct radeon_device *rdev,
+						struct radeon_ps *radeon_state,
+						NISLANDS_SMC_SWSTATE *smc_state)
+{
+        struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+        struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	struct ni_power_info *ni_pi = ni_get_pi(rdev);
+	struct ni_ps *state = ni_get_ps(radeon_state);
+	u32 prev_sclk;
+	u32 max_sclk;
+	u32 min_sclk;
+	int i, ret;
+	u32 tdp_limit;
+	u32 near_tdp_limit;
+	u32 power_boost_limit;
+	u8 max_ps_percent;
+
+	if (ni_pi->enable_power_containment == false)
+		return 0;
+
+	if (state->performance_level_count == 0)
+		return -EINVAL;
+
+	if (smc_state->levelCount != state->performance_level_count)
+		return -EINVAL;
+
+	ret = ni_calculate_adjusted_tdp_limits(rdev,
+					       false, /* ??? */
+					       rdev->pm.dpm.tdp_adjustment,
+					       &tdp_limit,
+					       &near_tdp_limit);
+	if (ret)
+		return ret;
+
+	power_boost_limit = ni_calculate_power_boost_limit(rdev, radeon_state, near_tdp_limit);
+
+	ret = rv770_write_smc_sram_dword(rdev,
+					 pi->state_table_start +
+					 offsetof(NISLANDS_SMC_STATETABLE, dpm2Params) +
+					 offsetof(PP_NIslands_DPM2Parameters, PowerBoostLimit),
+					 ni_scale_power_for_smc(power_boost_limit, ni_get_smc_power_scaling_factor(rdev)),
+					 pi->sram_end);
+	if (ret)
+		power_boost_limit = 0;
+
+	smc_state->levels[0].dpm2.MaxPS = 0;
+	smc_state->levels[0].dpm2.NearTDPDec = 0;
+	smc_state->levels[0].dpm2.AboveSafeInc = 0;
+	smc_state->levels[0].dpm2.BelowSafeInc = 0;
+	smc_state->levels[0].stateFlags |= power_boost_limit ? PPSMC_STATEFLAG_POWERBOOST : 0;
+
+	for (i = 1; i < state->performance_level_count; i++) {
+		prev_sclk = state->performance_levels[i-1].sclk;
+		max_sclk  = state->performance_levels[i].sclk;
+		max_ps_percent = (i != (state->performance_level_count - 1)) ?
+			NISLANDS_DPM2_MAXPS_PERCENT_M : NISLANDS_DPM2_MAXPS_PERCENT_H;
+
+		if (max_sclk < prev_sclk)
+			return -EINVAL;
+
+		if ((max_ps_percent == 0) || (prev_sclk == max_sclk) || eg_pi->uvd_enabled)
+			min_sclk = max_sclk;
+		else if (1 == i)
+			min_sclk = prev_sclk;
+		else
+			min_sclk = (prev_sclk * (u32)max_ps_percent) / 100;
+
+		if (min_sclk < state->performance_levels[0].sclk)
+			min_sclk = state->performance_levels[0].sclk;
+
+		if (min_sclk == 0)
+			return -EINVAL;
+
+		smc_state->levels[i].dpm2.MaxPS =
+			(u8)((NISLANDS_DPM2_MAX_PULSE_SKIP * (max_sclk - min_sclk)) / max_sclk);
+		smc_state->levels[i].dpm2.NearTDPDec = NISLANDS_DPM2_NEAR_TDP_DEC;
+		smc_state->levels[i].dpm2.AboveSafeInc = NISLANDS_DPM2_ABOVE_SAFE_INC;
+		smc_state->levels[i].dpm2.BelowSafeInc = NISLANDS_DPM2_BELOW_SAFE_INC;
+		smc_state->levels[i].stateFlags |=
+			((i != (state->performance_level_count - 1)) && power_boost_limit) ?
+			PPSMC_STATEFLAG_POWERBOOST : 0;
+	}
+
+	return 0;
+}
+
+static int ni_populate_sq_ramping_values(struct radeon_device *rdev,
+					 struct radeon_ps *radeon_state,
+					 NISLANDS_SMC_SWSTATE *smc_state)
+{
+	struct ni_power_info *ni_pi = ni_get_pi(rdev);
+	struct ni_ps *state = ni_get_ps(radeon_state);
+	u32 sq_power_throttle;
+	u32 sq_power_throttle2;
+	bool enable_sq_ramping = ni_pi->enable_sq_ramping;
+	int i;
+
+	if (state->performance_level_count == 0)
+		return -EINVAL;
+
+	if (smc_state->levelCount != state->performance_level_count)
+		return -EINVAL;
+
+	if (rdev->pm.dpm.sq_ramping_threshold == 0)
+		return -EINVAL;
+
+	if (NISLANDS_DPM2_SQ_RAMP_MAX_POWER > (MAX_POWER_MASK >> MAX_POWER_SHIFT))
+		enable_sq_ramping = false;
+
+	if (NISLANDS_DPM2_SQ_RAMP_MIN_POWER > (MIN_POWER_MASK >> MIN_POWER_SHIFT))
+		enable_sq_ramping = false;
+
+	if (NISLANDS_DPM2_SQ_RAMP_MAX_POWER_DELTA > (MAX_POWER_DELTA_MASK >> MAX_POWER_DELTA_SHIFT))
+		enable_sq_ramping = false;
+
+	if (NISLANDS_DPM2_SQ_RAMP_STI_SIZE > (STI_SIZE_MASK >> STI_SIZE_SHIFT))
+		enable_sq_ramping = false;
+
+	if (NISLANDS_DPM2_SQ_RAMP_LTI_RATIO <= (LTI_RATIO_MASK >> LTI_RATIO_SHIFT))
+		enable_sq_ramping = false;
+
+	for (i = 0; i < state->performance_level_count; i++) {
+		sq_power_throttle  = 0;
+		sq_power_throttle2 = 0;
+
+		if ((state->performance_levels[i].sclk >= rdev->pm.dpm.sq_ramping_threshold) &&
+		    enable_sq_ramping) {
+			sq_power_throttle |= MAX_POWER(NISLANDS_DPM2_SQ_RAMP_MAX_POWER);
+			sq_power_throttle |= MIN_POWER(NISLANDS_DPM2_SQ_RAMP_MIN_POWER);
+			sq_power_throttle2 |= MAX_POWER_DELTA(NISLANDS_DPM2_SQ_RAMP_MAX_POWER_DELTA);
+			sq_power_throttle2 |= STI_SIZE(NISLANDS_DPM2_SQ_RAMP_STI_SIZE);
+			sq_power_throttle2 |= LTI_RATIO(NISLANDS_DPM2_SQ_RAMP_LTI_RATIO);
+		} else {
+			sq_power_throttle |= MAX_POWER_MASK | MIN_POWER_MASK;
+			sq_power_throttle2 |= MAX_POWER_DELTA_MASK | STI_SIZE_MASK | LTI_RATIO_MASK;
+		}
+
+		smc_state->levels[i].SQPowerThrottle   = cpu_to_be32(sq_power_throttle);
+		smc_state->levels[i].SQPowerThrottle_2 = cpu_to_be32(sq_power_throttle2);
+	}
+
+	return 0;
+}
+
+static int ni_enable_power_containment(struct radeon_device *rdev, bool enable)
+{
+        struct ni_power_info *ni_pi = ni_get_pi(rdev);
+	PPSMC_Result smc_result;
+	int ret = 0;
+
+	if (ni_pi->enable_power_containment) {
+		if (enable) {
+			struct radeon_ps *radeon_new_state = rdev->pm.dpm.requested_ps;
+
+			if (!r600_is_uvd_state(radeon_new_state->class, radeon_new_state->class2)) {
+				smc_result = rv770_send_msg_to_smc(rdev, PPSMC_TDPClampingActive);
+				if (smc_result != PPSMC_Result_OK) {
+					ret = -EINVAL;
+					ni_pi->pc_enabled = false;
+				} else {
+					ni_pi->pc_enabled = true;
+				}
+			}
+		} else {
+			smc_result = rv770_send_msg_to_smc(rdev, PPSMC_TDPClampingInactive);
+			if (smc_result != PPSMC_Result_OK)
+				ret = -EINVAL;
+			ni_pi->pc_enabled = false;
+		}
+	}
+
+	return ret;
+}
+
+static int ni_convert_power_state_to_smc(struct radeon_device *rdev,
+					 struct radeon_ps *radeon_state,
+					 NISLANDS_SMC_SWSTATE *smc_state)
+{
+        struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	struct ni_power_info *ni_pi = ni_get_pi(rdev);
+	struct ni_ps *state = ni_get_ps(radeon_state);
+	int i, ret;
+	u32 threshold = state->performance_levels[state->performance_level_count - 1].sclk * 100 / 100;
+
+	if (!(radeon_state->caps & ATOM_PPLIB_DISALLOW_ON_DC))
+		smc_state->flags |= PPSMC_SWSTATE_FLAG_DC;
+
+	smc_state->levelCount = 0;
+
+	if (state->performance_level_count > NISLANDS_MAX_SMC_PERFORMANCE_LEVELS_PER_SWSTATE)
+		return -EINVAL;
+
+	for (i = 0; i < state->performance_level_count; i++) {
+		ret = ni_convert_power_level_to_smc(rdev, &state->performance_levels[i],
+						    &smc_state->levels[i]);
+		smc_state->levels[i].arbRefreshState =
+			(u8)(NISLANDS_DRIVER_STATE_ARB_INDEX + i);
+
+		if (ret)
+			return ret;
+
+		if (ni_pi->enable_power_containment)
+			smc_state->levels[i].displayWatermark =
+				(state->performance_levels[i].sclk < threshold) ?
+				PPSMC_DISPLAY_WATERMARK_LOW : PPSMC_DISPLAY_WATERMARK_HIGH;
+		else
+			smc_state->levels[i].displayWatermark = (i < 2) ?
+				PPSMC_DISPLAY_WATERMARK_LOW : PPSMC_DISPLAY_WATERMARK_HIGH;
+
+		if (eg_pi->dynamic_ac_timing)
+			smc_state->levels[i].ACIndex = NISLANDS_MCREGISTERTABLE_FIRST_DRIVERSTATE_SLOT + i;
+		else
+			smc_state->levels[i].ACIndex = 0;
+
+		smc_state->levelCount++;
+	}
+
+	rv770_write_smc_soft_register(rdev, NI_SMC_SOFT_REGISTER_watermark_threshold,
+				      cpu_to_be32(threshold / 512));
+
+	ni_populate_smc_sp(rdev, radeon_state, smc_state);
+
+	ret = ni_populate_power_containment_values(rdev, radeon_state, smc_state);
+	if (ret)
+		ni_pi->enable_power_containment = false;
+
+	ret = ni_populate_sq_ramping_values(rdev, radeon_state, smc_state);
+	if (ret)
+		ni_pi->enable_sq_ramping = false;
+
+	return ni_populate_smc_t(rdev, radeon_state, smc_state);
+}
+
+static int ni_upload_sw_state(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	struct radeon_ps *radeon_new_state = rdev->pm.dpm.requested_ps;
+	u16 address = pi->state_table_start +
+		offsetof(NISLANDS_SMC_STATETABLE, driverState);
+	u16 state_size = sizeof(NISLANDS_SMC_SWSTATE) +
+		((NISLANDS_MAX_SMC_PERFORMANCE_LEVELS_PER_SWSTATE - 1) * sizeof(NISLANDS_SMC_HW_PERFORMANCE_LEVEL));
+	int ret;
+	NISLANDS_SMC_SWSTATE *smc_state = kzalloc(state_size, GFP_KERNEL);
+
+	if (smc_state == NULL)
+		return -ENOMEM;
+
+	ret = ni_convert_power_state_to_smc(rdev, radeon_new_state, smc_state);
+	if (ret)
+		goto done;
+
+	ret = rv770_copy_bytes_to_smc(rdev, address, (u8 *)smc_state, state_size, pi->sram_end);
+
+done:
+	kfree(smc_state);
+
+	return ret;
+}
+
+static int ni_set_mc_special_registers(struct radeon_device *rdev,
+				       struct ni_mc_reg_table *table)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	u8 i, j, k;
+	u32 temp_reg;
+
+	for (i = 0, j = table->last; i < table->last; i++) {
+		switch (table->mc_reg_address[i].s1) {
+		case MC_SEQ_MISC1 >> 2:
+			if (j >= SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE)
+				return -EINVAL;
+			temp_reg = RREG32(MC_PMG_CMD_EMRS);
+			table->mc_reg_address[j].s1 = MC_PMG_CMD_EMRS >> 2;
+			table->mc_reg_address[j].s0 = MC_SEQ_PMG_CMD_EMRS_LP >> 2;
+			for (k = 0; k < table->num_entries; k++)
+				table->mc_reg_table_entry[k].mc_data[j] =
+					((temp_reg & 0xffff0000)) |
+					((table->mc_reg_table_entry[k].mc_data[i] & 0xffff0000) >> 16);
+			j++;
+			if (j >= SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE)
+				return -EINVAL;
+
+			temp_reg = RREG32(MC_PMG_CMD_MRS);
+			table->mc_reg_address[j].s1 = MC_PMG_CMD_MRS >> 2;
+			table->mc_reg_address[j].s0 = MC_SEQ_PMG_CMD_MRS_LP >> 2;
+			for(k = 0; k < table->num_entries; k++) {
+				table->mc_reg_table_entry[k].mc_data[j] =
+					(temp_reg & 0xffff0000) |
+					(table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff);
+				if (!pi->mem_gddr5)
+					table->mc_reg_table_entry[k].mc_data[j] |= 0x100;
+			}
+			j++;
+			if (j > SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE)
+				return -EINVAL;
+			break;
+		case MC_SEQ_RESERVE_M >> 2:
+			temp_reg = RREG32(MC_PMG_CMD_MRS1);
+			table->mc_reg_address[j].s1 = MC_PMG_CMD_MRS1 >> 2;
+			table->mc_reg_address[j].s0 = MC_SEQ_PMG_CMD_MRS1_LP >> 2;
+			for (k = 0; k < table->num_entries; k++)
+				table->mc_reg_table_entry[k].mc_data[j] =
+					(temp_reg & 0xffff0000) |
+					(table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff);
+			j++;
+			if (j > SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE)
+				return -EINVAL;
+			break;
+		default:
+			break;
+		}
+	}
+
+	table->last = j;
+
+	return 0;
+}
+
+static bool ni_check_s0_mc_reg_index(u16 in_reg, u16 *out_reg)
+{
+	bool result = true;
+
+	switch (in_reg) {
+        case  MC_SEQ_RAS_TIMING >> 2:
+		*out_reg = MC_SEQ_RAS_TIMING_LP >> 2;
+		break;
+        case MC_SEQ_CAS_TIMING >> 2:
+		*out_reg = MC_SEQ_CAS_TIMING_LP >> 2;
+		break;
+        case MC_SEQ_MISC_TIMING >> 2:
+		*out_reg = MC_SEQ_MISC_TIMING_LP >> 2;
+		break;
+        case MC_SEQ_MISC_TIMING2 >> 2:
+		*out_reg = MC_SEQ_MISC_TIMING2_LP >> 2;
+		break;
+        case MC_SEQ_RD_CTL_D0 >> 2:
+		*out_reg = MC_SEQ_RD_CTL_D0_LP >> 2;
+		break;
+        case MC_SEQ_RD_CTL_D1 >> 2:
+		*out_reg = MC_SEQ_RD_CTL_D1_LP >> 2;
+		break;
+        case MC_SEQ_WR_CTL_D0 >> 2:
+		*out_reg = MC_SEQ_WR_CTL_D0_LP >> 2;
+		break;
+        case MC_SEQ_WR_CTL_D1 >> 2:
+		*out_reg = MC_SEQ_WR_CTL_D1_LP >> 2;
+		break;
+        case MC_PMG_CMD_EMRS >> 2:
+		*out_reg = MC_SEQ_PMG_CMD_EMRS_LP >> 2;
+		break;
+        case MC_PMG_CMD_MRS >> 2:
+		*out_reg = MC_SEQ_PMG_CMD_MRS_LP >> 2;
+		break;
+        case MC_PMG_CMD_MRS1 >> 2:
+		*out_reg = MC_SEQ_PMG_CMD_MRS1_LP >> 2;
+		break;
+        case MC_SEQ_PMG_TIMING >> 2:
+		*out_reg = MC_SEQ_PMG_TIMING_LP >> 2;
+		break;
+        case MC_PMG_CMD_MRS2 >> 2:
+		*out_reg = MC_SEQ_PMG_CMD_MRS2_LP >> 2;
+		break;
+        default:
+		result = false;
+		break;
+	}
+
+	return result;
+}
+
+static void ni_set_valid_flag(struct ni_mc_reg_table *table)
+{
+	u8 i, j;
+
+	for (i = 0; i < table->last; i++) {
+		for (j = 1; j < table->num_entries; j++) {
+			if (table->mc_reg_table_entry[j-1].mc_data[i] != table->mc_reg_table_entry[j].mc_data[i]) {
+				table->valid_flag |= 1 << i;
+				break;
+			}
+		}
+	}
+}
+
+static void ni_set_s0_mc_reg_index(struct ni_mc_reg_table *table)
+{
+	u32 i;
+	u16 address;
+
+	for (i = 0; i < table->last; i++)
+		table->mc_reg_address[i].s0 =
+			ni_check_s0_mc_reg_index(table->mc_reg_address[i].s1, &address) ?
+			address : table->mc_reg_address[i].s1;
+}
+
+static int ni_copy_vbios_mc_reg_table(struct atom_mc_reg_table *table,
+				      struct ni_mc_reg_table *ni_table)
+{
+	u8 i, j;
+
+	if (table->last > SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE)
+		return -EINVAL;
+	if (table->num_entries > MAX_AC_TIMING_ENTRIES)
+		return -EINVAL;
+
+	for (i = 0; i < table->last; i++)
+		ni_table->mc_reg_address[i].s1 = table->mc_reg_address[i].s1;
+	ni_table->last = table->last;
+
+	for (i = 0; i < table->num_entries; i++) {
+		ni_table->mc_reg_table_entry[i].mclk_max =
+			table->mc_reg_table_entry[i].mclk_max;
+		for (j = 0; j < table->last; j++)
+			ni_table->mc_reg_table_entry[i].mc_data[j] =
+				table->mc_reg_table_entry[i].mc_data[j];
+	}
+	ni_table->num_entries = table->num_entries;
+
+	return 0;
+}
+
+static int ni_initialize_mc_reg_table(struct radeon_device *rdev)
+{
+	struct ni_power_info *ni_pi = ni_get_pi(rdev);
+	int ret;
+	struct atom_mc_reg_table *table;
+	struct ni_mc_reg_table *ni_table = &ni_pi->mc_reg_table;
+	u8 module_index = rv770_get_memory_module_index(rdev);
+
+        table = kzalloc(sizeof(struct atom_mc_reg_table), GFP_KERNEL);
+        if (!table)
+                return -ENOMEM;
+
+	WREG32(MC_SEQ_RAS_TIMING_LP, RREG32(MC_SEQ_RAS_TIMING));
+	WREG32(MC_SEQ_CAS_TIMING_LP, RREG32(MC_SEQ_CAS_TIMING));
+	WREG32(MC_SEQ_MISC_TIMING_LP, RREG32(MC_SEQ_MISC_TIMING));
+	WREG32(MC_SEQ_MISC_TIMING2_LP, RREG32(MC_SEQ_MISC_TIMING2));
+	WREG32(MC_SEQ_PMG_CMD_EMRS_LP, RREG32(MC_PMG_CMD_EMRS));
+	WREG32(MC_SEQ_PMG_CMD_MRS_LP, RREG32(MC_PMG_CMD_MRS));
+	WREG32(MC_SEQ_PMG_CMD_MRS1_LP, RREG32(MC_PMG_CMD_MRS1));
+	WREG32(MC_SEQ_WR_CTL_D0_LP, RREG32(MC_SEQ_WR_CTL_D0));
+	WREG32(MC_SEQ_WR_CTL_D1_LP, RREG32(MC_SEQ_WR_CTL_D1));
+	WREG32(MC_SEQ_RD_CTL_D0_LP, RREG32(MC_SEQ_RD_CTL_D0));
+	WREG32(MC_SEQ_RD_CTL_D1_LP, RREG32(MC_SEQ_RD_CTL_D1));
+	WREG32(MC_SEQ_PMG_TIMING_LP, RREG32(MC_SEQ_PMG_TIMING));
+	WREG32(MC_SEQ_PMG_CMD_MRS2_LP, RREG32(MC_PMG_CMD_MRS2));
+
+	ret = radeon_atom_init_mc_reg_table(rdev, module_index, table);
+
+        if (ret)
+                goto init_mc_done;
+
+	ret = ni_copy_vbios_mc_reg_table(table, ni_table);
+
+        if (ret)
+                goto init_mc_done;
+
+	ni_set_s0_mc_reg_index(ni_table);
+
+	ret = ni_set_mc_special_registers(rdev, ni_table);
+
+        if (ret)
+                goto init_mc_done;
+
+	ni_set_valid_flag(ni_table);
+
+init_mc_done:
+        kfree(table);
+
+	return ret;
+}
+
+static void ni_populate_mc_reg_addresses(struct radeon_device *rdev,
+					 SMC_NIslands_MCRegisters *mc_reg_table)
+{
+	struct ni_power_info *ni_pi = ni_get_pi(rdev);
+	u32 i, j;
+
+	for (i = 0, j = 0; j < ni_pi->mc_reg_table.last; j++) {
+		if (ni_pi->mc_reg_table.valid_flag & (1 << j)) {
+			if (i >= SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE)
+				break;
+			mc_reg_table->address[i].s0 =
+				cpu_to_be16(ni_pi->mc_reg_table.mc_reg_address[j].s0);
+			mc_reg_table->address[i].s1 =
+				cpu_to_be16(ni_pi->mc_reg_table.mc_reg_address[j].s1);
+			i++;
+		}
+	}
+	mc_reg_table->last = (u8)i;
+}
+
+
+static void ni_convert_mc_registers(struct ni_mc_reg_entry *entry,
+				    SMC_NIslands_MCRegisterSet *data,
+				    u32 num_entries, u32 valid_flag)
+{
+	u32 i, j;
+
+	for (i = 0, j = 0; j < num_entries; j++) {
+		if (valid_flag & (1 << j)) {
+			data->value[i] = cpu_to_be32(entry->mc_data[j]);
+			i++;
+		}
+	}
+}
+
+static void ni_convert_mc_reg_table_entry_to_smc(struct radeon_device *rdev,
+						 struct rv7xx_pl *pl,
+						 SMC_NIslands_MCRegisterSet *mc_reg_table_data)
+{
+	struct ni_power_info *ni_pi = ni_get_pi(rdev);
+	u32 i = 0;
+
+	for (i = 0; i < ni_pi->mc_reg_table.num_entries; i++) {
+		if (pl->mclk <= ni_pi->mc_reg_table.mc_reg_table_entry[i].mclk_max)
+			break;
+	}
+
+	if ((i == ni_pi->mc_reg_table.num_entries) && (i > 0))
+		--i;
+
+	ni_convert_mc_registers(&ni_pi->mc_reg_table.mc_reg_table_entry[i],
+				mc_reg_table_data,
+				ni_pi->mc_reg_table.last,
+				ni_pi->mc_reg_table.valid_flag);
+}
+
+static void ni_convert_mc_reg_table_to_smc(struct radeon_device *rdev,
+					   struct radeon_ps *radeon_state,
+					   SMC_NIslands_MCRegisters *mc_reg_table)
+{
+	struct ni_ps *state = ni_get_ps(radeon_state);
+	int i;
+
+	for (i = 0; i < state->performance_level_count; i++) {
+		ni_convert_mc_reg_table_entry_to_smc(rdev,
+						     &state->performance_levels[i],
+						     &mc_reg_table->data[NISLANDS_MCREGISTERTABLE_FIRST_DRIVERSTATE_SLOT + i]);
+	}
+}
+
+static int ni_populate_mc_reg_table(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+        struct ni_power_info *ni_pi = ni_get_pi(rdev);
+        struct radeon_ps *radeon_boot_state = rdev->pm.dpm.boot_ps;
+	struct ni_ps *boot_state = ni_get_ps(radeon_boot_state);
+	SMC_NIslands_MCRegisters *mc_reg_table = &ni_pi->smc_mc_reg_table;
+
+	memset(mc_reg_table, 0, sizeof(SMC_NIslands_MCRegisters));
+
+	rv770_write_smc_soft_register(rdev, NI_SMC_SOFT_REGISTER_seq_index, 1);
+
+	ni_populate_mc_reg_addresses(rdev, mc_reg_table);
+
+	ni_convert_mc_reg_table_entry_to_smc(rdev, &boot_state->performance_levels[0],
+					     &mc_reg_table->data[0]);
+
+	ni_convert_mc_registers(&ni_pi->mc_reg_table.mc_reg_table_entry[0],
+				&mc_reg_table->data[1],
+				ni_pi->mc_reg_table.last,
+				ni_pi->mc_reg_table.valid_flag);
+
+	ni_convert_mc_reg_table_to_smc(rdev, radeon_boot_state, mc_reg_table);
+
+	return rv770_copy_bytes_to_smc(rdev, eg_pi->mc_reg_table_start,
+				       (u8 *)mc_reg_table,
+				       sizeof(SMC_NIslands_MCRegisters),
+				       pi->sram_end);
+}
+
+static int ni_upload_mc_reg_table(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+        struct ni_power_info *ni_pi = ni_get_pi(rdev);
+	struct radeon_ps *radeon_new_state = rdev->pm.dpm.requested_ps;
+	struct ni_ps *ni_new_state = ni_get_ps(radeon_new_state);
+	SMC_NIslands_MCRegisters *mc_reg_table = &ni_pi->smc_mc_reg_table;
+	u16 address;
+
+	memset(mc_reg_table, 0, sizeof(SMC_NIslands_MCRegisters));
+
+	ni_convert_mc_reg_table_to_smc(rdev, radeon_new_state, mc_reg_table);
+
+	address = eg_pi->mc_reg_table_start +
+		(u16)offsetof(SMC_NIslands_MCRegisters, data[NISLANDS_MCREGISTERTABLE_FIRST_DRIVERSTATE_SLOT]);
+
+	return rv770_copy_bytes_to_smc(rdev, address,
+				       (u8 *)&mc_reg_table->data[NISLANDS_MCREGISTERTABLE_FIRST_DRIVERSTATE_SLOT],
+				       sizeof(SMC_NIslands_MCRegisterSet) * ni_new_state->performance_level_count,
+				       pi->sram_end);
+}
+
+static int ni_init_driver_calculated_leakage_table(struct radeon_device *rdev,
+						   PP_NIslands_CACTABLES *cac_tables)
+{
+	struct ni_power_info *ni_pi = ni_get_pi(rdev);
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	u32 leakage = 0;
+	unsigned int i, j, table_size;
+	s32 t;
+	u32 smc_leakage, max_leakage = 0;
+	u32 scaling_factor;
+
+	table_size = eg_pi->vddc_voltage_table.count;
+
+	if (SMC_NISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES < table_size)
+		table_size = SMC_NISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES;
+
+	scaling_factor = ni_get_smc_power_scaling_factor(rdev);
+
+	for (i = 0; i < SMC_NISLANDS_LKGE_LUT_NUM_OF_TEMP_ENTRIES; i++) {
+		for (j = 0; j < table_size; j++) {
+			t = (1000 * ((i + 1) * 8));
+
+			if (t < ni_pi->cac_data.leakage_minimum_temperature)
+				t = ni_pi->cac_data.leakage_minimum_temperature;
+
+			ni_calculate_leakage_for_v_and_t(rdev,
+							 &ni_pi->cac_data.leakage_coefficients,
+							 eg_pi->vddc_voltage_table.entries[j].value,
+							 t,
+							 ni_pi->cac_data.i_leakage,
+							 &leakage);
+
+			smc_leakage = ni_scale_power_for_smc(leakage, scaling_factor) / 1000;
+			if (smc_leakage > max_leakage)
+				max_leakage = smc_leakage;
+
+			cac_tables->cac_lkge_lut[i][j] = cpu_to_be32(smc_leakage);
+		}
+	}
+
+	for (j = table_size; j < SMC_NISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES; j++) {
+		for (i = 0; i < SMC_NISLANDS_LKGE_LUT_NUM_OF_TEMP_ENTRIES; i++)
+			cac_tables->cac_lkge_lut[i][j] = cpu_to_be32(max_leakage);
+	}
+	return 0;
+}
+
+static int ni_init_simplified_leakage_table(struct radeon_device *rdev,
+					    PP_NIslands_CACTABLES *cac_tables)
+{
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	struct radeon_cac_leakage_table *leakage_table =
+		&rdev->pm.dpm.dyn_state.cac_leakage_table;
+	u32 i, j, table_size;
+	u32 smc_leakage, max_leakage = 0;
+	u32 scaling_factor;
+
+	if (!leakage_table)
+		return -EINVAL;
+
+	table_size = leakage_table->count;
+
+	if (eg_pi->vddc_voltage_table.count != table_size)
+		table_size = (eg_pi->vddc_voltage_table.count < leakage_table->count) ?
+			eg_pi->vddc_voltage_table.count : leakage_table->count;
+
+	if (SMC_NISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES < table_size)
+		table_size = SMC_NISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES;
+
+	if (table_size == 0)
+		return -EINVAL;
+
+	scaling_factor = ni_get_smc_power_scaling_factor(rdev);
+
+	for (j = 0; j < table_size; j++) {
+		smc_leakage = leakage_table->entries[j].leakage;
+
+		if (smc_leakage > max_leakage)
+			max_leakage = smc_leakage;
+
+		for (i = 0; i < SMC_NISLANDS_LKGE_LUT_NUM_OF_TEMP_ENTRIES; i++)
+			cac_tables->cac_lkge_lut[i][j] =
+				cpu_to_be32(ni_scale_power_for_smc(smc_leakage, scaling_factor));
+	}
+
+	for (j = table_size; j < SMC_NISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES; j++) {
+		for (i = 0; i < SMC_NISLANDS_LKGE_LUT_NUM_OF_TEMP_ENTRIES; i++)
+			cac_tables->cac_lkge_lut[i][j] =
+				cpu_to_be32(ni_scale_power_for_smc(max_leakage, scaling_factor));
+	}
+	return 0;
+}
+
+static int ni_initialize_smc_cac_tables(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	struct ni_power_info *ni_pi = ni_get_pi(rdev);
+	PP_NIslands_CACTABLES *cac_tables = NULL;
+	int i, ret;
+        u32 reg;
+
+	if (ni_pi->enable_cac == false)
+		return 0;
+
+	cac_tables = kzalloc(sizeof(PP_NIslands_CACTABLES), GFP_KERNEL);
+	if (!cac_tables)
+		return -ENOMEM;
+
+	reg = RREG32(CG_CAC_CTRL) & ~(TID_CNT_MASK | TID_UNIT_MASK);
+	reg |= (TID_CNT(ni_pi->cac_weights->tid_cnt) |
+		TID_UNIT(ni_pi->cac_weights->tid_unit));
+	WREG32(CG_CAC_CTRL, reg);
+
+	for (i = 0; i < NISLANDS_DCCAC_MAX_LEVELS; i++)
+		ni_pi->dc_cac_table[i] = ni_pi->cac_weights->dc_cac[i];
+
+	for (i = 0; i < SMC_NISLANDS_BIF_LUT_NUM_OF_ENTRIES; i++)
+		cac_tables->cac_bif_lut[i] = ni_pi->cac_weights->pcie_cac[i];
+
+	ni_pi->cac_data.i_leakage = rdev->pm.dpm.cac_leakage;
+	ni_pi->cac_data.pwr_const = 0;
+	ni_pi->cac_data.dc_cac_value = ni_pi->dc_cac_table[NISLANDS_DCCAC_LEVEL_0];
+	ni_pi->cac_data.bif_cac_value = 0;
+	ni_pi->cac_data.mc_wr_weight = ni_pi->cac_weights->mc_write_weight;
+	ni_pi->cac_data.mc_rd_weight = ni_pi->cac_weights->mc_read_weight;
+	ni_pi->cac_data.allow_ovrflw = 0;
+	ni_pi->cac_data.l2num_win_tdp = ni_pi->lta_window_size;
+	ni_pi->cac_data.num_win_tdp = 0;
+	ni_pi->cac_data.lts_truncate_n = ni_pi->lts_truncate;
+
+	if (ni_pi->driver_calculate_cac_leakage)
+		ret = ni_init_driver_calculated_leakage_table(rdev, cac_tables);
+	else
+		ret = ni_init_simplified_leakage_table(rdev, cac_tables);
+
+	if (ret)
+		goto done_free;
+
+	cac_tables->pwr_const      = cpu_to_be32(ni_pi->cac_data.pwr_const);
+	cac_tables->dc_cacValue    = cpu_to_be32(ni_pi->cac_data.dc_cac_value);
+	cac_tables->bif_cacValue   = cpu_to_be32(ni_pi->cac_data.bif_cac_value);
+	cac_tables->AllowOvrflw    = ni_pi->cac_data.allow_ovrflw;
+	cac_tables->MCWrWeight     = ni_pi->cac_data.mc_wr_weight;
+	cac_tables->MCRdWeight     = ni_pi->cac_data.mc_rd_weight;
+	cac_tables->numWin_TDP     = ni_pi->cac_data.num_win_tdp;
+	cac_tables->l2numWin_TDP   = ni_pi->cac_data.l2num_win_tdp;
+	cac_tables->lts_truncate_n = ni_pi->cac_data.lts_truncate_n;
+
+	ret = rv770_copy_bytes_to_smc(rdev, ni_pi->cac_table_start, (u8 *)cac_tables,
+				      sizeof(PP_NIslands_CACTABLES), pi->sram_end);
+
+done_free:
+	if (ret) {
+		ni_pi->enable_cac = false;
+		ni_pi->enable_power_containment = false;
+	}
+
+	kfree(cac_tables);
+
+	return 0;
+}
+
+static int ni_initialize_hardware_cac_manager(struct radeon_device *rdev)
+{
+	struct ni_power_info *ni_pi = ni_get_pi(rdev);
+	u32 reg;
+
+	if (!ni_pi->enable_cac ||
+	    !ni_pi->cac_configuration_required)
+		return 0;
+
+	if (ni_pi->cac_weights == NULL)
+		return -EINVAL;
+
+	reg = RREG32_CG(CG_CAC_REGION_1_WEIGHT_0) & ~(WEIGHT_TCP_SIG0_MASK |
+						      WEIGHT_TCP_SIG1_MASK |
+						      WEIGHT_TA_SIG_MASK);
+	reg |= (WEIGHT_TCP_SIG0(ni_pi->cac_weights->weight_tcp_sig0) |
+		WEIGHT_TCP_SIG1(ni_pi->cac_weights->weight_tcp_sig1) |
+		WEIGHT_TA_SIG(ni_pi->cac_weights->weight_ta_sig));
+	WREG32_CG(CG_CAC_REGION_1_WEIGHT_0, reg);
+
+	reg = RREG32_CG(CG_CAC_REGION_1_WEIGHT_1) & ~(WEIGHT_TCC_EN0_MASK |
+						      WEIGHT_TCC_EN1_MASK |
+						      WEIGHT_TCC_EN2_MASK);
+	reg |= (WEIGHT_TCC_EN0(ni_pi->cac_weights->weight_tcc_en0) |
+		WEIGHT_TCC_EN1(ni_pi->cac_weights->weight_tcc_en1) |
+		WEIGHT_TCC_EN2(ni_pi->cac_weights->weight_tcc_en2));
+	WREG32_CG(CG_CAC_REGION_1_WEIGHT_1, reg);
+
+	reg = RREG32_CG(CG_CAC_REGION_2_WEIGHT_0) & ~(WEIGHT_CB_EN0_MASK |
+						      WEIGHT_CB_EN1_MASK |
+						      WEIGHT_CB_EN2_MASK |
+						      WEIGHT_CB_EN3_MASK);
+	reg |= (WEIGHT_CB_EN0(ni_pi->cac_weights->weight_cb_en0) |
+		WEIGHT_CB_EN1(ni_pi->cac_weights->weight_cb_en1) |
+		WEIGHT_CB_EN2(ni_pi->cac_weights->weight_cb_en2) |
+		WEIGHT_CB_EN3(ni_pi->cac_weights->weight_cb_en3));
+	WREG32_CG(CG_CAC_REGION_2_WEIGHT_0, reg);
+
+	reg = RREG32_CG(CG_CAC_REGION_2_WEIGHT_1) & ~(WEIGHT_DB_SIG0_MASK |
+						      WEIGHT_DB_SIG1_MASK |
+						      WEIGHT_DB_SIG2_MASK |
+						      WEIGHT_DB_SIG3_MASK);
+	reg |= (WEIGHT_DB_SIG0(ni_pi->cac_weights->weight_db_sig0) |
+		WEIGHT_DB_SIG1(ni_pi->cac_weights->weight_db_sig1) |
+		WEIGHT_DB_SIG2(ni_pi->cac_weights->weight_db_sig2) |
+		WEIGHT_DB_SIG3(ni_pi->cac_weights->weight_db_sig3));
+	WREG32_CG(CG_CAC_REGION_2_WEIGHT_1, reg);
+
+	reg = RREG32_CG(CG_CAC_REGION_2_WEIGHT_2) & ~(WEIGHT_SXM_SIG0_MASK |
+						      WEIGHT_SXM_SIG1_MASK |
+						      WEIGHT_SXM_SIG2_MASK |
+						      WEIGHT_SXS_SIG0_MASK |
+						      WEIGHT_SXS_SIG1_MASK);
+	reg |= (WEIGHT_SXM_SIG0(ni_pi->cac_weights->weight_sxm_sig0) |
+		WEIGHT_SXM_SIG1(ni_pi->cac_weights->weight_sxm_sig1) |
+		WEIGHT_SXM_SIG2(ni_pi->cac_weights->weight_sxm_sig2) |
+		WEIGHT_SXS_SIG0(ni_pi->cac_weights->weight_sxs_sig0) |
+		WEIGHT_SXS_SIG1(ni_pi->cac_weights->weight_sxs_sig1));
+	WREG32_CG(CG_CAC_REGION_2_WEIGHT_2, reg);
+
+	reg = RREG32_CG(CG_CAC_REGION_3_WEIGHT_0) & ~(WEIGHT_XBR_0_MASK |
+						      WEIGHT_XBR_1_MASK |
+						      WEIGHT_XBR_2_MASK |
+						      WEIGHT_SPI_SIG0_MASK);
+	reg |= (WEIGHT_XBR_0(ni_pi->cac_weights->weight_xbr_0) |
+		WEIGHT_XBR_1(ni_pi->cac_weights->weight_xbr_1) |
+		WEIGHT_XBR_2(ni_pi->cac_weights->weight_xbr_2) |
+		WEIGHT_SPI_SIG0(ni_pi->cac_weights->weight_spi_sig0));
+	WREG32_CG(CG_CAC_REGION_3_WEIGHT_0, reg);
+
+	reg = RREG32_CG(CG_CAC_REGION_3_WEIGHT_1) & ~(WEIGHT_SPI_SIG1_MASK |
+						      WEIGHT_SPI_SIG2_MASK |
+						      WEIGHT_SPI_SIG3_MASK |
+						      WEIGHT_SPI_SIG4_MASK |
+						      WEIGHT_SPI_SIG5_MASK);
+	reg |= (WEIGHT_SPI_SIG1(ni_pi->cac_weights->weight_spi_sig1) |
+		WEIGHT_SPI_SIG2(ni_pi->cac_weights->weight_spi_sig2) |
+		WEIGHT_SPI_SIG3(ni_pi->cac_weights->weight_spi_sig3) |
+		WEIGHT_SPI_SIG4(ni_pi->cac_weights->weight_spi_sig4) |
+		WEIGHT_SPI_SIG5(ni_pi->cac_weights->weight_spi_sig5));
+	WREG32_CG(CG_CAC_REGION_3_WEIGHT_1, reg);
+
+	reg = RREG32_CG(CG_CAC_REGION_4_WEIGHT_0) & ~(WEIGHT_LDS_SIG0_MASK |
+						      WEIGHT_LDS_SIG1_MASK |
+						      WEIGHT_SC_MASK);
+	reg |= (WEIGHT_LDS_SIG0(ni_pi->cac_weights->weight_lds_sig0) |
+		WEIGHT_LDS_SIG1(ni_pi->cac_weights->weight_lds_sig1) |
+		WEIGHT_SC(ni_pi->cac_weights->weight_sc));
+	WREG32_CG(CG_CAC_REGION_4_WEIGHT_0, reg);
+
+	reg = RREG32_CG(CG_CAC_REGION_4_WEIGHT_1) & ~(WEIGHT_BIF_MASK |
+						      WEIGHT_CP_MASK |
+						      WEIGHT_PA_SIG0_MASK |
+						      WEIGHT_PA_SIG1_MASK |
+						      WEIGHT_VGT_SIG0_MASK);
+	reg |= (WEIGHT_BIF(ni_pi->cac_weights->weight_bif) |
+		WEIGHT_CP(ni_pi->cac_weights->weight_cp) |
+		WEIGHT_PA_SIG0(ni_pi->cac_weights->weight_pa_sig0) |
+		WEIGHT_PA_SIG1(ni_pi->cac_weights->weight_pa_sig1) |
+		WEIGHT_VGT_SIG0(ni_pi->cac_weights->weight_vgt_sig0));
+	WREG32_CG(CG_CAC_REGION_4_WEIGHT_1, reg);
+
+	reg = RREG32_CG(CG_CAC_REGION_4_WEIGHT_2) & ~(WEIGHT_VGT_SIG1_MASK |
+						      WEIGHT_VGT_SIG2_MASK |
+						      WEIGHT_DC_SIG0_MASK |
+						      WEIGHT_DC_SIG1_MASK |
+						      WEIGHT_DC_SIG2_MASK);
+	reg |= (WEIGHT_VGT_SIG1(ni_pi->cac_weights->weight_vgt_sig1) |
+		WEIGHT_VGT_SIG2(ni_pi->cac_weights->weight_vgt_sig2) |
+		WEIGHT_DC_SIG0(ni_pi->cac_weights->weight_dc_sig0) |
+		WEIGHT_DC_SIG1(ni_pi->cac_weights->weight_dc_sig1) |
+		WEIGHT_DC_SIG2(ni_pi->cac_weights->weight_dc_sig2));
+	WREG32_CG(CG_CAC_REGION_4_WEIGHT_2, reg);
+
+	reg = RREG32_CG(CG_CAC_REGION_4_WEIGHT_3) & ~(WEIGHT_DC_SIG3_MASK |
+						      WEIGHT_UVD_SIG0_MASK |
+						      WEIGHT_UVD_SIG1_MASK |
+						      WEIGHT_SPARE0_MASK |
+						      WEIGHT_SPARE1_MASK);
+	reg |= (WEIGHT_DC_SIG3(ni_pi->cac_weights->weight_dc_sig3) |
+		WEIGHT_UVD_SIG0(ni_pi->cac_weights->weight_uvd_sig0) |
+		WEIGHT_UVD_SIG1(ni_pi->cac_weights->weight_uvd_sig1) |
+		WEIGHT_SPARE0(ni_pi->cac_weights->weight_spare0) |
+		WEIGHT_SPARE1(ni_pi->cac_weights->weight_spare1));
+	WREG32_CG(CG_CAC_REGION_4_WEIGHT_3, reg);
+
+	reg = RREG32_CG(CG_CAC_REGION_5_WEIGHT_0) & ~(WEIGHT_SQ_VSP_MASK |
+						      WEIGHT_SQ_VSP0_MASK);
+	reg |= (WEIGHT_SQ_VSP(ni_pi->cac_weights->weight_sq_vsp) |
+		WEIGHT_SQ_VSP0(ni_pi->cac_weights->weight_sq_vsp0));
+	WREG32_CG(CG_CAC_REGION_5_WEIGHT_0, reg);
+
+	reg = RREG32_CG(CG_CAC_REGION_5_WEIGHT_1) & ~(WEIGHT_SQ_GPR_MASK);
+	reg |= WEIGHT_SQ_GPR(ni_pi->cac_weights->weight_sq_gpr);
+	WREG32_CG(CG_CAC_REGION_5_WEIGHT_1, reg);
+
+	reg = RREG32_CG(CG_CAC_REGION_4_OVERRIDE_4) & ~(OVR_MODE_SPARE_0_MASK |
+							OVR_VAL_SPARE_0_MASK |
+							OVR_MODE_SPARE_1_MASK |
+							OVR_VAL_SPARE_1_MASK);
+	reg |= (OVR_MODE_SPARE_0(ni_pi->cac_weights->ovr_mode_spare_0) |
+		OVR_VAL_SPARE_0(ni_pi->cac_weights->ovr_val_spare_0) |
+		OVR_MODE_SPARE_1(ni_pi->cac_weights->ovr_mode_spare_1) |
+		OVR_VAL_SPARE_1(ni_pi->cac_weights->ovr_val_spare_1));
+	WREG32_CG(CG_CAC_REGION_4_OVERRIDE_4, reg);
+
+	reg = RREG32(SQ_CAC_THRESHOLD) & ~(VSP_MASK |
+					   VSP0_MASK |
+					   GPR_MASK);
+	reg |= (VSP(ni_pi->cac_weights->vsp) |
+		VSP0(ni_pi->cac_weights->vsp0) |
+		GPR(ni_pi->cac_weights->gpr));
+	WREG32(SQ_CAC_THRESHOLD, reg);
+
+	reg = (MCDW_WR_ENABLE |
+	       MCDX_WR_ENABLE |
+	       MCDY_WR_ENABLE |
+	       MCDZ_WR_ENABLE |
+	       INDEX(0x09D4));
+	WREG32(MC_CG_CONFIG, reg);
+
+	reg = (READ_WEIGHT(ni_pi->cac_weights->mc_read_weight) |
+	       WRITE_WEIGHT(ni_pi->cac_weights->mc_write_weight) |
+	       ALLOW_OVERFLOW);
+	WREG32(MC_CG_DATAPORT, reg);
+
+	return 0;
+}
+
+static int ni_enable_smc_cac(struct radeon_device *rdev, bool enable)
+{
+	struct ni_power_info *ni_pi = ni_get_pi(rdev);
+	int ret = 0;
+	PPSMC_Result smc_result;
+
+	if (ni_pi->enable_cac) {
+		if (enable) {
+			struct radeon_ps *radeon_new_state = rdev->pm.dpm.requested_ps;
+
+			if (!r600_is_uvd_state(radeon_new_state->class, radeon_new_state->class2)) {
+				smc_result = rv770_send_msg_to_smc(rdev, PPSMC_MSG_CollectCAC_PowerCorreln);
+
+				if (ni_pi->support_cac_long_term_average) {
+					smc_result = rv770_send_msg_to_smc(rdev, PPSMC_CACLongTermAvgEnable);
+					if (PPSMC_Result_OK != smc_result)
+						ni_pi->support_cac_long_term_average = false;
+				}
+
+				smc_result = rv770_send_msg_to_smc(rdev, PPSMC_MSG_EnableCac);
+				if (PPSMC_Result_OK != smc_result)
+					ret = -EINVAL;
+
+				ni_pi->cac_enabled = (PPSMC_Result_OK == smc_result) ? true : false;
+			}
+		} else if (ni_pi->cac_enabled) {
+			smc_result = rv770_send_msg_to_smc(rdev, PPSMC_MSG_DisableCac);
+
+			ni_pi->cac_enabled = false;
+
+			if (ni_pi->support_cac_long_term_average) {
+				smc_result = rv770_send_msg_to_smc(rdev, PPSMC_CACLongTermAvgDisable);
+				if (PPSMC_Result_OK != smc_result)
+					ni_pi->support_cac_long_term_average = false;
+			}
+		}
+	}
+
+	return ret;
+}
+
+static int ni_pcie_performance_request(struct radeon_device *rdev,
+				       u8 perf_req, bool advertise)
+{
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+
+#if defined(CONFIG_ACPI)
+	if ((perf_req == PCIE_PERF_REQ_PECI_GEN1) ||
+            (perf_req == PCIE_PERF_REQ_PECI_GEN2)) {
+		if (eg_pi->pcie_performance_request_registered == false)
+			radeon_acpi_pcie_notify_device_ready(rdev);
+		eg_pi->pcie_performance_request_registered = true;
+		return radeon_acpi_pcie_performance_request(rdev, perf_req, advertise);
+	} else if ((perf_req == PCIE_PERF_REQ_REMOVE_REGISTRY) &&
+                   eg_pi->pcie_performance_request_registered) {
+		eg_pi->pcie_performance_request_registered = false;
+		return radeon_acpi_pcie_performance_request(rdev, perf_req, advertise);
+	}
+#endif
+	return 0;
+}
+
+static int ni_advertise_gen2_capability(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	u32 tmp;
+
+        tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL);
+
+        if ((tmp & LC_OTHER_SIDE_EVER_SENT_GEN2) &&
+            (tmp & LC_OTHER_SIDE_SUPPORTS_GEN2))
+                pi->pcie_gen2 = true;
+        else
+		pi->pcie_gen2 = false;
+
+	if (!pi->pcie_gen2)
+		ni_pcie_performance_request(rdev, PCIE_PERF_REQ_PECI_GEN2, true);
+
+	return 0;
+}
+
+static void ni_enable_bif_dynamic_pcie_gen2(struct radeon_device *rdev,
+					    bool enable)
+{
+        struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+        u32 tmp, bif;
+
+	tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL);
+
+	if ((tmp & LC_OTHER_SIDE_EVER_SENT_GEN2) &&
+	    (tmp & LC_OTHER_SIDE_SUPPORTS_GEN2)) {
+		if (enable) {
+			if (!pi->boot_in_gen2) {
+				bif = RREG32(CG_BIF_REQ_AND_RSP) & ~CG_CLIENT_REQ_MASK;
+				bif |= CG_CLIENT_REQ(0xd);
+				WREG32(CG_BIF_REQ_AND_RSP, bif);
+			}
+			tmp &= ~LC_HW_VOLTAGE_IF_CONTROL_MASK;
+			tmp |= LC_HW_VOLTAGE_IF_CONTROL(1);
+			tmp |= LC_GEN2_EN_STRAP;
+
+			tmp |= LC_CLR_FAILED_SPD_CHANGE_CNT;
+			WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp);
+			udelay(10);
+			tmp &= ~LC_CLR_FAILED_SPD_CHANGE_CNT;
+			WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp);
+		} else {
+			if (!pi->boot_in_gen2) {
+				bif = RREG32(CG_BIF_REQ_AND_RSP) & ~CG_CLIENT_REQ_MASK;
+				bif |= CG_CLIENT_REQ(0xd);
+				WREG32(CG_BIF_REQ_AND_RSP, bif);
+
+				tmp &= ~LC_HW_VOLTAGE_IF_CONTROL_MASK;
+				tmp &= ~LC_GEN2_EN_STRAP;
+			}
+			WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp);
+		}
+	}
+}
+
+static void ni_enable_dynamic_pcie_gen2(struct radeon_device *rdev,
+					bool enable)
+{
+	ni_enable_bif_dynamic_pcie_gen2(rdev, enable);
+
+	if (enable)
+		WREG32_P(GENERAL_PWRMGT, ENABLE_GEN2PCIE, ~ENABLE_GEN2PCIE);
+	else
+                WREG32_P(GENERAL_PWRMGT, 0, ~ENABLE_GEN2PCIE);
+}
+
+void ni_dpm_setup_asic(struct radeon_device *rdev)
+{
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+
+	ni_read_clock_registers(rdev);
+	btc_read_arb_registers(rdev);
+	rv770_get_memory_type(rdev);
+	if (eg_pi->pcie_performance_request)
+		ni_advertise_gen2_capability(rdev);
+	rv770_get_pcie_gen2_status(rdev);
+	rv770_enable_acpi_pm(rdev);
+}
+
+int ni_dpm_enable(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+
+	if (pi->gfx_clock_gating)
+		ni_cg_clockgating_default(rdev);
+        if (btc_dpm_enabled(rdev))
+                return -EINVAL;
+	if (pi->mg_clock_gating)
+		ni_mg_clockgating_default(rdev);
+	if (eg_pi->ls_clock_gating)
+		ni_ls_clockgating_default(rdev);
+	if (pi->voltage_control) {
+		rv770_enable_voltage_control(rdev, true);
+		cypress_construct_voltage_tables(rdev);
+	}
+	if (eg_pi->dynamic_ac_timing)
+		ni_initialize_mc_reg_table(rdev);
+	if (pi->dynamic_ss)
+		cypress_enable_spread_spectrum(rdev, true);
+	if (pi->thermal_protection)
+		rv770_enable_thermal_protection(rdev, true);
+	rv770_setup_bsp(rdev);
+	rv770_program_git(rdev);
+	rv770_program_tp(rdev);
+	rv770_program_tpp(rdev);
+	rv770_program_sstp(rdev);
+	cypress_enable_display_gap(rdev);
+	rv770_program_vc(rdev);
+	if (pi->dynamic_pcie_gen2)
+		ni_enable_dynamic_pcie_gen2(rdev, true);
+	if (rv770_upload_firmware(rdev))
+		return -EINVAL;
+	ni_process_firmware_header(rdev);
+	ni_initial_switch_from_arb_f0_to_f1(rdev);
+	ni_init_smc_table(rdev);
+	ni_init_smc_spll_table(rdev);
+	ni_init_arb_table_index(rdev);
+	if (eg_pi->dynamic_ac_timing)
+		ni_populate_mc_reg_table(rdev);
+	ni_initialize_smc_cac_tables(rdev);
+	ni_initialize_hardware_cac_manager(rdev);
+	ni_populate_smc_tdp_limits(rdev);
+	ni_program_response_times(rdev);
+	r7xx_start_smc(rdev);
+	cypress_notify_smc_display_change(rdev, false);
+	cypress_enable_sclk_control(rdev, true);
+	if (eg_pi->memory_transition)
+		cypress_enable_mclk_control(rdev, true);
+	cypress_start_dpm(rdev);
+	if (pi->gfx_clock_gating)
+		ni_gfx_clockgating_enable(rdev, true);
+	if (pi->mg_clock_gating)
+		ni_mg_clockgating_enable(rdev, true);
+	if (eg_pi->ls_clock_gating)
+		ni_ls_clockgating_enable(rdev, true);
+
+	if (rdev->irq.installed &&
+	    r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
+		PPSMC_Result result;
+
+		rv770_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, 0xff * 1000);
+		rdev->irq.dpm_thermal = true;
+		radeon_irq_set(rdev);
+		result = rv770_send_msg_to_smc(rdev, PPSMC_MSG_EnableThermalInterrupt);
+
+		if (result != PPSMC_Result_OK)
+			DRM_DEBUG_KMS("Could not enable thermal interrupts.\n");
+	}
+
+	rv770_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true);
+
+	return 0;
+}
+
+void ni_dpm_disable(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+
+	if (!btc_dpm_enabled(rdev))
+		return;
+	rv770_clear_vc(rdev);
+	if (pi->thermal_protection)
+		rv770_enable_thermal_protection(rdev, false);
+	ni_enable_power_containment(rdev, false);
+	ni_enable_smc_cac(rdev, false);
+	cypress_enable_spread_spectrum(rdev, false);
+	rv770_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, false);
+	if (pi->dynamic_pcie_gen2)
+		ni_enable_dynamic_pcie_gen2(rdev, false);
+
+	if (rdev->irq.installed &&
+	    r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
+		rdev->irq.dpm_thermal = false;
+		radeon_irq_set(rdev);
+	}
+
+	if (pi->gfx_clock_gating)
+		ni_gfx_clockgating_enable(rdev, false);
+	if (pi->mg_clock_gating)
+		ni_mg_clockgating_enable(rdev, false);
+	if (eg_pi->ls_clock_gating)
+		ni_ls_clockgating_enable(rdev, false);
+	ni_stop_dpm(rdev);
+	btc_reset_to_default(rdev);
+	ni_stop_smc(rdev);
+	ni_force_switch_to_arb_f0(rdev);
+}
+
+int ni_power_control_set_level(struct radeon_device *rdev)
+{
+	ni_restrict_performance_levels_before_switch(rdev);
+	rv770_halt_smc(rdev);
+	ni_populate_smc_tdp_limits(rdev);
+	rv770_resume_smc(rdev);
+	rv770_set_sw_state(rdev);
+
+	return 0;
+}
+
+int ni_dpm_set_power_state(struct radeon_device *rdev)
+{
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	int ret;
+
+	ni_apply_state_adjust_rules(rdev);
+
+	ni_restrict_performance_levels_before_switch(rdev);
+	ni_enable_power_containment(rdev, false);
+	ni_enable_smc_cac(rdev, false);
+	rv770_halt_smc(rdev);
+	if (eg_pi->smu_uvd_hs)
+		btc_notify_uvd_to_smc(rdev);
+	ni_upload_sw_state(rdev);
+	if (eg_pi->dynamic_ac_timing)
+		ni_upload_mc_reg_table(rdev);
+	ret = ni_program_memory_timing_parameters(rdev);
+	if (ret)
+		return ret;
+	rv770_resume_smc(rdev);
+	rv770_set_sw_state(rdev);
+	ni_enable_smc_cac(rdev, true);
+	ni_enable_power_containment(rdev, true);
+
+	return 0;
+}
+
+void ni_dpm_reset_asic(struct radeon_device *rdev)
+{
+	ni_restrict_performance_levels_before_switch(rdev);
+	rv770_set_boot_state(rdev);
+}
+
+union power_info {
+	struct _ATOM_POWERPLAY_INFO info;
+	struct _ATOM_POWERPLAY_INFO_V2 info_2;
+	struct _ATOM_POWERPLAY_INFO_V3 info_3;
+	struct _ATOM_PPLIB_POWERPLAYTABLE pplib;
+	struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2;
+	struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3;
+};
+
+union pplib_clock_info {
+	struct _ATOM_PPLIB_R600_CLOCK_INFO r600;
+	struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780;
+	struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen;
+	struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo;
+};
+
+union pplib_power_state {
+	struct _ATOM_PPLIB_STATE v1;
+	struct _ATOM_PPLIB_STATE_V2 v2;
+};
+
+static void ni_parse_pplib_non_clock_info(struct radeon_device *rdev,
+					  struct radeon_ps *rps,
+					  struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info,
+					  u8 table_rev)
+{
+	rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings);
+	rps->class = le16_to_cpu(non_clock_info->usClassification);
+	rps->class2 = le16_to_cpu(non_clock_info->usClassification2);
+
+	if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) {
+		rps->vclk = le32_to_cpu(non_clock_info->ulVCLK);
+		rps->dclk = le32_to_cpu(non_clock_info->ulDCLK);
+	} else if (r600_is_uvd_state(rps->class, rps->class2)) {
+		rps->vclk = RV770_DEFAULT_VCLK_FREQ;
+		rps->dclk = RV770_DEFAULT_DCLK_FREQ;
+	} else {
+		rps->vclk = 0;
+		rps->dclk = 0;
+	}
+
+	if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT)
+		rdev->pm.dpm.boot_ps = rps;
+	if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
+		rdev->pm.dpm.uvd_ps = rps;
+}
+
+static void ni_parse_pplib_clock_info(struct radeon_device *rdev,
+				      struct radeon_ps *rps, int index,
+				      union pplib_clock_info *clock_info)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	struct ni_ps *ps = ni_get_ps(rps);
+	u16 vddc;
+	struct rv7xx_pl *pl = &ps->performance_levels[index];
+
+	ps->performance_level_count = index + 1;
+
+	pl->sclk = le16_to_cpu(clock_info->evergreen.usEngineClockLow);
+	pl->sclk |= clock_info->evergreen.ucEngineClockHigh << 16;
+	pl->mclk = le16_to_cpu(clock_info->evergreen.usMemoryClockLow);
+	pl->mclk |= clock_info->evergreen.ucMemoryClockHigh << 16;
+
+	pl->vddc = le16_to_cpu(clock_info->evergreen.usVDDC);
+	pl->vddci = le16_to_cpu(clock_info->evergreen.usVDDCI);
+	pl->flags = le32_to_cpu(clock_info->evergreen.ulFlags);
+
+	/* patch up vddc if necessary */
+	if (pl->vddc == 0xff01) {
+		if (radeon_atom_get_max_vddc(rdev, 0, 0, &vddc) == 0)
+			pl->vddc = vddc;
+	}
+
+	if (rps->class & ATOM_PPLIB_CLASSIFICATION_ACPI) {
+		pi->acpi_vddc = pl->vddc;
+		eg_pi->acpi_vddci = pl->vddci;
+		if (ps->performance_levels[0].flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2)
+			pi->acpi_pcie_gen2 = true;
+		else
+			pi->acpi_pcie_gen2 = false;
+	}
+
+	if (rps->class2 & ATOM_PPLIB_CLASSIFICATION2_ULV) {
+		eg_pi->ulv.supported = true;
+		eg_pi->ulv.pl = pl;
+	}
+
+	if (pi->min_vddc_in_table > pl->vddc)
+		pi->min_vddc_in_table = pl->vddc;
+
+	if (pi->max_vddc_in_table < pl->vddc)
+		pi->max_vddc_in_table = pl->vddc;
+
+	/* patch up boot state */
+	if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) {
+		u16 vddc, vddci;
+		radeon_atombios_get_default_voltages(rdev, &vddc, &vddci);
+		pl->mclk = rdev->clock.default_mclk;
+		pl->sclk = rdev->clock.default_sclk;
+		pl->vddc = vddc;
+		pl->vddci = vddci;
+	}
+
+	if ((rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) ==
+	    ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE) {
+		rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.sclk = pl->sclk;
+		rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.mclk = pl->mclk;
+		rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.vddc = pl->vddc;
+		rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.vddci = pl->vddci;
+	}
+}
+
+static int ni_parse_power_table(struct radeon_device *rdev)
+{
+	struct radeon_mode_info *mode_info = &rdev->mode_info;
+	struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
+	union pplib_power_state *power_state;
+	int i, j;
+	union pplib_clock_info *clock_info;
+	union power_info *power_info;
+	int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
+        u16 data_offset;
+	u8 frev, crev;
+	struct ni_ps *ps;
+
+	if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
+				   &frev, &crev, &data_offset))
+		return -EINVAL;
+	power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
+
+	rdev->pm.dpm.ps = kzalloc(sizeof(struct radeon_ps) *
+				  power_info->pplib.ucNumStates, GFP_KERNEL);
+	if (!rdev->pm.dpm.ps)
+		return -ENOMEM;
+	rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps);
+	rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime);
+	rdev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime);
+
+	for (i = 0; i < power_info->pplib.ucNumStates; i++) {
+		power_state = (union pplib_power_state *)
+			(mode_info->atom_context->bios + data_offset +
+			 le16_to_cpu(power_info->pplib.usStateArrayOffset) +
+			 i * power_info->pplib.ucStateEntrySize);
+		non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
+			(mode_info->atom_context->bios + data_offset +
+			 le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset) +
+			 (power_state->v1.ucNonClockStateIndex *
+			  power_info->pplib.ucNonClockSize));
+		if (power_info->pplib.ucStateEntrySize - 1) {
+			ps = kzalloc(sizeof(struct ni_ps), GFP_KERNEL);
+			if (ps == NULL) {
+				kfree(rdev->pm.dpm.ps);
+				return -ENOMEM;
+			}
+			rdev->pm.dpm.ps[i].ps_priv = ps;
+			ni_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i],
+							 non_clock_info,
+							 power_info->pplib.ucNonClockSize);
+			for (j = 0; j < (power_info->pplib.ucStateEntrySize - 1); j++) {
+				clock_info = (union pplib_clock_info *)
+					(mode_info->atom_context->bios + data_offset +
+					 le16_to_cpu(power_info->pplib.usClockInfoArrayOffset) +
+					 (power_state->v1.ucClockStateIndices[j] *
+					  power_info->pplib.ucClockInfoSize));
+				ni_parse_pplib_clock_info(rdev,
+							  &rdev->pm.dpm.ps[i], j,
+							  clock_info);
+			}
+		}
+	}
+	rdev->pm.dpm.num_ps = power_info->pplib.ucNumStates;
+	return 0;
+}
+
+int ni_dpm_init(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi;
+	struct evergreen_power_info *eg_pi;
+	struct ni_power_info *ni_pi;
+	int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info);
+	u16 data_offset, size;
+	u8 frev, crev;
+	struct atom_clock_dividers dividers;
+	int ret;
+
+	ni_pi = kzalloc(sizeof(struct ni_power_info), GFP_KERNEL);
+	if (ni_pi == NULL)
+		return -ENOMEM;
+	rdev->pm.dpm.priv = ni_pi;
+	eg_pi = &ni_pi->eg;
+	pi = &eg_pi->rv7xx;
+
+	rv770_get_max_vddc(rdev);
+
+	eg_pi->ulv.supported = false;
+	pi->acpi_vddc = 0;
+	eg_pi->acpi_vddci = 0;
+	pi->min_vddc_in_table = 0;
+	pi->max_vddc_in_table = 0;
+
+	ret = ni_parse_power_table(rdev);
+	if (ret)
+		return ret;
+	ret = r600_parse_extended_power_table(rdev);
+	if (ret)
+		return ret;
+
+	ni_patch_dependency_tables_based_on_leakage(rdev);
+
+	if (rdev->pm.dpm.voltage_response_time == 0)
+		rdev->pm.dpm.voltage_response_time = R600_VOLTAGERESPONSETIME_DFLT;
+	if (rdev->pm.dpm.backbias_response_time == 0)
+		rdev->pm.dpm.backbias_response_time = R600_BACKBIASRESPONSETIME_DFLT;
+
+	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
+					     0, false, &dividers);
+	if (ret)
+		pi->ref_div = dividers.ref_div + 1;
+	else
+		pi->ref_div = R600_REFERENCEDIVIDER_DFLT;
+
+	pi->rlp = RV770_RLP_DFLT;
+	pi->rmp = RV770_RMP_DFLT;
+	pi->lhp = RV770_LHP_DFLT;
+	pi->lmp = RV770_LMP_DFLT;
+
+	eg_pi->ats[0].rlp = RV770_RLP_DFLT;
+	eg_pi->ats[0].rmp = RV770_RMP_DFLT;
+	eg_pi->ats[0].lhp = RV770_LHP_DFLT;
+	eg_pi->ats[0].lmp = RV770_LMP_DFLT;
+
+	eg_pi->ats[1].rlp = BTC_RLP_UVD_DFLT;
+	eg_pi->ats[1].rmp = BTC_RMP_UVD_DFLT;
+	eg_pi->ats[1].lhp = BTC_LHP_UVD_DFLT;
+	eg_pi->ats[1].lmp = BTC_LMP_UVD_DFLT;
+
+	eg_pi->smu_uvd_hs = true;
+
+	if (rdev->pdev->device == 0x6707) {
+		pi->mclk_strobe_mode_threshold = 55000;
+		pi->mclk_edc_enable_threshold = 55000;
+		eg_pi->mclk_edc_wr_enable_threshold = 55000;
+	} else {
+		pi->mclk_strobe_mode_threshold = 40000;
+		pi->mclk_edc_enable_threshold = 40000;
+		eg_pi->mclk_edc_wr_enable_threshold = 40000;
+	}
+	ni_pi->mclk_rtt_mode_threshold = eg_pi->mclk_edc_wr_enable_threshold;
+
+	pi->voltage_control =
+		radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC);
+
+	pi->mvdd_control =
+		radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_MVDDC);
+
+	eg_pi->vddci_control =
+		radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDCI);
+
+	if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
+                                   &frev, &crev, &data_offset)) {
+		pi->sclk_ss = true;
+		pi->mclk_ss = true;
+		pi->dynamic_ss = true;
+	} else {
+		pi->sclk_ss = false;
+		pi->mclk_ss = false;
+		pi->dynamic_ss = true;
+	}
+
+	pi->asi = RV770_ASI_DFLT;
+	pi->pasi = CYPRESS_HASI_DFLT;
+	pi->vrc = CYPRESS_VRC_DFLT;
+
+	pi->power_gating = false;
+
+	pi->gfx_clock_gating = true;
+
+	pi->mg_clock_gating = true;
+	pi->mgcgtssm = true;
+	eg_pi->ls_clock_gating = false;
+	eg_pi->sclk_deep_sleep = false;
+
+	pi->dynamic_pcie_gen2 = true;
+
+	if (pi->gfx_clock_gating &&
+	    (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE))
+		pi->thermal_protection = true;
+	else
+		pi->thermal_protection = false;
+
+	pi->display_gap = true;
+
+	pi->dcodt = true;
+
+	pi->ulps = true;
+
+	eg_pi->dynamic_ac_timing = true;
+	eg_pi->abm = true;
+	eg_pi->mcls = true;
+	eg_pi->light_sleep = true;
+	eg_pi->memory_transition = true;
+#if defined(CONFIG_ACPI)
+	eg_pi->pcie_performance_request =
+		radeon_acpi_is_pcie_performance_request_supported(rdev);
+#else
+	eg_pi->pcie_performance_request = false;
+#endif
+
+	eg_pi->dll_default_on = false;
+
+	eg_pi->sclk_deep_sleep = false;
+
+	pi->mclk_stutter_mode_threshold = 0;
+
+	pi->sram_end = SMC_RAM_END;
+
+	rdev->pm.dpm.dyn_state.mclk_sclk_ratio = 3;
+	rdev->pm.dpm.dyn_state.vddc_vddci_delta = 200;
+	rdev->pm.dpm.dyn_state.min_vddc_for_pcie_gen2 = 900;
+	rdev->pm.dpm.dyn_state.valid_sclk_values.count = ARRAY_SIZE(btc_valid_sclk);
+	rdev->pm.dpm.dyn_state.valid_sclk_values.values = btc_valid_sclk;
+	rdev->pm.dpm.dyn_state.valid_mclk_values.count = 0;
+	rdev->pm.dpm.dyn_state.valid_mclk_values.values = NULL;
+	rdev->pm.dpm.dyn_state.sclk_mclk_delta = 12500;
+
+	ni_pi->cac_data.leakage_coefficients.at = 516;
+	ni_pi->cac_data.leakage_coefficients.bt = 18;
+	ni_pi->cac_data.leakage_coefficients.av = 51;
+	ni_pi->cac_data.leakage_coefficients.bv = 2957;
+
+	switch (rdev->pdev->device) {
+	case 0x6700:
+	case 0x6701:
+	case 0x6702:
+	case 0x6703:
+	case 0x6718:
+		ni_pi->cac_weights = &cac_weights_cayman_xt;
+		break;
+	case 0x6705:
+	case 0x6719:
+	case 0x671D:
+	case 0x671C:
+	default:
+		ni_pi->cac_weights = &cac_weights_cayman_pro;
+		break;
+	case 0x6704:
+	case 0x6706:
+	case 0x6707:
+	case 0x6708:
+	case 0x6709:
+		ni_pi->cac_weights = &cac_weights_cayman_le;
+		break;
+	}
+
+	if (ni_pi->cac_weights->enable_power_containment_by_default) {
+		ni_pi->enable_power_containment = true;
+		ni_pi->enable_cac = true;
+		ni_pi->enable_sq_ramping = true;
+	} else {
+		ni_pi->enable_power_containment = false;
+		ni_pi->enable_cac = false;
+		ni_pi->enable_sq_ramping = false;
+	}
+
+	ni_pi->driver_calculate_cac_leakage = false;
+	ni_pi->cac_configuration_required = true;
+
+	if (ni_pi->cac_configuration_required) {
+		ni_pi->support_cac_long_term_average = true;
+		ni_pi->lta_window_size = ni_pi->cac_weights->l2_lta_window_size;
+		ni_pi->lts_truncate = ni_pi->cac_weights->lts_truncate;
+	} else {
+		ni_pi->support_cac_long_term_average = false;
+		ni_pi->lta_window_size = 0;
+		ni_pi->lts_truncate = 0;
+	}
+
+	ni_pi->use_power_boost_limit = true;
+
+	return 0;
+}
+
+void ni_dpm_fini(struct radeon_device *rdev)
+{
+	int i;
+
+	for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
+		kfree(rdev->pm.dpm.ps[i].ps_priv);
+	}
+	kfree(rdev->pm.dpm.ps);
+	kfree(rdev->pm.dpm.priv);
+	r600_free_extended_power_table(rdev);
+}
+
+void ni_dpm_print_power_state(struct radeon_device *rdev,
+			      struct radeon_ps *rps)
+{
+	struct ni_ps *ps = ni_get_ps(rps);
+	struct rv7xx_pl *pl;
+	int i;
+
+	r600_dpm_print_class_info(rps->class, rps->class2);
+	r600_dpm_print_cap_info(rps->caps);
+	printk("\tuvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
+	for (i = 0; i < ps->performance_level_count; i++) {
+		pl = &ps->performance_levels[i];
+		printk("\t\tpower level 0    sclk: %u mclk: %u vddc: %u vddci: %u\n",
+		       pl->sclk, pl->mclk, pl->vddc, pl->vddci);
+	}
+	r600_dpm_print_ps_status(rdev, rps);
+}
+
+u32 ni_dpm_get_sclk(struct radeon_device *rdev, bool low)
+{
+	struct ni_ps *requested_state = ni_get_ps(rdev->pm.dpm.requested_ps);
+
+	if (low)
+		return requested_state->performance_levels[0].sclk;
+	else
+		return requested_state->performance_levels[requested_state->performance_level_count - 1].sclk;
+}
+
+u32 ni_dpm_get_mclk(struct radeon_device *rdev, bool low)
+{
+	struct ni_ps *requested_state = ni_get_ps(rdev->pm.dpm.requested_ps);
+
+	if (low)
+		return requested_state->performance_levels[0].mclk;
+	else
+		return requested_state->performance_levels[requested_state->performance_level_count - 1].mclk;
+}
+
diff --git a/drivers/gpu/drm/radeon/ni_dpm.h b/drivers/gpu/drm/radeon/ni_dpm.h
new file mode 100644
index 0000000..e10f747
--- /dev/null
+++ b/drivers/gpu/drm/radeon/ni_dpm.h
@@ -0,0 +1,233 @@
+/*
+ * Copyright 2012 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef __NI_DPM_H__
+#define __NI_DPM_H__
+
+#include "cypress_dpm.h"
+#include "btc_dpm.h"
+#include "nislands_smc.h"
+
+struct ni_clock_registers {
+	u32 cg_spll_func_cntl;
+	u32 cg_spll_func_cntl_2;
+	u32 cg_spll_func_cntl_3;
+	u32 cg_spll_func_cntl_4;
+	u32 cg_spll_spread_spectrum;
+	u32 cg_spll_spread_spectrum_2;
+	u32 mclk_pwrmgt_cntl;
+	u32 dll_cntl;
+	u32 mpll_ad_func_cntl;
+	u32 mpll_ad_func_cntl_2;
+	u32 mpll_dq_func_cntl;
+	u32 mpll_dq_func_cntl_2;
+	u32 mpll_ss1;
+	u32 mpll_ss2;
+};
+
+struct ni_mc_reg_entry {
+	u32 mclk_max;
+	u32 mc_data[SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE];
+};
+
+struct ni_mc_reg_table {
+	u8 last;
+	u8 num_entries;
+	u16 valid_flag;
+	struct ni_mc_reg_entry mc_reg_table_entry[MAX_AC_TIMING_ENTRIES];
+	SMC_NIslands_MCRegisterAddress mc_reg_address[SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE];
+};
+
+#define NISLANDS_MCREGISTERTABLE_FIRST_DRIVERSTATE_SLOT 2
+
+enum ni_dc_cac_level
+{
+	NISLANDS_DCCAC_LEVEL_0 = 0,
+	NISLANDS_DCCAC_LEVEL_1,
+	NISLANDS_DCCAC_LEVEL_2,
+	NISLANDS_DCCAC_LEVEL_3,
+	NISLANDS_DCCAC_LEVEL_4,
+	NISLANDS_DCCAC_LEVEL_5,
+	NISLANDS_DCCAC_LEVEL_6,
+	NISLANDS_DCCAC_LEVEL_7,
+	NISLANDS_DCCAC_MAX_LEVELS
+};
+
+struct ni_leakage_coeffients
+{
+	u32 at;
+	u32 bt;
+	u32 av;
+	u32 bv;
+	s32 t_slope;
+	s32 t_intercept;
+	u32 t_ref;
+};
+
+struct ni_cac_data
+{
+	struct ni_leakage_coeffients leakage_coefficients;
+	u32 i_leakage;
+	s32 leakage_minimum_temperature;
+	u32 pwr_const;
+	u32 dc_cac_value;
+	u32 bif_cac_value;
+	u32 lkge_pwr;
+	u8 mc_wr_weight;
+	u8 mc_rd_weight;
+	u8 allow_ovrflw;
+	u8 num_win_tdp;
+	u8 l2num_win_tdp;
+	u8 lts_truncate_n;
+};
+
+struct ni_cac_weights
+{
+	u32 weight_tcp_sig0;
+	u32 weight_tcp_sig1;
+	u32 weight_ta_sig;
+	u32 weight_tcc_en0;
+	u32 weight_tcc_en1;
+	u32 weight_tcc_en2;
+	u32 weight_cb_en0;
+	u32 weight_cb_en1;
+	u32 weight_cb_en2;
+	u32 weight_cb_en3;
+	u32 weight_db_sig0;
+	u32 weight_db_sig1;
+	u32 weight_db_sig2;
+	u32 weight_db_sig3;
+	u32 weight_sxm_sig0;
+	u32 weight_sxm_sig1;
+	u32 weight_sxm_sig2;
+	u32 weight_sxs_sig0;
+	u32 weight_sxs_sig1;
+	u32 weight_xbr_0;
+	u32 weight_xbr_1;
+	u32 weight_xbr_2;
+	u32 weight_spi_sig0;
+	u32 weight_spi_sig1;
+	u32 weight_spi_sig2;
+	u32 weight_spi_sig3;
+	u32 weight_spi_sig4;
+	u32 weight_spi_sig5;
+	u32 weight_lds_sig0;
+	u32 weight_lds_sig1;
+	u32 weight_sc;
+	u32 weight_bif;
+	u32 weight_cp;
+	u32 weight_pa_sig0;
+	u32 weight_pa_sig1;
+	u32 weight_vgt_sig0;
+	u32 weight_vgt_sig1;
+	u32 weight_vgt_sig2;
+	u32 weight_dc_sig0;
+	u32 weight_dc_sig1;
+	u32 weight_dc_sig2;
+	u32 weight_dc_sig3;
+	u32 weight_uvd_sig0;
+	u32 weight_uvd_sig1;
+	u32 weight_spare0;
+	u32 weight_spare1;
+	u32 weight_sq_vsp;
+	u32 weight_sq_vsp0;
+	u32 weight_sq_gpr;
+	u32 ovr_mode_spare_0;
+	u32 ovr_val_spare_0;
+	u32 ovr_mode_spare_1;
+	u32 ovr_val_spare_1;
+	u32 vsp;
+	u32 vsp0;
+	u32 gpr;
+	u8 mc_read_weight;
+	u8 mc_write_weight;
+	u32 tid_cnt;
+	u32 tid_unit;
+	u32 l2_lta_window_size;
+	u32 lts_truncate;
+	u32 dc_cac[NISLANDS_DCCAC_MAX_LEVELS];
+	u32 pcie_cac[SMC_NISLANDS_BIF_LUT_NUM_OF_ENTRIES];
+	bool enable_power_containment_by_default;
+};
+
+struct ni_ps {
+	u16 performance_level_count;
+	bool dc_compatible;
+	struct rv7xx_pl performance_levels[NISLANDS_MAX_SMC_PERFORMANCE_LEVELS_PER_SWSTATE];
+};
+
+struct ni_power_info {
+	/* must be first! */
+	struct evergreen_power_info eg;
+	struct ni_clock_registers clock_registers;
+	struct ni_mc_reg_table mc_reg_table;
+	u32 mclk_rtt_mode_threshold;
+	/* flags */
+	bool use_power_boost_limit;
+	bool support_cac_long_term_average;
+	bool cac_enabled;
+	bool cac_configuration_required;
+	bool driver_calculate_cac_leakage;
+	bool pc_enabled;
+	bool enable_power_containment;
+	bool enable_cac;
+	bool enable_sq_ramping;
+	/* smc offsets */
+	u16 arb_table_start;
+	u16 fan_table_start;
+	u16 cac_table_start;
+	u16 spll_table_start;
+	/* CAC stuff */
+	struct ni_cac_data cac_data;
+	u32 dc_cac_table[NISLANDS_DCCAC_MAX_LEVELS];
+	const struct ni_cac_weights *cac_weights;
+	u8 lta_window_size;
+	u8 lts_truncate;
+	struct ni_ps hw_ps;
+	/* scratch structs */
+	SMC_NIslands_MCRegisters smc_mc_reg_table;
+	NISLANDS_SMC_STATETABLE smc_statetable;
+};
+
+#define NISLANDS_INITIAL_STATE_ARB_INDEX    0
+#define NISLANDS_ACPI_STATE_ARB_INDEX       1
+#define NISLANDS_ULV_STATE_ARB_INDEX        2
+#define NISLANDS_DRIVER_STATE_ARB_INDEX     3
+
+#define NISLANDS_DPM2_MAX_PULSE_SKIP        256
+
+#define NISLANDS_DPM2_NEAR_TDP_DEC          10
+#define NISLANDS_DPM2_ABOVE_SAFE_INC        5
+#define NISLANDS_DPM2_BELOW_SAFE_INC        20
+
+#define NISLANDS_DPM2_TDP_SAFE_LIMIT_PERCENT            80
+
+#define NISLANDS_DPM2_MAXPS_PERCENT_H                   90
+#define NISLANDS_DPM2_MAXPS_PERCENT_M                   0
+
+#define NISLANDS_DPM2_SQ_RAMP_MAX_POWER                 0x3FFF
+#define NISLANDS_DPM2_SQ_RAMP_MIN_POWER                 0x12
+#define NISLANDS_DPM2_SQ_RAMP_MAX_POWER_DELTA           0x15
+#define NISLANDS_DPM2_SQ_RAMP_STI_SIZE                  0x1E
+#define NISLANDS_DPM2_SQ_RAMP_LTI_RATIO                 0xF
+
+#endif
diff --git a/drivers/gpu/drm/radeon/nid.h b/drivers/gpu/drm/radeon/nid.h
index 7b8da52..1775043 100644
--- a/drivers/gpu/drm/radeon/nid.h
+++ b/drivers/gpu/drm/radeon/nid.h
@@ -492,6 +492,558 @@
 /* TN SMU registers */
 #define	TN_CURRENT_GNB_TEMP				0x1F390
 
+/* pm registers */
+#define	SMC_MSG						0x20c
+#define		HOST_SMC_MSG(x)				((x) << 0)
+#define		HOST_SMC_MSG_MASK			(0xff << 0)
+#define		HOST_SMC_MSG_SHIFT			0
+#define		HOST_SMC_RESP(x)			((x) << 8)
+#define		HOST_SMC_RESP_MASK			(0xff << 8)
+#define		HOST_SMC_RESP_SHIFT			8
+#define		SMC_HOST_MSG(x)				((x) << 16)
+#define		SMC_HOST_MSG_MASK			(0xff << 16)
+#define		SMC_HOST_MSG_SHIFT			16
+#define		SMC_HOST_RESP(x)			((x) << 24)
+#define		SMC_HOST_RESP_MASK			(0xff << 24)
+#define		SMC_HOST_RESP_SHIFT			24
+
+#define	CG_SPLL_FUNC_CNTL				0x600
+#define		SPLL_RESET				(1 << 0)
+#define		SPLL_SLEEP				(1 << 1)
+#define		SPLL_BYPASS_EN				(1 << 3)
+#define		SPLL_REF_DIV(x)				((x) << 4)
+#define		SPLL_REF_DIV_MASK			(0x3f << 4)
+#define		SPLL_PDIV_A(x)				((x) << 20)
+#define		SPLL_PDIV_A_MASK			(0x7f << 20)
+#define		SPLL_PDIV_A_SHIFT			20
+#define	CG_SPLL_FUNC_CNTL_2				0x604
+#define		SCLK_MUX_SEL(x)				((x) << 0)
+#define		SCLK_MUX_SEL_MASK			(0x1ff << 0)
+#define	CG_SPLL_FUNC_CNTL_3				0x608
+#define		SPLL_FB_DIV(x)				((x) << 0)
+#define		SPLL_FB_DIV_MASK			(0x3ffffff << 0)
+#define		SPLL_FB_DIV_SHIFT			0
+#define		SPLL_DITHEN				(1 << 28)
+
+#define MPLL_CNTL_MODE                                  0x61c
+#       define SS_SSEN                                  (1 << 24)
+#       define SS_DSMODE_EN                             (1 << 25)
+
+#define	MPLL_AD_FUNC_CNTL				0x624
+#define		CLKF(x)					((x) << 0)
+#define		CLKF_MASK				(0x7f << 0)
+#define		CLKR(x)					((x) << 7)
+#define		CLKR_MASK				(0x1f << 7)
+#define		CLKFRAC(x)				((x) << 12)
+#define		CLKFRAC_MASK				(0x1f << 12)
+#define		YCLK_POST_DIV(x)			((x) << 17)
+#define		YCLK_POST_DIV_MASK			(3 << 17)
+#define		IBIAS(x)				((x) << 20)
+#define		IBIAS_MASK				(0x3ff << 20)
+#define		RESET					(1 << 30)
+#define		PDNB					(1 << 31)
+#define	MPLL_AD_FUNC_CNTL_2				0x628
+#define		BYPASS					(1 << 19)
+#define		BIAS_GEN_PDNB				(1 << 24)
+#define		RESET_EN				(1 << 25)
+#define		VCO_MODE				(1 << 29)
+#define	MPLL_DQ_FUNC_CNTL				0x62c
+#define	MPLL_DQ_FUNC_CNTL_2				0x630
+
+#define GENERAL_PWRMGT                                  0x63c
+#       define GLOBAL_PWRMGT_EN                         (1 << 0)
+#       define STATIC_PM_EN                             (1 << 1)
+#       define THERMAL_PROTECTION_DIS                   (1 << 2)
+#       define THERMAL_PROTECTION_TYPE                  (1 << 3)
+#       define ENABLE_GEN2PCIE                          (1 << 4)
+#       define ENABLE_GEN2XSP                           (1 << 5)
+#       define SW_SMIO_INDEX(x)                         ((x) << 6)
+#       define SW_SMIO_INDEX_MASK                       (3 << 6)
+#       define SW_SMIO_INDEX_SHIFT                      6
+#       define LOW_VOLT_D2_ACPI                         (1 << 8)
+#       define LOW_VOLT_D3_ACPI                         (1 << 9)
+#       define VOLT_PWRMGT_EN                           (1 << 10)
+#       define BACKBIAS_PAD_EN                          (1 << 18)
+#       define BACKBIAS_VALUE                           (1 << 19)
+#       define DYN_SPREAD_SPECTRUM_EN                   (1 << 23)
+#       define AC_DC_SW                                 (1 << 24)
+
+#define SCLK_PWRMGT_CNTL                                  0x644
+#       define SCLK_PWRMGT_OFF                            (1 << 0)
+#       define SCLK_LOW_D1                                (1 << 1)
+#       define FIR_RESET                                  (1 << 4)
+#       define FIR_FORCE_TREND_SEL                        (1 << 5)
+#       define FIR_TREND_MODE                             (1 << 6)
+#       define DYN_GFX_CLK_OFF_EN                         (1 << 7)
+#       define GFX_CLK_FORCE_ON                           (1 << 8)
+#       define GFX_CLK_REQUEST_OFF                        (1 << 9)
+#       define GFX_CLK_FORCE_OFF                          (1 << 10)
+#       define GFX_CLK_OFF_ACPI_D1                        (1 << 11)
+#       define GFX_CLK_OFF_ACPI_D2                        (1 << 12)
+#       define GFX_CLK_OFF_ACPI_D3                        (1 << 13)
+#       define DYN_LIGHT_SLEEP_EN                         (1 << 14)
+#define	MCLK_PWRMGT_CNTL				0x648
+#       define DLL_SPEED(x)				((x) << 0)
+#       define DLL_SPEED_MASK				(0x1f << 0)
+#       define MPLL_PWRMGT_OFF                          (1 << 5)
+#       define DLL_READY                                (1 << 6)
+#       define MC_INT_CNTL                              (1 << 7)
+#       define MRDCKA0_PDNB                             (1 << 8)
+#       define MRDCKA1_PDNB                             (1 << 9)
+#       define MRDCKB0_PDNB                             (1 << 10)
+#       define MRDCKB1_PDNB                             (1 << 11)
+#       define MRDCKC0_PDNB                             (1 << 12)
+#       define MRDCKC1_PDNB                             (1 << 13)
+#       define MRDCKD0_PDNB                             (1 << 14)
+#       define MRDCKD1_PDNB                             (1 << 15)
+#       define MRDCKA0_RESET                            (1 << 16)
+#       define MRDCKA1_RESET                            (1 << 17)
+#       define MRDCKB0_RESET                            (1 << 18)
+#       define MRDCKB1_RESET                            (1 << 19)
+#       define MRDCKC0_RESET                            (1 << 20)
+#       define MRDCKC1_RESET                            (1 << 21)
+#       define MRDCKD0_RESET                            (1 << 22)
+#       define MRDCKD1_RESET                            (1 << 23)
+#       define DLL_READY_READ                           (1 << 24)
+#       define USE_DISPLAY_GAP                          (1 << 25)
+#       define USE_DISPLAY_URGENT_NORMAL                (1 << 26)
+#       define MPLL_TURNOFF_D2                          (1 << 28)
+#define	DLL_CNTL					0x64c
+#       define MRDCKA0_BYPASS                           (1 << 24)
+#       define MRDCKA1_BYPASS                           (1 << 25)
+#       define MRDCKB0_BYPASS                           (1 << 26)
+#       define MRDCKB1_BYPASS                           (1 << 27)
+#       define MRDCKC0_BYPASS                           (1 << 28)
+#       define MRDCKC1_BYPASS                           (1 << 29)
+#       define MRDCKD0_BYPASS                           (1 << 30)
+#       define MRDCKD1_BYPASS                           (1 << 31)
+
+#define CG_AT                                           0x6d4
+#       define CG_R(x)					((x) << 0)
+#       define CG_R_MASK				(0xffff << 0)
+#       define CG_L(x)					((x) << 16)
+#       define CG_L_MASK				(0xffff << 16)
+
+#define	CG_BIF_REQ_AND_RSP				0x7f4
+#define		CG_CLIENT_REQ(x)			((x) << 0)
+#define		CG_CLIENT_REQ_MASK			(0xff << 0)
+#define		CG_CLIENT_REQ_SHIFT			0
+#define		CG_CLIENT_RESP(x)			((x) << 8)
+#define		CG_CLIENT_RESP_MASK			(0xff << 8)
+#define		CG_CLIENT_RESP_SHIFT			8
+#define		CLIENT_CG_REQ(x)			((x) << 16)
+#define		CLIENT_CG_REQ_MASK			(0xff << 16)
+#define		CLIENT_CG_REQ_SHIFT			16
+#define		CLIENT_CG_RESP(x)			((x) << 24)
+#define		CLIENT_CG_RESP_MASK			(0xff << 24)
+#define		CLIENT_CG_RESP_SHIFT			24
+
+#define	CG_SPLL_SPREAD_SPECTRUM				0x790
+#define		SSEN					(1 << 0)
+#define		CLK_S(x)				((x) << 4)
+#define		CLK_S_MASK				(0xfff << 4)
+#define		CLK_S_SHIFT				4
+#define	CG_SPLL_SPREAD_SPECTRUM_2			0x794
+#define		CLK_V(x)				((x) << 0)
+#define		CLK_V_MASK				(0x3ffffff << 0)
+#define		CLK_V_SHIFT				0
+
+#define SMC_SCRATCH0                                    0x81c
+
+#define	CG_SPLL_FUNC_CNTL_4				0x850
+
+#define	MPLL_SS1					0x85c
+#define		CLKV(x)					((x) << 0)
+#define		CLKV_MASK				(0x3ffffff << 0)
+#define	MPLL_SS2					0x860
+#define		CLKS(x)					((x) << 0)
+#define		CLKS_MASK				(0xfff << 0)
+
+#define	CG_CAC_CTRL					0x88c
+#define		TID_CNT(x)				((x) << 0)
+#define		TID_CNT_MASK				(0x3fff << 0)
+#define		TID_UNIT(x)				((x) << 14)
+#define		TID_UNIT_MASK				(0xf << 14)
+
+#define MC_CG_CONFIG                                    0x25bc
+#define         MCDW_WR_ENABLE                          (1 << 0)
+#define         MCDX_WR_ENABLE                          (1 << 1)
+#define         MCDY_WR_ENABLE                          (1 << 2)
+#define         MCDZ_WR_ENABLE                          (1 << 3)
+#define		MC_RD_ENABLE(x)				((x) << 4)
+#define		MC_RD_ENABLE_MASK			(3 << 4)
+#define		INDEX(x)				((x) << 6)
+#define		INDEX_MASK				(0xfff << 6)
+#define		INDEX_SHIFT				6
+
+#define	MC_ARB_CAC_CNTL					0x2750
+#define         ENABLE                                  (1 << 0)
+#define		READ_WEIGHT(x)				((x) << 1)
+#define		READ_WEIGHT_MASK			(0x3f << 1)
+#define		READ_WEIGHT_SHIFT			1
+#define		WRITE_WEIGHT(x)				((x) << 7)
+#define		WRITE_WEIGHT_MASK			(0x3f << 7)
+#define		WRITE_WEIGHT_SHIFT			7
+#define         ALLOW_OVERFLOW                          (1 << 13)
+
+#define	MC_ARB_DRAM_TIMING				0x2774
+#define	MC_ARB_DRAM_TIMING2				0x2778
+
+#define	MC_ARB_RFSH_RATE				0x27b0
+#define		POWERMODE0(x)				((x) << 0)
+#define		POWERMODE0_MASK				(0xff << 0)
+#define		POWERMODE0_SHIFT			0
+#define		POWERMODE1(x)				((x) << 8)
+#define		POWERMODE1_MASK				(0xff << 8)
+#define		POWERMODE1_SHIFT			8
+#define		POWERMODE2(x)				((x) << 16)
+#define		POWERMODE2_MASK				(0xff << 16)
+#define		POWERMODE2_SHIFT			16
+#define		POWERMODE3(x)				((x) << 24)
+#define		POWERMODE3_MASK				(0xff << 24)
+#define		POWERMODE3_SHIFT			24
+
+#define MC_ARB_CG                                       0x27e8
+#define		CG_ARB_REQ(x)				((x) << 0)
+#define		CG_ARB_REQ_MASK				(0xff << 0)
+#define		CG_ARB_REQ_SHIFT			0
+#define		CG_ARB_RESP(x)				((x) << 8)
+#define		CG_ARB_RESP_MASK			(0xff << 8)
+#define		CG_ARB_RESP_SHIFT			8
+#define		ARB_CG_REQ(x)				((x) << 16)
+#define		ARB_CG_REQ_MASK				(0xff << 16)
+#define		ARB_CG_REQ_SHIFT			16
+#define		ARB_CG_RESP(x)				((x) << 24)
+#define		ARB_CG_RESP_MASK			(0xff << 24)
+#define		ARB_CG_RESP_SHIFT			24
+
+#define	MC_ARB_DRAM_TIMING_1				0x27f0
+#define	MC_ARB_DRAM_TIMING_2				0x27f4
+#define	MC_ARB_DRAM_TIMING_3				0x27f8
+#define	MC_ARB_DRAM_TIMING2_1				0x27fc
+#define	MC_ARB_DRAM_TIMING2_2				0x2800
+#define	MC_ARB_DRAM_TIMING2_3				0x2804
+#define MC_ARB_BURST_TIME                               0x2808
+#define		STATE0(x)				((x) << 0)
+#define		STATE0_MASK				(0x1f << 0)
+#define		STATE0_SHIFT				0
+#define		STATE1(x)				((x) << 5)
+#define		STATE1_MASK				(0x1f << 5)
+#define		STATE1_SHIFT				5
+#define		STATE2(x)				((x) << 10)
+#define		STATE2_MASK				(0x1f << 10)
+#define		STATE2_SHIFT				10
+#define		STATE3(x)				((x) << 15)
+#define		STATE3_MASK				(0x1f << 15)
+#define		STATE3_SHIFT				15
+
+#define MC_CG_DATAPORT                                  0x2884
+
+#define MC_SEQ_RAS_TIMING                               0x28a0
+#define MC_SEQ_CAS_TIMING                               0x28a4
+#define MC_SEQ_MISC_TIMING                              0x28a8
+#define MC_SEQ_MISC_TIMING2                             0x28ac
+#define MC_SEQ_PMG_TIMING                               0x28b0
+#define MC_SEQ_RD_CTL_D0                                0x28b4
+#define MC_SEQ_RD_CTL_D1                                0x28b8
+#define MC_SEQ_WR_CTL_D0                                0x28bc
+#define MC_SEQ_WR_CTL_D1                                0x28c0
+
+#define MC_SEQ_MISC0                                    0x2a00
+#define         MC_SEQ_MISC0_GDDR5_SHIFT                28
+#define         MC_SEQ_MISC0_GDDR5_MASK                 0xf0000000
+#define         MC_SEQ_MISC0_GDDR5_VALUE                5
+#define MC_SEQ_MISC1                                    0x2a04
+#define MC_SEQ_RESERVE_M                                0x2a08
+#define MC_PMG_CMD_EMRS                                 0x2a0c
+
+#define MC_SEQ_MISC3                                    0x2a2c
+
+#define MC_SEQ_MISC5                                    0x2a54
+#define MC_SEQ_MISC6                                    0x2a58
+
+#define MC_SEQ_MISC7                                    0x2a64
+
+#define MC_SEQ_RAS_TIMING_LP                            0x2a6c
+#define MC_SEQ_CAS_TIMING_LP                            0x2a70
+#define MC_SEQ_MISC_TIMING_LP                           0x2a74
+#define MC_SEQ_MISC_TIMING2_LP                          0x2a78
+#define MC_SEQ_WR_CTL_D0_LP                             0x2a7c
+#define MC_SEQ_WR_CTL_D1_LP                             0x2a80
+#define MC_SEQ_PMG_CMD_EMRS_LP                          0x2a84
+#define MC_SEQ_PMG_CMD_MRS_LP                           0x2a88
+
+#define MC_PMG_CMD_MRS                                  0x2aac
+
+#define MC_SEQ_RD_CTL_D0_LP                             0x2b1c
+#define MC_SEQ_RD_CTL_D1_LP                             0x2b20
+
+#define MC_PMG_CMD_MRS1                                 0x2b44
+#define MC_SEQ_PMG_CMD_MRS1_LP                          0x2b48
+#define MC_SEQ_PMG_TIMING_LP                            0x2b4c
+
+#define MC_PMG_CMD_MRS2                                 0x2b5c
+#define MC_SEQ_PMG_CMD_MRS2_LP                          0x2b60
+
+#define	LB_SYNC_RESET_SEL				0x6b28
+#define		LB_SYNC_RESET_SEL_MASK			(3 << 0)
+#define		LB_SYNC_RESET_SEL_SHIFT			0
+
+#define	DC_STUTTER_CNTL					0x6b30
+#define		DC_STUTTER_ENABLE_A			(1 << 0)
+#define		DC_STUTTER_ENABLE_B			(1 << 1)
+
+#define SQ_CAC_THRESHOLD                                0x8e4c
+#define		VSP(x)					((x) << 0)
+#define		VSP_MASK				(0xff << 0)
+#define		VSP_SHIFT				0
+#define		VSP0(x)					((x) << 8)
+#define		VSP0_MASK				(0xff << 8)
+#define		VSP0_SHIFT				8
+#define		GPR(x)					((x) << 16)
+#define		GPR_MASK				(0xff << 16)
+#define		GPR_SHIFT				16
+
+#define SQ_POWER_THROTTLE                               0x8e58
+#define		MIN_POWER(x)				((x) << 0)
+#define		MIN_POWER_MASK				(0x3fff << 0)
+#define		MIN_POWER_SHIFT				0
+#define		MAX_POWER(x)				((x) << 16)
+#define		MAX_POWER_MASK				(0x3fff << 16)
+#define		MAX_POWER_SHIFT				0
+#define SQ_POWER_THROTTLE2                              0x8e5c
+#define		MAX_POWER_DELTA(x)			((x) << 0)
+#define		MAX_POWER_DELTA_MASK			(0x3fff << 0)
+#define		MAX_POWER_DELTA_SHIFT			0
+#define		STI_SIZE(x)				((x) << 16)
+#define		STI_SIZE_MASK				(0x3ff << 16)
+#define		STI_SIZE_SHIFT				16
+#define		LTI_RATIO(x)				((x) << 27)
+#define		LTI_RATIO_MASK				(0xf << 27)
+#define		LTI_RATIO_SHIFT				27
+
+/* CG indirect registers */
+#define CG_CAC_REGION_1_WEIGHT_0                        0x83
+#define		WEIGHT_TCP_SIG0(x)			((x) << 0)
+#define		WEIGHT_TCP_SIG0_MASK			(0x3f << 0)
+#define		WEIGHT_TCP_SIG0_SHIFT			0
+#define		WEIGHT_TCP_SIG1(x)			((x) << 6)
+#define		WEIGHT_TCP_SIG1_MASK			(0x3f << 6)
+#define		WEIGHT_TCP_SIG1_SHIFT			6
+#define		WEIGHT_TA_SIG(x)			((x) << 12)
+#define		WEIGHT_TA_SIG_MASK			(0x3f << 12)
+#define		WEIGHT_TA_SIG_SHIFT			12
+#define CG_CAC_REGION_1_WEIGHT_1                        0x84
+#define		WEIGHT_TCC_EN0(x)			((x) << 0)
+#define		WEIGHT_TCC_EN0_MASK			(0x3f << 0)
+#define		WEIGHT_TCC_EN0_SHIFT			0
+#define		WEIGHT_TCC_EN1(x)			((x) << 6)
+#define		WEIGHT_TCC_EN1_MASK			(0x3f << 6)
+#define		WEIGHT_TCC_EN1_SHIFT			6
+#define		WEIGHT_TCC_EN2(x)			((x) << 12)
+#define		WEIGHT_TCC_EN2_MASK			(0x3f << 12)
+#define		WEIGHT_TCC_EN2_SHIFT			12
+#define		WEIGHT_TCC_EN3(x)			((x) << 18)
+#define		WEIGHT_TCC_EN3_MASK			(0x3f << 18)
+#define		WEIGHT_TCC_EN3_SHIFT			18
+#define CG_CAC_REGION_2_WEIGHT_0                        0x85
+#define		WEIGHT_CB_EN0(x)			((x) << 0)
+#define		WEIGHT_CB_EN0_MASK			(0x3f << 0)
+#define		WEIGHT_CB_EN0_SHIFT			0
+#define		WEIGHT_CB_EN1(x)			((x) << 6)
+#define		WEIGHT_CB_EN1_MASK			(0x3f << 6)
+#define		WEIGHT_CB_EN1_SHIFT			6
+#define		WEIGHT_CB_EN2(x)			((x) << 12)
+#define		WEIGHT_CB_EN2_MASK			(0x3f << 12)
+#define		WEIGHT_CB_EN2_SHIFT			12
+#define		WEIGHT_CB_EN3(x)			((x) << 18)
+#define		WEIGHT_CB_EN3_MASK			(0x3f << 18)
+#define		WEIGHT_CB_EN3_SHIFT			18
+#define CG_CAC_REGION_2_WEIGHT_1                        0x86
+#define		WEIGHT_DB_SIG0(x)			((x) << 0)
+#define		WEIGHT_DB_SIG0_MASK			(0x3f << 0)
+#define		WEIGHT_DB_SIG0_SHIFT			0
+#define		WEIGHT_DB_SIG1(x)			((x) << 6)
+#define		WEIGHT_DB_SIG1_MASK			(0x3f << 6)
+#define		WEIGHT_DB_SIG1_SHIFT			6
+#define		WEIGHT_DB_SIG2(x)			((x) << 12)
+#define		WEIGHT_DB_SIG2_MASK			(0x3f << 12)
+#define		WEIGHT_DB_SIG2_SHIFT			12
+#define		WEIGHT_DB_SIG3(x)			((x) << 18)
+#define		WEIGHT_DB_SIG3_MASK			(0x3f << 18)
+#define		WEIGHT_DB_SIG3_SHIFT			18
+#define CG_CAC_REGION_2_WEIGHT_2                        0x87
+#define		WEIGHT_SXM_SIG0(x)			((x) << 0)
+#define		WEIGHT_SXM_SIG0_MASK			(0x3f << 0)
+#define		WEIGHT_SXM_SIG0_SHIFT			0
+#define		WEIGHT_SXM_SIG1(x)			((x) << 6)
+#define		WEIGHT_SXM_SIG1_MASK			(0x3f << 6)
+#define		WEIGHT_SXM_SIG1_SHIFT			6
+#define		WEIGHT_SXM_SIG2(x)			((x) << 12)
+#define		WEIGHT_SXM_SIG2_MASK			(0x3f << 12)
+#define		WEIGHT_SXM_SIG2_SHIFT			12
+#define		WEIGHT_SXS_SIG0(x)			((x) << 18)
+#define		WEIGHT_SXS_SIG0_MASK			(0x3f << 18)
+#define		WEIGHT_SXS_SIG0_SHIFT			18
+#define		WEIGHT_SXS_SIG1(x)			((x) << 24)
+#define		WEIGHT_SXS_SIG1_MASK			(0x3f << 24)
+#define		WEIGHT_SXS_SIG1_SHIFT			24
+#define CG_CAC_REGION_3_WEIGHT_0                        0x88
+#define		WEIGHT_XBR_0(x)				((x) << 0)
+#define		WEIGHT_XBR_0_MASK			(0x3f << 0)
+#define		WEIGHT_XBR_0_SHIFT			0
+#define		WEIGHT_XBR_1(x)				((x) << 6)
+#define		WEIGHT_XBR_1_MASK			(0x3f << 6)
+#define		WEIGHT_XBR_1_SHIFT			6
+#define		WEIGHT_XBR_2(x)				((x) << 12)
+#define		WEIGHT_XBR_2_MASK			(0x3f << 12)
+#define		WEIGHT_XBR_2_SHIFT			12
+#define		WEIGHT_SPI_SIG0(x)			((x) << 18)
+#define		WEIGHT_SPI_SIG0_MASK			(0x3f << 18)
+#define		WEIGHT_SPI_SIG0_SHIFT			18
+#define CG_CAC_REGION_3_WEIGHT_1                        0x89
+#define		WEIGHT_SPI_SIG1(x)			((x) << 0)
+#define		WEIGHT_SPI_SIG1_MASK			(0x3f << 0)
+#define		WEIGHT_SPI_SIG1_SHIFT			0
+#define		WEIGHT_SPI_SIG2(x)			((x) << 6)
+#define		WEIGHT_SPI_SIG2_MASK			(0x3f << 6)
+#define		WEIGHT_SPI_SIG2_SHIFT			6
+#define		WEIGHT_SPI_SIG3(x)			((x) << 12)
+#define		WEIGHT_SPI_SIG3_MASK			(0x3f << 12)
+#define		WEIGHT_SPI_SIG3_SHIFT			12
+#define		WEIGHT_SPI_SIG4(x)			((x) << 18)
+#define		WEIGHT_SPI_SIG4_MASK			(0x3f << 18)
+#define		WEIGHT_SPI_SIG4_SHIFT			18
+#define		WEIGHT_SPI_SIG5(x)			((x) << 24)
+#define		WEIGHT_SPI_SIG5_MASK			(0x3f << 24)
+#define		WEIGHT_SPI_SIG5_SHIFT			24
+#define CG_CAC_REGION_4_WEIGHT_0                        0x8a
+#define		WEIGHT_LDS_SIG0(x)			((x) << 0)
+#define		WEIGHT_LDS_SIG0_MASK			(0x3f << 0)
+#define		WEIGHT_LDS_SIG0_SHIFT			0
+#define		WEIGHT_LDS_SIG1(x)			((x) << 6)
+#define		WEIGHT_LDS_SIG1_MASK			(0x3f << 6)
+#define		WEIGHT_LDS_SIG1_SHIFT			6
+#define		WEIGHT_SC(x)				((x) << 24)
+#define		WEIGHT_SC_MASK				(0x3f << 24)
+#define		WEIGHT_SC_SHIFT				24
+#define CG_CAC_REGION_4_WEIGHT_1                        0x8b
+#define		WEIGHT_BIF(x)				((x) << 0)
+#define		WEIGHT_BIF_MASK				(0x3f << 0)
+#define		WEIGHT_BIF_SHIFT			0
+#define		WEIGHT_CP(x)				((x) << 6)
+#define		WEIGHT_CP_MASK				(0x3f << 6)
+#define		WEIGHT_CP_SHIFT				6
+#define		WEIGHT_PA_SIG0(x)			((x) << 12)
+#define		WEIGHT_PA_SIG0_MASK			(0x3f << 12)
+#define		WEIGHT_PA_SIG0_SHIFT			12
+#define		WEIGHT_PA_SIG1(x)			((x) << 18)
+#define		WEIGHT_PA_SIG1_MASK			(0x3f << 18)
+#define		WEIGHT_PA_SIG1_SHIFT			18
+#define		WEIGHT_VGT_SIG0(x)			((x) << 24)
+#define		WEIGHT_VGT_SIG0_MASK			(0x3f << 24)
+#define		WEIGHT_VGT_SIG0_SHIFT			24
+#define CG_CAC_REGION_4_WEIGHT_2                        0x8c
+#define		WEIGHT_VGT_SIG1(x)			((x) << 0)
+#define		WEIGHT_VGT_SIG1_MASK			(0x3f << 0)
+#define		WEIGHT_VGT_SIG1_SHIFT			0
+#define		WEIGHT_VGT_SIG2(x)			((x) << 6)
+#define		WEIGHT_VGT_SIG2_MASK			(0x3f << 6)
+#define		WEIGHT_VGT_SIG2_SHIFT			6
+#define		WEIGHT_DC_SIG0(x)			((x) << 12)
+#define		WEIGHT_DC_SIG0_MASK			(0x3f << 12)
+#define		WEIGHT_DC_SIG0_SHIFT			12
+#define		WEIGHT_DC_SIG1(x)			((x) << 18)
+#define		WEIGHT_DC_SIG1_MASK			(0x3f << 18)
+#define		WEIGHT_DC_SIG1_SHIFT			18
+#define		WEIGHT_DC_SIG2(x)			((x) << 24)
+#define		WEIGHT_DC_SIG2_MASK			(0x3f << 24)
+#define		WEIGHT_DC_SIG2_SHIFT			24
+#define CG_CAC_REGION_4_WEIGHT_3                        0x8d
+#define		WEIGHT_DC_SIG3(x)			((x) << 0)
+#define		WEIGHT_DC_SIG3_MASK			(0x3f << 0)
+#define		WEIGHT_DC_SIG3_SHIFT			0
+#define		WEIGHT_UVD_SIG0(x)			((x) << 6)
+#define		WEIGHT_UVD_SIG0_MASK			(0x3f << 6)
+#define		WEIGHT_UVD_SIG0_SHIFT			6
+#define		WEIGHT_UVD_SIG1(x)			((x) << 12)
+#define		WEIGHT_UVD_SIG1_MASK			(0x3f << 12)
+#define		WEIGHT_UVD_SIG1_SHIFT			12
+#define		WEIGHT_SPARE0(x)			((x) << 18)
+#define		WEIGHT_SPARE0_MASK			(0x3f << 18)
+#define		WEIGHT_SPARE0_SHIFT			18
+#define		WEIGHT_SPARE1(x)			((x) << 24)
+#define		WEIGHT_SPARE1_MASK			(0x3f << 24)
+#define		WEIGHT_SPARE1_SHIFT			24
+#define CG_CAC_REGION_5_WEIGHT_0                        0x8e
+#define		WEIGHT_SQ_VSP(x)			((x) << 0)
+#define		WEIGHT_SQ_VSP_MASK			(0x3fff << 0)
+#define		WEIGHT_SQ_VSP_SHIFT			0
+#define		WEIGHT_SQ_VSP0(x)			((x) << 14)
+#define		WEIGHT_SQ_VSP0_MASK			(0x3fff << 14)
+#define		WEIGHT_SQ_VSP0_SHIFT			14
+#define CG_CAC_REGION_4_OVERRIDE_4                      0xab
+#define		OVR_MODE_SPARE_0(x)			((x) << 16)
+#define		OVR_MODE_SPARE_0_MASK			(0x1 << 16)
+#define		OVR_MODE_SPARE_0_SHIFT			16
+#define		OVR_VAL_SPARE_0(x)			((x) << 17)
+#define		OVR_VAL_SPARE_0_MASK			(0x1 << 17)
+#define		OVR_VAL_SPARE_0_SHIFT			17
+#define		OVR_MODE_SPARE_1(x)			((x) << 18)
+#define		OVR_MODE_SPARE_1_MASK			(0x3f << 18)
+#define		OVR_MODE_SPARE_1_SHIFT			18
+#define		OVR_VAL_SPARE_1(x)			((x) << 19)
+#define		OVR_VAL_SPARE_1_MASK			(0x3f << 19)
+#define		OVR_VAL_SPARE_1_SHIFT			19
+#define CG_CAC_REGION_5_WEIGHT_1                        0xb7
+#define		WEIGHT_SQ_GPR(x)			((x) << 0)
+#define		WEIGHT_SQ_GPR_MASK			(0x3fff << 0)
+#define		WEIGHT_SQ_GPR_SHIFT			0
+#define		WEIGHT_SQ_LDS(x)			((x) << 14)
+#define		WEIGHT_SQ_LDS_MASK			(0x3fff << 14)
+#define		WEIGHT_SQ_LDS_SHIFT			14
+
+/* PCIE link stuff */
+#define PCIE_LC_TRAINING_CNTL                             0xa1 /* PCIE_P */
+#define PCIE_LC_LINK_WIDTH_CNTL                           0xa2 /* PCIE_P */
+#       define LC_LINK_WIDTH_SHIFT                        0
+#       define LC_LINK_WIDTH_MASK                         0x7
+#       define LC_LINK_WIDTH_X0                           0
+#       define LC_LINK_WIDTH_X1                           1
+#       define LC_LINK_WIDTH_X2                           2
+#       define LC_LINK_WIDTH_X4                           3
+#       define LC_LINK_WIDTH_X8                           4
+#       define LC_LINK_WIDTH_X16                          6
+#       define LC_LINK_WIDTH_RD_SHIFT                     4
+#       define LC_LINK_WIDTH_RD_MASK                      0x70
+#       define LC_RECONFIG_ARC_MISSING_ESCAPE             (1 << 7)
+#       define LC_RECONFIG_NOW                            (1 << 8)
+#       define LC_RENEGOTIATION_SUPPORT                   (1 << 9)
+#       define LC_RENEGOTIATE_EN                          (1 << 10)
+#       define LC_SHORT_RECONFIG_EN                       (1 << 11)
+#       define LC_UPCONFIGURE_SUPPORT                     (1 << 12)
+#       define LC_UPCONFIGURE_DIS                         (1 << 13)
+#define PCIE_LC_SPEED_CNTL                                0xa4 /* PCIE_P */
+#       define LC_GEN2_EN_STRAP                           (1 << 0)
+#       define LC_TARGET_LINK_SPEED_OVERRIDE_EN           (1 << 1)
+#       define LC_FORCE_EN_HW_SPEED_CHANGE                (1 << 5)
+#       define LC_FORCE_DIS_HW_SPEED_CHANGE               (1 << 6)
+#       define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_MASK      (0x3 << 8)
+#       define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_SHIFT     3
+#       define LC_CURRENT_DATA_RATE                       (1 << 11)
+#       define LC_HW_VOLTAGE_IF_CONTROL(x)                ((x) << 12)
+#       define LC_HW_VOLTAGE_IF_CONTROL_MASK              (3 << 12)
+#       define LC_HW_VOLTAGE_IF_CONTROL_SHIFT             12
+#       define LC_VOLTAGE_TIMER_SEL_MASK                  (0xf << 14)
+#       define LC_CLR_FAILED_SPD_CHANGE_CNT               (1 << 21)
+#       define LC_OTHER_SIDE_EVER_SENT_GEN2               (1 << 23)
+#       define LC_OTHER_SIDE_SUPPORTS_GEN2                (1 << 24)
+#define MM_CFGREGS_CNTL                                   0x544c
+#       define MM_WR_TO_CFG_EN                            (1 << 3)
+#define LINK_CNTL2                                        0x88 /* F0 */
+#       define TARGET_LINK_SPEED_MASK                     (0xf << 0)
+#       define SELECTABLE_DEEMPHASIS                      (1 << 6)
+
 /*
  * UVD
  */
diff --git a/drivers/gpu/drm/radeon/nislands_smc.h b/drivers/gpu/drm/radeon/nislands_smc.h
new file mode 100644
index 0000000..3cf8fc0
--- /dev/null
+++ b/drivers/gpu/drm/radeon/nislands_smc.h
@@ -0,0 +1,329 @@
+/*
+ * Copyright 2012 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef __NISLANDS_SMC_H__
+#define __NISLANDS_SMC_H__
+
+#pragma pack(push, 1)
+
+#define NISLANDS_MAX_SMC_PERFORMANCE_LEVELS_PER_SWSTATE 16
+
+struct PP_NIslands_Dpm2PerfLevel
+{
+    uint8_t     MaxPS;
+    uint8_t     TgtAct;
+    uint8_t     MaxPS_StepInc;
+    uint8_t     MaxPS_StepDec;
+    uint8_t     PSST;
+    uint8_t     NearTDPDec;
+    uint8_t     AboveSafeInc;
+    uint8_t     BelowSafeInc;
+    uint8_t     PSDeltaLimit;
+    uint8_t     PSDeltaWin;
+    uint8_t     Reserved[6];
+};
+
+typedef struct PP_NIslands_Dpm2PerfLevel PP_NIslands_Dpm2PerfLevel;
+
+struct PP_NIslands_DPM2Parameters
+{
+    uint32_t    TDPLimit;
+    uint32_t    NearTDPLimit;
+    uint32_t    SafePowerLimit;
+    uint32_t    PowerBoostLimit;
+};
+typedef struct PP_NIslands_DPM2Parameters PP_NIslands_DPM2Parameters;
+
+struct NISLANDS_SMC_SCLK_VALUE
+{
+    uint32_t        vCG_SPLL_FUNC_CNTL;
+    uint32_t        vCG_SPLL_FUNC_CNTL_2;
+    uint32_t        vCG_SPLL_FUNC_CNTL_3;
+    uint32_t        vCG_SPLL_FUNC_CNTL_4;
+    uint32_t        vCG_SPLL_SPREAD_SPECTRUM;
+    uint32_t        vCG_SPLL_SPREAD_SPECTRUM_2;
+    uint32_t        sclk_value;
+};
+
+typedef struct NISLANDS_SMC_SCLK_VALUE NISLANDS_SMC_SCLK_VALUE;
+
+struct NISLANDS_SMC_MCLK_VALUE
+{
+    uint32_t        vMPLL_FUNC_CNTL;
+    uint32_t        vMPLL_FUNC_CNTL_1;
+    uint32_t        vMPLL_FUNC_CNTL_2;
+    uint32_t        vMPLL_AD_FUNC_CNTL;
+    uint32_t        vMPLL_AD_FUNC_CNTL_2;
+    uint32_t        vMPLL_DQ_FUNC_CNTL;
+    uint32_t        vMPLL_DQ_FUNC_CNTL_2;
+    uint32_t        vMCLK_PWRMGT_CNTL;
+    uint32_t        vDLL_CNTL;
+    uint32_t        vMPLL_SS;
+    uint32_t        vMPLL_SS2;
+    uint32_t        mclk_value;
+};
+
+typedef struct NISLANDS_SMC_MCLK_VALUE NISLANDS_SMC_MCLK_VALUE;
+
+struct NISLANDS_SMC_VOLTAGE_VALUE
+{
+    uint16_t             value;
+    uint8_t              index;
+    uint8_t              padding;
+};
+
+typedef struct NISLANDS_SMC_VOLTAGE_VALUE NISLANDS_SMC_VOLTAGE_VALUE;
+
+struct NISLANDS_SMC_HW_PERFORMANCE_LEVEL
+{
+    uint8_t                     arbValue;
+    uint8_t                     ACIndex;
+    uint8_t                     displayWatermark;
+    uint8_t                     gen2PCIE;
+    uint8_t                     reserved1;
+    uint8_t                     reserved2;
+    uint8_t                     strobeMode;
+    uint8_t                     mcFlags;
+    uint32_t                    aT;
+    uint32_t                    bSP;
+    NISLANDS_SMC_SCLK_VALUE     sclk;
+    NISLANDS_SMC_MCLK_VALUE     mclk;
+    NISLANDS_SMC_VOLTAGE_VALUE  vddc;
+    NISLANDS_SMC_VOLTAGE_VALUE  mvdd;
+    NISLANDS_SMC_VOLTAGE_VALUE  vddci;
+    NISLANDS_SMC_VOLTAGE_VALUE  std_vddc;
+    uint32_t                    powergate_en;
+    uint8_t                     hUp;
+    uint8_t                     hDown;
+    uint8_t                     stateFlags;
+    uint8_t                     arbRefreshState;
+    uint32_t                    SQPowerThrottle;
+    uint32_t                    SQPowerThrottle_2;
+    uint32_t                    reserved[2];
+    PP_NIslands_Dpm2PerfLevel   dpm2;
+};
+
+#define NISLANDS_SMC_STROBE_RATIO    0x0F
+#define NISLANDS_SMC_STROBE_ENABLE   0x10
+
+#define NISLANDS_SMC_MC_EDC_RD_FLAG  0x01
+#define NISLANDS_SMC_MC_EDC_WR_FLAG  0x02
+#define NISLANDS_SMC_MC_RTT_ENABLE   0x04
+#define NISLANDS_SMC_MC_STUTTER_EN   0x08
+
+typedef struct NISLANDS_SMC_HW_PERFORMANCE_LEVEL NISLANDS_SMC_HW_PERFORMANCE_LEVEL;
+
+struct NISLANDS_SMC_SWSTATE
+{
+    uint8_t                             flags;
+    uint8_t                             levelCount;
+    uint8_t                             padding2;
+    uint8_t                             padding3;
+    NISLANDS_SMC_HW_PERFORMANCE_LEVEL   levels[1];
+};
+
+typedef struct NISLANDS_SMC_SWSTATE NISLANDS_SMC_SWSTATE;
+
+#define NISLANDS_SMC_VOLTAGEMASK_VDDC  0
+#define NISLANDS_SMC_VOLTAGEMASK_MVDD  1
+#define NISLANDS_SMC_VOLTAGEMASK_VDDCI 2
+#define NISLANDS_SMC_VOLTAGEMASK_MAX   4
+
+struct NISLANDS_SMC_VOLTAGEMASKTABLE
+{
+    uint8_t  highMask[NISLANDS_SMC_VOLTAGEMASK_MAX];
+    uint32_t lowMask[NISLANDS_SMC_VOLTAGEMASK_MAX];
+};
+
+typedef struct NISLANDS_SMC_VOLTAGEMASKTABLE NISLANDS_SMC_VOLTAGEMASKTABLE;
+
+#define NISLANDS_MAX_NO_VREG_STEPS 32
+
+struct NISLANDS_SMC_STATETABLE
+{
+    uint8_t                             thermalProtectType;
+    uint8_t                             systemFlags;
+    uint8_t                             maxVDDCIndexInPPTable;
+    uint8_t                             extraFlags;
+    uint8_t                             highSMIO[NISLANDS_MAX_NO_VREG_STEPS];
+    uint32_t                            lowSMIO[NISLANDS_MAX_NO_VREG_STEPS];
+    NISLANDS_SMC_VOLTAGEMASKTABLE       voltageMaskTable;
+    PP_NIslands_DPM2Parameters          dpm2Params;
+    NISLANDS_SMC_SWSTATE                initialState;
+    NISLANDS_SMC_SWSTATE                ACPIState;
+    NISLANDS_SMC_SWSTATE                ULVState;
+    NISLANDS_SMC_SWSTATE                driverState;
+    NISLANDS_SMC_HW_PERFORMANCE_LEVEL   dpmLevels[NISLANDS_MAX_SMC_PERFORMANCE_LEVELS_PER_SWSTATE - 1];
+};
+
+typedef struct NISLANDS_SMC_STATETABLE NISLANDS_SMC_STATETABLE;
+
+#define NI_SMC_SOFT_REGISTERS_START        0x108
+
+#define NI_SMC_SOFT_REGISTER_mclk_chg_timeout        0x0
+#define NI_SMC_SOFT_REGISTER_delay_bbias             0xC
+#define NI_SMC_SOFT_REGISTER_delay_vreg              0x10
+#define NI_SMC_SOFT_REGISTER_delay_acpi              0x2C
+#define NI_SMC_SOFT_REGISTER_seq_index               0x64
+#define NI_SMC_SOFT_REGISTER_mvdd_chg_time           0x68
+#define NI_SMC_SOFT_REGISTER_mclk_switch_lim         0x78
+#define NI_SMC_SOFT_REGISTER_watermark_threshold     0x80
+#define NI_SMC_SOFT_REGISTER_mc_block_delay          0x84
+#define NI_SMC_SOFT_REGISTER_uvd_enabled             0x98
+
+#define SMC_NISLANDS_MC_TPP_CAC_NUM_OF_ENTRIES 16
+#define SMC_NISLANDS_LKGE_LUT_NUM_OF_TEMP_ENTRIES 16
+#define SMC_NISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES 16
+#define SMC_NISLANDS_BIF_LUT_NUM_OF_ENTRIES 4
+
+struct SMC_NISLANDS_MC_TPP_CAC_TABLE
+{
+    uint32_t    tpp[SMC_NISLANDS_MC_TPP_CAC_NUM_OF_ENTRIES];
+    uint32_t    cacValue[SMC_NISLANDS_MC_TPP_CAC_NUM_OF_ENTRIES];
+};
+
+typedef struct SMC_NISLANDS_MC_TPP_CAC_TABLE SMC_NISLANDS_MC_TPP_CAC_TABLE;
+
+
+struct PP_NIslands_CACTABLES
+{
+    uint32_t                cac_bif_lut[SMC_NISLANDS_BIF_LUT_NUM_OF_ENTRIES];
+    uint32_t                cac_lkge_lut[SMC_NISLANDS_LKGE_LUT_NUM_OF_TEMP_ENTRIES][SMC_NISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES];
+
+    uint32_t                pwr_const;
+
+    uint32_t                dc_cacValue;
+    uint32_t                bif_cacValue;
+    uint32_t                lkge_pwr;
+
+    uint8_t                 cac_width;
+    uint8_t                 window_size_p2;
+
+    uint8_t                 num_drop_lsb;
+    uint8_t                 padding_0;
+
+    uint32_t                last_power;
+
+    uint8_t                 AllowOvrflw;
+    uint8_t                 MCWrWeight;
+    uint8_t                 MCRdWeight;
+    uint8_t                 padding_1[9];
+
+    uint8_t                 enableWinAvg;
+    uint8_t                 numWin_TDP;
+    uint8_t                 l2numWin_TDP;
+    uint8_t                 WinIndex;
+
+    uint32_t                dynPwr_TDP[4];
+    uint32_t                lkgePwr_TDP[4];
+    uint32_t                power_TDP[4];
+    uint32_t                avg_dynPwr_TDP;
+    uint32_t                avg_lkgePwr_TDP;
+    uint32_t                avg_power_TDP;
+    uint32_t                lts_power_TDP;
+    uint8_t                 lts_truncate_n;
+    uint8_t                 padding_2[7];
+};
+
+typedef struct PP_NIslands_CACTABLES PP_NIslands_CACTABLES;
+
+#define SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE 32
+#define SMC_NISLANDS_MC_REGISTER_ARRAY_SET_COUNT 20
+
+struct SMC_NIslands_MCRegisterAddress
+{
+    uint16_t s0;
+    uint16_t s1;
+};
+
+typedef struct SMC_NIslands_MCRegisterAddress SMC_NIslands_MCRegisterAddress;
+
+
+struct SMC_NIslands_MCRegisterSet
+{
+    uint32_t value[SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE];
+};
+
+typedef struct SMC_NIslands_MCRegisterSet SMC_NIslands_MCRegisterSet;
+
+struct SMC_NIslands_MCRegisters
+{
+    uint8_t                             last;
+    uint8_t                             reserved[3];
+    SMC_NIslands_MCRegisterAddress      address[SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE];
+    SMC_NIslands_MCRegisterSet          data[SMC_NISLANDS_MC_REGISTER_ARRAY_SET_COUNT];
+};
+
+typedef struct SMC_NIslands_MCRegisters SMC_NIslands_MCRegisters;
+
+struct SMC_NIslands_MCArbDramTimingRegisterSet
+{
+    uint32_t mc_arb_dram_timing;
+    uint32_t mc_arb_dram_timing2;
+    uint8_t  mc_arb_rfsh_rate;
+    uint8_t  padding[3];
+};
+
+typedef struct SMC_NIslands_MCArbDramTimingRegisterSet SMC_NIslands_MCArbDramTimingRegisterSet;
+
+struct SMC_NIslands_MCArbDramTimingRegisters
+{
+    uint8_t                                     arb_current;
+    uint8_t                                     reserved[3];
+    SMC_NIslands_MCArbDramTimingRegisterSet     data[20];
+};
+
+typedef struct SMC_NIslands_MCArbDramTimingRegisters SMC_NIslands_MCArbDramTimingRegisters;
+
+struct SMC_NISLANDS_SPLL_DIV_TABLE
+{
+    uint32_t    freq[256];
+    uint32_t    ss[256];
+};
+
+#define SMC_NISLANDS_SPLL_DIV_TABLE_FBDIV_MASK  0x01ffffff
+#define SMC_NISLANDS_SPLL_DIV_TABLE_FBDIV_SHIFT 0
+#define SMC_NISLANDS_SPLL_DIV_TABLE_PDIV_MASK   0xfe000000
+#define SMC_NISLANDS_SPLL_DIV_TABLE_PDIV_SHIFT  25
+#define SMC_NISLANDS_SPLL_DIV_TABLE_CLKV_MASK   0x000fffff
+#define SMC_NISLANDS_SPLL_DIV_TABLE_CLKV_SHIFT  0
+#define SMC_NISLANDS_SPLL_DIV_TABLE_CLKS_MASK   0xfff00000
+#define SMC_NISLANDS_SPLL_DIV_TABLE_CLKS_SHIFT  20
+
+typedef struct SMC_NISLANDS_SPLL_DIV_TABLE SMC_NISLANDS_SPLL_DIV_TABLE;
+
+#define NISLANDS_SMC_FIRMWARE_HEADER_LOCATION 0x100
+
+#define NISLANDS_SMC_FIRMWARE_HEADER_version                   0x0
+#define NISLANDS_SMC_FIRMWARE_HEADER_flags                     0x4
+#define NISLANDS_SMC_FIRMWARE_HEADER_softRegisters             0x8
+#define NISLANDS_SMC_FIRMWARE_HEADER_stateTable                0xC
+#define NISLANDS_SMC_FIRMWARE_HEADER_fanTable                  0x10
+#define NISLANDS_SMC_FIRMWARE_HEADER_cacTable                  0x14
+#define NISLANDS_SMC_FIRMWARE_HEADER_mcRegisterTable           0x20
+#define NISLANDS_SMC_FIRMWARE_HEADER_mcArbDramAutoRefreshTable 0x2C
+#define NISLANDS_SMC_FIRMWARE_HEADER_spllTable                 0x30
+
+#pragma pack(pop)
+
+#endif
+
diff --git a/drivers/gpu/drm/radeon/ppsmc.h b/drivers/gpu/drm/radeon/ppsmc.h
index 3d0786f..607982a 100644
--- a/drivers/gpu/drm/radeon/ppsmc.h
+++ b/drivers/gpu/drm/radeon/ppsmc.h
@@ -46,6 +46,7 @@
 #define PPSMC_DISPLAY_WATERMARK_HIGH                    1
 
 #define PPSMC_STATEFLAG_AUTO_PULSE_SKIP    0x01
+#define PPSMC_STATEFLAG_POWERBOOST         0x02
 
 #define PPSMC_Result_OK             ((uint8_t)0x01)
 #define PPSMC_Result_Failed         ((uint8_t)0xFF)
@@ -56,17 +57,28 @@ typedef uint8_t PPSMC_Result;
 #define PPSMC_MSG_Resume                    ((uint8_t)0x11)
 #define PPSMC_MSG_TwoLevelsDisabled         ((uint8_t)0x15)
 #define PPSMC_MSG_EnableThermalInterrupt    ((uint8_t)0x16)
+#define PPSMC_MSG_RunningOnAC               ((uint8_t)0x17)
 #define PPSMC_MSG_SwitchToSwState           ((uint8_t)0x20)
 #define PPSMC_MSG_SwitchToInitialState      ((uint8_t)0x40)
 #define PPSMC_MSG_NoForcedLevel             ((uint8_t)0x41)
 #define PPSMC_MSG_SwitchToMinimumPower      ((uint8_t)0x51)
 #define PPSMC_MSG_ResumeFromMinimumPower    ((uint8_t)0x52)
+#define PPSMC_MSG_EnableCac                 ((uint8_t)0x53)
+#define PPSMC_MSG_DisableCac                ((uint8_t)0x54)
+#define PPSMC_TDPClampingActive             ((uint8_t)0x59)
+#define PPSMC_TDPClampingInactive           ((uint8_t)0x5A)
 #define PPSMC_MSG_NoDisplay                 ((uint8_t)0x5D)
 #define PPSMC_MSG_HasDisplay                ((uint8_t)0x5E)
+#define PPSMC_MSG_UVDPowerOFF               ((uint8_t)0x60)
+#define PPSMC_MSG_UVDPowerON                ((uint8_t)0x61)
 #define PPSMC_MSG_EnableULV                 ((uint8_t)0x62)
 #define PPSMC_MSG_DisableULV                ((uint8_t)0x63)
 #define PPSMC_MSG_EnterULV                  ((uint8_t)0x64)
 #define PPSMC_MSG_ExitULV                   ((uint8_t)0x65)
+#define PPSMC_CACLongTermAvgEnable          ((uint8_t)0x6E)
+#define PPSMC_CACLongTermAvgDisable         ((uint8_t)0x6F)
+#define PPSMC_MSG_CollectCAC_PowerCorreln   ((uint8_t)0x7A)
+#define PPSMC_MSG_SetEnabledLevels          ((uint8_t)0x82)
 #define PPSMC_MSG_ResetToDefaults           ((uint8_t)0x84)
 
 /* TN */
diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c
index 5dcbb28..e6703ef 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.c
+++ b/drivers/gpu/drm/radeon/radeon_asic.c
@@ -1804,6 +1804,18 @@ static struct radeon_asic cayman_asic = {
 		.set_uvd_clocks = &evergreen_set_uvd_clocks,
 		.get_temperature = &evergreen_get_temp,
 	},
+	.dpm = {
+		.init = &ni_dpm_init,
+		.setup_asic = &ni_dpm_setup_asic,
+		.enable = &ni_dpm_enable,
+		.disable = &ni_dpm_disable,
+		.set_power_state = &ni_dpm_set_power_state,
+		.display_configuration_changed = &cypress_dpm_display_configuration_changed,
+		.fini = &ni_dpm_fini,
+		.get_sclk = &ni_dpm_get_sclk,
+		.get_mclk = &ni_dpm_get_mclk,
+		.print_power_state = &ni_dpm_print_power_state,
+	},
 	.pflip = {
 		.pre_page_flip = &evergreen_pre_page_flip,
 		.page_flip = &evergreen_page_flip,
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index 4d3f93d..2fef64d 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -581,6 +581,16 @@ bool cayman_gfx_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring);
 bool cayman_dma_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring);
 void cayman_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm);
 
+int ni_dpm_init(struct radeon_device *rdev);
+void ni_dpm_setup_asic(struct radeon_device *rdev);
+int ni_dpm_enable(struct radeon_device *rdev);
+void ni_dpm_disable(struct radeon_device *rdev);
+int ni_dpm_set_power_state(struct radeon_device *rdev);
+void ni_dpm_fini(struct radeon_device *rdev);
+u32 ni_dpm_get_sclk(struct radeon_device *rdev, bool low);
+u32 ni_dpm_get_mclk(struct radeon_device *rdev, bool low);
+void ni_dpm_print_power_state(struct radeon_device *rdev,
+			      struct radeon_ps *ps);
 int trinity_dpm_init(struct radeon_device *rdev);
 int trinity_dpm_enable(struct radeon_device *rdev);
 void trinity_dpm_disable(struct radeon_device *rdev);
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
index 2eb41be..01ff18b 100644
--- a/drivers/gpu/drm/radeon/radeon_pm.c
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
@@ -1100,6 +1100,7 @@ int radeon_pm_init(struct radeon_device *rdev)
 	case CHIP_BARTS:
 	case CHIP_TURKS:
 	case CHIP_CAICOS:
+	case CHIP_CAYMAN:
 	case CHIP_ARUBA:
 		if (radeon_dpm == 1)
 			rdev->pm.pm_method = PM_METHOD_DPM;
diff --git a/drivers/gpu/drm/radeon/radeon_ucode.h b/drivers/gpu/drm/radeon/radeon_ucode.h
index e592e27..51beb4c 100644
--- a/drivers/gpu/drm/radeon/radeon_ucode.h
+++ b/drivers/gpu/drm/radeon/radeon_ucode.h
@@ -100,4 +100,9 @@
 #define CAICOS_SMC_INT_VECTOR_START  0xffc0
 #define CAICOS_SMC_INT_VECTOR_SIZE   0x0040
 
+#define CAYMAN_SMC_UCODE_START       0x0100
+#define CAYMAN_SMC_UCODE_SIZE        0x79ec
+#define CAYMAN_SMC_INT_VECTOR_START  0xffc0
+#define CAYMAN_SMC_INT_VECTOR_SIZE   0x0040
+
 #endif
diff --git a/drivers/gpu/drm/radeon/rv770_smc.c b/drivers/gpu/drm/radeon/rv770_smc.c
index 0078c59..ab95da5 100644
--- a/drivers/gpu/drm/radeon/rv770_smc.c
+++ b/drivers/gpu/drm/radeon/rv770_smc.c
@@ -254,6 +254,26 @@ static const u8 caicos_smc_int_vectors[] =
 	0x05, 0x0A, 0x05, 0x0A
 };
 
+static const u8 cayman_smc_int_vectors[] =
+{
+	0x12, 0x05, 0x12, 0x05,
+	0x12, 0x05, 0x12, 0x05,
+	0x12, 0x05, 0x12, 0x05,
+	0x12, 0x05, 0x12, 0x05,
+	0x12, 0x05, 0x12, 0x05,
+	0x12, 0x05, 0x12, 0x05,
+	0x12, 0x05, 0x12, 0x05,
+	0x12, 0x05, 0x12, 0x05,
+	0x12, 0x05, 0x12, 0x05,
+	0x12, 0x05, 0x12, 0x05,
+	0x12, 0x05, 0x12, 0x05,
+	0x12, 0x05, 0x12, 0x05,
+	0x12, 0x05, 0x18, 0xEA,
+	0x12, 0x20, 0x1C, 0x34,
+	0x1C, 0x34, 0x08, 0x72,
+	0x08, 0x72, 0x08, 0x72
+};
+
 int rv770_set_smc_sram_address(struct radeon_device *rdev,
 			       u16 smc_address, u16 limit)
 {
@@ -544,6 +564,13 @@ int rv770_load_smc_ucode(struct radeon_device *rdev,
 		int_vect_start_address = CAICOS_SMC_INT_VECTOR_START;
 		int_vect_size = CAICOS_SMC_INT_VECTOR_SIZE;
 		break;
+	case CHIP_CAYMAN:
+		ucode_start_address = CAYMAN_SMC_UCODE_START;
+		ucode_size = CAYMAN_SMC_UCODE_SIZE;
+		int_vect = (const u8 *)&cayman_smc_int_vectors;
+		int_vect_start_address = CAYMAN_SMC_INT_VECTOR_START;
+		int_vect_size = CAYMAN_SMC_INT_VECTOR_SIZE;
+		break;
 	default:
 		DRM_ERROR("unknown asic in smc ucode loader\n");
 		BUG();
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 094/165] drm/radeon/cayman: update tdp limits in set_power_state
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (93 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 093/165] drm/radeon/kms: add dpm support for cayman alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 095/165] drm/radeon/dpm/rs780: restructure code alexdeucher
                   ` (18 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/ni_dpm.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/radeon/ni_dpm.c b/drivers/gpu/drm/radeon/ni_dpm.c
index 635bf04..44016f2 100644
--- a/drivers/gpu/drm/radeon/ni_dpm.c
+++ b/drivers/gpu/drm/radeon/ni_dpm.c
@@ -3644,6 +3644,7 @@ int ni_dpm_set_power_state(struct radeon_device *rdev)
 	ret = ni_program_memory_timing_parameters(rdev);
 	if (ret)
 		return ret;
+	ni_populate_smc_tdp_limits(rdev);
 	rv770_resume_smc(rdev);
 	rv770_set_sw_state(rdev);
 	ni_enable_smc_cac(rdev, true);
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 095/165] drm/radeon/dpm/rs780: restructure code
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (94 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 094/165] drm/radeon/cayman: update tdp limits in set_power_state alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 096/165] drm/radeon/dpm/rv6xx: " alexdeucher
                   ` (17 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Needed to properly handle dynamic state adjustment.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/rs780_dpm.c |   52 ++++++++++++++++++++++--------------
 1 files changed, 32 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/radeon/rs780_dpm.c b/drivers/gpu/drm/radeon/rs780_dpm.c
index a1497a6..8af1a04 100644
--- a/drivers/gpu/drm/radeon/rs780_dpm.c
+++ b/drivers/gpu/drm/radeon/rs780_dpm.c
@@ -71,10 +71,11 @@ static void rs780_get_pm_mode_parameters(struct radeon_device *rdev)
 
 static void rs780_voltage_scaling_enable(struct radeon_device *rdev, bool enable);
 
-static int rs780_initialize_dpm_power_state(struct radeon_device *rdev)
+static int rs780_initialize_dpm_power_state(struct radeon_device *rdev,
+					    struct radeon_ps *boot_ps)
 {
 	struct atom_clock_dividers dividers;
-	struct igp_ps *default_state = rs780_get_ps(rdev->pm.dpm.boot_ps);
+	struct igp_ps *default_state = rs780_get_ps(boot_ps);
 	int i, ret;
 
 	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
@@ -104,7 +105,8 @@ static int rs780_initialize_dpm_power_state(struct radeon_device *rdev)
 	return 0;
 }
 
-static int rs780_initialize_dpm_parameters(struct radeon_device *rdev)
+static int rs780_initialize_dpm_parameters(struct radeon_device *rdev,
+					   struct radeon_ps *boot_ps)
 {
 	int ret = 0;
 	int i;
@@ -140,7 +142,7 @@ static int rs780_initialize_dpm_parameters(struct radeon_device *rdev)
 	r600_vid_rt_set_vrt(rdev, R600_VOLTAGERESPONSETIME_DFLT);
 	r600_vid_rt_set_ssu(rdev, R600_SPLLSTEPUNIT_DFLT);
 
-	ret = rs780_initialize_dpm_power_state(rdev);
+	ret = rs780_initialize_dpm_power_state(rdev, boot_ps);
 
 	r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_LOW,     0);
 	r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_MEDIUM,  0);
@@ -401,11 +403,13 @@ static void rs780_force_voltage_to_high(struct radeon_device *rdev)
 	WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
 }
 
-static int rs780_set_engine_clock_scaling(struct radeon_device *rdev)
+static int rs780_set_engine_clock_scaling(struct radeon_device *rdev,
+					  struct radeon_ps *new_ps,
+					  struct radeon_ps *old_ps)
 {
 	struct atom_clock_dividers min_dividers, max_dividers, current_max_dividers;
-	struct igp_ps *new_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
-	struct igp_ps *old_state = rs780_get_ps(rdev->pm.dpm.current_ps);
+	struct igp_ps *new_state = rs780_get_ps(new_ps);
+	struct igp_ps *old_state = rs780_get_ps(old_ps);
 	int ret;
 
 	if ((new_state->sclk_high == old_state->sclk_high) &&
@@ -451,10 +455,12 @@ static int rs780_set_engine_clock_scaling(struct radeon_device *rdev)
 	return 0;
 }
 
-static void rs780_set_engine_clock_spc(struct radeon_device *rdev)
+static void rs780_set_engine_clock_spc(struct radeon_device *rdev,
+				       struct radeon_ps *new_ps,
+				       struct radeon_ps *old_ps)
 {
-	struct igp_ps *new_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
-	struct igp_ps *old_state = rs780_get_ps(rdev->pm.dpm.current_ps);
+	struct igp_ps *new_state = rs780_get_ps(new_ps);
+	struct igp_ps *old_state = rs780_get_ps(old_ps);
 	struct igp_power_info *pi = rs780_get_pi(rdev);
 
 	if ((new_state->sclk_high == old_state->sclk_high) &&
@@ -468,10 +474,12 @@ static void rs780_set_engine_clock_spc(struct radeon_device *rdev)
 
 }
 
-static void rs780_activate_engine_clk_scaling(struct radeon_device *rdev)
+static void rs780_activate_engine_clk_scaling(struct radeon_device *rdev,
+					      struct radeon_ps *new_ps,
+					      struct radeon_ps *old_ps)
 {
-	struct igp_ps *new_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
-	struct igp_ps *old_state = rs780_get_ps(rdev->pm.dpm.current_ps);
+	struct igp_ps *new_state = rs780_get_ps(new_ps);
+	struct igp_ps *old_state = rs780_get_ps(old_ps);
 
 	if ((new_state->sclk_high == old_state->sclk_high) &&
 	    (new_state->sclk_low == old_state->sclk_low))
@@ -493,9 +501,10 @@ static u32 rs780_get_voltage_for_vddc_level(struct radeon_device *rdev,
 		return pi->max_voltage;
 }
 
-static void rs780_enable_voltage_scaling(struct radeon_device *rdev)
+static void rs780_enable_voltage_scaling(struct radeon_device *rdev,
+					 struct radeon_ps *new_ps)
 {
-	struct igp_ps *new_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
+	struct igp_ps *new_state = rs780_get_ps(new_ps);
 	struct igp_power_info *pi = rs780_get_pi(rdev);
 	enum rs780_vddc_level vddc_high, vddc_low;
 
@@ -536,13 +545,14 @@ static void rs780_enable_voltage_scaling(struct radeon_device *rdev)
 int rs780_dpm_enable(struct radeon_device *rdev)
 {
 	struct igp_power_info *pi = rs780_get_pi(rdev);
+	struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps;
 
 	rs780_get_pm_mode_parameters(rdev);
 	rs780_disable_vbios_powersaving(rdev);
 
 	if (r600_dynamicpm_enabled(rdev))
 		return -EINVAL;
-	if (rs780_initialize_dpm_parameters(rdev))
+	if (rs780_initialize_dpm_parameters(rdev, boot_ps))
 		return -EINVAL;
 	rs780_start_dpm(rdev);
 
@@ -591,6 +601,8 @@ void rs780_dpm_disable(struct radeon_device *rdev)
 int rs780_dpm_set_power_state(struct radeon_device *rdev)
 {
 	struct igp_power_info *pi = rs780_get_pi(rdev);
+	struct radeon_ps *new_ps = rdev->pm.dpm.requested_ps;
+	struct radeon_ps *old_ps = rdev->pm.dpm.current_ps;
 
 	rs780_get_pm_mode_parameters(rdev);
 
@@ -599,13 +611,13 @@ int rs780_dpm_set_power_state(struct radeon_device *rdev)
 		mdelay(5);
 	}
 
-	rs780_set_engine_clock_scaling(rdev);
-	rs780_set_engine_clock_spc(rdev);
+	rs780_set_engine_clock_scaling(rdev, new_ps, old_ps);
+	rs780_set_engine_clock_spc(rdev, new_ps, old_ps);
 
-	rs780_activate_engine_clk_scaling(rdev);
+	rs780_activate_engine_clk_scaling(rdev, new_ps, old_ps);
 
 	if (pi->voltage_control)
-		rs780_enable_voltage_scaling(rdev);
+		rs780_enable_voltage_scaling(rdev, new_ps);
 
 	return 0;
 }
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 096/165] drm/radeon/dpm/rv6xx: restructure code
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (95 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 095/165] drm/radeon/dpm/rs780: restructure code alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 097/165] drm/radeon/dpm/rv7xx: " alexdeucher
                   ` (16 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Needed to properly handle dynamic state adjustment.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/rv6xx_dpm.c |  115 +++++++++++++++++++++--------------
 1 files changed, 69 insertions(+), 46 deletions(-)

diff --git a/drivers/gpu/drm/radeon/rv6xx_dpm.c b/drivers/gpu/drm/radeon/rv6xx_dpm.c
index fa4beb2..e8f07b1 100644
--- a/drivers/gpu/drm/radeon/rv6xx_dpm.c
+++ b/drivers/gpu/drm/radeon/rv6xx_dpm.c
@@ -961,9 +961,11 @@ static void rv6xx_program_voltage_gpio_pins(struct radeon_device *rdev)
 					 rv6xx_get_master_voltage_mask(rdev));
 }
 
-static void rv6xx_enable_static_voltage_control(struct radeon_device *rdev, bool enable)
+static void rv6xx_enable_static_voltage_control(struct radeon_device *rdev,
+						struct radeon_ps *new_ps,
+						bool enable)
 {
-	struct rv6xx_ps *new_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps);
+	struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps);
 
 	if (enable)
 		radeon_atom_set_voltage(rdev,
@@ -1039,9 +1041,10 @@ static void rv6xx_calculate_ap(struct radeon_device *rdev,
 
 }
 
-static void rv6xx_calculate_stepping_parameters(struct radeon_device *rdev)
+static void rv6xx_calculate_stepping_parameters(struct radeon_device *rdev,
+						struct radeon_ps *new_ps)
 {
-	struct rv6xx_ps *new_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps);
+	struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps);
 
 	rv6xx_calculate_engine_speed_stepping_parameters(rdev, new_state);
 	rv6xx_calculate_memory_clock_stepping_parameters(rdev, new_state);
@@ -1191,10 +1194,12 @@ static void rv6xx_program_display_gap(struct radeon_device *rdev)
 	WREG32(CG_DISPLAY_GAP_CNTL, tmp);
 }
 
-static void rv6xx_set_sw_voltage_to_safe(struct radeon_device *rdev)
+static void rv6xx_set_sw_voltage_to_safe(struct radeon_device *rdev,
+					 struct radeon_ps *new_ps,
+					 struct radeon_ps *old_ps)
 {
-	struct rv6xx_ps *new_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps);
-	struct rv6xx_ps *old_state = rv6xx_get_ps(rdev->pm.dpm.current_ps);
+	struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps);
+	struct rv6xx_ps *old_state = rv6xx_get_ps(old_ps);
 	u16 safe_voltage;
 
 	safe_voltage = (new_state->low.vddc >= old_state->low.vddc) ?
@@ -1207,9 +1212,10 @@ static void rv6xx_set_sw_voltage_to_safe(struct radeon_device *rdev)
 		 ~SW_GPIO_INDEX_MASK);
 }
 
-static void rv6xx_set_sw_voltage_to_low(struct radeon_device *rdev)
+static void rv6xx_set_sw_voltage_to_low(struct radeon_device *rdev,
+					struct radeon_ps *old_ps)
 {
-	struct rv6xx_ps *old_state = rv6xx_get_ps(rdev->pm.dpm.current_ps);
+	struct rv6xx_ps *old_state = rv6xx_get_ps(old_ps);
 
 	rv6xx_program_voltage_stepping_entry(rdev, R600_POWER_LEVEL_CTXSW,
 					     old_state->low.vddc);
@@ -1218,10 +1224,12 @@ static void rv6xx_set_sw_voltage_to_low(struct radeon_device *rdev)
 		~SW_GPIO_INDEX_MASK);
 }
 
-static void rv6xx_set_safe_backbias(struct radeon_device *rdev)
+static void rv6xx_set_safe_backbias(struct radeon_device *rdev,
+				    struct radeon_ps *new_ps,
+				    struct radeon_ps *old_ps)
 {
-	struct rv6xx_ps *new_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps);
-	struct rv6xx_ps *old_state = rv6xx_get_ps(rdev->pm.dpm.current_ps);
+	struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps);
+	struct rv6xx_ps *old_state = rv6xx_get_ps(old_ps);
 
 	if ((new_state->low.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) &&
 	    (old_state->low.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE))
@@ -1230,10 +1238,12 @@ static void rv6xx_set_safe_backbias(struct radeon_device *rdev)
 		WREG32_P(GENERAL_PWRMGT, 0, ~BACKBIAS_VALUE);
 }
 
-static void rv6xx_set_safe_pcie_gen2(struct radeon_device *rdev)
+static void rv6xx_set_safe_pcie_gen2(struct radeon_device *rdev,
+				     struct radeon_ps *new_ps,
+				     struct radeon_ps *old_ps)
 {
-	struct rv6xx_ps *new_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps);
-	struct rv6xx_ps *old_state = rv6xx_get_ps(rdev->pm.dpm.current_ps);
+	struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps);
+	struct rv6xx_ps *old_state = rv6xx_get_ps(old_ps);
 
 	if ((new_state->low.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) !=
 	    (old_state->low.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2))
@@ -1290,10 +1300,12 @@ static int rv6xx_step_sw_voltage(struct radeon_device *rdev,
 	return 0;
 }
 
-static int rv6xx_step_voltage_if_increasing(struct radeon_device *rdev)
+static int rv6xx_step_voltage_if_increasing(struct radeon_device *rdev,
+					    struct radeon_ps *new_ps,
+					    struct radeon_ps *old_ps)
 {
-	struct rv6xx_ps *new_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps);
-	struct rv6xx_ps *old_state = rv6xx_get_ps(rdev->pm.dpm.current_ps);
+	struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps);
+	struct rv6xx_ps *old_state = rv6xx_get_ps(old_ps);
 
 	if (new_state->low.vddc > old_state->low.vddc)
 		return rv6xx_step_sw_voltage(rdev,
@@ -1303,10 +1315,12 @@ static int rv6xx_step_voltage_if_increasing(struct radeon_device *rdev)
 	return 0;
 }
 
-static int rv6xx_step_voltage_if_decreasing(struct radeon_device *rdev)
+static int rv6xx_step_voltage_if_decreasing(struct radeon_device *rdev,
+					    struct radeon_ps *new_ps,
+					    struct radeon_ps *old_ps)
 {
-	struct rv6xx_ps *new_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps);
-	struct rv6xx_ps *old_state = rv6xx_get_ps(rdev->pm.dpm.current_ps);
+	struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps);
+	struct rv6xx_ps *old_state = rv6xx_get_ps(old_ps);
 
 	if (new_state->low.vddc < old_state->low.vddc)
 		return rv6xx_step_sw_voltage(rdev,
@@ -1399,10 +1413,12 @@ static void rv6xx_enable_thermal_protection(struct radeon_device *rdev,
 		r600_enable_thermal_protection(rdev, enable);
 }
 
-static void rv6xx_generate_transition_stepping(struct radeon_device *rdev)
+static void rv6xx_generate_transition_stepping(struct radeon_device *rdev,
+					       struct radeon_ps *new_ps,
+					       struct radeon_ps *old_ps)
 {
-	struct rv6xx_ps *new_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps);
-	struct rv6xx_ps *old_state = rv6xx_get_ps(rdev->pm.dpm.current_ps);
+	struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps);
+	struct rv6xx_ps *old_state = rv6xx_get_ps(old_ps);
 	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
 
 	rv6xx_generate_steps(rdev,
@@ -1411,9 +1427,10 @@ static void rv6xx_generate_transition_stepping(struct radeon_device *rdev)
 			     0, &pi->hw.medium_sclk_index);
 }
 
-static void rv6xx_generate_low_step(struct radeon_device *rdev)
+static void rv6xx_generate_low_step(struct radeon_device *rdev,
+				    struct radeon_ps *new_ps)
 {
-	struct rv6xx_ps *new_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps);
+	struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps);
 	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
 
 	pi->hw.low_sclk_index = 0;
@@ -1430,9 +1447,10 @@ static void rv6xx_invalidate_intermediate_steps(struct radeon_device *rdev)
 						  pi->hw.medium_sclk_index);
 }
 
-static void rv6xx_generate_stepping_table(struct radeon_device *rdev)
+static void rv6xx_generate_stepping_table(struct radeon_device *rdev,
+					  struct radeon_ps *new_ps)
 {
-	struct rv6xx_ps *new_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps);
+	struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps);
 	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
 
 	pi->hw.low_sclk_index = 0;
@@ -1472,9 +1490,10 @@ static void rv6xx_reset_lvtm_data_sync(struct radeon_device *rdev)
 }
 
 static void rv6xx_enable_dynamic_pcie_gen2(struct radeon_device *rdev,
+					   struct radeon_ps *new_ps,
 					   bool enable)
 {
-	struct rv6xx_ps *new_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps);
+	struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps);
 
 	if (enable) {
 		rv6xx_enable_bif_dynamic_pcie_gen2(rdev, true);
@@ -1491,6 +1510,7 @@ static void rv6xx_enable_dynamic_pcie_gen2(struct radeon_device *rdev,
 int rv6xx_dpm_enable(struct radeon_device *rdev)
 {
 	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+	struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps;
 
 	if (r600_dynamicpm_enabled(rdev))
 		return -EINVAL;
@@ -1518,12 +1538,12 @@ int rv6xx_dpm_enable(struct radeon_device *rdev)
 
 	rv6xx_program_power_level_enter_state(rdev);
 
-	rv6xx_calculate_stepping_parameters(rdev);
+	rv6xx_calculate_stepping_parameters(rdev, boot_ps);
 
 	if (pi->voltage_control)
 		rv6xx_program_voltage_gpio_pins(rdev);
 
-	rv6xx_generate_stepping_table(rdev);
+	rv6xx_generate_stepping_table(rdev, boot_ps);
 
 	rv6xx_program_stepping_parameters_except_lowest_entry(rdev);
 	rv6xx_program_stepping_parameters_lowest_entry(rdev);
@@ -1550,10 +1570,10 @@ int rv6xx_dpm_enable(struct radeon_device *rdev)
 	r600_start_dpm(rdev);
 
 	if (pi->voltage_control)
-		rv6xx_enable_static_voltage_control(rdev, false);
+		rv6xx_enable_static_voltage_control(rdev, boot_ps, false);
 
 	if (pi->dynamic_pcie_gen2)
-		rv6xx_enable_dynamic_pcie_gen2(rdev, true);
+		rv6xx_enable_dynamic_pcie_gen2(rdev, boot_ps, true);
 
 	if (pi->gfx_clock_gating)
 		r600_gfx_clockgating_enable(rdev, true);
@@ -1564,6 +1584,7 @@ int rv6xx_dpm_enable(struct radeon_device *rdev)
 void rv6xx_dpm_disable(struct radeon_device *rdev)
 {
 	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+	struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps;
 
 	if (!r600_dynamicpm_enabled(rdev))
 		return;
@@ -1587,10 +1608,10 @@ void rv6xx_dpm_disable(struct radeon_device *rdev)
 	rv6xx_enable_spread_spectrum(rdev, false);
 
 	if (pi->voltage_control)
-		rv6xx_enable_static_voltage_control(rdev, true);
+		rv6xx_enable_static_voltage_control(rdev, boot_ps, true);
 
 	if (pi->dynamic_pcie_gen2)
-		rv6xx_enable_dynamic_pcie_gen2(rdev, false);
+		rv6xx_enable_dynamic_pcie_gen2(rdev, boot_ps, false);
 
 	if (rdev->irq.installed &&
 	    r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
@@ -1607,6 +1628,8 @@ void rv6xx_dpm_disable(struct radeon_device *rdev)
 int rv6xx_dpm_set_power_state(struct radeon_device *rdev)
 {
 	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+	struct radeon_ps *new_ps = rdev->pm.dpm.requested_ps;
+	struct radeon_ps *old_ps = rdev->pm.dpm.current_ps;
 
 	rv6xx_clear_vc(rdev);
 	r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true);
@@ -1619,20 +1642,20 @@ int rv6xx_dpm_set_power_state(struct radeon_device *rdev)
 	r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, false);
 	r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, false);
 
-	rv6xx_generate_transition_stepping(rdev);
+	rv6xx_generate_transition_stepping(rdev, new_ps, old_ps);
 	rv6xx_program_power_level_medium_for_transition(rdev);
 
 	if (pi->voltage_control) {
-		rv6xx_set_sw_voltage_to_safe(rdev);
+		rv6xx_set_sw_voltage_to_safe(rdev, new_ps, old_ps);
 		if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC)
-			rv6xx_set_sw_voltage_to_low(rdev);
+			rv6xx_set_sw_voltage_to_low(rdev, old_ps);
 	}
 
 	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS)
-		rv6xx_set_safe_backbias(rdev);
+		rv6xx_set_safe_backbias(rdev, new_ps, old_ps);
 
 	if (pi->dynamic_pcie_gen2)
-		rv6xx_set_safe_pcie_gen2(rdev);
+		rv6xx_set_safe_pcie_gen2(rdev, new_ps, old_ps);
 
 	if (pi->voltage_control)
 		rv6xx_enable_dynamic_voltage_control(rdev, false);
@@ -1642,7 +1665,7 @@ int rv6xx_dpm_set_power_state(struct radeon_device *rdev)
 
 	if (pi->voltage_control) {
 		if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC)
-			rv6xx_step_voltage_if_increasing(rdev);
+			rv6xx_step_voltage_if_increasing(rdev, new_ps, old_ps);
 		msleep((rdev->pm.dpm.voltage_response_time + 999) / 1000);
 	}
 
@@ -1650,9 +1673,9 @@ int rv6xx_dpm_set_power_state(struct radeon_device *rdev)
 	r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, false);
 	r600_wait_for_power_level_unequal(rdev, R600_POWER_LEVEL_LOW);
 
-	rv6xx_generate_low_step(rdev);
+	rv6xx_generate_low_step(rdev, new_ps);
 	rv6xx_invalidate_intermediate_steps(rdev);
-	rv6xx_calculate_stepping_parameters(rdev);
+	rv6xx_calculate_stepping_parameters(rdev, new_ps);
 	rv6xx_program_stepping_parameters_lowest_entry(rdev);
 	rv6xx_program_power_level_low_to_lowest_state(rdev);
 
@@ -1662,7 +1685,7 @@ int rv6xx_dpm_set_power_state(struct radeon_device *rdev)
 
 	if (pi->voltage_control) {
 		if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC)
-			rv6xx_step_voltage_if_decreasing(rdev);
+			rv6xx_step_voltage_if_decreasing(rdev, new_ps, old_ps);
 		rv6xx_enable_dynamic_voltage_control(rdev, true);
 	}
 
@@ -1670,11 +1693,11 @@ int rv6xx_dpm_set_power_state(struct radeon_device *rdev)
 		rv6xx_enable_dynamic_backbias_control(rdev, true);
 
 	if (pi->dynamic_pcie_gen2)
-		rv6xx_enable_dynamic_pcie_gen2(rdev, true);
+		rv6xx_enable_dynamic_pcie_gen2(rdev, new_ps, true);
 
 	rv6xx_reset_lvtm_data_sync(rdev);
 
-	rv6xx_generate_stepping_table(rdev);
+	rv6xx_generate_stepping_table(rdev, new_ps);
 	rv6xx_program_stepping_parameters_except_lowest_entry(rdev);
 	rv6xx_program_power_level_low(rdev);
 	rv6xx_program_power_level_medium(rdev);
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 097/165] drm/radeon/dpm/rv7xx: restructure code
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (96 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 096/165] drm/radeon/dpm/rv6xx: " alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 098/165] drm/radeon/dpm/evergreen: " alexdeucher
                   ` (15 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Needed to properly handle dynamic state adjustment.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/btc_dpm.c     |    6 ++-
 drivers/gpu/drm/radeon/cypress_dpm.c |    6 ++-
 drivers/gpu/drm/radeon/rv740_dpm.c   |    1 -
 drivers/gpu/drm/radeon/rv770_dpm.c   |   77 ++++++++++++++++++----------------
 drivers/gpu/drm/radeon/rv770_dpm.h   |    8 +++-
 5 files changed, 55 insertions(+), 43 deletions(-)

diff --git a/drivers/gpu/drm/radeon/btc_dpm.c b/drivers/gpu/drm/radeon/btc_dpm.c
index 79f5ed4..3ae4de6 100644
--- a/drivers/gpu/drm/radeon/btc_dpm.c
+++ b/drivers/gpu/drm/radeon/btc_dpm.c
@@ -2233,6 +2233,8 @@ void btc_dpm_reset_asic(struct radeon_device *rdev)
 int btc_dpm_set_power_state(struct radeon_device *rdev)
 {
 	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	struct radeon_ps *new_ps = rdev->pm.dpm.requested_ps;
+	struct radeon_ps *old_ps = rdev->pm.dpm.current_ps;
 
 	btc_apply_state_adjust_rules(rdev);
 
@@ -2243,7 +2245,7 @@ int btc_dpm_set_power_state(struct radeon_device *rdev)
 	if (eg_pi->pcie_performance_request)
 		cypress_notify_link_speed_change_before_state_change(rdev);
 
-	rv770_set_uvd_clock_before_set_eng_clock(rdev);
+	rv770_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps);
 	rv770_halt_smc(rdev);
 	btc_set_at_for_uvd(rdev);
 	if (eg_pi->smu_uvd_hs)
@@ -2257,7 +2259,7 @@ int btc_dpm_set_power_state(struct radeon_device *rdev)
 
 	rv770_resume_smc(rdev);
 	rv770_set_sw_state(rdev);
-	rv770_set_uvd_clock_after_set_eng_clock(rdev);
+	rv770_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps);
 
 	if (eg_pi->pcie_performance_request)
 		cypress_notify_link_speed_change_after_state_change(rdev);
diff --git a/drivers/gpu/drm/radeon/cypress_dpm.c b/drivers/gpu/drm/radeon/cypress_dpm.c
index 22297b1..c9026ed 100644
--- a/drivers/gpu/drm/radeon/cypress_dpm.c
+++ b/drivers/gpu/drm/radeon/cypress_dpm.c
@@ -1930,13 +1930,15 @@ void cypress_dpm_disable(struct radeon_device *rdev)
 int cypress_dpm_set_power_state(struct radeon_device *rdev)
 {
 	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	struct radeon_ps *new_ps = rdev->pm.dpm.requested_ps;
+	struct radeon_ps *old_ps = rdev->pm.dpm.current_ps;
 
 	rv770_restrict_performance_levels_before_switch(rdev);
 
 	if (eg_pi->pcie_performance_request)
 		cypress_notify_link_speed_change_before_state_change(rdev);
 
-	rv770_set_uvd_clock_before_set_eng_clock(rdev);
+	rv770_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps);
 	rv770_halt_smc(rdev);
 	cypress_upload_sw_state(rdev);
 
@@ -1947,7 +1949,7 @@ int cypress_dpm_set_power_state(struct radeon_device *rdev)
 
 	rv770_resume_smc(rdev);
 	rv770_set_sw_state(rdev);
-	rv770_set_uvd_clock_after_set_eng_clock(rdev);
+	rv770_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps);
 
 	if (eg_pi->pcie_performance_request)
 		cypress_notify_link_speed_change_after_state_change(rdev);
diff --git a/drivers/gpu/drm/radeon/rv740_dpm.c b/drivers/gpu/drm/radeon/rv740_dpm.c
index d0d750e..7aa1608 100644
--- a/drivers/gpu/drm/radeon/rv740_dpm.c
+++ b/drivers/gpu/drm/radeon/rv740_dpm.c
@@ -29,7 +29,6 @@
 #include "rv770_dpm.h"
 #include "atom.h"
 
-struct rv7xx_ps *rv770_get_ps(struct radeon_ps *rps);
 struct rv7xx_power_info *rv770_get_pi(struct radeon_device *rdev);
 
 u32 rv740_get_decoded_reference_divider(u32 encoded_ref)
diff --git a/drivers/gpu/drm/radeon/rv770_dpm.c b/drivers/gpu/drm/radeon/rv770_dpm.c
index f5efa4c..db1dfbc 100644
--- a/drivers/gpu/drm/radeon/rv770_dpm.c
+++ b/drivers/gpu/drm/radeon/rv770_dpm.c
@@ -1155,10 +1155,10 @@ static int rv770_populate_smc_mvdd_table(struct radeon_device *rdev,
 	return 0;
 }
 
-static int rv770_init_smc_table(struct radeon_device *rdev)
+static int rv770_init_smc_table(struct radeon_device *rdev,
+				struct radeon_ps *radeon_boot_state)
 {
 	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
-	struct radeon_ps *radeon_boot_state = rdev->pm.dpm.boot_ps;
 	struct rv7xx_ps *boot_state = rv770_get_ps(radeon_boot_state);
 	RV770_SMC_STATETABLE *table = &pi->smc_statetable;
 	int ret;
@@ -1364,10 +1364,9 @@ static void rv770_enable_dynamic_pcie_gen2(struct radeon_device *rdev,
 		WREG32_P(GENERAL_PWRMGT, 0, ~ENABLE_GEN2PCIE);
 }
 
-static void r7xx_program_memory_timing_parameters(struct radeon_device *rdev)
+static void r7xx_program_memory_timing_parameters(struct radeon_device *rdev,
+						  struct radeon_ps *radeon_new_state)
 {
-	struct radeon_ps *radeon_new_state = rdev->pm.dpm.requested_ps;
-
 	if ((rdev->family == CHIP_RV730) ||
 	    (rdev->family == CHIP_RV710) ||
 	    (rdev->family == CHIP_RV740))
@@ -1376,10 +1375,10 @@ static void r7xx_program_memory_timing_parameters(struct radeon_device *rdev)
 		rv770_program_memory_timing_parameters(rdev, radeon_new_state);
 }
 
-static int rv770_upload_sw_state(struct radeon_device *rdev)
+static int rv770_upload_sw_state(struct radeon_device *rdev,
+				 struct radeon_ps *radeon_new_state)
 {
 	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
-	struct radeon_ps *radeon_new_state = rdev->pm.dpm.requested_ps;
 	u16 address = pi->state_table_start +
 		offsetof(RV770_SMC_STATETABLE, driverState);
 	RV770_SMC_SWSTATE state = { 0 };
@@ -1426,36 +1425,38 @@ int rv770_set_boot_state(struct radeon_device *rdev)
 	return 0;
 }
 
-void rv770_set_uvd_clock_before_set_eng_clock(struct radeon_device *rdev)
+void rv770_set_uvd_clock_before_set_eng_clock(struct radeon_device *rdev,
+					      struct radeon_ps *new_ps,
+					      struct radeon_ps *old_ps)
 {
-	struct rv7xx_ps *new_state = rv770_get_ps(rdev->pm.dpm.requested_ps);
-	struct rv7xx_ps *current_state = rv770_get_ps(rdev->pm.dpm.current_ps);
+	struct rv7xx_ps *new_state = rv770_get_ps(new_ps);
+	struct rv7xx_ps *current_state = rv770_get_ps(old_ps);
 
-	if ((rdev->pm.dpm.requested_ps->vclk == rdev->pm.dpm.current_ps->vclk) &&
-	    (rdev->pm.dpm.requested_ps->dclk == rdev->pm.dpm.current_ps->dclk))
+	if ((new_ps->vclk == old_ps->vclk) &&
+	    (new_ps->dclk == old_ps->dclk))
 		return;
 
 	if (new_state->high.sclk >= current_state->high.sclk)
 		return;
 
-	radeon_set_uvd_clocks(rdev, rdev->pm.dpm.requested_ps->vclk,
-			      rdev->pm.dpm.requested_ps->dclk);
+	radeon_set_uvd_clocks(rdev, new_ps->vclk, old_ps->dclk);
 }
 
-void rv770_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev)
+void rv770_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev,
+					     struct radeon_ps *new_ps,
+					     struct radeon_ps *old_ps)
 {
-	struct rv7xx_ps *new_state = rv770_get_ps(rdev->pm.dpm.requested_ps);
-	struct rv7xx_ps *current_state = rv770_get_ps(rdev->pm.dpm.current_ps);
+	struct rv7xx_ps *new_state = rv770_get_ps(new_ps);
+	struct rv7xx_ps *current_state = rv770_get_ps(old_ps);
 
-	if ((rdev->pm.dpm.requested_ps->vclk == rdev->pm.dpm.current_ps->vclk) &&
-	    (rdev->pm.dpm.requested_ps->dclk == rdev->pm.dpm.current_ps->dclk))
+	if ((new_ps->vclk == old_ps->vclk) &&
+	    (new_ps->dclk == old_ps->dclk))
 		return;
 
 	if (new_state->high.sclk < current_state->high.sclk)
 		return;
 
-	radeon_set_uvd_clocks(rdev, rdev->pm.dpm.requested_ps->vclk,
-			      rdev->pm.dpm.requested_ps->dclk);
+	radeon_set_uvd_clocks(rdev, new_ps->vclk, new_ps->dclk);
 }
 
 int rv770_restrict_performance_levels_before_switch(struct radeon_device *rdev)
@@ -1709,11 +1710,11 @@ void rv770_program_response_times(struct radeon_device *rdev)
 #endif
 }
 
-static void rv770_program_dcodt_before_state_switch(struct radeon_device *rdev)
+static void rv770_program_dcodt_before_state_switch(struct radeon_device *rdev,
+						    struct radeon_ps *radeon_new_state,
+						    struct radeon_ps *radeon_current_state)
 {
 	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
-	struct radeon_ps *radeon_new_state = rdev->pm.dpm.requested_ps;
-	struct radeon_ps *radeon_current_state = rdev->pm.dpm.current_ps;
 	struct rv7xx_ps *new_state = rv770_get_ps(radeon_new_state);
 	struct rv7xx_ps *current_state = rv770_get_ps(radeon_current_state);
 	bool current_use_dc = false;
@@ -1738,11 +1739,11 @@ static void rv770_program_dcodt_before_state_switch(struct radeon_device *rdev)
 		rv730_program_dcodt(rdev, new_use_dc);
 }
 
-static void rv770_program_dcodt_after_state_switch(struct radeon_device *rdev)
+static void rv770_program_dcodt_after_state_switch(struct radeon_device *rdev,
+						   struct radeon_ps *radeon_new_state,
+						   struct radeon_ps *radeon_current_state)
 {
 	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
-	struct radeon_ps *radeon_new_state = rdev->pm.dpm.requested_ps;
-	struct radeon_ps *radeon_current_state = rdev->pm.dpm.current_ps;
 	struct rv7xx_ps *new_state = rv770_get_ps(radeon_new_state);
 	struct rv7xx_ps *current_state = rv770_get_ps(radeon_current_state);
 	bool current_use_dc = false;
@@ -1862,6 +1863,7 @@ int rv770_set_thermal_temperature_range(struct radeon_device *rdev,
 int rv770_dpm_enable(struct radeon_device *rdev)
 {
 	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps;
 
 	if (pi->gfx_clock_gating)
 		rv770_restore_cgcg(rdev);
@@ -1904,7 +1906,7 @@ int rv770_dpm_enable(struct radeon_device *rdev)
 	if (rv770_upload_firmware(rdev))
 		return -EINVAL;
 	/* get ucode version ?  */
-	if (rv770_init_smc_table(rdev))
+	if (rv770_init_smc_table(rdev, boot_ps))
 		return -EINVAL;
 	rv770_program_response_times(rdev);
 	r7xx_start_smc(rdev);
@@ -1979,19 +1981,21 @@ void rv770_dpm_disable(struct radeon_device *rdev)
 int rv770_dpm_set_power_state(struct radeon_device *rdev)
 {
 	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	struct radeon_ps *new_ps = rdev->pm.dpm.requested_ps;
+	struct radeon_ps *old_ps = rdev->pm.dpm.current_ps;
 
 	rv770_restrict_performance_levels_before_switch(rdev);
-	rv770_set_uvd_clock_before_set_eng_clock(rdev);
+	rv770_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps);
 	rv770_halt_smc(rdev);
-	rv770_upload_sw_state(rdev);
-	r7xx_program_memory_timing_parameters(rdev);
+	rv770_upload_sw_state(rdev, new_ps);
+	r7xx_program_memory_timing_parameters(rdev, new_ps);
 	if (pi->dcodt)
-		rv770_program_dcodt_before_state_switch(rdev);
+		rv770_program_dcodt_before_state_switch(rdev, new_ps, old_ps);
 	rv770_resume_smc(rdev);
 	rv770_set_sw_state(rdev);
 	if (pi->dcodt)
-		rv770_program_dcodt_after_state_switch(rdev);
-	rv770_set_uvd_clock_after_set_eng_clock(rdev);
+		rv770_program_dcodt_after_state_switch(rdev, new_ps, old_ps);
+	rv770_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps);
 
 	return 0;
 }
@@ -1999,13 +2003,14 @@ int rv770_dpm_set_power_state(struct radeon_device *rdev)
 void rv770_dpm_reset_asic(struct radeon_device *rdev)
 {
 	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps;
 
 	rv770_restrict_performance_levels_before_switch(rdev);
 	if (pi->dcodt)
-		rv770_program_dcodt_before_state_switch(rdev);
+		rv770_program_dcodt_before_state_switch(rdev, boot_ps, boot_ps);
 	rv770_set_boot_state(rdev);
 	if (pi->dcodt)
-		rv770_program_dcodt_after_state_switch(rdev);
+		rv770_program_dcodt_after_state_switch(rdev, boot_ps, boot_ps);
 }
 
 void rv770_dpm_setup_asic(struct radeon_device *rdev)
diff --git a/drivers/gpu/drm/radeon/rv770_dpm.h b/drivers/gpu/drm/radeon/rv770_dpm.h
index dfb133f..22586df 100644
--- a/drivers/gpu/drm/radeon/rv770_dpm.h
+++ b/drivers/gpu/drm/radeon/rv770_dpm.h
@@ -266,8 +266,12 @@ int rv770_resume_smc(struct radeon_device *rdev);
 int rv770_set_sw_state(struct radeon_device *rdev);
 int rv770_set_boot_state(struct radeon_device *rdev);
 int rv7xx_parse_power_table(struct radeon_device *rdev);
-void rv770_set_uvd_clock_before_set_eng_clock(struct radeon_device *rdev);
-void rv770_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev);
+void rv770_set_uvd_clock_before_set_eng_clock(struct radeon_device *rdev,
+					      struct radeon_ps *new_ps,
+					      struct radeon_ps *old_ps);
+void rv770_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev,
+					     struct radeon_ps *new_ps,
+					     struct radeon_ps *old_ps);
 
 /* smc */
 int rv770_read_smc_soft_register(struct radeon_device *rdev,
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 098/165] drm/radeon/dpm/evergreen: restructure code
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (97 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 097/165] drm/radeon/dpm/rv7xx: " alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:22 ` [PATCH 099/165] drm/radeon/dpm/btc: " alexdeucher
                   ` (14 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Needed to properly handle dynamic state adjustment.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/btc_dpm.c     |   13 ++++---
 drivers/gpu/drm/radeon/cypress_dpm.c |   62 +++++++++++++++++----------------
 drivers/gpu/drm/radeon/cypress_dpm.h |   20 ++++++++---
 3 files changed, 53 insertions(+), 42 deletions(-)

diff --git a/drivers/gpu/drm/radeon/btc_dpm.c b/drivers/gpu/drm/radeon/btc_dpm.c
index 3ae4de6..73a0ba3 100644
--- a/drivers/gpu/drm/radeon/btc_dpm.c
+++ b/drivers/gpu/drm/radeon/btc_dpm.c
@@ -2243,26 +2243,26 @@ int btc_dpm_set_power_state(struct radeon_device *rdev)
 	rv770_restrict_performance_levels_before_switch(rdev);
 
 	if (eg_pi->pcie_performance_request)
-		cypress_notify_link_speed_change_before_state_change(rdev);
+		cypress_notify_link_speed_change_before_state_change(rdev, new_ps, old_ps);
 
 	rv770_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps);
 	rv770_halt_smc(rdev);
 	btc_set_at_for_uvd(rdev);
 	if (eg_pi->smu_uvd_hs)
 		btc_notify_uvd_to_smc(rdev);
-	cypress_upload_sw_state(rdev);
+	cypress_upload_sw_state(rdev, new_ps);
 
 	if (eg_pi->dynamic_ac_timing)
-		cypress_upload_mc_reg_table(rdev);
+		cypress_upload_mc_reg_table(rdev, new_ps);
 
-	cypress_program_memory_timing_parameters(rdev);
+	cypress_program_memory_timing_parameters(rdev, new_ps);
 
 	rv770_resume_smc(rdev);
 	rv770_set_sw_state(rdev);
 	rv770_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps);
 
 	if (eg_pi->pcie_performance_request)
-		cypress_notify_link_speed_change_after_state_change(rdev);
+		cypress_notify_link_speed_change_after_state_change(rdev, new_ps, old_ps);
 
 	btc_set_power_state_conditionally_enable_ulv(rdev);
 
@@ -2273,6 +2273,7 @@ int btc_dpm_enable(struct radeon_device *rdev)
 {
 	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
 	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps;
 
 	if (pi->gfx_clock_gating)
 		btc_cg_clock_gating_default(rdev);
@@ -2325,7 +2326,7 @@ int btc_dpm_enable(struct radeon_device *rdev)
 	btc_init_smc_table(rdev);
 
 	if (eg_pi->dynamic_ac_timing)
-		cypress_populate_mc_reg_table(rdev);
+		cypress_populate_mc_reg_table(rdev, boot_ps);
 
 	cypress_program_response_times(rdev);
 	r7xx_start_smc(rdev);
diff --git a/drivers/gpu/drm/radeon/cypress_dpm.c b/drivers/gpu/drm/radeon/cypress_dpm.c
index c9026ed..1ce1f08 100644
--- a/drivers/gpu/drm/radeon/cypress_dpm.c
+++ b/drivers/gpu/drm/radeon/cypress_dpm.c
@@ -353,10 +353,10 @@ static u32 cypress_get_maximum_link_speed(struct radeon_ps *radeon_state)
 	return 0;
 }
 
-void cypress_notify_link_speed_change_after_state_change(struct radeon_device *rdev)
+void cypress_notify_link_speed_change_after_state_change(struct radeon_device *rdev,
+							 struct radeon_ps *radeon_new_state,
+							 struct radeon_ps *radeon_current_state)
 {
-	struct radeon_ps *radeon_new_state = rdev->pm.dpm.requested_ps;
-	struct radeon_ps *radeon_current_state = rdev->pm.dpm.current_ps;
 	u32 pcie_link_speed_target =  cypress_get_maximum_link_speed(radeon_new_state);
 	u32 pcie_link_speed_current = cypress_get_maximum_link_speed(radeon_current_state);
 	u8 request;
@@ -373,10 +373,10 @@ void cypress_notify_link_speed_change_after_state_change(struct radeon_device *r
 	}
 }
 
-void cypress_notify_link_speed_change_before_state_change(struct radeon_device *rdev)
+void cypress_notify_link_speed_change_before_state_change(struct radeon_device *rdev,
+							  struct radeon_ps *radeon_new_state,
+							  struct radeon_ps *radeon_current_state)
 {
-	struct radeon_ps *radeon_new_state = rdev->pm.dpm.requested_ps;
-	struct radeon_ps *radeon_current_state = rdev->pm.dpm.current_ps;
 	u32 pcie_link_speed_target =  cypress_get_maximum_link_speed(radeon_new_state);
 	u32 pcie_link_speed_current = cypress_get_maximum_link_speed(radeon_current_state);
 	u8 request;
@@ -856,10 +856,10 @@ static void cypress_convert_mc_reg_table_to_smc(struct radeon_device *rdev,
 						  &mc_reg_table->data[4]);
 }
 
-int cypress_upload_sw_state(struct radeon_device *rdev)
+int cypress_upload_sw_state(struct radeon_device *rdev,
+			    struct radeon_ps *radeon_new_state)
 {
 	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
-	struct radeon_ps *radeon_new_state = rdev->pm.dpm.requested_ps;
 	u16 address = pi->state_table_start +
 		offsetof(RV770_SMC_STATETABLE, driverState);
 	RV770_SMC_SWSTATE state = { 0 };
@@ -874,11 +874,11 @@ int cypress_upload_sw_state(struct radeon_device *rdev)
 				    pi->sram_end);
 }
 
-int cypress_upload_mc_reg_table(struct radeon_device *rdev)
+int cypress_upload_mc_reg_table(struct radeon_device *rdev,
+				struct radeon_ps *radeon_new_state)
 {
 	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
 	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
-	struct radeon_ps *radeon_new_state = rdev->pm.dpm.requested_ps;
 	SMC_Evergreen_MCRegisters mc_reg_table = { 0 };
 	u16 address;
 
@@ -914,9 +914,9 @@ u32 cypress_calculate_burst_time(struct radeon_device *rdev,
 	return burst_time;
 }
 
-void cypress_program_memory_timing_parameters(struct radeon_device *rdev)
+void cypress_program_memory_timing_parameters(struct radeon_device *rdev,
+					      struct radeon_ps *radeon_new_state)
 {
-	struct radeon_ps *radeon_new_state = rdev->pm.dpm.requested_ps;
 	struct rv7xx_ps *new_state = rv770_get_ps(radeon_new_state);
 	u32 mc_arb_burst_time = RREG32(MC_ARB_BURST_TIME);
 
@@ -1106,9 +1106,9 @@ static void cypress_wait_for_mc_sequencer(struct radeon_device *rdev, u8 value)
 	}
 }
 
-static void cypress_force_mc_use_s1(struct radeon_device *rdev)
+static void cypress_force_mc_use_s1(struct radeon_device *rdev,
+				    struct radeon_ps *radeon_boot_state)
 {
-	struct radeon_ps *radeon_boot_state = rdev->pm.dpm.boot_ps;
 	struct rv7xx_ps *boot_state = rv770_get_ps(radeon_boot_state);
 	u32 strobe_mode;
 	u32 mc_seq_cg;
@@ -1167,9 +1167,9 @@ static void cypress_copy_ac_timing_from_s1_to_s0(struct radeon_device *rdev)
 	}
 }
 
-static void cypress_force_mc_use_s0(struct radeon_device *rdev)
+static void cypress_force_mc_use_s0(struct radeon_device *rdev,
+				    struct radeon_ps *radeon_boot_state)
 {
-	struct radeon_ps *radeon_boot_state = rdev->pm.dpm.boot_ps;
 	struct rv7xx_ps *boot_state = rv770_get_ps(radeon_boot_state);
 	u32 strobe_mode;
 	u32 mc_seq_cg;
@@ -1601,10 +1601,10 @@ int cypress_get_mvdd_configuration(struct radeon_device *rdev)
 	return 0;
 }
 
-static int cypress_init_smc_table(struct radeon_device *rdev)
+static int cypress_init_smc_table(struct radeon_device *rdev,
+				  struct radeon_ps *radeon_boot_state)
 {
 	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
-	struct radeon_ps *radeon_boot_state = rdev->pm.dpm.boot_ps;
 	RV770_SMC_STATETABLE *table = &pi->smc_statetable;
 	int ret;
 
@@ -1653,11 +1653,11 @@ static int cypress_init_smc_table(struct radeon_device *rdev)
 				       pi->sram_end);
 }
 
-int cypress_populate_mc_reg_table(struct radeon_device *rdev)
+int cypress_populate_mc_reg_table(struct radeon_device *rdev,
+				  struct radeon_ps *radeon_boot_state)
 {
 	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
 	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
-	struct radeon_ps *radeon_boot_state = rdev->pm.dpm.boot_ps;
 	struct rv7xx_ps *boot_state = rv770_get_ps(radeon_boot_state);
 	SMC_Evergreen_MCRegisters mc_reg_table = { 0 };
 
@@ -1797,6 +1797,7 @@ int cypress_dpm_enable(struct radeon_device *rdev)
 {
 	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
 	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps;
 
 	if (pi->gfx_clock_gating)
 		rv770_restore_cgcg(rdev);
@@ -1814,9 +1815,9 @@ int cypress_dpm_enable(struct radeon_device *rdev)
 
 	if (eg_pi->dynamic_ac_timing) {
 		cypress_set_mc_reg_address_table(rdev);
-		cypress_force_mc_use_s0(rdev);
+		cypress_force_mc_use_s0(rdev, boot_ps);
 		cypress_initialize_mc_reg_table(rdev);
-		cypress_force_mc_use_s1(rdev);
+		cypress_force_mc_use_s1(rdev, boot_ps);
 	}
 
 	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS)
@@ -1845,11 +1846,11 @@ int cypress_dpm_enable(struct radeon_device *rdev)
 
 	cypress_get_table_locations(rdev);
 
-	if (cypress_init_smc_table(rdev))
+	if (cypress_init_smc_table(rdev, boot_ps))
 		return -EINVAL;
 
 	if (eg_pi->dynamic_ac_timing)
-		cypress_populate_mc_reg_table(rdev);
+		cypress_populate_mc_reg_table(rdev, boot_ps);
 
 	cypress_program_response_times(rdev);
 
@@ -1892,6 +1893,7 @@ void cypress_dpm_disable(struct radeon_device *rdev)
 {
 	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
 	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps;
 
 	if (!rv770_dpm_enabled(rdev))
 		return;
@@ -1922,7 +1924,7 @@ void cypress_dpm_disable(struct radeon_device *rdev)
 	cypress_enable_spread_spectrum(rdev, false);
 
 	if (eg_pi->dynamic_ac_timing)
-		cypress_force_mc_use_s1(rdev);
+		cypress_force_mc_use_s1(rdev, boot_ps);
 
 	rv770_reset_smio_status(rdev);
 }
@@ -1936,23 +1938,23 @@ int cypress_dpm_set_power_state(struct radeon_device *rdev)
 	rv770_restrict_performance_levels_before_switch(rdev);
 
 	if (eg_pi->pcie_performance_request)
-		cypress_notify_link_speed_change_before_state_change(rdev);
+		cypress_notify_link_speed_change_before_state_change(rdev, new_ps, old_ps);
 
 	rv770_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps);
 	rv770_halt_smc(rdev);
-	cypress_upload_sw_state(rdev);
+	cypress_upload_sw_state(rdev, new_ps);
 
 	if (eg_pi->dynamic_ac_timing)
-		cypress_upload_mc_reg_table(rdev);
+		cypress_upload_mc_reg_table(rdev, new_ps);
 
-	cypress_program_memory_timing_parameters(rdev);
+	cypress_program_memory_timing_parameters(rdev, new_ps);
 
 	rv770_resume_smc(rdev);
 	rv770_set_sw_state(rdev);
 	rv770_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps);
 
 	if (eg_pi->pcie_performance_request)
-		cypress_notify_link_speed_change_after_state_change(rdev);
+		cypress_notify_link_speed_change_after_state_change(rdev, new_ps, old_ps);
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/radeon/cypress_dpm.h b/drivers/gpu/drm/radeon/cypress_dpm.h
index 9b6198e..5b19364 100644
--- a/drivers/gpu/drm/radeon/cypress_dpm.h
+++ b/drivers/gpu/drm/radeon/cypress_dpm.h
@@ -120,18 +120,26 @@ int cypress_populate_smc_initial_state(struct radeon_device *rdev,
 				       RV770_SMC_STATETABLE *table);
 u32 cypress_calculate_burst_time(struct radeon_device *rdev,
 				 u32 engine_clock, u32 memory_clock);
-void cypress_notify_link_speed_change_before_state_change(struct radeon_device *rdev);
-int cypress_upload_sw_state(struct radeon_device *rdev);
-int cypress_upload_mc_reg_table(struct radeon_device *rdev);
-void cypress_program_memory_timing_parameters(struct radeon_device *rdev);
-void cypress_notify_link_speed_change_after_state_change(struct radeon_device *rdev);
+void cypress_notify_link_speed_change_before_state_change(struct radeon_device *rdev,
+							  struct radeon_ps *radeon_new_state,
+							  struct radeon_ps *radeon_current_state);
+int cypress_upload_sw_state(struct radeon_device *rdev,
+			    struct radeon_ps *radeon_new_state);
+int cypress_upload_mc_reg_table(struct radeon_device *rdev,
+				struct radeon_ps *radeon_new_state);
+void cypress_program_memory_timing_parameters(struct radeon_device *rdev,
+					      struct radeon_ps *radeon_new_state);
+void cypress_notify_link_speed_change_after_state_change(struct radeon_device *rdev,
+							 struct radeon_ps *radeon_new_state,
+							 struct radeon_ps *radeon_current_state);
 int cypress_construct_voltage_tables(struct radeon_device *rdev);
 int cypress_get_mvdd_configuration(struct radeon_device *rdev);
 void cypress_enable_spread_spectrum(struct radeon_device *rdev,
 				    bool enable);
 void cypress_enable_display_gap(struct radeon_device *rdev);
 int cypress_get_table_locations(struct radeon_device *rdev);
-int cypress_populate_mc_reg_table(struct radeon_device *rdev);
+int cypress_populate_mc_reg_table(struct radeon_device *rdev,
+				  struct radeon_ps *radeon_boot_state);
 void cypress_program_response_times(struct radeon_device *rdev);
 int cypress_notify_smc_display_change(struct radeon_device *rdev,
 				      bool has_display);
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 099/165] drm/radeon/dpm/btc: restructure code
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (98 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 098/165] drm/radeon/dpm/evergreen: " alexdeucher
@ 2013-06-26 13:22 ` alexdeucher
  2013-06-26 13:23 ` [PATCH 100/165] drm/radeon/dpm/cayman: " alexdeucher
                   ` (13 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Needed to properly handle dynamic state adjustment.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/btc_dpm.c |   30 +++++++++++++++---------------
 drivers/gpu/drm/radeon/btc_dpm.h |    3 ++-
 drivers/gpu/drm/radeon/ni_dpm.c  |    3 ++-
 3 files changed, 19 insertions(+), 17 deletions(-)

diff --git a/drivers/gpu/drm/radeon/btc_dpm.c b/drivers/gpu/drm/radeon/btc_dpm.c
index 73a0ba3..30aed00 100644
--- a/drivers/gpu/drm/radeon/btc_dpm.c
+++ b/drivers/gpu/drm/radeon/btc_dpm.c
@@ -1604,11 +1604,11 @@ bool btc_dpm_enabled(struct radeon_device *rdev)
 		return false;
 }
 
-static int btc_init_smc_table(struct radeon_device *rdev)
+static int btc_init_smc_table(struct radeon_device *rdev,
+			      struct radeon_ps *radeon_boot_state)
 {
 	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
 	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
-	struct radeon_ps *radeon_boot_state = rdev->pm.dpm.boot_ps;
 	RV770_SMC_STATETABLE *table = &pi->smc_statetable;
 	int ret;
 
@@ -1668,11 +1668,11 @@ static int btc_init_smc_table(struct radeon_device *rdev)
 				       pi->sram_end);
 }
 
-static void btc_set_at_for_uvd(struct radeon_device *rdev)
+static void btc_set_at_for_uvd(struct radeon_device *rdev,
+			       struct radeon_ps *radeon_new_state)
 {
 	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
 	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
-	struct radeon_ps *radeon_new_state = rdev->pm.dpm.requested_ps;
 	int idx = 0;
 
 	if (r600_is_uvd_state(radeon_new_state->class, radeon_new_state->class2))
@@ -1692,9 +1692,9 @@ static void btc_set_at_for_uvd(struct radeon_device *rdev)
 
 }
 
-void btc_notify_uvd_to_smc(struct radeon_device *rdev)
+void btc_notify_uvd_to_smc(struct radeon_device *rdev,
+			   struct radeon_ps *radeon_new_state)
 {
-	struct radeon_ps *radeon_new_state = rdev->pm.dpm.requested_ps;
 	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
 
 	if (r600_is_uvd_state(radeon_new_state->class, radeon_new_state->class2)) {
@@ -1814,11 +1814,11 @@ static int btc_enable_ulv(struct radeon_device *rdev)
 	return 0;
 }
 
-static int btc_set_power_state_conditionally_enable_ulv(struct radeon_device *rdev)
+static int btc_set_power_state_conditionally_enable_ulv(struct radeon_device *rdev,
+							struct radeon_ps *radeon_new_state)
 {
 	int ret = 0;
 	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
-	struct radeon_ps *radeon_new_state = rdev->pm.dpm.requested_ps;
 
 	if (eg_pi->ulv.supported) {
 		if (btc_is_state_ulv_compatible(rdev, radeon_new_state)) {
@@ -2059,10 +2059,10 @@ static void btc_init_stutter_mode(struct radeon_device *rdev)
 	}
 }
 
-static void btc_apply_state_adjust_rules(struct radeon_device *rdev)
+static void btc_apply_state_adjust_rules(struct radeon_device *rdev,
+					 struct radeon_ps *rps)
 {
 	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
-	struct radeon_ps *rps = rdev->pm.dpm.requested_ps;
 	struct rv7xx_ps *ps = rv770_get_ps(rps);
 	struct radeon_clock_and_voltage_limits *max_limits;
 	bool disable_mclk_switching;
@@ -2236,7 +2236,7 @@ int btc_dpm_set_power_state(struct radeon_device *rdev)
 	struct radeon_ps *new_ps = rdev->pm.dpm.requested_ps;
 	struct radeon_ps *old_ps = rdev->pm.dpm.current_ps;
 
-	btc_apply_state_adjust_rules(rdev);
+	btc_apply_state_adjust_rules(rdev, new_ps);
 
 	btc_disable_ulv(rdev);
 	btc_set_boot_state_timing(rdev);
@@ -2247,9 +2247,9 @@ int btc_dpm_set_power_state(struct radeon_device *rdev)
 
 	rv770_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps);
 	rv770_halt_smc(rdev);
-	btc_set_at_for_uvd(rdev);
+	btc_set_at_for_uvd(rdev, new_ps);
 	if (eg_pi->smu_uvd_hs)
-		btc_notify_uvd_to_smc(rdev);
+		btc_notify_uvd_to_smc(rdev, new_ps);
 	cypress_upload_sw_state(rdev, new_ps);
 
 	if (eg_pi->dynamic_ac_timing)
@@ -2264,7 +2264,7 @@ int btc_dpm_set_power_state(struct radeon_device *rdev)
 	if (eg_pi->pcie_performance_request)
 		cypress_notify_link_speed_change_after_state_change(rdev, new_ps, old_ps);
 
-	btc_set_power_state_conditionally_enable_ulv(rdev);
+	btc_set_power_state_conditionally_enable_ulv(rdev, new_ps);
 
 	return 0;
 }
@@ -2323,7 +2323,7 @@ int btc_dpm_enable(struct radeon_device *rdev)
 		return -EINVAL;
 
 	cypress_get_table_locations(rdev);
-	btc_init_smc_table(rdev);
+	btc_init_smc_table(rdev, boot_ps);
 
 	if (eg_pi->dynamic_ac_timing)
 		cypress_populate_mc_reg_table(rdev, boot_ps);
diff --git a/drivers/gpu/drm/radeon/btc_dpm.h b/drivers/gpu/drm/radeon/btc_dpm.h
index c22d39f..1a15e0e 100644
--- a/drivers/gpu/drm/radeon/btc_dpm.h
+++ b/drivers/gpu/drm/radeon/btc_dpm.h
@@ -51,6 +51,7 @@ void btc_apply_voltage_delta_rules(struct radeon_device *rdev,
 				   u16 *vddc, u16 *vddci);
 bool btc_dpm_enabled(struct radeon_device *rdev);
 int btc_reset_to_default(struct radeon_device *rdev);
-void btc_notify_uvd_to_smc(struct radeon_device *rdev);
+void btc_notify_uvd_to_smc(struct radeon_device *rdev,
+			   struct radeon_ps *radeon_new_state);
 
 #endif
diff --git a/drivers/gpu/drm/radeon/ni_dpm.c b/drivers/gpu/drm/radeon/ni_dpm.c
index 44016f2..9f68115 100644
--- a/drivers/gpu/drm/radeon/ni_dpm.c
+++ b/drivers/gpu/drm/radeon/ni_dpm.c
@@ -3628,6 +3628,7 @@ int ni_power_control_set_level(struct radeon_device *rdev)
 int ni_dpm_set_power_state(struct radeon_device *rdev)
 {
 	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	struct radeon_ps *new_ps = rdev->pm.dpm.requested_ps;
 	int ret;
 
 	ni_apply_state_adjust_rules(rdev);
@@ -3637,7 +3638,7 @@ int ni_dpm_set_power_state(struct radeon_device *rdev)
 	ni_enable_smc_cac(rdev, false);
 	rv770_halt_smc(rdev);
 	if (eg_pi->smu_uvd_hs)
-		btc_notify_uvd_to_smc(rdev);
+		btc_notify_uvd_to_smc(rdev, new_ps);
 	ni_upload_sw_state(rdev);
 	if (eg_pi->dynamic_ac_timing)
 		ni_upload_mc_reg_table(rdev);
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 100/165] drm/radeon/dpm/cayman: restructure code
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (99 preceding siblings ...)
  2013-06-26 13:22 ` [PATCH 099/165] drm/radeon/dpm/btc: " alexdeucher
@ 2013-06-26 13:23 ` alexdeucher
  2013-06-26 13:23 ` [PATCH 101/165] drm/radeon/dpm/sumo: " alexdeucher
                   ` (12 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:23 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Needed to properly handle dynamic state adjustment.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/ni_dpm.c |   69 ++++++++++++++++++++------------------
 1 files changed, 36 insertions(+), 33 deletions(-)

diff --git a/drivers/gpu/drm/radeon/ni_dpm.c b/drivers/gpu/drm/radeon/ni_dpm.c
index 9f68115..ebc9837 100644
--- a/drivers/gpu/drm/radeon/ni_dpm.c
+++ b/drivers/gpu/drm/radeon/ni_dpm.c
@@ -788,10 +788,10 @@ static void ni_calculate_leakage_for_v_and_t(struct radeon_device *rdev,
 	ni_calculate_leakage_for_v_and_t_formula(coeff, v, t, i_leakage, leakage);
 }
 
-static void ni_apply_state_adjust_rules(struct radeon_device *rdev)
+static void ni_apply_state_adjust_rules(struct radeon_device *rdev,
+					struct radeon_ps *rps)
 {
 	struct ni_power_info *ni_pi = ni_get_pi(rdev);
-	struct radeon_ps *rps = rdev->pm.dpm.requested_ps;
 	struct ni_ps *ps = ni_get_ps(rps);
 	struct radeon_clock_and_voltage_limits *max_limits;
 	bool disable_mclk_switching;
@@ -1434,13 +1434,13 @@ static int ni_calculate_adjusted_tdp_limits(struct radeon_device *rdev,
 	return 0;
 }
 
-static int ni_populate_smc_tdp_limits(struct radeon_device *rdev)
+static int ni_populate_smc_tdp_limits(struct radeon_device *rdev,
+				      struct radeon_ps *radeon_state)
 {
 	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
 	struct ni_power_info *ni_pi = ni_get_pi(rdev);
 
 	if (ni_pi->enable_power_containment) {
-		struct radeon_ps *radeon_state = rdev->pm.dpm.requested_ps;
 		NISLANDS_SMC_STATETABLE *smc_table = &ni_pi->smc_statetable;
 		u32 scaling_factor = ni_get_smc_power_scaling_factor(rdev);
 		u32 tdp_limit;
@@ -1647,10 +1647,9 @@ static int ni_do_program_memory_timing_parameters(struct radeon_device *rdev,
 	return ret;
 }
 
-static int ni_program_memory_timing_parameters(struct radeon_device *rdev)
+static int ni_program_memory_timing_parameters(struct radeon_device *rdev,
+					       struct radeon_ps *radeon_new_state)
 {
-	struct radeon_ps *radeon_new_state = rdev->pm.dpm.requested_ps;
-
 	return ni_do_program_memory_timing_parameters(rdev, radeon_new_state,
 						      NISLANDS_DRIVER_STATE_ARB_INDEX);
 }
@@ -2576,7 +2575,9 @@ static int ni_populate_sq_ramping_values(struct radeon_device *rdev,
 	return 0;
 }
 
-static int ni_enable_power_containment(struct radeon_device *rdev, bool enable)
+static int ni_enable_power_containment(struct radeon_device *rdev,
+				       struct radeon_ps *radeon_new_state,
+				       bool enable)
 {
         struct ni_power_info *ni_pi = ni_get_pi(rdev);
 	PPSMC_Result smc_result;
@@ -2584,8 +2585,6 @@ static int ni_enable_power_containment(struct radeon_device *rdev, bool enable)
 
 	if (ni_pi->enable_power_containment) {
 		if (enable) {
-			struct radeon_ps *radeon_new_state = rdev->pm.dpm.requested_ps;
-
 			if (!r600_is_uvd_state(radeon_new_state->class, radeon_new_state->class2)) {
 				smc_result = rv770_send_msg_to_smc(rdev, PPSMC_TDPClampingActive);
 				if (smc_result != PPSMC_Result_OK) {
@@ -2665,10 +2664,10 @@ static int ni_convert_power_state_to_smc(struct radeon_device *rdev,
 	return ni_populate_smc_t(rdev, radeon_state, smc_state);
 }
 
-static int ni_upload_sw_state(struct radeon_device *rdev)
+static int ni_upload_sw_state(struct radeon_device *rdev,
+			      struct radeon_ps *radeon_new_state)
 {
 	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
-	struct radeon_ps *radeon_new_state = rdev->pm.dpm.requested_ps;
 	u16 address = pi->state_table_start +
 		offsetof(NISLANDS_SMC_STATETABLE, driverState);
 	u16 state_size = sizeof(NISLANDS_SMC_SWSTATE) +
@@ -2974,12 +2973,12 @@ static void ni_convert_mc_reg_table_to_smc(struct radeon_device *rdev,
 	}
 }
 
-static int ni_populate_mc_reg_table(struct radeon_device *rdev)
+static int ni_populate_mc_reg_table(struct radeon_device *rdev,
+				    struct radeon_ps *radeon_boot_state)
 {
 	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
 	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
         struct ni_power_info *ni_pi = ni_get_pi(rdev);
-        struct radeon_ps *radeon_boot_state = rdev->pm.dpm.boot_ps;
 	struct ni_ps *boot_state = ni_get_ps(radeon_boot_state);
 	SMC_NIslands_MCRegisters *mc_reg_table = &ni_pi->smc_mc_reg_table;
 
@@ -3005,12 +3004,12 @@ static int ni_populate_mc_reg_table(struct radeon_device *rdev)
 				       pi->sram_end);
 }
 
-static int ni_upload_mc_reg_table(struct radeon_device *rdev)
+static int ni_upload_mc_reg_table(struct radeon_device *rdev,
+				  struct radeon_ps *radeon_new_state)
 {
 	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
 	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
         struct ni_power_info *ni_pi = ni_get_pi(rdev);
-	struct radeon_ps *radeon_new_state = rdev->pm.dpm.requested_ps;
 	struct ni_ps *ni_new_state = ni_get_ps(radeon_new_state);
 	SMC_NIslands_MCRegisters *mc_reg_table = &ni_pi->smc_mc_reg_table;
 	u16 address;
@@ -3359,7 +3358,9 @@ static int ni_initialize_hardware_cac_manager(struct radeon_device *rdev)
 	return 0;
 }
 
-static int ni_enable_smc_cac(struct radeon_device *rdev, bool enable)
+static int ni_enable_smc_cac(struct radeon_device *rdev,
+			     struct radeon_ps *radeon_new_state,
+			     bool enable)
 {
 	struct ni_power_info *ni_pi = ni_get_pi(rdev);
 	int ret = 0;
@@ -3367,8 +3368,6 @@ static int ni_enable_smc_cac(struct radeon_device *rdev, bool enable)
 
 	if (ni_pi->enable_cac) {
 		if (enable) {
-			struct radeon_ps *radeon_new_state = rdev->pm.dpm.requested_ps;
-
 			if (!r600_is_uvd_state(radeon_new_state->class, radeon_new_state->class2)) {
 				smc_result = rv770_send_msg_to_smc(rdev, PPSMC_MSG_CollectCAC_PowerCorreln);
 
@@ -3507,6 +3506,7 @@ int ni_dpm_enable(struct radeon_device *rdev)
 {
 	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
 	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps;
 
 	if (pi->gfx_clock_gating)
 		ni_cg_clockgating_default(rdev);
@@ -3543,10 +3543,10 @@ int ni_dpm_enable(struct radeon_device *rdev)
 	ni_init_smc_spll_table(rdev);
 	ni_init_arb_table_index(rdev);
 	if (eg_pi->dynamic_ac_timing)
-		ni_populate_mc_reg_table(rdev);
+		ni_populate_mc_reg_table(rdev, boot_ps);
 	ni_initialize_smc_cac_tables(rdev);
 	ni_initialize_hardware_cac_manager(rdev);
-	ni_populate_smc_tdp_limits(rdev);
+	ni_populate_smc_tdp_limits(rdev, boot_ps);
 	ni_program_response_times(rdev);
 	r7xx_start_smc(rdev);
 	cypress_notify_smc_display_change(rdev, false);
@@ -3583,14 +3583,15 @@ void ni_dpm_disable(struct radeon_device *rdev)
 {
 	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
 	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps;
 
 	if (!btc_dpm_enabled(rdev))
 		return;
 	rv770_clear_vc(rdev);
 	if (pi->thermal_protection)
 		rv770_enable_thermal_protection(rdev, false);
-	ni_enable_power_containment(rdev, false);
-	ni_enable_smc_cac(rdev, false);
+	ni_enable_power_containment(rdev, boot_ps, false);
+	ni_enable_smc_cac(rdev, boot_ps, false);
 	cypress_enable_spread_spectrum(rdev, false);
 	rv770_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, false);
 	if (pi->dynamic_pcie_gen2)
@@ -3616,9 +3617,11 @@ void ni_dpm_disable(struct radeon_device *rdev)
 
 int ni_power_control_set_level(struct radeon_device *rdev)
 {
+	struct radeon_ps *new_ps = rdev->pm.dpm.requested_ps;
+
 	ni_restrict_performance_levels_before_switch(rdev);
 	rv770_halt_smc(rdev);
-	ni_populate_smc_tdp_limits(rdev);
+	ni_populate_smc_tdp_limits(rdev, new_ps);
 	rv770_resume_smc(rdev);
 	rv770_set_sw_state(rdev);
 
@@ -3631,25 +3634,25 @@ int ni_dpm_set_power_state(struct radeon_device *rdev)
 	struct radeon_ps *new_ps = rdev->pm.dpm.requested_ps;
 	int ret;
 
-	ni_apply_state_adjust_rules(rdev);
+	ni_apply_state_adjust_rules(rdev, new_ps);
 
 	ni_restrict_performance_levels_before_switch(rdev);
-	ni_enable_power_containment(rdev, false);
-	ni_enable_smc_cac(rdev, false);
+	ni_enable_power_containment(rdev, new_ps, false);
+	ni_enable_smc_cac(rdev, new_ps, false);
 	rv770_halt_smc(rdev);
 	if (eg_pi->smu_uvd_hs)
 		btc_notify_uvd_to_smc(rdev, new_ps);
-	ni_upload_sw_state(rdev);
+	ni_upload_sw_state(rdev, new_ps);
 	if (eg_pi->dynamic_ac_timing)
-		ni_upload_mc_reg_table(rdev);
-	ret = ni_program_memory_timing_parameters(rdev);
+		ni_upload_mc_reg_table(rdev, new_ps);
+	ret = ni_program_memory_timing_parameters(rdev, new_ps);
 	if (ret)
 		return ret;
-	ni_populate_smc_tdp_limits(rdev);
+	ni_populate_smc_tdp_limits(rdev, new_ps);
 	rv770_resume_smc(rdev);
 	rv770_set_sw_state(rdev);
-	ni_enable_smc_cac(rdev, true);
-	ni_enable_power_containment(rdev, true);
+	ni_enable_smc_cac(rdev, new_ps, true);
+	ni_enable_power_containment(rdev, new_ps, true);
 
 	return 0;
 }
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 101/165] drm/radeon/dpm/sumo: restructure code
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (100 preceding siblings ...)
  2013-06-26 13:23 ` [PATCH 100/165] drm/radeon/dpm/cayman: " alexdeucher
@ 2013-06-26 13:23 ` alexdeucher
  2013-06-26 13:23 ` [PATCH 102/165] drm/radeon/dpm/tn: " alexdeucher
                   ` (11 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:23 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Needed to properly handle dynamic state adjustment.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/sumo_dpm.c |  143 +++++++++++++++++++++----------------
 1 files changed, 81 insertions(+), 62 deletions(-)

diff --git a/drivers/gpu/drm/radeon/sumo_dpm.c b/drivers/gpu/drm/radeon/sumo_dpm.c
index 3805302..f5de850 100644
--- a/drivers/gpu/drm/radeon/sumo_dpm.c
+++ b/drivers/gpu/drm/radeon/sumo_dpm.c
@@ -342,10 +342,11 @@ static void sumo_init_bsp(struct radeon_device *rdev)
 }
 
 
-static void sumo_program_bsp(struct radeon_device *rdev)
+static void sumo_program_bsp(struct radeon_device *rdev,
+			     struct radeon_ps *rps)
 {
 	struct sumo_power_info *pi = sumo_get_pi(rdev);
-	struct sumo_ps *ps = sumo_get_ps(rdev->pm.dpm.requested_ps);
+	struct sumo_ps *ps = sumo_get_ps(rps);
 	u32 i;
 	u32 highest_engine_clock = ps->levels[ps->num_levels - 1].sclk;
 
@@ -384,10 +385,11 @@ static void sumo_write_at(struct radeon_device *rdev,
 		WREG32(CG_AT_7, value);
 }
 
-static void sumo_program_at(struct radeon_device *rdev)
+static void sumo_program_at(struct radeon_device *rdev,
+			    struct radeon_ps *rps)
 {
 	struct sumo_power_info *pi = sumo_get_pi(rdev);
-	struct sumo_ps *ps = sumo_get_ps(rdev->pm.dpm.requested_ps);
+	struct sumo_ps *ps = sumo_get_ps(rps);
 	u32 asi;
 	u32 i;
 	u32 m_a;
@@ -662,10 +664,11 @@ static void sumo_enable_power_level_0(struct radeon_device *rdev)
 	sumo_power_level_enable(rdev, 0, true);
 }
 
-static void sumo_patch_boost_state(struct radeon_device *rdev)
+static void sumo_patch_boost_state(struct radeon_device *rdev,
+				   struct radeon_ps *rps)
 {
 	struct sumo_power_info *pi = sumo_get_pi(rdev);
-	struct sumo_ps *new_ps = sumo_get_ps(rdev->pm.dpm.requested_ps);
+	struct sumo_ps *new_ps = sumo_get_ps(rps);
 
 	if (new_ps->flags & SUMO_POWERSTATE_FLAGS_BOOST_STATE) {
 		pi->boost_pl = new_ps->levels[new_ps->num_levels - 1];
@@ -675,10 +678,12 @@ static void sumo_patch_boost_state(struct radeon_device *rdev)
 	}
 }
 
-static void sumo_pre_notify_alt_vddnb_change(struct radeon_device *rdev)
+static void sumo_pre_notify_alt_vddnb_change(struct radeon_device *rdev,
+					     struct radeon_ps *new_rps,
+					     struct radeon_ps *old_rps)
 {
-	struct sumo_ps *new_ps = sumo_get_ps(rdev->pm.dpm.requested_ps);
-	struct sumo_ps *old_ps = sumo_get_ps(rdev->pm.dpm.current_ps);
+	struct sumo_ps *new_ps = sumo_get_ps(new_rps);
+	struct sumo_ps *old_ps = sumo_get_ps(old_rps);
 	u32 nbps1_old = 0;
 	u32 nbps1_new = 0;
 
@@ -691,10 +696,12 @@ static void sumo_pre_notify_alt_vddnb_change(struct radeon_device *rdev)
 		sumo_smu_notify_alt_vddnb_change(rdev, 0, 0);
 }
 
-static void sumo_post_notify_alt_vddnb_change(struct radeon_device *rdev)
+static void sumo_post_notify_alt_vddnb_change(struct radeon_device *rdev,
+					      struct radeon_ps *new_rps,
+					      struct radeon_ps *old_rps)
 {
-	struct sumo_ps *new_ps = sumo_get_ps(rdev->pm.dpm.requested_ps);
-	struct sumo_ps *old_ps = sumo_get_ps(rdev->pm.dpm.current_ps);
+	struct sumo_ps *new_ps = sumo_get_ps(new_rps);
+	struct sumo_ps *old_ps = sumo_get_ps(old_rps);
 	u32 nbps1_old = 0;
 	u32 nbps1_new = 0;
 
@@ -707,9 +714,11 @@ static void sumo_post_notify_alt_vddnb_change(struct radeon_device *rdev)
 		sumo_smu_notify_alt_vddnb_change(rdev, 1, 1);
 }
 
-static void sumo_enable_boost(struct radeon_device *rdev, bool enable)
+static void sumo_enable_boost(struct radeon_device *rdev,
+			      struct radeon_ps *rps,
+			      bool enable)
 {
-	struct sumo_ps *new_ps = sumo_get_ps(rdev->pm.dpm.requested_ps);
+	struct sumo_ps *new_ps = sumo_get_ps(rps);
 
 	if (enable) {
 		if (new_ps->flags & SUMO_POWERSTATE_FLAGS_BOOST_STATE)
@@ -718,9 +727,10 @@ static void sumo_enable_boost(struct radeon_device *rdev, bool enable)
 		sumo_boost_state_enable(rdev, false);
 }
 
-static void sumo_update_current_power_levels(struct radeon_device *rdev)
+static void sumo_update_current_power_levels(struct radeon_device *rdev,
+					     struct radeon_ps *rps)
 {
-	struct sumo_ps *new_ps = sumo_get_ps(rdev->pm.dpm.requested_ps);
+	struct sumo_ps *new_ps = sumo_get_ps(rps);
 	struct sumo_power_info *pi = sumo_get_pi(rdev);
 
 	pi->current_ps = *new_ps;
@@ -736,9 +746,10 @@ static void sumo_set_forced_level_0(struct radeon_device *rdev)
 	sumo_set_forced_level(rdev, 0);
 }
 
-static void sumo_program_wl(struct radeon_device *rdev)
+static void sumo_program_wl(struct radeon_device *rdev,
+			    struct radeon_ps *rps)
 {
-	struct sumo_ps *new_ps = sumo_get_ps(rdev->pm.dpm.requested_ps);
+	struct sumo_ps *new_ps = sumo_get_ps(rps);
 	u32 dpm_ctrl4 = RREG32(CG_SCLK_DPM_CTRL_4);
 
 	dpm_ctrl4 &= 0xFFFFFF00;
@@ -750,11 +761,13 @@ static void sumo_program_wl(struct radeon_device *rdev)
 	WREG32(CG_SCLK_DPM_CTRL_4, dpm_ctrl4);
 }
 
-static void sumo_program_power_levels_0_to_n(struct radeon_device *rdev)
+static void sumo_program_power_levels_0_to_n(struct radeon_device *rdev,
+					     struct radeon_ps *new_rps,
+					     struct radeon_ps *old_rps)
 {
 	struct sumo_power_info *pi = sumo_get_pi(rdev);
-	struct sumo_ps *new_ps = sumo_get_ps(rdev->pm.dpm.requested_ps);
-	struct sumo_ps *old_ps = sumo_get_ps(rdev->pm.dpm.current_ps);
+	struct sumo_ps *new_ps = sumo_get_ps(new_rps);
+	struct sumo_ps *old_ps = sumo_get_ps(old_rps);
 	u32 i;
 	u32 n_current_state_levels = (old_ps == NULL) ? 1 : old_ps->num_levels;
 
@@ -811,38 +824,40 @@ static void sumo_program_bootup_state(struct radeon_device *rdev)
 		sumo_power_level_enable(rdev, i, false);
 }
 
-static void sumo_set_uvd_clock_before_set_eng_clock(struct radeon_device *rdev)
+static void sumo_set_uvd_clock_before_set_eng_clock(struct radeon_device *rdev,
+						    struct radeon_ps *new_rps,
+						    struct radeon_ps *old_rps)
 {
-	struct sumo_ps *new_ps = sumo_get_ps(rdev->pm.dpm.requested_ps);
-	struct sumo_ps *current_ps = sumo_get_ps(rdev->pm.dpm.current_ps);
+	struct sumo_ps *new_ps = sumo_get_ps(new_rps);
+	struct sumo_ps *current_ps = sumo_get_ps(old_rps);
 
-	if ((rdev->pm.dpm.requested_ps->vclk == rdev->pm.dpm.current_ps->vclk) &&
-	    (rdev->pm.dpm.requested_ps->dclk == rdev->pm.dpm.current_ps->dclk))
+	if ((new_rps->vclk == old_rps->vclk) &&
+	    (new_rps->dclk == old_rps->dclk))
 		return;
 
 	if (new_ps->levels[new_ps->num_levels - 1].sclk >=
 	    current_ps->levels[current_ps->num_levels - 1].sclk)
 		return;
 
-	radeon_set_uvd_clocks(rdev, rdev->pm.dpm.requested_ps->vclk,
-			      rdev->pm.dpm.requested_ps->dclk);
+	radeon_set_uvd_clocks(rdev, new_rps->vclk, new_rps->dclk);
 }
 
-static void sumo_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev)
+static void sumo_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev,
+						   struct radeon_ps *new_rps,
+						   struct radeon_ps *old_rps)
 {
-	struct sumo_ps *new_ps = sumo_get_ps(rdev->pm.dpm.requested_ps);
-	struct sumo_ps *current_ps = sumo_get_ps(rdev->pm.dpm.current_ps);
+	struct sumo_ps *new_ps = sumo_get_ps(new_rps);
+	struct sumo_ps *current_ps = sumo_get_ps(old_rps);
 
-	if ((rdev->pm.dpm.requested_ps->vclk == rdev->pm.dpm.current_ps->vclk) &&
-	    (rdev->pm.dpm.requested_ps->dclk == rdev->pm.dpm.current_ps->dclk))
+	if ((new_rps->vclk == old_rps->vclk) &&
+	    (new_rps->dclk == old_rps->dclk))
 		return;
 
 	if (new_ps->levels[new_ps->num_levels - 1].sclk <
 	    current_ps->levels[current_ps->num_levels - 1].sclk)
 		return;
 
-	radeon_set_uvd_clocks(rdev, rdev->pm.dpm.requested_ps->vclk,
-			      rdev->pm.dpm.requested_ps->dclk);
+	radeon_set_uvd_clocks(rdev, new_rps->vclk, new_rps->dclk);
 }
 
 void sumo_take_smu_control(struct radeon_device *rdev, bool enable)
@@ -960,10 +975,11 @@ static void sumo_program_dc_hto(struct radeon_device *rdev)
 	WREG32(CG_SCLK_DPM_CTRL_4, cg_sclk_dpm_ctrl_4);
 }
 
-static void sumo_force_nbp_state(struct radeon_device *rdev)
+static void sumo_force_nbp_state(struct radeon_device *rdev,
+				 struct radeon_ps *rps)
 {
 	struct sumo_power_info *pi = sumo_get_pi(rdev);
-	struct sumo_ps *new_ps = sumo_get_ps(rdev->pm.dpm.requested_ps);
+	struct sumo_ps *new_ps = sumo_get_ps(rps);
 
 	if (!pi->driver_nbps_policy_disable) {
 		if (new_ps->flags & SUMO_POWERSTATE_FLAGS_FORCE_NBPS1_STATE)
@@ -1061,11 +1077,12 @@ static void sumo_patch_thermal_state(struct radeon_device *rdev,
 		ps->levels[0].ss_divider_index = 0;
 }
 
-static void sumo_apply_state_adjust_rules(struct radeon_device *rdev)
+static void sumo_apply_state_adjust_rules(struct radeon_device *rdev,
+					  struct radeon_ps *new_rps,
+					  struct radeon_ps *old_rps)
 {
-	struct radeon_ps *rps = rdev->pm.dpm.requested_ps;
-	struct sumo_ps *ps = sumo_get_ps(rps);
-	struct sumo_ps *current_ps = sumo_get_ps(rdev->pm.dpm.current_ps);
+	struct sumo_ps *ps = sumo_get_ps(new_rps);
+	struct sumo_ps *current_ps = sumo_get_ps(old_rps);
 	struct sumo_power_info *pi = sumo_get_pi(rdev);
 	u32 min_voltage = 0; /* ??? */
 	u32 min_sclk = pi->sys_info.min_sclk; /* XXX check against disp reqs */
@@ -1077,17 +1094,17 @@ static void sumo_apply_state_adjust_rules(struct radeon_device *rdev)
 	rdev->pm.dpm.hw_ps.ps_priv = &pi->hw_ps;
 	ps = &pi->hw_ps;
 
-	if (rps->class & ATOM_PPLIB_CLASSIFICATION_THERMAL)
+	if (new_rps->class & ATOM_PPLIB_CLASSIFICATION_THERMAL)
 		return sumo_patch_thermal_state(rdev, ps, current_ps);
 
 	if (pi->enable_boost) {
-		if (rps->class & ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE)
+		if (new_rps->class & ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE)
 			ps->flags |= SUMO_POWERSTATE_FLAGS_BOOST_STATE;
 	}
 
-	if ((rps->class & ATOM_PPLIB_CLASSIFICATION_UI_BATTERY) ||
-	    (rps->class & ATOM_PPLIB_CLASSIFICATION_SDSTATE) ||
-	    (rps->class & ATOM_PPLIB_CLASSIFICATION_HDSTATE))
+	if ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_UI_BATTERY) ||
+	    (new_rps->class & ATOM_PPLIB_CLASSIFICATION_SDSTATE) ||
+	    (new_rps->class & ATOM_PPLIB_CLASSIFICATION_HDSTATE))
 		ps->flags |= SUMO_POWERSTATE_FLAGS_FORCE_NBPS1_STATE;
 
 	for (i = 0; i < ps->num_levels; i++) {
@@ -1120,8 +1137,8 @@ static void sumo_apply_state_adjust_rules(struct radeon_device *rdev)
 
 		if (ps->flags & SUMO_POWERSTATE_FLAGS_FORCE_NBPS1_STATE)
 			ps->levels[i].allow_gnb_slow = 1;
-		else if ((rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE) ||
-			 (rps->class2 & ATOM_PPLIB_CLASSIFICATION2_MVC))
+		else if ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE) ||
+			 (new_rps->class2 & ATOM_PPLIB_CLASSIFICATION2_MVC))
 			ps->levels[i].allow_gnb_slow = 0;
 		else if (i == ps->num_levels - 1)
 			ps->levels[i].allow_gnb_slow = 0;
@@ -1240,36 +1257,38 @@ void sumo_dpm_disable(struct radeon_device *rdev)
 int sumo_dpm_set_power_state(struct radeon_device *rdev)
 {
 	struct sumo_power_info *pi = sumo_get_pi(rdev);
+	struct radeon_ps *new_ps = rdev->pm.dpm.requested_ps;
+	struct radeon_ps *old_ps = rdev->pm.dpm.current_ps;
 
 	if (pi->enable_dynamic_patch_ps)
-		sumo_apply_state_adjust_rules(rdev);
+		sumo_apply_state_adjust_rules(rdev, new_ps, old_ps);
 	if (pi->enable_dpm)
-		sumo_set_uvd_clock_before_set_eng_clock(rdev);
-	sumo_update_current_power_levels(rdev);
+		sumo_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps);
+	sumo_update_current_power_levels(rdev, new_ps);
 	if (pi->enable_boost) {
-		sumo_enable_boost(rdev, false);
-		sumo_patch_boost_state(rdev);
+		sumo_enable_boost(rdev, new_ps, false);
+		sumo_patch_boost_state(rdev, new_ps);
 	}
 	if (pi->enable_dpm) {
-		sumo_pre_notify_alt_vddnb_change(rdev);
+		sumo_pre_notify_alt_vddnb_change(rdev, new_ps, old_ps);
 		sumo_enable_power_level_0(rdev);
 		sumo_set_forced_level_0(rdev);
 		sumo_set_forced_mode_enabled(rdev);
 		sumo_wait_for_level_0(rdev);
-		sumo_program_power_levels_0_to_n(rdev);
-		sumo_program_wl(rdev);
-		sumo_program_bsp(rdev);
-		sumo_program_at(rdev);
-		sumo_force_nbp_state(rdev);
+		sumo_program_power_levels_0_to_n(rdev, new_ps, old_ps);
+		sumo_program_wl(rdev, new_ps);
+		sumo_program_bsp(rdev, new_ps);
+		sumo_program_at(rdev, new_ps);
+		sumo_force_nbp_state(rdev, new_ps);
 		sumo_set_forced_mode_disabled(rdev);
 		sumo_set_forced_mode_enabled(rdev);
 		sumo_set_forced_mode_disabled(rdev);
-		sumo_post_notify_alt_vddnb_change(rdev);
+		sumo_post_notify_alt_vddnb_change(rdev, new_ps, old_ps);
 	}
 	if (pi->enable_boost)
-		sumo_enable_boost(rdev, true);
+		sumo_enable_boost(rdev, new_ps, true);
 	if (pi->enable_dpm)
-		sumo_set_uvd_clock_after_set_eng_clock(rdev);
+		sumo_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps);
 
 	return 0;
 }
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 102/165] drm/radeon/dpm/tn: restructure code
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (101 preceding siblings ...)
  2013-06-26 13:23 ` [PATCH 101/165] drm/radeon/dpm/sumo: " alexdeucher
@ 2013-06-26 13:23 ` alexdeucher
  2013-06-26 13:23 ` [PATCH 103/165] drm/radeon/dpm: add new pre/post_set_power_state callbacks alexdeucher
                   ` (10 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:23 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Needed to properly handle dynamic state adjustment.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/trinity_dpm.c |   93 +++++++++++++++++++---------------
 1 files changed, 52 insertions(+), 41 deletions(-)

diff --git a/drivers/gpu/drm/radeon/trinity_dpm.c b/drivers/gpu/drm/radeon/trinity_dpm.c
index 0c1b50a..103efbc 100644
--- a/drivers/gpu/drm/radeon/trinity_dpm.c
+++ b/drivers/gpu/drm/radeon/trinity_dpm.c
@@ -337,7 +337,9 @@ static const u32 trinity_override_mgpg_sequences[] =
 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);
-static void trinity_apply_state_adjust_rules(struct radeon_device *rdev);
+static void trinity_apply_state_adjust_rules(struct radeon_device *rdev,
+					     struct radeon_ps *new_rps,
+					     struct radeon_ps *old_rps);
 
 struct trinity_ps *trinity_get_ps(struct radeon_ps *rps)
 {
@@ -830,18 +832,21 @@ static void trinity_unforce_levels(struct radeon_device *rdev)
 	trinity_dpm_no_forced_level(rdev);
 }
 
-static void trinity_update_current_power_levels(struct radeon_device *rdev)
+static void trinity_update_current_power_levels(struct radeon_device *rdev,
+						struct radeon_ps *rps)
 {
-	struct trinity_ps *new_ps = trinity_get_ps(rdev->pm.dpm.requested_ps);
+	struct trinity_ps *new_ps = trinity_get_ps(rps);
 	struct trinity_power_info *pi = trinity_get_pi(rdev);
 
 	pi->current_ps = *new_ps;
 }
 
-static void trinity_program_power_levels_0_to_n(struct radeon_device *rdev)
+static void trinity_program_power_levels_0_to_n(struct radeon_device *rdev,
+						struct radeon_ps *new_rps,
+						struct radeon_ps *old_rps)
 {
-	struct trinity_ps *new_ps = trinity_get_ps(rdev->pm.dpm.requested_ps);
-	struct trinity_ps *old_ps = trinity_get_ps(rdev->pm.dpm.current_ps);
+	struct trinity_ps *new_ps = trinity_get_ps(new_rps);
+	struct trinity_ps *old_ps = trinity_get_ps(old_rps);
 	u32 i;
 	u32 n_current_state_levels = (old_ps == NULL) ? 1 : old_ps->num_levels;
 
@@ -919,19 +924,19 @@ static bool trinity_uvd_clocks_equal(struct radeon_ps *rps1,
 }
 
 static void trinity_setup_uvd_clocks(struct radeon_device *rdev,
-				     struct radeon_ps *current_rps,
-				     struct radeon_ps *new_rps)
+				     struct radeon_ps *new_rps,
+				     struct radeon_ps *old_rps)
 {
 	struct trinity_power_info *pi = trinity_get_pi(rdev);
 
 	if (pi->uvd_dpm) {
 		if (trinity_uvd_clocks_zero(new_rps) &&
-		    !trinity_uvd_clocks_zero(current_rps)) {
+		    !trinity_uvd_clocks_zero(old_rps)) {
 			trinity_setup_uvd_dpm_interval(rdev, 0);
 		} else if (!trinity_uvd_clocks_zero(new_rps)) {
 			trinity_setup_uvd_clock_table(rdev, new_rps);
 
-			if (trinity_uvd_clocks_zero(current_rps)) {
+			if (trinity_uvd_clocks_zero(old_rps)) {
 				u32 tmp = RREG32(CG_MISC_REG);
 				tmp &= 0xfffffffd;
 				WREG32(CG_MISC_REG, tmp);
@@ -944,37 +949,39 @@ static void trinity_setup_uvd_clocks(struct radeon_device *rdev,
 		trinity_uvd_dpm_config(rdev);
 	} else {
 		if (trinity_uvd_clocks_zero(new_rps) ||
-		    trinity_uvd_clocks_equal(new_rps, current_rps))
+		    trinity_uvd_clocks_equal(new_rps, old_rps))
 			return;
 
 		radeon_set_uvd_clocks(rdev, new_rps->vclk, new_rps->dclk);
 	}
 }
 
-static void trinity_set_uvd_clock_before_set_eng_clock(struct radeon_device *rdev)
+static void trinity_set_uvd_clock_before_set_eng_clock(struct radeon_device *rdev,
+						       struct radeon_ps *new_rps,
+						       struct radeon_ps *old_rps)
 {
-	struct trinity_ps *new_ps = trinity_get_ps(rdev->pm.dpm.requested_ps);
-	struct trinity_ps *current_ps = trinity_get_ps(rdev->pm.dpm.current_ps);
+	struct trinity_ps *new_ps = trinity_get_ps(new_rps);
+	struct trinity_ps *current_ps = trinity_get_ps(new_rps);
 
 	if (new_ps->levels[new_ps->num_levels - 1].sclk >=
 	    current_ps->levels[current_ps->num_levels - 1].sclk)
 		return;
 
-	trinity_setup_uvd_clocks(rdev, rdev->pm.dpm.current_ps,
-				 rdev->pm.dpm.requested_ps);
+	trinity_setup_uvd_clocks(rdev, new_rps, old_rps);
 }
 
-static void trinity_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev)
+static void trinity_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev,
+						      struct radeon_ps *new_rps,
+						      struct radeon_ps *old_rps)
 {
-	struct trinity_ps *new_ps = trinity_get_ps(rdev->pm.dpm.requested_ps);
-	struct trinity_ps *current_ps = trinity_get_ps(rdev->pm.dpm.current_ps);
+	struct trinity_ps *new_ps = trinity_get_ps(new_rps);
+	struct trinity_ps *current_ps = trinity_get_ps(old_rps);
 
 	if (new_ps->levels[new_ps->num_levels - 1].sclk <
 	    current_ps->levels[current_ps->num_levels - 1].sclk)
 		return;
 
-	trinity_setup_uvd_clocks(rdev, rdev->pm.dpm.current_ps,
-				 rdev->pm.dpm.requested_ps);
+	trinity_setup_uvd_clocks(rdev, new_rps, old_rps);
 }
 
 static void trinity_program_ttt(struct radeon_device *rdev)
@@ -1102,10 +1109,11 @@ static void trinity_get_min_sclk_divider(struct radeon_device *rdev)
 		(RREG32_SMC(CC_SMU_MISC_FUSES) & MinSClkDid_MASK) >> MinSClkDid_SHIFT;
 }
 
-static void trinity_setup_nbp_sim(struct radeon_device *rdev)
+static void trinity_setup_nbp_sim(struct radeon_device *rdev,
+				  struct radeon_ps *rps)
 {
 	struct trinity_power_info *pi = trinity_get_pi(rdev);
-	struct trinity_ps *new_ps = trinity_get_ps(rdev->pm.dpm.requested_ps);
+	struct trinity_ps *new_ps = trinity_get_ps(rps);
 	u32 nbpsconfig;
 
 	if (pi->sys_info.nb_dpm_enable) {
@@ -1122,21 +1130,23 @@ static void trinity_setup_nbp_sim(struct radeon_device *rdev)
 int trinity_dpm_set_power_state(struct radeon_device *rdev)
 {
 	struct trinity_power_info *pi = trinity_get_pi(rdev);
+	struct radeon_ps *new_ps = rdev->pm.dpm.requested_ps;
+	struct radeon_ps *old_ps = rdev->pm.dpm.current_ps;
 
-	trinity_apply_state_adjust_rules(rdev);
-	trinity_update_current_power_levels(rdev);
+	trinity_apply_state_adjust_rules(rdev, new_ps, old_ps);
+	trinity_update_current_power_levels(rdev, new_ps);
 
 	trinity_acquire_mutex(rdev);
 	if (pi->enable_dpm) {
-		trinity_set_uvd_clock_before_set_eng_clock(rdev);
+		trinity_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps);
 		trinity_enable_power_level_0(rdev);
 		trinity_force_level_0(rdev);
 		trinity_wait_for_level_0(rdev);
-		trinity_setup_nbp_sim(rdev);
-		trinity_program_power_levels_0_to_n(rdev);
+		trinity_setup_nbp_sim(rdev, new_ps);
+		trinity_program_power_levels_0_to_n(rdev, new_ps, old_ps);
 		trinity_force_level_0(rdev);
 		trinity_unforce_levels(rdev);
-		trinity_set_uvd_clock_after_set_eng_clock(rdev);
+		trinity_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps);
 	}
 	trinity_release_mutex(rdev);
 
@@ -1366,11 +1376,12 @@ static void trinity_adjust_uvd_state(struct radeon_device *rdev,
 
 
 
-static void trinity_apply_state_adjust_rules(struct radeon_device *rdev)
+static void trinity_apply_state_adjust_rules(struct radeon_device *rdev,
+					     struct radeon_ps *new_rps,
+					     struct radeon_ps *old_rps)
 {
-	struct radeon_ps *rps = rdev->pm.dpm.requested_ps;
-	struct trinity_ps *ps = trinity_get_ps(rps);
-	struct trinity_ps *current_ps = trinity_get_ps(rdev->pm.dpm.current_ps);
+	struct trinity_ps *ps = trinity_get_ps(new_rps);
+	struct trinity_ps *current_ps = trinity_get_ps(old_rps);
 	struct trinity_power_info *pi = trinity_get_pi(rdev);
 	u32 min_voltage = 0; /* ??? */
 	u32 min_sclk = pi->sys_info.min_sclk; /* XXX check against disp reqs */
@@ -1384,10 +1395,10 @@ static void trinity_apply_state_adjust_rules(struct radeon_device *rdev)
 	rdev->pm.dpm.hw_ps.ps_priv = &pi->hw_ps;
 	ps = &pi->hw_ps;
 
-	if (rps->class & ATOM_PPLIB_CLASSIFICATION_THERMAL)
+	if (new_rps->class & ATOM_PPLIB_CLASSIFICATION_THERMAL)
 		return trinity_patch_thermal_state(rdev, ps, current_ps);
 
-	trinity_adjust_uvd_state(rdev, rps);
+	trinity_adjust_uvd_state(rdev, new_rps);
 
 	for (i = 0; i < ps->num_levels; i++) {
 		if (ps->levels[i].vddc_index < min_voltage)
@@ -1410,8 +1421,8 @@ static void trinity_apply_state_adjust_rules(struct radeon_device *rdev)
 			trinity_calculate_vce_wm(rdev, ps->levels[0].sclk);
 	}
 
-	if ((rps->class & (ATOM_PPLIB_CLASSIFICATION_HDSTATE | ATOM_PPLIB_CLASSIFICATION_SDSTATE)) ||
-	    ((rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) == ATOM_PPLIB_CLASSIFICATION_UI_BATTERY))
+	if ((new_rps->class & (ATOM_PPLIB_CLASSIFICATION_HDSTATE | ATOM_PPLIB_CLASSIFICATION_SDSTATE)) ||
+	    ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) == ATOM_PPLIB_CLASSIFICATION_UI_BATTERY))
 		ps->bapm_flags |= TRINITY_POWERSTATE_FLAGS_BAPM_DISABLE;
 
 	if (pi->sys_info.nb_dpm_enable) {
@@ -1420,10 +1431,10 @@ static void trinity_apply_state_adjust_rules(struct radeon_device *rdev)
 		ps->DpmXNbPsLo = 0x2;
 		ps->DpmXNbPsHi = 0x1;
 
-		if ((rps->class & (ATOM_PPLIB_CLASSIFICATION_HDSTATE | ATOM_PPLIB_CLASSIFICATION_SDSTATE)) ||
-		    ((rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) == ATOM_PPLIB_CLASSIFICATION_UI_BATTERY)) {
-			force_high = ((rps->class & ATOM_PPLIB_CLASSIFICATION_HDSTATE) ||
-				      ((rps->class & ATOM_PPLIB_CLASSIFICATION_SDSTATE) &&
+		if ((new_rps->class & (ATOM_PPLIB_CLASSIFICATION_HDSTATE | ATOM_PPLIB_CLASSIFICATION_SDSTATE)) ||
+		    ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) == ATOM_PPLIB_CLASSIFICATION_UI_BATTERY)) {
+			force_high = ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_HDSTATE) ||
+				      ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_SDSTATE) &&
 				       (pi->sys_info.uma_channel_number == 1)));
 			force_high = (num_active_displays >= 3) || force_high;
 			ps->Dpm0PgNbPsLo = force_high ? 0x2 : 0x3;
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 103/165] drm/radeon/dpm: add new pre/post_set_power_state callbacks
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (102 preceding siblings ...)
  2013-06-26 13:23 ` [PATCH 102/165] drm/radeon/dpm/tn: " alexdeucher
@ 2013-06-26 13:23 ` alexdeucher
  2013-06-26 13:23 ` [PATCH 104/165] drm/radeon/dpm: add pre/post_set_power_state callbacks (6xx-eg) alexdeucher
                   ` (9 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:23 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Needed to properly handle dynamic state adjustment.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/radeon.h    |    4 ++++
 drivers/gpu/drm/radeon/radeon_pm.c |   11 +++++++++++
 2 files changed, 15 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 16c7d52..657d224 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -1616,7 +1616,9 @@ struct radeon_asic {
 		void (*setup_asic)(struct radeon_device *rdev);
 		int (*enable)(struct radeon_device *rdev);
 		void (*disable)(struct radeon_device *rdev);
+		int (*pre_set_power_state)(struct radeon_device *rdev);
 		int (*set_power_state)(struct radeon_device *rdev);
+		void (*post_set_power_state)(struct radeon_device *rdev);
 		void (*display_configuration_changed)(struct radeon_device *rdev);
 		void (*fini)(struct radeon_device *rdev);
 		u32 (*get_sclk)(struct radeon_device *rdev, bool low);
@@ -2326,7 +2328,9 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v);
 #define radeon_dpm_setup_asic(rdev) rdev->asic->dpm.setup_asic((rdev))
 #define radeon_dpm_enable(rdev) rdev->asic->dpm.enable((rdev))
 #define radeon_dpm_disable(rdev) rdev->asic->dpm.disable((rdev))
+#define radeon_dpm_pre_set_power_state(rdev) rdev->asic->dpm.pre_set_power_state((rdev))
 #define radeon_dpm_set_power_state(rdev) rdev->asic->dpm.set_power_state((rdev))
+#define radeon_dpm_post_set_power_state(rdev) rdev->asic->dpm.post_set_power_state((rdev))
 #define radeon_dpm_display_configuration_changed(rdev) rdev->asic->dpm.display_configuration_changed((rdev))
 #define radeon_dpm_fini(rdev) rdev->asic->dpm.fini((rdev))
 #define radeon_dpm_get_sclk(rdev, l) rdev->asic->dpm.get_sclk((rdev), (l))
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
index 01ff18b..a50efb0 100644
--- a/drivers/gpu/drm/radeon/radeon_pm.c
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
@@ -703,6 +703,7 @@ static void radeon_dpm_change_power_state_locked(struct radeon_device *rdev)
 	int i;
 	struct radeon_ps *ps;
 	enum radeon_pm_state_type dpm_state;
+	int ret;
 
 	/* if dpm init failed */
 	if (!rdev->pm.dpm_enabled)
@@ -769,6 +770,12 @@ static void radeon_dpm_change_power_state_locked(struct radeon_device *rdev)
 	down_write(&rdev->pm.mclk_lock);
 	mutex_lock(&rdev->ring_lock);
 
+	if (rdev->asic->dpm.pre_set_power_state) {
+		ret = radeon_dpm_pre_set_power_state(rdev);
+		if (ret)
+			goto done;
+	}
+
 	/* update display watermarks based on new power state */
 	radeon_bandwidth_update(rdev);
 	/* update displays */
@@ -790,6 +797,10 @@ static void radeon_dpm_change_power_state_locked(struct radeon_device *rdev)
 	/* update current power state */
 	rdev->pm.dpm.current_ps = rdev->pm.dpm.requested_ps;
 
+	if (rdev->asic->dpm.post_set_power_state)
+		radeon_dpm_post_set_power_state(rdev);
+
+done:
 	mutex_unlock(&rdev->ring_lock);
 	up_write(&rdev->pm.mclk_lock);
 	mutex_unlock(&rdev->ddev->struct_mutex);
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 104/165] drm/radeon/dpm: add pre/post_set_power_state callbacks (6xx-eg)
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (103 preceding siblings ...)
  2013-06-26 13:23 ` [PATCH 103/165] drm/radeon/dpm: add new pre/post_set_power_state callbacks alexdeucher
@ 2013-06-26 13:23 ` alexdeucher
  2013-06-26 13:23 ` [PATCH 105/165] drm/radeon/dpm: add pre/post_set_power_state callback (sumo) alexdeucher
                   ` (8 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:23 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

For r6xx-evergreen, they are no-ops as they don't support
any dynamic state adjustment.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/r600_dpm.c    |   10 ++++++++++
 drivers/gpu/drm/radeon/radeon_asic.c |    8 ++++++++
 drivers/gpu/drm/radeon/radeon_asic.h |    2 ++
 3 files changed, 20 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/radeon/r600_dpm.c b/drivers/gpu/drm/radeon/r600_dpm.c
index c9f9647..bcb1967 100644
--- a/drivers/gpu/drm/radeon/r600_dpm.c
+++ b/drivers/gpu/drm/radeon/r600_dpm.c
@@ -662,6 +662,16 @@ void r600_stop_dpm(struct radeon_device *rdev)
 	r600_dynamicpm_enable(rdev, false);
 }
 
+int r600_dpm_pre_set_power_state(struct radeon_device *rdev)
+{
+	return 0;
+}
+
+void r600_dpm_post_set_power_state(struct radeon_device *rdev)
+{
+
+}
+
 bool r600_is_uvd_state(u32 class, u32 class2)
 {
 	if (class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c
index e6703ef..5014bd1 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.c
+++ b/drivers/gpu/drm/radeon/radeon_asic.c
@@ -1110,7 +1110,9 @@ static struct radeon_asic rv6xx_asic = {
 		.setup_asic = &rv6xx_setup_asic,
 		.enable = &rv6xx_dpm_enable,
 		.disable = &rv6xx_dpm_disable,
+		.pre_set_power_state = &r600_dpm_pre_set_power_state,
 		.set_power_state = &rv6xx_dpm_set_power_state,
+		.post_set_power_state = &r600_dpm_post_set_power_state,
 		.display_configuration_changed = &rv6xx_dpm_display_configuration_changed,
 		.fini = &rv6xx_dpm_fini,
 		.get_sclk = &rv6xx_dpm_get_sclk,
@@ -1211,7 +1213,9 @@ static struct radeon_asic rs780_asic = {
 		.setup_asic = &rs780_dpm_setup_asic,
 		.enable = &rs780_dpm_enable,
 		.disable = &rs780_dpm_disable,
+		.pre_set_power_state = &r600_dpm_pre_set_power_state,
 		.set_power_state = &rs780_dpm_set_power_state,
+		.post_set_power_state = &r600_dpm_post_set_power_state,
 		.display_configuration_changed = &rs780_dpm_display_configuration_changed,
 		.fini = &rs780_dpm_fini,
 		.get_sclk = &rs780_dpm_get_sclk,
@@ -1322,7 +1326,9 @@ static struct radeon_asic rv770_asic = {
 		.setup_asic = &rv770_dpm_setup_asic,
 		.enable = &rv770_dpm_enable,
 		.disable = &rv770_dpm_disable,
+		.pre_set_power_state = &r600_dpm_pre_set_power_state,
 		.set_power_state = &rv770_dpm_set_power_state,
+		.post_set_power_state = &r600_dpm_post_set_power_state,
 		.display_configuration_changed = &rv770_dpm_display_configuration_changed,
 		.fini = &rv770_dpm_fini,
 		.get_sclk = &rv770_dpm_get_sclk,
@@ -1433,7 +1439,9 @@ static struct radeon_asic evergreen_asic = {
 		.setup_asic = &cypress_dpm_setup_asic,
 		.enable = &cypress_dpm_enable,
 		.disable = &cypress_dpm_disable,
+		.pre_set_power_state = &r600_dpm_pre_set_power_state,
 		.set_power_state = &cypress_dpm_set_power_state,
+		.post_set_power_state = &r600_dpm_post_set_power_state,
 		.display_configuration_changed = &cypress_dpm_display_configuration_changed,
 		.fini = &cypress_dpm_fini,
 		.get_sclk = &rv770_dpm_get_sclk,
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index 2fef64d..d7d4662 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -396,6 +396,8 @@ int r600_mc_wait_for_idle(struct radeon_device *rdev);
 u32 r600_get_xclk(struct radeon_device *rdev);
 uint64_t r600_get_gpu_clock_counter(struct radeon_device *rdev);
 int rv6xx_get_temp(struct radeon_device *rdev);
+int r600_dpm_pre_set_power_state(struct radeon_device *rdev);
+void r600_dpm_post_set_power_state(struct radeon_device *rdev);
 /* rv6xx dpm */
 int rv6xx_dpm_init(struct radeon_device *rdev);
 int rv6xx_dpm_enable(struct radeon_device *rdev);
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 105/165] drm/radeon/dpm: add pre/post_set_power_state callback (sumo)
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (104 preceding siblings ...)
  2013-06-26 13:23 ` [PATCH 104/165] drm/radeon/dpm: add pre/post_set_power_state callbacks (6xx-eg) alexdeucher
@ 2013-06-26 13:23 ` alexdeucher
  2013-06-26 13:23 ` [PATCH 106/165] drm/radeon/dpm: add pre/post_set_power_state callback (TN) alexdeucher
                   ` (7 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:23 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

This properly implemented dynamic state adjustment by
using a working copy of the requested and current
power states.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/radeon_asic.c |    2 +
 drivers/gpu/drm/radeon/radeon_asic.h |    2 +
 drivers/gpu/drm/radeon/sumo_dpm.c    |   74 ++++++++++++++++++++++++---------
 drivers/gpu/drm/radeon/sumo_dpm.h    |    6 ++-
 4 files changed, 62 insertions(+), 22 deletions(-)

diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c
index 5014bd1..c5d70da 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.c
+++ b/drivers/gpu/drm/radeon/radeon_asic.c
@@ -1552,7 +1552,9 @@ static struct radeon_asic sumo_asic = {
 		.setup_asic = &sumo_dpm_setup_asic,
 		.enable = &sumo_dpm_enable,
 		.disable = &sumo_dpm_disable,
+		.pre_set_power_state = &sumo_dpm_pre_set_power_state,
 		.set_power_state = &sumo_dpm_set_power_state,
+		.post_set_power_state = &sumo_dpm_post_set_power_state,
 		.display_configuration_changed = &sumo_dpm_display_configuration_changed,
 		.fini = &sumo_dpm_fini,
 		.get_sclk = &sumo_dpm_get_sclk,
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index d7d4662..817fc26 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -541,7 +541,9 @@ void btc_dpm_fini(struct radeon_device *rdev);
 int sumo_dpm_init(struct radeon_device *rdev);
 int sumo_dpm_enable(struct radeon_device *rdev);
 void sumo_dpm_disable(struct radeon_device *rdev);
+int sumo_dpm_pre_set_power_state(struct radeon_device *rdev);
 int sumo_dpm_set_power_state(struct radeon_device *rdev);
+void sumo_dpm_post_set_power_state(struct radeon_device *rdev);
 void sumo_dpm_setup_asic(struct radeon_device *rdev);
 void sumo_dpm_display_configuration_changed(struct radeon_device *rdev);
 void sumo_dpm_fini(struct radeon_device *rdev);
diff --git a/drivers/gpu/drm/radeon/sumo_dpm.c b/drivers/gpu/drm/radeon/sumo_dpm.c
index f5de850..10700e1 100644
--- a/drivers/gpu/drm/radeon/sumo_dpm.c
+++ b/drivers/gpu/drm/radeon/sumo_dpm.c
@@ -727,15 +727,6 @@ static void sumo_enable_boost(struct radeon_device *rdev,
 		sumo_boost_state_enable(rdev, false);
 }
 
-static void sumo_update_current_power_levels(struct radeon_device *rdev,
-					     struct radeon_ps *rps)
-{
-	struct sumo_ps *new_ps = sumo_get_ps(rps);
-	struct sumo_power_info *pi = sumo_get_pi(rdev);
-
-	pi->current_ps = *new_ps;
-}
-
 static void sumo_set_forced_level(struct radeon_device *rdev, u32 index)
 {
 	WREG32_P(CG_SCLK_DPM_CTRL_3, FORCE_SCLK_STATE(index), ~FORCE_SCLK_STATE_MASK);
@@ -1089,11 +1080,6 @@ static void sumo_apply_state_adjust_rules(struct radeon_device *rdev,
 	u32 sclk_in_sr = pi->sys_info.min_sclk; /* ??? */
 	u32 i;
 
-	/* point to the hw copy since this function will modify the ps */
-	pi->hw_ps = *ps;
-	rdev->pm.dpm.hw_ps.ps_priv = &pi->hw_ps;
-	ps = &pi->hw_ps;
-
 	if (new_rps->class & ATOM_PPLIB_CLASSIFICATION_THERMAL)
 		return sumo_patch_thermal_state(rdev, ps, current_ps);
 
@@ -1192,6 +1178,28 @@ static int sumo_set_thermal_temperature_range(struct radeon_device *rdev,
 	return 0;
 }
 
+static void sumo_update_current_ps(struct radeon_device *rdev,
+				   struct radeon_ps *rps)
+{
+	struct sumo_ps *new_ps = sumo_get_ps(rps);
+	struct sumo_power_info *pi = sumo_get_pi(rdev);
+
+	pi->current_rps = *rps;
+	pi->current_ps = *new_ps;
+	pi->current_rps.ps_priv = &pi->current_ps;
+}
+
+static void sumo_update_requested_ps(struct radeon_device *rdev,
+				     struct radeon_ps *rps)
+{
+	struct sumo_ps *new_ps = sumo_get_ps(rps);
+	struct sumo_power_info *pi = sumo_get_pi(rdev);
+
+	pi->requested_rps = *rps;
+	pi->requested_ps = *new_ps;
+	pi->requested_rps.ps_priv = &pi->requested_ps;
+}
+
 int sumo_dpm_enable(struct radeon_device *rdev)
 {
 	struct sumo_power_info *pi = sumo_get_pi(rdev);
@@ -1230,6 +1238,8 @@ int sumo_dpm_enable(struct radeon_device *rdev)
 		radeon_irq_set(rdev);
 	}
 
+	sumo_update_current_ps(rdev, rdev->pm.dpm.boot_ps);
+
 	return 0;
 }
 
@@ -1252,19 +1262,34 @@ void sumo_dpm_disable(struct radeon_device *rdev)
 		rdev->irq.dpm_thermal = false;
 		radeon_irq_set(rdev);
 	}
+
+	sumo_update_current_ps(rdev, rdev->pm.dpm.boot_ps);
 }
 
-int sumo_dpm_set_power_state(struct radeon_device *rdev)
+int sumo_dpm_pre_set_power_state(struct radeon_device *rdev)
 {
 	struct sumo_power_info *pi = sumo_get_pi(rdev);
-	struct radeon_ps *new_ps = rdev->pm.dpm.requested_ps;
-	struct radeon_ps *old_ps = rdev->pm.dpm.current_ps;
+	struct radeon_ps requested_ps = *rdev->pm.dpm.requested_ps;
+	struct radeon_ps *new_ps = &requested_ps;
+
+	sumo_update_requested_ps(rdev, new_ps);
 
 	if (pi->enable_dynamic_patch_ps)
-		sumo_apply_state_adjust_rules(rdev, new_ps, old_ps);
+		sumo_apply_state_adjust_rules(rdev,
+					      &pi->requested_rps,
+					      &pi->current_rps);
+
+	return 0;
+}
+
+int sumo_dpm_set_power_state(struct radeon_device *rdev)
+{
+	struct sumo_power_info *pi = sumo_get_pi(rdev);
+	struct radeon_ps *new_ps = &pi->requested_rps;
+	struct radeon_ps *old_ps = &pi->current_rps;
+
 	if (pi->enable_dpm)
 		sumo_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps);
-	sumo_update_current_power_levels(rdev, new_ps);
 	if (pi->enable_boost) {
 		sumo_enable_boost(rdev, new_ps, false);
 		sumo_patch_boost_state(rdev, new_ps);
@@ -1293,6 +1318,14 @@ int sumo_dpm_set_power_state(struct radeon_device *rdev)
 	return 0;
 }
 
+void sumo_dpm_post_set_power_state(struct radeon_device *rdev)
+{
+	struct sumo_power_info *pi = sumo_get_pi(rdev);
+	struct radeon_ps *new_ps = &pi->requested_rps;
+
+	sumo_update_current_ps(rdev, new_ps);
+}
+
 void sumo_dpm_reset_asic(struct radeon_device *rdev)
 {
 	sumo_program_bootup_state(rdev);
@@ -1751,7 +1784,8 @@ void sumo_dpm_fini(struct radeon_device *rdev)
 
 u32 sumo_dpm_get_sclk(struct radeon_device *rdev, bool low)
 {
-	struct sumo_ps *requested_state = sumo_get_ps(rdev->pm.dpm.requested_ps);
+	struct sumo_power_info *pi = sumo_get_pi(rdev);
+	struct sumo_ps *requested_state = sumo_get_ps(&pi->requested_rps);
 
 	if (low)
 		return requested_state->levels[0].sclk;
diff --git a/drivers/gpu/drm/radeon/sumo_dpm.h b/drivers/gpu/drm/radeon/sumo_dpm.h
index a40b62a..a3a7a61 100644
--- a/drivers/gpu/drm/radeon/sumo_dpm.h
+++ b/drivers/gpu/drm/radeon/sumo_dpm.h
@@ -116,7 +116,6 @@ struct sumo_power_info {
 	struct sumo_pl acpi_pl;
 	struct sumo_pl boot_pl;
 	struct sumo_pl boost_pl;
-	struct sumo_ps current_ps;
 	bool disable_gfx_power_gating_in_uvd;
 	bool driver_nbps_policy_disable;
 	bool enable_alt_vddnb;
@@ -129,7 +128,10 @@ struct sumo_power_info {
 	bool enable_dynamic_patch_ps;
 	bool enable_dpm;
 	bool enable_boost;
-	struct sumo_ps hw_ps;
+	struct radeon_ps current_rps;
+	struct sumo_ps current_ps;
+	struct radeon_ps requested_rps;
+	struct sumo_ps requested_ps;
 };
 
 #define SUMO_UTC_DFLT_00                     0x48
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 106/165] drm/radeon/dpm: add pre/post_set_power_state callback (TN)
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (105 preceding siblings ...)
  2013-06-26 13:23 ` [PATCH 105/165] drm/radeon/dpm: add pre/post_set_power_state callback (sumo) alexdeucher
@ 2013-06-26 13:23 ` alexdeucher
  2013-06-26 13:23 ` [PATCH 107/165] drm/radeon/dpm: add pre/post_set_power_state callback (BTC) alexdeucher
                   ` (6 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:23 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

This properly implemented dynamic state adjustment by
using a working copy of the requested and current
power states.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/radeon_asic.c |    2 +
 drivers/gpu/drm/radeon/radeon_asic.h |    2 +
 drivers/gpu/drm/radeon/trinity_dpm.c |   73 ++++++++++++++++++++++++---------
 drivers/gpu/drm/radeon/trinity_dpm.h |    6 ++-
 4 files changed, 61 insertions(+), 22 deletions(-)

diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c
index c5d70da..c78519c 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.c
+++ b/drivers/gpu/drm/radeon/radeon_asic.c
@@ -1971,7 +1971,9 @@ static struct radeon_asic trinity_asic = {
 		.setup_asic = &trinity_dpm_setup_asic,
 		.enable = &trinity_dpm_enable,
 		.disable = &trinity_dpm_disable,
+		.pre_set_power_state = &trinity_dpm_pre_set_power_state,
 		.set_power_state = &trinity_dpm_set_power_state,
+		.post_set_power_state = &trinity_dpm_post_set_power_state,
 		.display_configuration_changed = &trinity_dpm_display_configuration_changed,
 		.fini = &trinity_dpm_fini,
 		.get_sclk = &trinity_dpm_get_sclk,
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index 817fc26..14d992d 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -598,7 +598,9 @@ void ni_dpm_print_power_state(struct radeon_device *rdev,
 int trinity_dpm_init(struct radeon_device *rdev);
 int trinity_dpm_enable(struct radeon_device *rdev);
 void trinity_dpm_disable(struct radeon_device *rdev);
+int trinity_dpm_pre_set_power_state(struct radeon_device *rdev);
 int trinity_dpm_set_power_state(struct radeon_device *rdev);
+void trinity_dpm_post_set_power_state(struct radeon_device *rdev);
 void trinity_dpm_setup_asic(struct radeon_device *rdev);
 void trinity_dpm_display_configuration_changed(struct radeon_device *rdev);
 void trinity_dpm_fini(struct radeon_device *rdev);
diff --git a/drivers/gpu/drm/radeon/trinity_dpm.c b/drivers/gpu/drm/radeon/trinity_dpm.c
index 103efbc..1699e93 100644
--- a/drivers/gpu/drm/radeon/trinity_dpm.c
+++ b/drivers/gpu/drm/radeon/trinity_dpm.c
@@ -832,15 +832,6 @@ static void trinity_unforce_levels(struct radeon_device *rdev)
 	trinity_dpm_no_forced_level(rdev);
 }
 
-static void trinity_update_current_power_levels(struct radeon_device *rdev,
-						struct radeon_ps *rps)
-{
-	struct trinity_ps *new_ps = trinity_get_ps(rps);
-	struct trinity_power_info *pi = trinity_get_pi(rdev);
-
-	pi->current_ps = *new_ps;
-}
-
 static void trinity_program_power_levels_0_to_n(struct radeon_device *rdev,
 						struct radeon_ps *new_rps,
 						struct radeon_ps *old_rps)
@@ -1046,6 +1037,28 @@ static int trinity_set_thermal_temperature_range(struct radeon_device *rdev,
 	return 0;
 }
 
+static void trinity_update_current_ps(struct radeon_device *rdev,
+				      struct radeon_ps *rps)
+{
+	struct trinity_ps *new_ps = trinity_get_ps(rps);
+	struct trinity_power_info *pi = trinity_get_pi(rdev);
+
+	pi->current_rps = *rps;
+	pi->current_ps = *new_ps;
+	pi->current_rps.ps_priv = &pi->current_ps;
+}
+
+static void trinity_update_requested_ps(struct radeon_device *rdev,
+					struct radeon_ps *rps)
+{
+	struct trinity_ps *new_ps = trinity_get_ps(rps);
+	struct trinity_power_info *pi = trinity_get_pi(rdev);
+
+	pi->requested_rps = *rps;
+	pi->requested_ps = *new_ps;
+	pi->requested_rps.ps_priv = &pi->requested_ps;
+}
+
 int trinity_dpm_enable(struct radeon_device *rdev)
 {
 	struct trinity_power_info *pi = trinity_get_pi(rdev);
@@ -1077,6 +1090,8 @@ int trinity_dpm_enable(struct radeon_device *rdev)
 		radeon_irq_set(rdev);
 	}
 
+	trinity_update_current_ps(rdev, rdev->pm.dpm.boot_ps);
+
 	return 0;
 }
 
@@ -1099,6 +1114,8 @@ void trinity_dpm_disable(struct radeon_device *rdev)
 		rdev->irq.dpm_thermal = false;
 		radeon_irq_set(rdev);
 	}
+
+	trinity_update_current_ps(rdev, rdev->pm.dpm.boot_ps);
 }
 
 static void trinity_get_min_sclk_divider(struct radeon_device *rdev)
@@ -1127,14 +1144,26 @@ static void trinity_setup_nbp_sim(struct radeon_device *rdev,
 	}
 }
 
-int trinity_dpm_set_power_state(struct radeon_device *rdev)
+int trinity_dpm_pre_set_power_state(struct radeon_device *rdev)
 {
 	struct trinity_power_info *pi = trinity_get_pi(rdev);
-	struct radeon_ps *new_ps = rdev->pm.dpm.requested_ps;
-	struct radeon_ps *old_ps = rdev->pm.dpm.current_ps;
+	struct radeon_ps requested_ps = *rdev->pm.dpm.requested_ps;
+	struct radeon_ps *new_ps = &requested_ps;
+
+	trinity_update_requested_ps(rdev, new_ps);
 
-	trinity_apply_state_adjust_rules(rdev, new_ps, old_ps);
-	trinity_update_current_power_levels(rdev, new_ps);
+	trinity_apply_state_adjust_rules(rdev,
+					 &pi->requested_rps,
+					 &pi->current_rps);
+
+	return 0;
+}
+
+int trinity_dpm_set_power_state(struct radeon_device *rdev)
+{
+	struct trinity_power_info *pi = trinity_get_pi(rdev);
+	struct radeon_ps *new_ps = &pi->requested_rps;
+	struct radeon_ps *old_ps = &pi->current_rps;
 
 	trinity_acquire_mutex(rdev);
 	if (pi->enable_dpm) {
@@ -1153,6 +1182,14 @@ int trinity_dpm_set_power_state(struct radeon_device *rdev)
 	return 0;
 }
 
+void trinity_dpm_post_set_power_state(struct radeon_device *rdev)
+{
+	struct trinity_power_info *pi = trinity_get_pi(rdev);
+	struct radeon_ps *new_ps = &pi->requested_rps;
+
+	trinity_update_current_ps(rdev, new_ps);
+}
+
 void trinity_dpm_setup_asic(struct radeon_device *rdev)
 {
 	trinity_acquire_mutex(rdev);
@@ -1390,11 +1427,6 @@ static void trinity_apply_state_adjust_rules(struct radeon_device *rdev,
 	bool force_high;
 	u32 num_active_displays = rdev->pm.dpm.new_active_crtc_count;
 
-	/* point to the hw copy since this function will modify the ps */
-	pi->hw_ps = *ps;
-	rdev->pm.dpm.hw_ps.ps_priv = &pi->hw_ps;
-	ps = &pi->hw_ps;
-
 	if (new_rps->class & ATOM_PPLIB_CLASSIFICATION_THERMAL)
 		return trinity_patch_thermal_state(rdev, ps, current_ps);
 
@@ -1833,7 +1865,8 @@ void trinity_dpm_fini(struct radeon_device *rdev)
 
 u32 trinity_dpm_get_sclk(struct radeon_device *rdev, bool low)
 {
-	struct trinity_ps *requested_state = trinity_get_ps(rdev->pm.dpm.requested_ps);
+	struct trinity_power_info *pi = trinity_get_pi(rdev);
+	struct trinity_ps *requested_state = trinity_get_ps(&pi->requested_rps);
 
 	if (low)
 		return requested_state->levels[0].sclk;
diff --git a/drivers/gpu/drm/radeon/trinity_dpm.h b/drivers/gpu/drm/radeon/trinity_dpm.h
index c663aed..c621b84 100644
--- a/drivers/gpu/drm/radeon/trinity_dpm.h
+++ b/drivers/gpu/drm/radeon/trinity_dpm.h
@@ -97,7 +97,6 @@ struct trinity_power_info {
 	u32 thermal_auto_throttling;
 	struct trinity_sys_info sys_info;
 	struct trinity_pl boot_pl;
-	struct trinity_ps current_ps;
 	u32 min_sclk_did;
 	bool enable_nbps_policy;
 	bool voltage_drop_in_dce;
@@ -110,7 +109,10 @@ struct trinity_power_info {
 	bool enable_dpm;
 	bool enable_sclk_ds;
 	bool uvd_dpm;
-	struct trinity_ps hw_ps;
+	struct radeon_ps current_rps;
+	struct trinity_ps current_ps;
+	struct radeon_ps requested_rps;
+	struct trinity_ps requested_ps;
 };
 
 #define TRINITY_AT_DFLT            30
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 107/165] drm/radeon/dpm: add pre/post_set_power_state callback (BTC)
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (106 preceding siblings ...)
  2013-06-26 13:23 ` [PATCH 106/165] drm/radeon/dpm: add pre/post_set_power_state callback (TN) alexdeucher
@ 2013-06-26 13:23 ` alexdeucher
  2013-06-26 13:23 ` [PATCH 108/165] drm/radeon/dpm: add pre/post_set_power_state callback (cayman) alexdeucher
                   ` (5 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:23 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

This properly implemented dynamic state adjustment by
using a working copy of the requested and current
power states.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/btc_dpm.c     |   81 +++++++++++++++++++++++++++++----
 drivers/gpu/drm/radeon/cypress_dpm.h |    5 ++-
 drivers/gpu/drm/radeon/radeon_asic.c |    6 ++-
 drivers/gpu/drm/radeon/radeon_asic.h |    4 ++
 4 files changed, 83 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/radeon/btc_dpm.c b/drivers/gpu/drm/radeon/btc_dpm.c
index 30aed00..7c7d58f 100644
--- a/drivers/gpu/drm/radeon/btc_dpm.c
+++ b/drivers/gpu/drm/radeon/btc_dpm.c
@@ -2062,18 +2062,12 @@ static void btc_init_stutter_mode(struct radeon_device *rdev)
 static void btc_apply_state_adjust_rules(struct radeon_device *rdev,
 					 struct radeon_ps *rps)
 {
-	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
 	struct rv7xx_ps *ps = rv770_get_ps(rps);
 	struct radeon_clock_and_voltage_limits *max_limits;
 	bool disable_mclk_switching;
 	u32 mclk, sclk;
 	u16 vddc, vddci;
 
-	/* point to the hw copy since this function will modify the ps */
-	eg_pi->hw_ps = *ps;
-	rdev->pm.dpm.hw_ps.ps_priv = &eg_pi->hw_ps;
-	ps = &eg_pi->hw_ps;
-
 	if (rdev->pm.dpm.new_active_crtc_count > 1)
 		disable_mclk_switching = true;
 	else
@@ -2222,6 +2216,28 @@ static void btc_apply_state_adjust_rules(struct radeon_device *rdev,
 		ps->high.flags &= ~ATOM_PPLIB_R600_FLAGS_PCIEGEN2;
 }
 
+static void btc_update_current_ps(struct radeon_device *rdev,
+				  struct radeon_ps *rps)
+{
+	struct rv7xx_ps *new_ps = rv770_get_ps(rps);
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+
+	eg_pi->current_rps = *rps;
+	eg_pi->current_ps = *new_ps;
+	eg_pi->current_rps.ps_priv = &eg_pi->current_ps;
+}
+
+static void btc_update_requested_ps(struct radeon_device *rdev,
+				    struct radeon_ps *rps)
+{
+	struct rv7xx_ps *new_ps = rv770_get_ps(rps);
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+
+	eg_pi->requested_rps = *rps;
+	eg_pi->requested_ps = *new_ps;
+	eg_pi->requested_rps.ps_priv = &eg_pi->requested_ps;
+}
+
 void btc_dpm_reset_asic(struct radeon_device *rdev)
 {
 	rv770_restrict_performance_levels_before_switch(rdev);
@@ -2230,13 +2246,24 @@ void btc_dpm_reset_asic(struct radeon_device *rdev)
 	rv770_set_boot_state(rdev);
 }
 
-int btc_dpm_set_power_state(struct radeon_device *rdev)
+int btc_dpm_pre_set_power_state(struct radeon_device *rdev)
 {
 	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
-	struct radeon_ps *new_ps = rdev->pm.dpm.requested_ps;
-	struct radeon_ps *old_ps = rdev->pm.dpm.current_ps;
+	struct radeon_ps requested_ps = *rdev->pm.dpm.requested_ps;
+	struct radeon_ps *new_ps = &requested_ps;
+
+	btc_update_requested_ps(rdev, new_ps);
+
+	btc_apply_state_adjust_rules(rdev, &eg_pi->requested_rps);
 
-	btc_apply_state_adjust_rules(rdev, new_ps);
+	return 0;
+}
+
+int btc_dpm_set_power_state(struct radeon_device *rdev)
+{
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	struct radeon_ps *new_ps = &eg_pi->requested_rps;
+	struct radeon_ps *old_ps = &eg_pi->current_rps;
 
 	btc_disable_ulv(rdev);
 	btc_set_boot_state_timing(rdev);
@@ -2269,6 +2296,14 @@ int btc_dpm_set_power_state(struct radeon_device *rdev)
 	return 0;
 }
 
+void btc_dpm_post_set_power_state(struct radeon_device *rdev)
+{
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	struct radeon_ps *new_ps = &eg_pi->requested_rps;
+
+	btc_update_current_ps(rdev, new_ps);
+}
+
 int btc_dpm_enable(struct radeon_device *rdev)
 {
 	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
@@ -2364,6 +2399,8 @@ int btc_dpm_enable(struct radeon_device *rdev)
 
 	btc_init_stutter_mode(rdev);
 
+	btc_update_current_ps(rdev, rdev->pm.dpm.boot_ps);
+
 	return 0;
 };
 
@@ -2402,6 +2439,8 @@ void btc_dpm_disable(struct radeon_device *rdev)
 	btc_reset_to_default(rdev);
 	btc_stop_smc(rdev);
 	cypress_enable_spread_spectrum(rdev, false);
+
+	btc_update_current_ps(rdev, rdev->pm.dpm.boot_ps);
 }
 
 void btc_dpm_setup_asic(struct radeon_device *rdev)
@@ -2586,3 +2625,25 @@ void btc_dpm_fini(struct radeon_device *rdev)
 	kfree(rdev->pm.dpm.priv);
 	r600_free_extended_power_table(rdev);
 }
+
+u32 btc_dpm_get_sclk(struct radeon_device *rdev, bool low)
+{
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	struct rv7xx_ps *requested_state = rv770_get_ps(&eg_pi->requested_rps);
+
+	if (low)
+		return requested_state->low.sclk;
+	else
+		return requested_state->high.sclk;
+}
+
+u32 btc_dpm_get_mclk(struct radeon_device *rdev, bool low)
+{
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	struct rv7xx_ps *requested_state = rv770_get_ps(&eg_pi->requested_rps);
+
+	if (low)
+		return requested_state->low.mclk;
+	else
+		return requested_state->high.mclk;
+}
diff --git a/drivers/gpu/drm/radeon/cypress_dpm.h b/drivers/gpu/drm/radeon/cypress_dpm.h
index 5b19364..4c3f18c 100644
--- a/drivers/gpu/drm/radeon/cypress_dpm.h
+++ b/drivers/gpu/drm/radeon/cypress_dpm.h
@@ -88,7 +88,10 @@ struct evergreen_power_info {
 	struct at ats[2];
 	/* smc offsets */
 	u16 mc_reg_table_start;
-	struct rv7xx_ps hw_ps;
+	struct radeon_ps current_rps;
+	struct rv7xx_ps current_ps;
+	struct radeon_ps requested_rps;
+	struct rv7xx_ps requested_ps;
 };
 
 #define CYPRESS_HASI_DFLT                               400000
diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c
index c78519c..25eeaa4 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.c
+++ b/drivers/gpu/drm/radeon/radeon_asic.c
@@ -1665,11 +1665,13 @@ static struct radeon_asic btc_asic = {
 		.setup_asic = &btc_dpm_setup_asic,
 		.enable = &btc_dpm_enable,
 		.disable = &btc_dpm_disable,
+		.pre_set_power_state = &btc_dpm_pre_set_power_state,
 		.set_power_state = &btc_dpm_set_power_state,
+		.post_set_power_state = &btc_dpm_post_set_power_state,
 		.display_configuration_changed = &cypress_dpm_display_configuration_changed,
 		.fini = &btc_dpm_fini,
-		.get_sclk = &rv770_dpm_get_sclk,
-		.get_mclk = &rv770_dpm_get_mclk,
+		.get_sclk = &btc_dpm_get_sclk,
+		.get_mclk = &btc_dpm_get_mclk,
 		.print_power_state = &rv770_dpm_print_power_state,
 	},
 	.pflip = {
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index 14d992d..696d6e9 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -536,8 +536,12 @@ int btc_dpm_init(struct radeon_device *rdev);
 void btc_dpm_setup_asic(struct radeon_device *rdev);
 int btc_dpm_enable(struct radeon_device *rdev);
 void btc_dpm_disable(struct radeon_device *rdev);
+int btc_dpm_pre_set_power_state(struct radeon_device *rdev);
 int btc_dpm_set_power_state(struct radeon_device *rdev);
+void btc_dpm_post_set_power_state(struct radeon_device *rdev);
 void btc_dpm_fini(struct radeon_device *rdev);
+u32 btc_dpm_get_sclk(struct radeon_device *rdev, bool low);
+u32 btc_dpm_get_mclk(struct radeon_device *rdev, bool low);
 int sumo_dpm_init(struct radeon_device *rdev);
 int sumo_dpm_enable(struct radeon_device *rdev);
 void sumo_dpm_disable(struct radeon_device *rdev);
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 108/165] drm/radeon/dpm: add pre/post_set_power_state callback (cayman)
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (107 preceding siblings ...)
  2013-06-26 13:23 ` [PATCH 107/165] drm/radeon/dpm: add pre/post_set_power_state callback (BTC) alexdeucher
@ 2013-06-26 13:23 ` alexdeucher
  2013-06-26 13:23 ` [PATCH 109/165] drm/radeon/dpm: remove broken dyn state remnants alexdeucher
                   ` (4 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:23 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

This properly implemented dynamic state adjustment by
using a working copy of the requested and current
power states.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/ni_dpm.c      |   65 ++++++++++++++++++++++++++++------
 drivers/gpu/drm/radeon/ni_dpm.h      |    3 +-
 drivers/gpu/drm/radeon/radeon_asic.c |    2 +
 drivers/gpu/drm/radeon/radeon_asic.h |    2 +
 4 files changed, 60 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/radeon/ni_dpm.c b/drivers/gpu/drm/radeon/ni_dpm.c
index ebc9837..01ecb80 100644
--- a/drivers/gpu/drm/radeon/ni_dpm.c
+++ b/drivers/gpu/drm/radeon/ni_dpm.c
@@ -791,7 +791,6 @@ static void ni_calculate_leakage_for_v_and_t(struct radeon_device *rdev,
 static void ni_apply_state_adjust_rules(struct radeon_device *rdev,
 					struct radeon_ps *rps)
 {
-	struct ni_power_info *ni_pi = ni_get_pi(rdev);
 	struct ni_ps *ps = ni_get_ps(rps);
 	struct radeon_clock_and_voltage_limits *max_limits;
 	bool disable_mclk_switching;
@@ -799,11 +798,6 @@ static void ni_apply_state_adjust_rules(struct radeon_device *rdev,
 	u16 vddc, vddci;
 	int i;
 
-	/* point to the hw copy since this function will modify the ps */
-	ni_pi->hw_ps = *ps;
-	rdev->pm.dpm.hw_ps.ps_priv = &ni_pi->hw_ps;
-	ps = &ni_pi->hw_ps;
-
 	if (rdev->pm.dpm.new_active_crtc_count > 1)
 		disable_mclk_switching = true;
 	else
@@ -3502,6 +3496,30 @@ void ni_dpm_setup_asic(struct radeon_device *rdev)
 	rv770_enable_acpi_pm(rdev);
 }
 
+static void ni_update_current_ps(struct radeon_device *rdev,
+				 struct radeon_ps *rps)
+{
+	struct ni_ps *new_ps = ni_get_ps(rps);
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+        struct ni_power_info *ni_pi = ni_get_pi(rdev);
+
+	eg_pi->current_rps = *rps;
+	ni_pi->current_ps = *new_ps;
+	eg_pi->current_rps.ps_priv = &ni_pi->current_ps;
+}
+
+static void ni_update_requested_ps(struct radeon_device *rdev,
+				   struct radeon_ps *rps)
+{
+	struct ni_ps *new_ps = ni_get_ps(rps);
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+        struct ni_power_info *ni_pi = ni_get_pi(rdev);
+
+	eg_pi->requested_rps = *rps;
+	ni_pi->requested_ps = *new_ps;
+	eg_pi->requested_rps.ps_priv = &ni_pi->requested_ps;
+}
+
 int ni_dpm_enable(struct radeon_device *rdev)
 {
 	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
@@ -3576,6 +3594,8 @@ int ni_dpm_enable(struct radeon_device *rdev)
 
 	rv770_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true);
 
+	ni_update_current_ps(rdev, boot_ps);
+
 	return 0;
 }
 
@@ -3613,6 +3633,8 @@ void ni_dpm_disable(struct radeon_device *rdev)
 	btc_reset_to_default(rdev);
 	ni_stop_smc(rdev);
 	ni_force_switch_to_arb_f0(rdev);
+
+	ni_update_current_ps(rdev, boot_ps);
 }
 
 int ni_power_control_set_level(struct radeon_device *rdev)
@@ -3628,14 +3650,25 @@ int ni_power_control_set_level(struct radeon_device *rdev)
 	return 0;
 }
 
+int ni_dpm_pre_set_power_state(struct radeon_device *rdev)
+{
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	struct radeon_ps requested_ps = *rdev->pm.dpm.requested_ps;
+	struct radeon_ps *new_ps = &requested_ps;
+
+	ni_update_requested_ps(rdev, new_ps);
+
+	ni_apply_state_adjust_rules(rdev, &eg_pi->requested_rps);
+
+	return 0;
+}
+
 int ni_dpm_set_power_state(struct radeon_device *rdev)
 {
 	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
-	struct radeon_ps *new_ps = rdev->pm.dpm.requested_ps;
+	struct radeon_ps *new_ps = &eg_pi->requested_rps;
 	int ret;
 
-	ni_apply_state_adjust_rules(rdev, new_ps);
-
 	ni_restrict_performance_levels_before_switch(rdev);
 	ni_enable_power_containment(rdev, new_ps, false);
 	ni_enable_smc_cac(rdev, new_ps, false);
@@ -3657,6 +3690,14 @@ int ni_dpm_set_power_state(struct radeon_device *rdev)
 	return 0;
 }
 
+void ni_dpm_post_set_power_state(struct radeon_device *rdev)
+{
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	struct radeon_ps *new_ps = &eg_pi->requested_rps;
+
+	ni_update_current_ps(rdev, new_ps);
+}
+
 void ni_dpm_reset_asic(struct radeon_device *rdev)
 {
 	ni_restrict_performance_levels_before_switch(rdev);
@@ -4078,7 +4119,8 @@ void ni_dpm_print_power_state(struct radeon_device *rdev,
 
 u32 ni_dpm_get_sclk(struct radeon_device *rdev, bool low)
 {
-	struct ni_ps *requested_state = ni_get_ps(rdev->pm.dpm.requested_ps);
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	struct ni_ps *requested_state = ni_get_ps(&eg_pi->requested_rps);
 
 	if (low)
 		return requested_state->performance_levels[0].sclk;
@@ -4088,7 +4130,8 @@ u32 ni_dpm_get_sclk(struct radeon_device *rdev, bool low)
 
 u32 ni_dpm_get_mclk(struct radeon_device *rdev, bool low)
 {
-	struct ni_ps *requested_state = ni_get_ps(rdev->pm.dpm.requested_ps);
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+	struct ni_ps *requested_state = ni_get_ps(&eg_pi->requested_rps);
 
 	if (low)
 		return requested_state->performance_levels[0].mclk;
diff --git a/drivers/gpu/drm/radeon/ni_dpm.h b/drivers/gpu/drm/radeon/ni_dpm.h
index e10f747..59c1692 100644
--- a/drivers/gpu/drm/radeon/ni_dpm.h
+++ b/drivers/gpu/drm/radeon/ni_dpm.h
@@ -202,7 +202,8 @@ struct ni_power_info {
 	const struct ni_cac_weights *cac_weights;
 	u8 lta_window_size;
 	u8 lts_truncate;
-	struct ni_ps hw_ps;
+	struct ni_ps current_ps;
+	struct ni_ps requested_ps;
 	/* scratch structs */
 	SMC_NIslands_MCRegisters smc_mc_reg_table;
 	NISLANDS_SMC_STATETABLE smc_statetable;
diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c
index 25eeaa4..e7162b1 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.c
+++ b/drivers/gpu/drm/radeon/radeon_asic.c
@@ -1821,7 +1821,9 @@ static struct radeon_asic cayman_asic = {
 		.setup_asic = &ni_dpm_setup_asic,
 		.enable = &ni_dpm_enable,
 		.disable = &ni_dpm_disable,
+		.pre_set_power_state = &ni_dpm_pre_set_power_state,
 		.set_power_state = &ni_dpm_set_power_state,
+		.post_set_power_state = &ni_dpm_post_set_power_state,
 		.display_configuration_changed = &cypress_dpm_display_configuration_changed,
 		.fini = &ni_dpm_fini,
 		.get_sclk = &ni_dpm_get_sclk,
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index 696d6e9..7b898bc 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -593,7 +593,9 @@ int ni_dpm_init(struct radeon_device *rdev);
 void ni_dpm_setup_asic(struct radeon_device *rdev);
 int ni_dpm_enable(struct radeon_device *rdev);
 void ni_dpm_disable(struct radeon_device *rdev);
+int ni_dpm_pre_set_power_state(struct radeon_device *rdev);
 int ni_dpm_set_power_state(struct radeon_device *rdev);
+void ni_dpm_post_set_power_state(struct radeon_device *rdev);
 void ni_dpm_fini(struct radeon_device *rdev);
 u32 ni_dpm_get_sclk(struct radeon_device *rdev, bool low);
 u32 ni_dpm_get_mclk(struct radeon_device *rdev, bool low);
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 109/165] drm/radeon/dpm: remove broken dyn state remnants
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (108 preceding siblings ...)
  2013-06-26 13:23 ` [PATCH 108/165] drm/radeon/dpm: add pre/post_set_power_state callback (cayman) alexdeucher
@ 2013-06-26 13:23 ` alexdeucher
  2013-06-26 13:23 ` [PATCH 110/165] drm/radeon: add missing UVD clock set in cayman dpm code alexdeucher
                   ` (3 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:23 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Now that the proper fix has been implemented I can
remove the last remnants of the initial implementation.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/radeon.h    |    1 -
 drivers/gpu/drm/radeon/radeon_pm.c |   24 +++++-------------------
 2 files changed, 5 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 657d224..0c6676a 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -1307,7 +1307,6 @@ struct radeon_dpm {
 	struct radeon_ps        *boot_ps;
 	/* default uvd power state */
 	struct radeon_ps        *uvd_ps;
-	struct radeon_ps        hw_ps;
 	enum radeon_pm_state_type state;
 	enum radeon_pm_state_type user_state;
 	u32                     platform_caps;
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
index a50efb0..c8688b3 100644
--- a/drivers/gpu/drm/radeon/radeon_pm.c
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
@@ -687,17 +687,6 @@ restart_search:
 	return NULL;
 }
 
-static void radeon_dpm_update_requested_ps(struct radeon_device *rdev,
-					   struct radeon_ps *ps)
-{
-	/* copy the ps to the hw ps and point the requested ps
-	 * at the hw state in case the driver wants to modify
-	 * the state dynamically.
-	 */
-	rdev->pm.dpm.hw_ps = *ps;
-	rdev->pm.dpm.requested_ps = &rdev->pm.dpm.hw_ps;
-}
-
 static void radeon_dpm_change_power_state_locked(struct radeon_device *rdev)
 {
 	int i;
@@ -719,7 +708,7 @@ static void radeon_dpm_change_power_state_locked(struct radeon_device *rdev)
 
 	ps = radeon_dpm_pick_power_state(rdev, dpm_state);
 	if (ps)
-		radeon_dpm_update_requested_ps(rdev, ps);
+		rdev->pm.dpm.requested_ps = ps;
 	else
 		return;
 
@@ -770,11 +759,9 @@ static void radeon_dpm_change_power_state_locked(struct radeon_device *rdev)
 	down_write(&rdev->pm.mclk_lock);
 	mutex_lock(&rdev->ring_lock);
 
-	if (rdev->asic->dpm.pre_set_power_state) {
-		ret = radeon_dpm_pre_set_power_state(rdev);
-		if (ret)
-			goto done;
-	}
+	ret = radeon_dpm_pre_set_power_state(rdev);
+	if (ret)
+		goto done;
 
 	/* update display watermarks based on new power state */
 	radeon_bandwidth_update(rdev);
@@ -797,8 +784,7 @@ static void radeon_dpm_change_power_state_locked(struct radeon_device *rdev)
 	/* update current power state */
 	rdev->pm.dpm.current_ps = rdev->pm.dpm.requested_ps;
 
-	if (rdev->asic->dpm.post_set_power_state)
-		radeon_dpm_post_set_power_state(rdev);
+	radeon_dpm_post_set_power_state(rdev);
 
 done:
 	mutex_unlock(&rdev->ring_lock);
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 110/165] drm/radeon: add missing UVD clock set in cayman dpm code
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (109 preceding siblings ...)
  2013-06-26 13:23 ` [PATCH 109/165] drm/radeon/dpm: remove broken dyn state remnants alexdeucher
@ 2013-06-26 13:23 ` alexdeucher
  2013-06-26 13:23 ` [PATCH 111/165] drm/radeon/dpm: remove local sumo_get_xclk() alexdeucher
                   ` (2 subsequent siblings)
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:23 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/ni_dpm.c |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/radeon/ni_dpm.c b/drivers/gpu/drm/radeon/ni_dpm.c
index 01ecb80..a88f0cb 100644
--- a/drivers/gpu/drm/radeon/ni_dpm.c
+++ b/drivers/gpu/drm/radeon/ni_dpm.c
@@ -3667,9 +3667,11 @@ int ni_dpm_set_power_state(struct radeon_device *rdev)
 {
 	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
 	struct radeon_ps *new_ps = &eg_pi->requested_rps;
+	struct radeon_ps *old_ps = &eg_pi->current_rps;
 	int ret;
 
 	ni_restrict_performance_levels_before_switch(rdev);
+	rv770_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps);
 	ni_enable_power_containment(rdev, new_ps, false);
 	ni_enable_smc_cac(rdev, new_ps, false);
 	rv770_halt_smc(rdev);
@@ -3684,6 +3686,7 @@ int ni_dpm_set_power_state(struct radeon_device *rdev)
 	ni_populate_smc_tdp_limits(rdev, new_ps);
 	rv770_resume_smc(rdev);
 	rv770_set_sw_state(rdev);
+	rv770_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps);
 	ni_enable_smc_cac(rdev, new_ps, true);
 	ni_enable_power_containment(rdev, new_ps, true);
 
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 111/165] drm/radeon/dpm: remove local sumo_get_xclk()
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (110 preceding siblings ...)
  2013-06-26 13:23 ` [PATCH 110/165] drm/radeon: add missing UVD clock set in cayman dpm code alexdeucher
@ 2013-06-26 13:23 ` alexdeucher
  2013-06-26 21:57 ` [PATCH 000/165] radeon drm-next patches Julian Wollrath
  2013-06-26 22:23 ` Alex Deucher
  113 siblings, 0 replies; 142+ messages in thread
From: alexdeucher @ 2013-06-26 13:23 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

From: Alex Deucher <alexander.deucher@amd.com>

Use the new asic callback instead.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/sumo_dpm.c    |   19 +++++++------------
 drivers/gpu/drm/radeon/sumo_dpm.h    |    1 -
 drivers/gpu/drm/radeon/sumo_smc.c    |    2 +-
 drivers/gpu/drm/radeon/trinity_dpm.c |    6 +++---
 4 files changed, 11 insertions(+), 17 deletions(-)

diff --git a/drivers/gpu/drm/radeon/sumo_dpm.c b/drivers/gpu/drm/radeon/sumo_dpm.c
index 10700e1..80fb3ac 100644
--- a/drivers/gpu/drm/radeon/sumo_dpm.c
+++ b/drivers/gpu/drm/radeon/sumo_dpm.c
@@ -84,11 +84,6 @@ struct sumo_power_info *sumo_get_pi(struct radeon_device *rdev)
 	return pi;
 }
 
-u32 sumo_get_xclk(struct radeon_device *rdev)
-{
-	return rdev->clock.spll.reference_freq;
-}
-
 static void sumo_gfx_clockgating_enable(struct radeon_device *rdev, bool enable)
 {
 	if (enable)
@@ -124,7 +119,7 @@ static void sumo_mg_clockgating_enable(struct radeon_device *rdev, bool enable)
 static void sumo_program_git(struct radeon_device *rdev)
 {
 	u32 p, u;
-	u32 xclk = sumo_get_xclk(rdev);
+	u32 xclk = radeon_get_xclk(rdev);
 
 	r600_calculate_u_and_p(SUMO_GICST_DFLT,
 			       xclk, 16, &p, &u);
@@ -135,7 +130,7 @@ static void sumo_program_git(struct radeon_device *rdev)
 static void sumo_program_grsd(struct radeon_device *rdev)
 {
 	u32 p, u;
-	u32 xclk = sumo_get_xclk(rdev);
+	u32 xclk = radeon_get_xclk(rdev);
 	u32 grs = 256 * 25 / 100;
 
 	r600_calculate_u_and_p(1, xclk, 14, &p, &u);
@@ -155,7 +150,7 @@ static void sumo_gfx_powergating_initialize(struct radeon_device *rdev)
 	u32 p, u;
 	u32 p_c, p_p, d_p;
 	u32 r_t, i_t;
-	u32 xclk = sumo_get_xclk(rdev);
+	u32 xclk = radeon_get_xclk(rdev);
 
 	if (rdev->family == CHIP_PALM) {
 		p_c = 4;
@@ -319,7 +314,7 @@ static void sumo_calculate_bsp(struct radeon_device *rdev,
 			       u32 high_clk)
 {
 	struct sumo_power_info *pi = sumo_get_pi(rdev);
-	u32 xclk = sumo_get_xclk(rdev);
+	u32 xclk = radeon_get_xclk(rdev);
 
 	pi->pasi = 65535 * 100 / high_clk;
 	pi->asi = 65535 * 100 / high_clk;
@@ -466,7 +461,7 @@ void sumo_clear_vc(struct radeon_device *rdev)
 void sumo_program_sstp(struct radeon_device *rdev)
 {
 	u32 p, u;
-	u32 xclk = sumo_get_xclk(rdev);
+	u32 xclk = radeon_get_xclk(rdev);
 
 	r600_calculate_u_and_p(SUMO_SST_DFLT,
 			       xclk, 16, &p, &u);
@@ -909,7 +904,7 @@ static void sumo_start_am(struct radeon_device *rdev)
 
 static void sumo_program_ttp(struct radeon_device *rdev)
 {
-	u32 xclk = sumo_get_xclk(rdev);
+	u32 xclk = radeon_get_xclk(rdev);
 	u32 p, u;
 	u32 cg_sclk_dpm_ctrl_5 = RREG32(CG_SCLK_DPM_CTRL_5);
 
@@ -955,7 +950,7 @@ static void sumo_program_dc_hto(struct radeon_device *rdev)
 {
 	u32 cg_sclk_dpm_ctrl_4 = RREG32(CG_SCLK_DPM_CTRL_4);
 	u32 p, u;
-	u32 xclk = sumo_get_xclk(rdev);
+	u32 xclk = radeon_get_xclk(rdev);
 
 	r600_calculate_u_and_p(100000,
 			       xclk, 14, &p, &u);
diff --git a/drivers/gpu/drm/radeon/sumo_dpm.h b/drivers/gpu/drm/radeon/sumo_dpm.h
index a3a7a61..07dda29 100644
--- a/drivers/gpu/drm/radeon/sumo_dpm.h
+++ b/drivers/gpu/drm/radeon/sumo_dpm.h
@@ -188,7 +188,6 @@ struct sumo_power_info {
 #define SUMO_GFXPOWERGATINGT_DFLT  100
 
 /* sumo_dpm.c */
-u32 sumo_get_xclk(struct radeon_device *rdev);
 void sumo_gfx_clockgating_initialize(struct radeon_device *rdev);
 void sumo_program_vc(struct radeon_device *rdev, u32 vrc);
 void sumo_clear_vc(struct radeon_device *rdev);
diff --git a/drivers/gpu/drm/radeon/sumo_smc.c b/drivers/gpu/drm/radeon/sumo_smc.c
index bc1a510..9cbf0b2 100644
--- a/drivers/gpu/drm/radeon/sumo_smc.c
+++ b/drivers/gpu/drm/radeon/sumo_smc.c
@@ -146,7 +146,7 @@ void sumo_enable_boost_timer(struct radeon_device *rdev)
 {
 	struct sumo_power_info *pi = sumo_get_pi(rdev);
 	u32 period, unit, timer_value;
-	u32 xclk = sumo_get_xclk(rdev);
+	u32 xclk = radeon_get_xclk(rdev);
 
 	unit = (RREG32_RCU(RCU_LCLK_SCALING_CNTL) & LCLK_SCALING_TIMER_PRESCALER_MASK)
 		>> LCLK_SCALING_TIMER_PRESCALER_SHIFT;
diff --git a/drivers/gpu/drm/radeon/trinity_dpm.c b/drivers/gpu/drm/radeon/trinity_dpm.c
index 1699e93..b2dc905 100644
--- a/drivers/gpu/drm/radeon/trinity_dpm.c
+++ b/drivers/gpu/drm/radeon/trinity_dpm.c
@@ -361,7 +361,7 @@ static void trinity_gfx_powergating_initialize(struct radeon_device *rdev)
 	u32 p, u;
 	u32 value;
 	struct atom_clock_dividers dividers;
-	u32 xclk = sumo_get_xclk(rdev);
+	u32 xclk = radeon_get_xclk(rdev);
 	u32 sssd = 1;
 	int ret;
 	u32 hw_rev = (RREG32(HW_REV) & ATI_REV_ID_MASK) >> ATI_REV_ID_SHIFT;
@@ -880,7 +880,7 @@ static void trinity_setup_uvd_dpm_interval(struct radeon_device *rdev,
 	u32 p, u;
 	u32 tp = RREG32_SMC(PM_TP);
 	u32 val;
-	u32 xclk = sumo_get_xclk(rdev);
+	u32 xclk = radeon_get_xclk(rdev);
 
 	r600_calculate_u_and_p(interval, xclk, 16, &p, &u);
 
@@ -1000,7 +1000,7 @@ static void trinity_program_sclk_dpm(struct radeon_device *rdev)
 	u32 p, u;
 	u32 tp = RREG32_SMC(PM_TP);
 	u32 ni;
-	u32 xclk = sumo_get_xclk(rdev);
+	u32 xclk = radeon_get_xclk(rdev);
 	u32 value;
 
 	r600_calculate_u_and_p(400, xclk, 16, &p, &u);
-- 
1.7.7.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* Re: [PATCH 023/165] drm/radeon/cik: fill in startup/shutdown callbacks (v4)
  2013-06-26 13:21 ` [PATCH 023/165] drm/radeon/cik: fill in startup/shutdown callbacks (v4) alexdeucher
@ 2013-06-26 15:03   ` Christian König
  0 siblings, 0 replies; 142+ messages in thread
From: Christian König @ 2013-06-26 15:03 UTC (permalink / raw)
  To: alexdeucher; +Cc: Alex Deucher, dri-devel

Am 26.06.2013 15:21, schrieb alexdeucher@gmail.com:
> From: Alex Deucher <alexander.deucher@amd.com>
>
> v2: update to latest driver changes
> v3: properly tear down vm on suspend
> v4: fix up irq init ordering
>
> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>

Just a copy&paste error, but some comments are referring to cayman and 
r500/r700 generations.

With that fixed the patch is:

Reviewed-by: Christian König <christian.koenig@amd.com>


> ---
>   drivers/gpu/drm/radeon/cik.c |  340 ++++++++++++++++++++++++++++++++++++++++++
>   1 files changed, 340 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
> index cf1e0b1..cbc64a2 100644
> --- a/drivers/gpu/drm/radeon/cik.c
> +++ b/drivers/gpu/drm/radeon/cik.c
> @@ -73,6 +73,8 @@ extern void r600_ih_ring_fini(struct radeon_device *rdev);
>   extern void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save);
>   extern void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save);
>   extern void si_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc);
> +extern void si_rlc_fini(struct radeon_device *rdev);
> +extern int si_rlc_init(struct radeon_device *rdev);
>   
>   #define BONAIRE_IO_MC_REGS_SIZE 36
>   
> @@ -4681,3 +4683,341 @@ restart_ih:
>   
>   	return IRQ_HANDLED;
>   }
> +
> +/*
> + * startup/shutdown callbacks
> + */
> +/**
> + * cik_startup - program the asic to a functional state
> + *
> + * @rdev: radeon_device pointer
> + *
> + * Programs the asic to a functional state (CIK).
> + * Called by cik_init() and cik_resume().
> + * Returns 0 for success, error for failure.
> + */
> +static int cik_startup(struct radeon_device *rdev)
> +{
> +	struct radeon_ring *ring;
> +	int r;
> +
> +	if (rdev->flags & RADEON_IS_IGP) {
> +		if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw ||
> +		    !rdev->mec_fw || !rdev->sdma_fw || !rdev->rlc_fw) {
> +			r = cik_init_microcode(rdev);
> +			if (r) {
> +				DRM_ERROR("Failed to load firmware!\n");
> +				return r;
> +			}
> +		}
> +	} else {
> +		if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw ||
> +		    !rdev->mec_fw || !rdev->sdma_fw || !rdev->rlc_fw ||
> +		    !rdev->mc_fw) {
> +			r = cik_init_microcode(rdev);
> +			if (r) {
> +				DRM_ERROR("Failed to load firmware!\n");
> +				return r;
> +			}
> +		}
> +
> +		r = ci_mc_load_microcode(rdev);
> +		if (r) {
> +			DRM_ERROR("Failed to load MC firmware!\n");
> +			return r;
> +		}
> +	}
> +
> +	r = r600_vram_scratch_init(rdev);
> +	if (r)
> +		return r;
> +
> +	cik_mc_program(rdev);
> +	r = cik_pcie_gart_enable(rdev);
> +	if (r)
> +		return r;
> +	cik_gpu_init(rdev);
> +
> +	/* allocate rlc buffers */
> +	r = si_rlc_init(rdev);
> +	if (r) {
> +		DRM_ERROR("Failed to init rlc BOs!\n");
> +		return r;
> +	}
> +
> +	/* allocate wb buffer */
> +	r = radeon_wb_init(rdev);
> +	if (r)
> +		return r;
> +
> +	r = radeon_fence_driver_start_ring(rdev, RADEON_RING_TYPE_GFX_INDEX);
> +	if (r) {
> +		dev_err(rdev->dev, "failed initializing CP fences (%d).\n", r);
> +		return r;
> +	}
> +
> +	r = radeon_fence_driver_start_ring(rdev, R600_RING_TYPE_DMA_INDEX);
> +	if (r) {
> +		dev_err(rdev->dev, "failed initializing DMA fences (%d).\n", r);
> +		return r;
> +	}
> +
> +	r = radeon_fence_driver_start_ring(rdev, CAYMAN_RING_TYPE_DMA1_INDEX);
> +	if (r) {
> +		dev_err(rdev->dev, "failed initializing DMA fences (%d).\n", r);
> +		return r;
> +	}
> +
> +	/* Enable IRQ */
> +	if (!rdev->irq.installed) {
> +		r = radeon_irq_kms_init(rdev);
> +		if (r)
> +			return r;
> +	}
> +
> +	r = cik_irq_init(rdev);
> +	if (r) {
> +		DRM_ERROR("radeon: IH init failed (%d).\n", r);
> +		radeon_irq_kms_fini(rdev);
> +		return r;
> +	}
> +	cik_irq_set(rdev);
> +
> +	ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
> +	r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP_RPTR_OFFSET,
> +			     CP_RB0_RPTR, CP_RB0_WPTR,
> +			     0, 0xfffff, RADEON_CP_PACKET2);
> +	if (r)
> +		return r;
> +
> +	ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX];
> +	r = radeon_ring_init(rdev, ring, ring->ring_size, R600_WB_DMA_RPTR_OFFSET,
> +			     SDMA0_GFX_RB_RPTR + SDMA0_REGISTER_OFFSET,
> +			     SDMA0_GFX_RB_WPTR + SDMA0_REGISTER_OFFSET,
> +			     2, 0xfffffffc, SDMA_PACKET(SDMA_OPCODE_NOP, 0, 0));
> +	if (r)
> +		return r;
> +
> +	ring = &rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX];
> +	r = radeon_ring_init(rdev, ring, ring->ring_size, CAYMAN_WB_DMA1_RPTR_OFFSET,
> +			     SDMA0_GFX_RB_RPTR + SDMA1_REGISTER_OFFSET,
> +			     SDMA0_GFX_RB_WPTR + SDMA1_REGISTER_OFFSET,
> +			     2, 0xfffffffc, SDMA_PACKET(SDMA_OPCODE_NOP, 0, 0));
> +	if (r)
> +		return r;
> +
> +	r = cik_cp_resume(rdev);
> +	if (r)
> +		return r;
> +
> +	r = cik_sdma_resume(rdev);
> +	if (r)
> +		return r;
> +
> +	r = radeon_ib_pool_init(rdev);
> +	if (r) {
> +		dev_err(rdev->dev, "IB initialization failed (%d).\n", r);
> +		return r;
> +	}
> +
> +	r = radeon_vm_manager_init(rdev);
> +	if (r) {
> +		dev_err(rdev->dev, "vm manager initialization failed (%d).\n", r);
> +		return r;
> +	}
> +
> +	return 0;
> +}
> +
> +/**
> + * cik_resume - resume the asic to a functional state
> + *
> + * @rdev: radeon_device pointer
> + *
> + * Programs the asic to a functional state (CIK).
> + * Called at resume.
> + * Returns 0 for success, error for failure.
> + */
> +int cik_resume(struct radeon_device *rdev)
> +{
> +	int r;
> +
> +	/* Do not reset GPU before posting, on rv770 hw unlike on r500 hw,
> +	 * posting will perform necessary task to bring back GPU into good
> +	 * shape.
> +	 */
> +	/* post card */
> +	atom_asic_init(rdev->mode_info.atom_context);
> +
> +	rdev->accel_working = true;
> +	r = cik_startup(rdev);
> +	if (r) {
> +		DRM_ERROR("cik startup failed on resume\n");
> +		rdev->accel_working = false;
> +		return r;
> +	}
> +
> +	return r;
> +
> +}
> +
> +/**
> + * cik_suspend - suspend the asic
> + *
> + * @rdev: radeon_device pointer
> + *
> + * Bring the chip into a state suitable for suspend (CIK).
> + * Called at suspend.
> + * Returns 0 for success.
> + */
> +int cik_suspend(struct radeon_device *rdev)
> +{
> +	radeon_vm_manager_fini(rdev);
> +	cik_cp_enable(rdev, false);
> +	cik_sdma_enable(rdev, false);
> +	cik_irq_suspend(rdev);
> +	radeon_wb_disable(rdev);
> +	cik_pcie_gart_disable(rdev);
> +	return 0;
> +}
> +
> +/* Plan is to move initialization in that function and use
> + * helper function so that radeon_device_init pretty much
> + * do nothing more than calling asic specific function. This
> + * should also allow to remove a bunch of callback function
> + * like vram_info.
> + */
> +/**
> + * cik_init - asic specific driver and hw init
> + *
> + * @rdev: radeon_device pointer
> + *
> + * Setup asic specific driver variables and program the hw
> + * to a functional state (CIK).
> + * Called at driver startup.
> + * Returns 0 for success, errors for failure.
> + */
> +int cik_init(struct radeon_device *rdev)
> +{
> +	struct radeon_ring *ring;
> +	int r;
> +
> +	/* Read BIOS */
> +	if (!radeon_get_bios(rdev)) {
> +		if (ASIC_IS_AVIVO(rdev))
> +			return -EINVAL;
> +	}
> +	/* Must be an ATOMBIOS */
> +	if (!rdev->is_atom_bios) {
> +		dev_err(rdev->dev, "Expecting atombios for cayman GPU\n");
> +		return -EINVAL;
> +	}
> +	r = radeon_atombios_init(rdev);
> +	if (r)
> +		return r;
> +
> +	/* Post card if necessary */
> +	if (!radeon_card_posted(rdev)) {
> +		if (!rdev->bios) {
> +			dev_err(rdev->dev, "Card not posted and no BIOS - ignoring\n");
> +			return -EINVAL;
> +		}
> +		DRM_INFO("GPU not posted. posting now...\n");
> +		atom_asic_init(rdev->mode_info.atom_context);
> +	}
> +	/* Initialize scratch registers */
> +	cik_scratch_init(rdev);
> +	/* Initialize surface registers */
> +	radeon_surface_init(rdev);
> +	/* Initialize clocks */
> +	radeon_get_clock_info(rdev->ddev);
> +
> +	/* Fence driver */
> +	r = radeon_fence_driver_init(rdev);
> +	if (r)
> +		return r;
> +
> +	/* initialize memory controller */
> +	r = cik_mc_init(rdev);
> +	if (r)
> +		return r;
> +	/* Memory manager */
> +	r = radeon_bo_init(rdev);
> +	if (r)
> +		return r;
> +
> +	ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
> +	ring->ring_obj = NULL;
> +	r600_ring_init(rdev, ring, 1024 * 1024);
> +
> +	ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX];
> +	ring->ring_obj = NULL;
> +	r600_ring_init(rdev, ring, 256 * 1024);
> +
> +	ring = &rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX];
> +	ring->ring_obj = NULL;
> +	r600_ring_init(rdev, ring, 256 * 1024);
> +
> +	rdev->ih.ring_obj = NULL;
> +	r600_ih_ring_init(rdev, 64 * 1024);
> +
> +	r = r600_pcie_gart_init(rdev);
> +	if (r)
> +		return r;
> +
> +	rdev->accel_working = true;
> +	r = cik_startup(rdev);
> +	if (r) {
> +		dev_err(rdev->dev, "disabling GPU acceleration\n");
> +		cik_cp_fini(rdev);
> +		cik_sdma_fini(rdev);
> +		cik_irq_fini(rdev);
> +		si_rlc_fini(rdev);
> +		radeon_wb_fini(rdev);
> +		radeon_ib_pool_fini(rdev);
> +		radeon_vm_manager_fini(rdev);
> +		radeon_irq_kms_fini(rdev);
> +		cik_pcie_gart_fini(rdev);
> +		rdev->accel_working = false;
> +	}
> +
> +	/* Don't start up if the MC ucode is missing.
> +	 * The default clocks and voltages before the MC ucode
> +	 * is loaded are not suffient for advanced operations.
> +	 */
> +	if (!rdev->mc_fw && !(rdev->flags & RADEON_IS_IGP)) {
> +		DRM_ERROR("radeon: MC ucode required for NI+.\n");
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +/**
> + * cik_fini - asic specific driver and hw fini
> + *
> + * @rdev: radeon_device pointer
> + *
> + * Tear down the asic specific driver variables and program the hw
> + * to an idle state (CIK).
> + * Called at driver unload.
> + */
> +void cik_fini(struct radeon_device *rdev)
> +{
> +	cik_cp_fini(rdev);
> +	cik_sdma_fini(rdev);
> +	cik_irq_fini(rdev);
> +	si_rlc_fini(rdev);
> +	radeon_wb_fini(rdev);
> +	radeon_vm_manager_fini(rdev);
> +	radeon_ib_pool_fini(rdev);
> +	radeon_irq_kms_fini(rdev);
> +	cik_pcie_gart_fini(rdev);
> +	r600_vram_scratch_fini(rdev);
> +	radeon_gem_fini(rdev);
> +	radeon_fence_driver_fini(rdev);
> +	radeon_bo_fini(rdev);
> +	radeon_atombios_fini(rdev);
> +	kfree(rdev->bios);
> +	rdev->bios = NULL;
> +}

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 050/165] drm/radeon: use callbacks for ring pointer handling
  2013-06-26 13:22 ` [PATCH 050/165] drm/radeon: use callbacks for ring pointer handling alexdeucher
@ 2013-06-26 15:31   ` Christian König
  0 siblings, 0 replies; 142+ messages in thread
From: Christian König @ 2013-06-26 15:31 UTC (permalink / raw)
  To: alexdeucher; +Cc: Alex Deucher, dri-devel

Am 26.06.2013 15:22, schrieb alexdeucher@gmail.com:
> From: Alex Deucher <alexander.deucher@amd.com>
>
> Add callbacks to the radeon_ring struct to handle
> rptr/wptr fetchs and wptr updates.
> We currently use one version for all rings, but this
> allows us to override with a ring specific versions.
>
> Needed for compute rings on CIK.
>
> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>

I'm ok with the general idea but let's put those callback into the 
radeon_asic.ring structure where they belong.

With this we should be able to remove most of the UVD and 
ptr_reg_shift/ptr_reg_mask special case handling.

Christian.

> ---
>   drivers/gpu/drm/radeon/radeon.h      |    5 +++
>   drivers/gpu/drm/radeon/radeon_ring.c |   55 +++++++++++++++++++++++++--------
>   2 files changed, 46 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
> index 9af0fa6..ad4e68a 100644
> --- a/drivers/gpu/drm/radeon/radeon.h
> +++ b/drivers/gpu/drm/radeon/radeon.h
> @@ -695,6 +695,11 @@ struct radeon_ring {
>   	u32			idx;
>   	u64			last_semaphore_signal_addr;
>   	u64			last_semaphore_wait_addr;
> +	struct {
> +		u32			(*get_rptr)(struct radeon_device *rdev, struct radeon_ring *ring);
> +		u32			(*get_wptr)(struct radeon_device *rdev, struct radeon_ring *ring);
> +		void			(*set_wptr)(struct radeon_device *rdev, struct radeon_ring *ring);
> +	} funcs;
>   };
>   
>   /*
> diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c
> index e17faa7..53018e9 100644
> --- a/drivers/gpu/drm/radeon/radeon_ring.c
> +++ b/drivers/gpu/drm/radeon/radeon_ring.c
> @@ -357,6 +357,38 @@ bool radeon_ring_supports_scratch_reg(struct radeon_device *rdev,
>   	}
>   }
>   
> +static u32 radeon_ring_get_rptr(struct radeon_device *rdev,
> +				struct radeon_ring *ring)
> +{
> +	u32 rptr;
> +
> +	if (rdev->wb.enabled && ring != &rdev->ring[R600_RING_TYPE_UVD_INDEX])
> +		rptr = le32_to_cpu(rdev->wb.wb[ring->rptr_offs/4]);
> +	else
> +		rptr = RREG32(ring->rptr_reg);
> +	rptr = (rptr & ring->ptr_reg_mask) >> ring->ptr_reg_shift;
> +
> +	return rptr;
> +}
> +
> +static u32 radeon_ring_get_wptr(struct radeon_device *rdev,
> +				struct radeon_ring *ring)
> +{
> +	u32 wptr;
> +
> +	wptr = RREG32(ring->wptr_reg);
> +	wptr = (wptr & ring->ptr_reg_mask) >> ring->ptr_reg_shift;
> +
> +	return wptr;
> +}
> +
> +static void radeon_ring_set_wptr(struct radeon_device *rdev,
> +				 struct radeon_ring *ring)
> +{
> +	WREG32(ring->wptr_reg, (ring->wptr << ring->ptr_reg_shift) & ring->ptr_reg_mask);
> +	(void)RREG32(ring->wptr_reg);
> +}
> +
>   /**
>    * radeon_ring_free_size - update the free size
>    *
> @@ -367,13 +399,7 @@ bool radeon_ring_supports_scratch_reg(struct radeon_device *rdev,
>    */
>   void radeon_ring_free_size(struct radeon_device *rdev, struct radeon_ring *ring)
>   {
> -	u32 rptr;
> -
> -	if (rdev->wb.enabled && ring != &rdev->ring[R600_RING_TYPE_UVD_INDEX])
> -		rptr = le32_to_cpu(rdev->wb.wb[ring->rptr_offs/4]);
> -	else
> -		rptr = RREG32(ring->rptr_reg);
> -	ring->rptr = (rptr & ring->ptr_reg_mask) >> ring->ptr_reg_shift;
> +	ring->rptr = ring->funcs.get_rptr(rdev, ring);
>   	/* This works because ring_size is a power of 2 */
>   	ring->ring_free_dw = (ring->rptr + (ring->ring_size / 4));
>   	ring->ring_free_dw -= ring->wptr;
> @@ -458,8 +484,7 @@ void radeon_ring_commit(struct radeon_device *rdev, struct radeon_ring *ring)
>   		radeon_ring_write(ring, ring->nop);
>   	}
>   	DRM_MEMORYBARRIER();
> -	WREG32(ring->wptr_reg, (ring->wptr << ring->ptr_reg_shift) & ring->ptr_reg_mask);
> -	(void)RREG32(ring->wptr_reg);
> +	ring->funcs.set_wptr(rdev, ring);
>   }
>   
>   /**
> @@ -561,7 +586,6 @@ void radeon_ring_lockup_update(struct radeon_ring *ring)
>   bool radeon_ring_test_lockup(struct radeon_device *rdev, struct radeon_ring *ring)
>   {
>   	unsigned long cjiffies, elapsed;
> -	uint32_t rptr;
>   
>   	cjiffies = jiffies;
>   	if (!time_after(cjiffies, ring->last_activity)) {
> @@ -569,8 +593,7 @@ bool radeon_ring_test_lockup(struct radeon_device *rdev, struct radeon_ring *rin
>   		radeon_ring_lockup_update(ring);
>   		return false;
>   	}
> -	rptr = RREG32(ring->rptr_reg);
> -	ring->rptr = (rptr & ring->ptr_reg_mask) >> ring->ptr_reg_shift;
> +	ring->rptr = ring->funcs.get_rptr(rdev, ring);
>   	if (ring->rptr != ring->last_rptr) {
>   		/* CP is still working no lockup */
>   		radeon_ring_lockup_update(ring);
> @@ -708,6 +731,10 @@ int radeon_ring_init(struct radeon_device *rdev, struct radeon_ring *ring, unsig
>   	ring->ptr_reg_shift = ptr_reg_shift;
>   	ring->ptr_reg_mask = ptr_reg_mask;
>   	ring->nop = nop;
> +	/* set the ptr callbacks */
> +	ring->funcs.get_rptr = &radeon_ring_get_rptr;
> +	ring->funcs.get_wptr = &radeon_ring_get_wptr;
> +	ring->funcs.set_wptr = &radeon_ring_set_wptr;
>   	/* Allocate ring buffer */
>   	if (ring->ring_obj == NULL) {
>   		r = radeon_bo_create(rdev, ring->ring_size, PAGE_SIZE, true,
> @@ -797,9 +824,9 @@ static int radeon_debugfs_ring_info(struct seq_file *m, void *data)
>   
>   	radeon_ring_free_size(rdev, ring);
>   	count = (ring->ring_size / 4) - ring->ring_free_dw;
> -	tmp = RREG32(ring->wptr_reg) >> ring->ptr_reg_shift;
> +	tmp = ring->funcs.get_wptr(rdev, ring);
>   	seq_printf(m, "wptr(0x%04x): 0x%08x [%5d]\n", ring->wptr_reg, tmp, tmp);
> -	tmp = RREG32(ring->rptr_reg) >> ring->ptr_reg_shift;
> +	tmp = ring->funcs.get_rptr(rdev, ring);
>   	seq_printf(m, "rptr(0x%04x): 0x%08x [%5d]\n", ring->rptr_reg, tmp, tmp);
>   	if (ring->rptr_save_reg) {
>   		seq_printf(m, "rptr next(0x%04x): 0x%08x\n", ring->rptr_save_reg,

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 076/165] drm/radeon/kms: add dpm support for rv6xx
  2013-06-26 13:22 ` [PATCH 076/165] drm/radeon/kms: add dpm support for rv6xx alexdeucher
@ 2013-06-26 16:45   ` Christian König
  0 siblings, 0 replies; 142+ messages in thread
From: Christian König @ 2013-06-26 16:45 UTC (permalink / raw)
  To: alexdeucher; +Cc: Alex Deucher, dri-devel

Am 26.06.2013 15:22, schrieb alexdeucher@gmail.com:
> From: Alex Deucher <alexander.deucher@amd.com>
>
> This adds dpm support for rv6xx asics.  This includes:
> - clockgating
> - dynamic engine clock scaling
> - dynamic memory clock scaling
> - dynamic voltage scaling
> - dynamic pcie gen1/gen2 switching
>
> Set radeon.dpm=1 to enable.
>
> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
> ---
>   drivers/gpu/drm/radeon/Makefile          |    2 +-
>   drivers/gpu/drm/radeon/r600.c            |   27 +
>   drivers/gpu/drm/radeon/r600_dpm.c        |   45 +
>   drivers/gpu/drm/radeon/r600_dpm.h        |    8 +
>   drivers/gpu/drm/radeon/r600d.h           |   13 +
>   drivers/gpu/drm/radeon/radeon.h          |    3 +
>   drivers/gpu/drm/radeon/radeon_asic.c     |   12 +
>   drivers/gpu/drm/radeon/radeon_asic.h     |   12 +
>   drivers/gpu/drm/radeon/radeon_atombios.c |    4 +-
>   drivers/gpu/drm/radeon/radeon_irq_kms.c  |    2 +
>   drivers/gpu/drm/radeon/radeon_mode.h     |    2 +
>   drivers/gpu/drm/radeon/radeon_pm.c       |    9 +
>   drivers/gpu/drm/radeon/rs780_dpm.c       |   12 +
>   drivers/gpu/drm/radeon/rv6xx_dpm.c       | 1991 ++++++++++++++++++++++++++++++
>   drivers/gpu/drm/radeon/rv6xx_dpm.h       |   95 ++
>   drivers/gpu/drm/radeon/rv6xxd.h          |  246 ++++
>   16 files changed, 2480 insertions(+), 3 deletions(-)
>   create mode 100644 drivers/gpu/drm/radeon/rv6xx_dpm.c
>   create mode 100644 drivers/gpu/drm/radeon/rv6xx_dpm.h
>   create mode 100644 drivers/gpu/drm/radeon/rv6xxd.h
>
> diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile
> index e44b046..3aa20dc 100644
> --- a/drivers/gpu/drm/radeon/Makefile
> +++ b/drivers/gpu/drm/radeon/Makefile
> @@ -77,7 +77,7 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \
>   	evergreen_hdmi.o radeon_trace_points.o ni.o cayman_blit_shaders.o \
>   	atombios_encoders.o radeon_semaphore.o radeon_sa.o atombios_i2c.o si.o \
>   	si_blit_shaders.o radeon_prime.o radeon_uvd.o cik.o cik_blit_shaders.o \
> -	r600_dpm.o rs780_dpm.o
> +	r600_dpm.o rs780_dpm.o rv6xx_dpm.o
>   
>   radeon-$(CONFIG_COMPAT) += radeon_ioc32.o
>   radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o
> diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
> index 4678ed1..7ea81c8 100644
> --- a/drivers/gpu/drm/radeon/r600.c
> +++ b/drivers/gpu/drm/radeon/r600.c
> @@ -3998,6 +3998,7 @@ int r600_irq_set(struct radeon_device *rdev)
>   	u32 hdmi0, hdmi1;
>   	u32 d1grph = 0, d2grph = 0;
>   	u32 dma_cntl;
> +	u32 thermal_int = 0;
>   
>   	if (!rdev->irq.installed) {
>   		WARN(1, "Can't enable IRQ/MSI because no handler is installed\n");
> @@ -4032,8 +4033,18 @@ int r600_irq_set(struct radeon_device *rdev)
>   		hdmi0 = RREG32(HDMI0_AUDIO_PACKET_CONTROL) & ~HDMI0_AZ_FORMAT_WTRIG_MASK;
>   		hdmi1 = RREG32(HDMI1_AUDIO_PACKET_CONTROL) & ~HDMI0_AZ_FORMAT_WTRIG_MASK;
>   	}
> +
>   	dma_cntl = RREG32(DMA_CNTL) & ~TRAP_ENABLE;
>   
> +	if ((rdev->family > CHIP_R600) && (rdev->family < CHIP_RV770)) {
> +		thermal_int = RREG32(CG_THERMAL_INT) &
> +			~(THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW);
> +		if (rdev->irq.dpm_thermal) {
> +			DRM_DEBUG("dpm thermal\n");
> +			thermal_int |= THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW;
> +		}
> +	}
> +
>   	if (atomic_read(&rdev->irq.ring_int[RADEON_RING_TYPE_GFX_INDEX])) {
>   		DRM_DEBUG("r600_irq_set: sw int\n");
>   		cp_int_cntl |= RB_INT_ENABLE;
> @@ -4115,6 +4126,9 @@ int r600_irq_set(struct radeon_device *rdev)
>   		WREG32(HDMI0_AUDIO_PACKET_CONTROL, hdmi0);
>   		WREG32(HDMI1_AUDIO_PACKET_CONTROL, hdmi1);
>   	}
> +	if ((rdev->family > CHIP_R600) && (rdev->family < CHIP_RV770)) {
> +		WREG32(CG_THERMAL_INT, thermal_int);
> +	}
>   
>   	return 0;
>   }
> @@ -4306,6 +4320,7 @@ int r600_irq_process(struct radeon_device *rdev)
>   	u32 ring_index;
>   	bool queue_hotplug = false;
>   	bool queue_hdmi = false;
> +	bool queue_thermal = false;
>   
>   	if (!rdev->ih.enabled || rdev->shutdown)
>   		return IRQ_NONE;
> @@ -4473,6 +4488,16 @@ restart_ih:
>   			DRM_DEBUG("IH: DMA trap\n");
>   			radeon_fence_process(rdev, R600_RING_TYPE_DMA_INDEX);
>   			break;
> +		case 230: /* thermal low to high */
> +			DRM_DEBUG("IH: thermal low to high\n");
> +			rdev->pm.dpm.thermal.high_to_low = false;
> +			queue_thermal = true;
> +			break;
> +		case 231: /* thermal high to low */
> +			DRM_DEBUG("IH: thermal high to low\n");
> +			rdev->pm.dpm.thermal.high_to_low = true;
> +			queue_thermal = true;
> +			break;
>   		case 233: /* GUI IDLE */
>   			DRM_DEBUG("IH: GUI idle\n");
>   			break;
> @@ -4489,6 +4514,8 @@ restart_ih:
>   		schedule_work(&rdev->hotplug_work);
>   	if (queue_hdmi)
>   		schedule_work(&rdev->audio_work);
> +	if (queue_thermal)
> +		schedule_work(&rdev->pm.dpm.thermal.work);
>   	rdev->ih.rptr = rptr;
>   	WREG32(IH_RB_RPTR, rdev->ih.rptr);
>   	atomic_set(&rdev->ih.lock, 0);
> diff --git a/drivers/gpu/drm/radeon/r600_dpm.c b/drivers/gpu/drm/radeon/r600_dpm.c
> index 91bc5ab..bf396a0 100644
> --- a/drivers/gpu/drm/radeon/r600_dpm.c
> +++ b/drivers/gpu/drm/radeon/r600_dpm.c
> @@ -676,3 +676,48 @@ bool r600_is_uvd_state(u32 class, u32 class2)
>   		return true;
>   	return false;
>   }
> +
> +int r600_set_thermal_temperature_range(struct radeon_device *rdev,
> +				       int min_temp, int max_temp)
> +{
> +	int low_temp = 0 * 1000;
> +	int high_temp = 255 * 1000;
> +
> +	if (low_temp < min_temp)
> +		low_temp = min_temp;
> +	if (high_temp > max_temp)
> +		high_temp = max_temp;
> +	if (high_temp < low_temp) {
> +		DRM_ERROR("invalid thermal range: %d - %d\n", low_temp, high_temp);
> +		return -EINVAL;
> +	}
> +
> +	WREG32_P(CG_THERMAL_INT, DIG_THERM_INTH(high_temp / 1000), ~DIG_THERM_INTH_MASK);
> +	WREG32_P(CG_THERMAL_INT, DIG_THERM_INTL(low_temp / 1000), ~DIG_THERM_INTL_MASK);
> +	WREG32_P(CG_THERMAL_CTRL, DIG_THERM_DPM(high_temp / 1000), ~DIG_THERM_DPM_MASK);
> +
> +	rdev->pm.dpm.thermal.min_temp = low_temp;
> +	rdev->pm.dpm.thermal.max_temp = high_temp;
> +
> +	return 0;
> +}
> +
> +bool r600_is_internal_thermal_sensor(enum radeon_int_thermal_type sensor)
> +{
> +	switch (sensor) {
> +	case THERMAL_TYPE_RV6XX:
> +	case THERMAL_TYPE_RV770:
> +	case THERMAL_TYPE_EVERGREEN:
> +	case THERMAL_TYPE_SUMO:
> +	case THERMAL_TYPE_NI:
> +		return true;
> +	case THERMAL_TYPE_ADT7473_WITH_INTERNAL:
> +	case THERMAL_TYPE_EMC2103_WITH_INTERNAL:
> +		return false; /* need special handling */
> +	case THERMAL_TYPE_NONE:
> +	case THERMAL_TYPE_EXTERNAL:
> +	case THERMAL_TYPE_EXTERNAL_GPIO:
> +	default:
> +		return false;
> +	}
> +}
> diff --git a/drivers/gpu/drm/radeon/r600_dpm.h b/drivers/gpu/drm/radeon/r600_dpm.h
> index 240a7ed..bd33aa1 100644
> --- a/drivers/gpu/drm/radeon/r600_dpm.h
> +++ b/drivers/gpu/drm/radeon/r600_dpm.h
> @@ -92,6 +92,10 @@
>   #define R600_PM_NUMBER_OF_VOLTAGE_LEVELS 4
>   #define R600_PM_NUMBER_OF_ACTIVITY_LEVELS 3
>   
> +/* XXX are these ok? */
> +#define R600_TEMP_RANGE_MIN (90 * 1000)
> +#define R600_TEMP_RANGE_MAX (120 * 1000)
> +
>   enum r600_power_level {
>   	R600_POWER_LEVEL_LOW = 0,
>   	R600_POWER_LEVEL_MEDIUM = 1,
> @@ -207,4 +211,8 @@ void r600_wait_for_power_level(struct radeon_device *rdev,
>   void r600_start_dpm(struct radeon_device *rdev);
>   void r600_stop_dpm(struct radeon_device *rdev);
>   
> +int r600_set_thermal_temperature_range(struct radeon_device *rdev,
> +				       int min_temp, int max_temp);
> +bool r600_is_internal_thermal_sensor(enum radeon_int_thermal_type sensor);
> +
>   #endif
> diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h
> index d6d385a..3bca4db 100644
> --- a/drivers/gpu/drm/radeon/r600d.h
> +++ b/drivers/gpu/drm/radeon/r600d.h
> @@ -302,10 +302,23 @@
>   #define	GRBM_SOFT_RESET					0x8020
>   #define		SOFT_RESET_CP					(1<<0)
>   
> +#define	CG_THERMAL_CTRL					0x7F0
> +#define		DIG_THERM_DPM(x)			((x) << 12)
> +#define		DIG_THERM_DPM_MASK			0x000FF000
> +#define		DIG_THERM_DPM_SHIFT			12
>   #define	CG_THERMAL_STATUS				0x7F4
>   #define		ASIC_T(x)			        ((x) << 0)
>   #define		ASIC_T_MASK			        0x1FF
>   #define		ASIC_T_SHIFT			        0
> +#define	CG_THERMAL_INT					0x7F8
> +#define		DIG_THERM_INTH(x)			((x) << 8)
> +#define		DIG_THERM_INTH_MASK			0x0000FF00
> +#define		DIG_THERM_INTH_SHIFT			8
> +#define		DIG_THERM_INTL(x)			((x) << 16)
> +#define		DIG_THERM_INTL_MASK			0x00FF0000
> +#define		DIG_THERM_INTL_SHIFT			16
> +#define 	THERM_INT_MASK_HIGH			(1 << 24)
> +#define 	THERM_INT_MASK_LOW			(1 << 25)
>   
>   #define	HDP_HOST_PATH_CNTL				0x2C00
>   #define	HDP_NONSURFACE_BASE				0x2C04
> diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
> index 7adc7a1..ce36130 100644
> --- a/drivers/gpu/drm/radeon/radeon.h
> +++ b/drivers/gpu/drm/radeon/radeon.h
> @@ -227,6 +227,8 @@ void radeon_atom_set_engine_dram_timings(struct radeon_device *rdev,
>   					 u32 eng_clock, u32 mem_clock);
>   int radeon_atom_get_voltage_step(struct radeon_device *rdev,
>   				 u8 voltage_type, u16 *voltage_step);
> +int radeon_atom_get_max_vddc(struct radeon_device *rdev, u8 voltage_type,
> +			     u16 voltage_id, u16 *voltage);
>   int radeon_atom_round_to_true_voltage(struct radeon_device *rdev,
>   				      u8 voltage_type,
>   				      u16 nominal_voltage,
> @@ -681,6 +683,7 @@ struct radeon_irq {
>   	bool				hpd[RADEON_MAX_HPD_PINS];
>   	bool				afmt[RADEON_MAX_AFMT_BLOCKS];
>   	union radeon_irq_stat_regs	stat_regs;
> +	bool				dpm_thermal;
>   };
>   
>   int radeon_irq_kms_init(struct radeon_device *rdev);
> diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c
> index db3c930..4705b02 100644
> --- a/drivers/gpu/drm/radeon/radeon_asic.c
> +++ b/drivers/gpu/drm/radeon/radeon_asic.c
> @@ -1105,6 +1105,18 @@ static struct radeon_asic rv6xx_asic = {
>   		.set_clock_gating = NULL,
>   		.get_temperature = &rv6xx_get_temp,
>   	},
> +	.dpm = {
> +		.init = &rv6xx_dpm_init,
> +		.setup_asic = &rv6xx_setup_asic,
> +		.enable = &rv6xx_dpm_enable,
> +		.disable = &rv6xx_dpm_disable,
> +		.set_power_state = &rv6xx_dpm_set_power_state,
> +		.display_configuration_changed = &rv6xx_dpm_display_configuration_changed,
> +		.fini = &rv6xx_dpm_fini,
> +		.get_sclk = &rv6xx_dpm_get_sclk,
> +		.get_mclk = &rv6xx_dpm_get_mclk,
> +		.print_power_state = &rv6xx_dpm_print_power_state,
> +	},
>   	.pflip = {
>   		.pre_page_flip = &rs600_pre_page_flip,
>   		.page_flip = &rs600_page_flip,
> diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
> index 134bf57..878766624 100644
> --- a/drivers/gpu/drm/radeon/radeon_asic.h
> +++ b/drivers/gpu/drm/radeon/radeon_asic.h
> @@ -396,6 +396,18 @@ int r600_mc_wait_for_idle(struct radeon_device *rdev);
>   u32 r600_get_xclk(struct radeon_device *rdev);
>   uint64_t r600_get_gpu_clock_counter(struct radeon_device *rdev);
>   int rv6xx_get_temp(struct radeon_device *rdev);
> +/* rv6xx dpm */
> +int rv6xx_dpm_init(struct radeon_device *rdev);
> +int rv6xx_dpm_enable(struct radeon_device *rdev);
> +void rv6xx_dpm_disable(struct radeon_device *rdev);
> +int rv6xx_dpm_set_power_state(struct radeon_device *rdev);
> +void rv6xx_setup_asic(struct radeon_device *rdev);
> +void rv6xx_dpm_display_configuration_changed(struct radeon_device *rdev);
> +void rv6xx_dpm_fini(struct radeon_device *rdev);
> +u32 rv6xx_dpm_get_sclk(struct radeon_device *rdev, bool low);
> +u32 rv6xx_dpm_get_mclk(struct radeon_device *rdev, bool low);
> +void rv6xx_dpm_print_power_state(struct radeon_device *rdev,
> +				 struct radeon_ps *ps);
>   /* rs780 dpm */
>   int rs780_dpm_init(struct radeon_device *rdev);
>   int rs780_dpm_enable(struct radeon_device *rdev);
> diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c
> index 90401fd..612d9bc 100644
> --- a/drivers/gpu/drm/radeon/radeon_atombios.c
> +++ b/drivers/gpu/drm/radeon/radeon_atombios.c
> @@ -2268,8 +2268,8 @@ static void radeon_atombios_add_pplib_thermal_controller(struct radeon_device *r
>   	}
>   }
>   
> -static void radeon_atombios_get_default_voltages(struct radeon_device *rdev,
> -						 u16 *vddc, u16 *vddci)
> +void radeon_atombios_get_default_voltages(struct radeon_device *rdev,
> +					  u16 *vddc, u16 *vddci)
>   {
>   	struct radeon_mode_info *mode_info = &rdev->mode_info;
>   	int index = GetIndexIntoMasterTable(DATA, FirmwareInfo);
> diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c
> index dbffeca..bcdefd1 100644
> --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c
> +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c
> @@ -116,6 +116,7 @@ void radeon_driver_irq_preinstall_kms(struct drm_device *dev)
>   	/* Disable *all* interrupts */
>   	for (i = 0; i < RADEON_NUM_RINGS; i++)
>   		atomic_set(&rdev->irq.ring_int[i], 0);
> +	rdev->irq.dpm_thermal = false;
>   	for (i = 0; i < RADEON_MAX_HPD_PINS; i++)
>   		rdev->irq.hpd[i] = false;
>   	for (i = 0; i < RADEON_MAX_CRTCS; i++) {
> @@ -163,6 +164,7 @@ void radeon_driver_irq_uninstall_kms(struct drm_device *dev)
>   	/* Disable *all* interrupts */
>   	for (i = 0; i < RADEON_NUM_RINGS; i++)
>   		atomic_set(&rdev->irq.ring_int[i], 0);
> +	rdev->irq.dpm_thermal = false;
>   	for (i = 0; i < RADEON_MAX_HPD_PINS; i++)
>   		rdev->irq.hpd[i] = false;
>   	for (i = 0; i < RADEON_MAX_CRTCS; i++) {
> diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
> index 5a1c69e..02bf4a7 100644
> --- a/drivers/gpu/drm/radeon/radeon_mode.h
> +++ b/drivers/gpu/drm/radeon/radeon_mode.h
> @@ -580,6 +580,8 @@ extern enum radeon_tv_std
>   radeon_combios_get_tv_info(struct radeon_device *rdev);
>   extern enum radeon_tv_std
>   radeon_atombios_get_tv_info(struct radeon_device *rdev);
> +extern void radeon_atombios_get_default_voltages(struct radeon_device *rdev,
> +						 u16 *vddc, u16 *vddci);
>   
>   extern struct drm_connector *
>   radeon_get_connector_for_encoder(struct drm_encoder *encoder);
> diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
> index 853a8a2..5cb01f2 100644
> --- a/drivers/gpu/drm/radeon/radeon_pm.c
> +++ b/drivers/gpu/drm/radeon/radeon_pm.c
> @@ -565,6 +565,9 @@ static void radeon_dpm_thermal_work_handler(struct work_struct *work)
>   	if (!rdev->pm.dpm_enabled)
>   		return;
>   
> +	if (!rdev->pm.dpm_enabled)
> +		return;
> +

Looks like the check is already present here. With that fixed the patch is:

Reviewed-by: Christian König <christian.koenig@amd.com>

>   	if (rdev->asic->pm.get_temperature) {
>   		int temp = radeon_get_temperature(rdev);
>   
> @@ -1030,6 +1033,11 @@ int radeon_pm_init(struct radeon_device *rdev)
>   {
>   	/* enable dpm on rv6xx+ */
>   	switch (rdev->family) {
> +	case CHIP_RV610:
> +	case CHIP_RV630:
> +	case CHIP_RV620:
> +	case CHIP_RV635:
> +	case CHIP_RV670:
>   	case CHIP_RS780:
>   	case CHIP_RS880:
>   		if (radeon_dpm == 1)
> @@ -1114,6 +1122,7 @@ static void radeon_pm_compute_clocks_old(struct radeon_device *rdev)
>   	if (rdev->pm.num_power_states < 2)
>   		return;
>   
> +	INIT_WORK(&rdev->pm.dpm.thermal.work, radeon_dpm_thermal_work_handler);
>   	mutex_lock(&rdev->pm.mutex);
>   
>   	rdev->pm.active_crtcs = 0;
> diff --git a/drivers/gpu/drm/radeon/rs780_dpm.c b/drivers/gpu/drm/radeon/rs780_dpm.c
> index f594900..a1497a6 100644
> --- a/drivers/gpu/drm/radeon/rs780_dpm.c
> +++ b/drivers/gpu/drm/radeon/rs780_dpm.c
> @@ -560,6 +560,12 @@ int rs780_dpm_enable(struct radeon_device *rdev)
>   	if (pi->gfx_clock_gating)
>   		r600_gfx_clockgating_enable(rdev, true);
>   
> +	if (rdev->irq.installed && (rdev->pm.int_thermal_type == THERMAL_TYPE_RV6XX)) {
> +		r600_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
> +		rdev->irq.dpm_thermal = true;
> +		radeon_irq_set(rdev);
> +	}
> +
>   	return 0;
>   }
>   
> @@ -574,6 +580,12 @@ void rs780_dpm_disable(struct radeon_device *rdev)
>   
>   	if (pi->gfx_clock_gating)
>   		r600_gfx_clockgating_enable(rdev, false);
> +
> +	if (rdev->irq.installed &&
> +	    (rdev->pm.int_thermal_type == THERMAL_TYPE_RV6XX)) {
> +		rdev->irq.dpm_thermal = false;
> +		radeon_irq_set(rdev);
> +	}
>   }
>   
>   int rs780_dpm_set_power_state(struct radeon_device *rdev)
> diff --git a/drivers/gpu/drm/radeon/rv6xx_dpm.c b/drivers/gpu/drm/radeon/rv6xx_dpm.c
> new file mode 100644
> index 0000000..fa4beb2
> --- /dev/null
> +++ b/drivers/gpu/drm/radeon/rv6xx_dpm.c
> @@ -0,0 +1,1991 @@
> +/*
> + * Copyright 2011 Advanced Micro Devices, Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + *
> + * Authors: Alex Deucher
> + */
> +
> +#include "drmP.h"
> +#include "radeon.h"
> +#include "rv6xxd.h"
> +#include "r600_dpm.h"
> +#include "rv6xx_dpm.h"
> +#include "atom.h"
> +
> +static u32 rv6xx_scale_count_given_unit(struct radeon_device *rdev,
> +					u32 unscaled_count, u32 unit);
> +
> +static struct rv6xx_ps *rv6xx_get_ps(struct radeon_ps *rps)
> +{
> +	struct rv6xx_ps *ps = rps->ps_priv;
> +
> +	return ps;
> +}
> +
> +static struct rv6xx_power_info *rv6xx_get_pi(struct radeon_device *rdev)
> +{
> +	struct rv6xx_power_info *pi = rdev->pm.dpm.priv;
> +
> +	return pi;
> +}
> +
> +static void rv6xx_force_pcie_gen1(struct radeon_device *rdev)
> +{
> +	u32 tmp;
> +	int i;
> +
> +	tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL);
> +	tmp &= LC_GEN2_EN;
> +	WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp);
> +
> +	tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL);
> +	tmp |= LC_INITIATE_LINK_SPEED_CHANGE;
> +	WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp);
> +
> +	for (i = 0; i < rdev->usec_timeout; i++) {
> +		if (!(RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL) & LC_CURRENT_DATA_RATE))
> +			break;
> +		udelay(1);
> +	}
> +
> +	tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL);
> +	tmp &= ~LC_INITIATE_LINK_SPEED_CHANGE;
> +	WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp);
> +}
> +
> +static void rv6xx_enable_pcie_gen2_support(struct radeon_device *rdev)
> +{
> +	u32 tmp;
> +
> +	tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL);
> +
> +	if ((tmp & LC_OTHER_SIDE_EVER_SENT_GEN2) &&
> +	    (tmp & LC_OTHER_SIDE_SUPPORTS_GEN2)) {
> +		tmp |= LC_GEN2_EN;
> +		WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp);
> +	}
> +}
> +
> +static void rv6xx_enable_bif_dynamic_pcie_gen2(struct radeon_device *rdev,
> +					       bool enable)
> +{
> +	u32 tmp;
> +
> +	tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL) & ~LC_HW_VOLTAGE_IF_CONTROL_MASK;
> +	if (enable)
> +		tmp |= LC_HW_VOLTAGE_IF_CONTROL(1);
> +	else
> +		tmp |= LC_HW_VOLTAGE_IF_CONTROL(0);
> +	WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp);
> +}
> +
> +static void rv6xx_enable_l0s(struct radeon_device *rdev)
> +{
> +	u32 tmp;
> +
> +	tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL) & ~LC_L0S_INACTIVITY_MASK;
> +	tmp |= LC_L0S_INACTIVITY(3);
> +	WREG32_PCIE_PORT(PCIE_LC_CNTL, tmp);
> +}
> +
> +static void rv6xx_enable_l1(struct radeon_device *rdev)
> +{
> +	u32 tmp;
> +
> +	tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL);
> +	tmp &= ~LC_L1_INACTIVITY_MASK;
> +	tmp |= LC_L1_INACTIVITY(4);
> +	tmp &= ~LC_PMI_TO_L1_DIS;
> +	tmp &= ~LC_ASPM_TO_L1_DIS;
> +	WREG32_PCIE_PORT(PCIE_LC_CNTL, tmp);
> +}
> +
> +static void rv6xx_enable_pll_sleep_in_l1(struct radeon_device *rdev)
> +{
> +	u32 tmp;
> +
> +	tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL) & ~LC_L1_INACTIVITY_MASK;
> +	tmp |= LC_L1_INACTIVITY(8);
> +	WREG32_PCIE_PORT(PCIE_LC_CNTL, tmp);
> +
> +	/* NOTE, this is a PCIE indirect reg, not PCIE PORT */
> +	tmp = RREG32_PCIE(PCIE_P_CNTL);
> +	tmp |= P_PLL_PWRDN_IN_L1L23;
> +	tmp &= ~P_PLL_BUF_PDNB;
> +	tmp &= ~P_PLL_PDNB;
> +	tmp |= P_ALLOW_PRX_FRONTEND_SHUTOFF;
> +	WREG32_PCIE(PCIE_P_CNTL, tmp);
> +}
> +
> +static int rv6xx_convert_clock_to_stepping(struct radeon_device *rdev,
> +					   u32 clock, struct rv6xx_sclk_stepping *step)
> +{
> +	int ret;
> +	struct atom_clock_dividers dividers;
> +
> +	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
> +					     clock, false, &dividers);
> +	if (ret)
> +		return ret;
> +
> +	if (dividers.enable_post_div)
> +		step->post_divider = 2 + (dividers.post_div & 0xF) + (dividers.post_div >> 4);
> +	else
> +		step->post_divider = 1;
> +
> +	step->vco_frequency = clock * step->post_divider;
> +
> +	return 0;
> +}
> +
> +static void rv6xx_output_stepping(struct radeon_device *rdev,
> +				  u32 step_index, struct rv6xx_sclk_stepping *step)
> +{
> +	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
> +	u32 ref_clk = rdev->clock.spll.reference_freq;
> +	u32 fb_divider;
> +	u32 spll_step_count = rv6xx_scale_count_given_unit(rdev,
> +							   R600_SPLLSTEPTIME_DFLT *
> +							   pi->spll_ref_div,
> +							   R600_SPLLSTEPUNIT_DFLT);
> +
> +	r600_engine_clock_entry_enable(rdev, step_index, true);
> +	r600_engine_clock_entry_enable_pulse_skipping(rdev, step_index, false);
> +
> +	if (step->post_divider == 1)
> +		r600_engine_clock_entry_enable_post_divider(rdev, step_index, false);
> +	else {
> +		u32 lo_len = (step->post_divider - 2) / 2;
> +		u32 hi_len = step->post_divider - 2 - lo_len;
> +
> +		r600_engine_clock_entry_enable_post_divider(rdev, step_index, true);
> +		r600_engine_clock_entry_set_post_divider(rdev, step_index, (hi_len << 4) | lo_len);
> +	}
> +
> +	fb_divider = ((step->vco_frequency * pi->spll_ref_div) / ref_clk) >>
> +		pi->fb_div_scale;
> +
> +	r600_engine_clock_entry_set_reference_divider(rdev, step_index,
> +						      pi->spll_ref_div - 1);
> +	r600_engine_clock_entry_set_feedback_divider(rdev, step_index, fb_divider);
> +	r600_engine_clock_entry_set_step_time(rdev, step_index, spll_step_count);
> +
> +}
> +
> +static struct rv6xx_sclk_stepping rv6xx_next_vco_step(struct radeon_device *rdev,
> +						      struct rv6xx_sclk_stepping *cur,
> +						      bool increasing_vco, u32 step_size)
> +{
> +	struct rv6xx_sclk_stepping next;
> +
> +	next.post_divider = cur->post_divider;
> +
> +	if (increasing_vco)
> +		next.vco_frequency = (cur->vco_frequency * (100 + step_size)) / 100;
> +	else
> +		next.vco_frequency = (cur->vco_frequency * 100 + 99 + step_size) / (100 + step_size);
> +
> +	return next;
> +}
> +
> +static bool rv6xx_can_step_post_div(struct radeon_device *rdev,
> +				    struct rv6xx_sclk_stepping *cur,
> +                                    struct rv6xx_sclk_stepping *target)
> +{
> +	return (cur->post_divider > target->post_divider) &&
> +		((cur->vco_frequency * target->post_divider) <=
> +		 (target->vco_frequency * (cur->post_divider - 1)));
> +}
> +
> +static struct rv6xx_sclk_stepping rv6xx_next_post_div_step(struct radeon_device *rdev,
> +							   struct rv6xx_sclk_stepping *cur,
> +							   struct rv6xx_sclk_stepping *target)
> +{
> +	struct rv6xx_sclk_stepping next = *cur;
> +
> +	while (rv6xx_can_step_post_div(rdev, &next, target))
> +		next.post_divider--;
> +
> +	return next;
> +}
> +
> +static bool rv6xx_reached_stepping_target(struct radeon_device *rdev,
> +					  struct rv6xx_sclk_stepping *cur,
> +					  struct rv6xx_sclk_stepping *target,
> +					  bool increasing_vco)
> +{
> +	return (increasing_vco && (cur->vco_frequency >= target->vco_frequency)) ||
> +		(!increasing_vco && (cur->vco_frequency <= target->vco_frequency));
> +}
> +
> +static void rv6xx_generate_steps(struct radeon_device *rdev,
> +				 u32 low, u32 high,
> +                                 u32 start_index, u8 *end_index)
> +{
> +	struct rv6xx_sclk_stepping cur;
> +	struct rv6xx_sclk_stepping target;
> +	bool increasing_vco;
> +	u32 step_index = start_index;
> +
> +	rv6xx_convert_clock_to_stepping(rdev, low, &cur);
> +	rv6xx_convert_clock_to_stepping(rdev, high, &target);
> +
> +	rv6xx_output_stepping(rdev, step_index++, &cur);
> +
> +	increasing_vco = (target.vco_frequency >= cur.vco_frequency);
> +
> +	if (target.post_divider > cur.post_divider)
> +		cur.post_divider = target.post_divider;
> +
> +	while (1) {
> +		struct rv6xx_sclk_stepping next;
> +
> +		if (rv6xx_can_step_post_div(rdev, &cur, &target))
> +			next = rv6xx_next_post_div_step(rdev, &cur, &target);
> +		else
> +			next = rv6xx_next_vco_step(rdev, &cur, increasing_vco, R600_VCOSTEPPCT_DFLT);
> +
> +		if (rv6xx_reached_stepping_target(rdev, &next, &target, increasing_vco)) {
> +			struct rv6xx_sclk_stepping tiny =
> +				rv6xx_next_vco_step(rdev, &target, !increasing_vco, R600_ENDINGVCOSTEPPCT_DFLT);
> +			tiny.post_divider = next.post_divider;
> +
> +			if (!rv6xx_reached_stepping_target(rdev, &tiny, &cur, !increasing_vco))
> +				rv6xx_output_stepping(rdev, step_index++, &tiny);
> +
> +			if ((next.post_divider != target.post_divider) &&
> +			    (next.vco_frequency != target.vco_frequency)) {
> +				struct rv6xx_sclk_stepping final_vco;
> +
> +				final_vco.vco_frequency = target.vco_frequency;
> +				final_vco.post_divider = next.post_divider;
> +
> +				rv6xx_output_stepping(rdev, step_index++, &final_vco);
> +			}
> +
> +			rv6xx_output_stepping(rdev, step_index++, &target);
> +			break;
> +		} else
> +			rv6xx_output_stepping(rdev, step_index++, &next);
> +
> +		cur = next;
> +	}
> +
> +	*end_index = (u8)step_index - 1;
> +
> +}
> +
> +static void rv6xx_generate_single_step(struct radeon_device *rdev,
> +				       u32 clock, u32 index)
> +{
> +	struct rv6xx_sclk_stepping step;
> +
> +	rv6xx_convert_clock_to_stepping(rdev, clock, &step);
> +	rv6xx_output_stepping(rdev, index, &step);
> +}
> +
> +static void rv6xx_invalidate_intermediate_steps_range(struct radeon_device *rdev,
> +						      u32 start_index, u32 end_index)
> +{
> +	u32 step_index;
> +
> +	for (step_index = start_index + 1; step_index < end_index; step_index++)
> +		r600_engine_clock_entry_enable(rdev, step_index, false);
> +}
> +
> +static void rv6xx_set_engine_spread_spectrum_clk_s(struct radeon_device *rdev,
> +						   u32 index, u32 clk_s)
> +{
> +	WREG32_P(CG_SPLL_SPREAD_SPECTRUM_LOW + (index * 4),
> +		 CLKS(clk_s), ~CLKS_MASK);
> +}
> +
> +static void rv6xx_set_engine_spread_spectrum_clk_v(struct radeon_device *rdev,
> +						   u32 index, u32 clk_v)
> +{
> +	WREG32_P(CG_SPLL_SPREAD_SPECTRUM_LOW + (index * 4),
> +		 CLKV(clk_v), ~CLKV_MASK);
> +}
> +
> +static void rv6xx_enable_engine_spread_spectrum(struct radeon_device *rdev,
> +						u32 index, bool enable)
> +{
> +	if (enable)
> +		WREG32_P(CG_SPLL_SPREAD_SPECTRUM_LOW + (index * 4),
> +			 SSEN, ~SSEN);
> +	else
> +		WREG32_P(CG_SPLL_SPREAD_SPECTRUM_LOW + (index * 4),
> +			 0, ~SSEN);
> +}
> +
> +static void rv6xx_set_memory_spread_spectrum_clk_s(struct radeon_device *rdev,
> +						   u32 clk_s)
> +{
> +	WREG32_P(CG_MPLL_SPREAD_SPECTRUM, CLKS(clk_s), ~CLKS_MASK);
> +}
> +
> +static void rv6xx_set_memory_spread_spectrum_clk_v(struct radeon_device *rdev,
> +						   u32 clk_v)
> +{
> +	WREG32_P(CG_MPLL_SPREAD_SPECTRUM, CLKV(clk_v), ~CLKV_MASK);
> +}
> +
> +static void rv6xx_enable_memory_spread_spectrum(struct radeon_device *rdev,
> +						bool enable)
> +{
> +	if (enable)
> +		WREG32_P(CG_MPLL_SPREAD_SPECTRUM, SSEN, ~SSEN);
> +	else
> +		WREG32_P(CG_MPLL_SPREAD_SPECTRUM, 0, ~SSEN);
> +}
> +
> +static void rv6xx_enable_dynamic_spread_spectrum(struct radeon_device *rdev,
> +						 bool enable)
> +{
> +	if (enable)
> +		WREG32_P(GENERAL_PWRMGT, DYN_SPREAD_SPECTRUM_EN, ~DYN_SPREAD_SPECTRUM_EN);
> +	else
> +		WREG32_P(GENERAL_PWRMGT, 0, ~DYN_SPREAD_SPECTRUM_EN);
> +}
> +
> +static void rv6xx_memory_clock_entry_enable_post_divider(struct radeon_device *rdev,
> +							 u32 index, bool enable)
> +{
> +	if (enable)
> +		WREG32_P(MPLL_FREQ_LEVEL_0 + (index * 4),
> +			 LEVEL0_MPLL_DIV_EN, ~LEVEL0_MPLL_DIV_EN);
> +	else
> +		WREG32_P(MPLL_FREQ_LEVEL_0 + (index * 4), 0, ~LEVEL0_MPLL_DIV_EN);
> +}
> +
> +static void rv6xx_memory_clock_entry_set_post_divider(struct radeon_device *rdev,
> +						      u32 index, u32 divider)
> +{
> +	WREG32_P(MPLL_FREQ_LEVEL_0 + (index * 4),
> +		 LEVEL0_MPLL_POST_DIV(divider), ~LEVEL0_MPLL_POST_DIV_MASK);
> +}
> +
> +static void rv6xx_memory_clock_entry_set_feedback_divider(struct radeon_device *rdev,
> +							  u32 index, u32 divider)
> +{
> +	WREG32_P(MPLL_FREQ_LEVEL_0 + (index * 4), LEVEL0_MPLL_FB_DIV(divider),
> +		 ~LEVEL0_MPLL_FB_DIV_MASK);
> +}
> +
> +static void rv6xx_memory_clock_entry_set_reference_divider(struct radeon_device *rdev,
> +							   u32 index, u32 divider)
> +{
> +	WREG32_P(MPLL_FREQ_LEVEL_0 + (index * 4),
> +		 LEVEL0_MPLL_REF_DIV(divider), ~LEVEL0_MPLL_REF_DIV_MASK);
> +}
> +
> +static void rv6xx_vid_response_set_brt(struct radeon_device *rdev, u32 rt)
> +{
> +	WREG32_P(VID_RT, BRT(rt), ~BRT_MASK);
> +}
> +
> +static void rv6xx_enable_engine_feedback_and_reference_sync(struct radeon_device *rdev)
> +{
> +	WREG32_P(SPLL_CNTL_MODE, SPLL_DIV_SYNC, ~SPLL_DIV_SYNC);
> +}
> +
> +static u64 rv6xx_clocks_per_unit(u32 unit)
> +{
> +	u64 tmp = 1 << (2 * unit);
> +
> +	return tmp;
> +}
> +
> +static u32 rv6xx_scale_count_given_unit(struct radeon_device *rdev,
> +					u32 unscaled_count, u32 unit)
> +{
> +	u32 count_per_unit = (u32)rv6xx_clocks_per_unit(unit);
> +
> +	return (unscaled_count + count_per_unit - 1) / count_per_unit;
> +}
> +
> +static u32 rv6xx_compute_count_for_delay(struct radeon_device *rdev,
> +					 u32 delay_us, u32 unit)
> +{
> +	u32 ref_clk = rdev->clock.spll.reference_freq;
> +
> +	return rv6xx_scale_count_given_unit(rdev, delay_us * (ref_clk / 100), unit);
> +}
> +
> +static void rv6xx_calculate_engine_speed_stepping_parameters(struct radeon_device *rdev,
> +							     struct rv6xx_ps *state)
> +{
> +	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
> +
> +	pi->hw.sclks[R600_POWER_LEVEL_LOW] =
> +		state->low.sclk;
> +	pi->hw.sclks[R600_POWER_LEVEL_MEDIUM] =
> +		state->medium.sclk;
> +	pi->hw.sclks[R600_POWER_LEVEL_HIGH] =
> +		state->high.sclk;
> +
> +	pi->hw.low_sclk_index = R600_POWER_LEVEL_LOW;
> +	pi->hw.medium_sclk_index = R600_POWER_LEVEL_MEDIUM;
> +	pi->hw.high_sclk_index = R600_POWER_LEVEL_HIGH;
> +}
> +
> +static void rv6xx_calculate_memory_clock_stepping_parameters(struct radeon_device *rdev,
> +							     struct rv6xx_ps *state)
> +{
> +	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
> +
> +	pi->hw.mclks[R600_POWER_LEVEL_CTXSW] =
> +		state->high.mclk;
> +	pi->hw.mclks[R600_POWER_LEVEL_HIGH] =
> +		state->high.mclk;
> +	pi->hw.mclks[R600_POWER_LEVEL_MEDIUM] =
> +		state->medium.mclk;
> +	pi->hw.mclks[R600_POWER_LEVEL_LOW] =
> +		state->low.mclk;
> +
> +	pi->hw.high_mclk_index = R600_POWER_LEVEL_HIGH;
> +
> +	if (state->high.mclk == state->medium.mclk)
> +		pi->hw.medium_mclk_index =
> +			pi->hw.high_mclk_index;
> +	else
> +		pi->hw.medium_mclk_index = R600_POWER_LEVEL_MEDIUM;
> +
> +
> +	if (state->medium.mclk == state->low.mclk)
> +		pi->hw.low_mclk_index =
> +			pi->hw.medium_mclk_index;
> +	else
> +		pi->hw.low_mclk_index = R600_POWER_LEVEL_LOW;
> +}
> +
> +static void rv6xx_calculate_voltage_stepping_parameters(struct radeon_device *rdev,
> +							struct rv6xx_ps *state)
> +{
> +	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
> +
> +	pi->hw.vddc[R600_POWER_LEVEL_CTXSW] = state->high.vddc;
> +	pi->hw.vddc[R600_POWER_LEVEL_HIGH] = state->high.vddc;
> +	pi->hw.vddc[R600_POWER_LEVEL_MEDIUM] = state->medium.vddc;
> +	pi->hw.vddc[R600_POWER_LEVEL_LOW] = state->low.vddc;
> +
> +	pi->hw.backbias[R600_POWER_LEVEL_CTXSW] =
> +		(state->high.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) ? true : false;
> +	pi->hw.backbias[R600_POWER_LEVEL_HIGH] =
> +		(state->high.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) ? true : false;
> +	pi->hw.backbias[R600_POWER_LEVEL_MEDIUM] =
> +		(state->medium.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) ? true : false;
> +	pi->hw.backbias[R600_POWER_LEVEL_LOW] =
> +		(state->low.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) ? true : false;
> +
> +	pi->hw.pcie_gen2[R600_POWER_LEVEL_HIGH] =
> +		(state->high.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) ? true : false;
> +	pi->hw.pcie_gen2[R600_POWER_LEVEL_MEDIUM] =
> +		(state->medium.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) ? true : false;
> +	pi->hw.pcie_gen2[R600_POWER_LEVEL_LOW] =
> +		(state->low.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) ? true : false;
> +
> +	pi->hw.high_vddc_index = R600_POWER_LEVEL_HIGH;
> +
> +	if ((state->high.vddc == state->medium.vddc) &&
> +	    ((state->high.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) ==
> +	     (state->medium.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE)))
> +		pi->hw.medium_vddc_index =
> +			pi->hw.high_vddc_index;
> +	else
> +		pi->hw.medium_vddc_index = R600_POWER_LEVEL_MEDIUM;
> +
> +	if ((state->medium.vddc == state->low.vddc) &&
> +	    ((state->medium.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) ==
> +	     (state->low.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE)))
> +		pi->hw.low_vddc_index =
> +			pi->hw.medium_vddc_index;
> +	else
> +		pi->hw.medium_vddc_index = R600_POWER_LEVEL_LOW;
> +}
> +
> +static inline u32 rv6xx_calculate_vco_frequency(u32 ref_clock,
> +						struct atom_clock_dividers *dividers,
> +						u32 fb_divider_scale)
> +{
> +	return ref_clock * ((dividers->fb_div & ~1) << fb_divider_scale) /
> +		(dividers->ref_div + 1);
> +}
> +
> +static inline u32 rv6xx_calculate_spread_spectrum_clk_v(u32 vco_freq, u32 ref_freq,
> +							u32 ss_rate, u32 ss_percent,
> +							u32 fb_divider_scale)
> +{
> +	u32 fb_divider = vco_freq / ref_freq;
> +
> +	return (ss_percent * ss_rate * 4 * (fb_divider * fb_divider) /
> +		(5375 * ((vco_freq * 10) / (4096 >> fb_divider_scale))));
> +}
> +
> +static inline u32 rv6xx_calculate_spread_spectrum_clk_s(u32 ss_rate, u32 ref_freq)
> +{
> +	return (((ref_freq * 10) / (ss_rate * 2)) - 1) / 4;
> +}
> +
> +static void rv6xx_program_engine_spread_spectrum(struct radeon_device *rdev,
> +						 u32 clock, enum r600_power_level level)
> +{
> +	u32 ref_clk = rdev->clock.spll.reference_freq;
> +	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
> +	struct atom_clock_dividers dividers;
> +	struct radeon_atom_ss ss;
> +	u32 vco_freq, clk_v, clk_s;
> +
> +	rv6xx_enable_engine_spread_spectrum(rdev, level, false);
> +
> +	if (clock && pi->sclk_ss) {
> +		if (radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, clock, false, &dividers) == 0) {
> +			vco_freq = rv6xx_calculate_vco_frequency(ref_clk, &dividers,
> +								 pi->fb_div_scale);
> +
> +			if (radeon_atombios_get_asic_ss_info(rdev, &ss,
> +							     ASIC_INTERNAL_ENGINE_SS, vco_freq)) {
> +				clk_v = rv6xx_calculate_spread_spectrum_clk_v(vco_freq,
> +									      (ref_clk / (dividers.ref_div + 1)),
> +									      ss.rate,
> +									      ss.percentage,
> +									      pi->fb_div_scale);
> +
> +				clk_s = rv6xx_calculate_spread_spectrum_clk_s(ss.rate,
> +									      (ref_clk / (dividers.ref_div + 1)));
> +
> +				rv6xx_set_engine_spread_spectrum_clk_v(rdev, level, clk_v);
> +				rv6xx_set_engine_spread_spectrum_clk_s(rdev, level, clk_s);
> +				rv6xx_enable_engine_spread_spectrum(rdev, level, true);
> +			}
> +		}
> +	}
> +}
> +
> +static void rv6xx_program_sclk_spread_spectrum_parameters_except_lowest_entry(struct radeon_device *rdev)
> +{
> +	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
> +
> +	rv6xx_program_engine_spread_spectrum(rdev,
> +					     pi->hw.sclks[R600_POWER_LEVEL_HIGH],
> +					     R600_POWER_LEVEL_HIGH);
> +
> +	rv6xx_program_engine_spread_spectrum(rdev,
> +					     pi->hw.sclks[R600_POWER_LEVEL_MEDIUM],
> +					     R600_POWER_LEVEL_MEDIUM);
> +
> +}
> +
> +static int rv6xx_program_mclk_stepping_entry(struct radeon_device *rdev,
> +					     u32 entry, u32 clock)
> +{
> +	struct atom_clock_dividers dividers;
> +
> +	if (radeon_atom_get_clock_dividers(rdev, COMPUTE_MEMORY_PLL_PARAM, clock, false, &dividers))
> +	    return -EINVAL;
> +
> +
> +	rv6xx_memory_clock_entry_set_reference_divider(rdev, entry, dividers.ref_div);
> +	rv6xx_memory_clock_entry_set_feedback_divider(rdev, entry, dividers.fb_div);
> +	rv6xx_memory_clock_entry_set_post_divider(rdev, entry, dividers.post_div);
> +
> +	if (dividers.enable_post_div)
> +		rv6xx_memory_clock_entry_enable_post_divider(rdev, entry, true);
> +	else
> +		rv6xx_memory_clock_entry_enable_post_divider(rdev, entry, false);
> +
> +	return 0;
> +}
> +
> +static void rv6xx_program_mclk_stepping_parameters_except_lowest_entry(struct radeon_device *rdev)
> +{
> +	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
> +	int i;
> +
> +	for (i = 1; i < R600_PM_NUMBER_OF_MCLKS; i++) {
> +		if (pi->hw.mclks[i])
> +			rv6xx_program_mclk_stepping_entry(rdev, i,
> +							  pi->hw.mclks[i]);
> +	}
> +}
> +
> +static void rv6xx_find_memory_clock_with_highest_vco(struct radeon_device *rdev,
> +						     u32 requested_memory_clock,
> +						     u32 ref_clk,
> +						     struct atom_clock_dividers *dividers,
> +						     u32 *vco_freq)
> +{
> +	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
> +	struct atom_clock_dividers req_dividers;
> +	u32 vco_freq_temp;
> +
> +	if (radeon_atom_get_clock_dividers(rdev, COMPUTE_MEMORY_PLL_PARAM,
> +					   requested_memory_clock, false, &req_dividers) == 0) {
> +		vco_freq_temp = rv6xx_calculate_vco_frequency(ref_clk, &req_dividers,
> +							      pi->fb_div_scale);
> +
> +		if (vco_freq_temp > *vco_freq) {
> +			*dividers = req_dividers;
> +			*vco_freq = vco_freq_temp;
> +		}
> +	}
> +}
> +
> +static void rv6xx_program_mclk_spread_spectrum_parameters(struct radeon_device *rdev)
> +{
> +	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
> +	u32 ref_clk = rdev->clock.mpll.reference_freq;
> +	struct atom_clock_dividers dividers;
> +	struct radeon_atom_ss ss;
> +	u32 vco_freq = 0, clk_v, clk_s;
> +
> +	rv6xx_enable_memory_spread_spectrum(rdev, false);
> +
> +	if (pi->mclk_ss) {
> +		rv6xx_find_memory_clock_with_highest_vco(rdev,
> +							 pi->hw.mclks[pi->hw.high_mclk_index],
> +							 ref_clk,
> +							 &dividers,
> +							 &vco_freq);
> +
> +		rv6xx_find_memory_clock_with_highest_vco(rdev,
> +							 pi->hw.mclks[pi->hw.medium_mclk_index],
> +							 ref_clk,
> +							 &dividers,
> +							 &vco_freq);
> +
> +		rv6xx_find_memory_clock_with_highest_vco(rdev,
> +							 pi->hw.mclks[pi->hw.low_mclk_index],
> +							 ref_clk,
> +							 &dividers,
> +							 &vco_freq);
> +
> +		if (vco_freq) {
> +			if (radeon_atombios_get_asic_ss_info(rdev, &ss,
> +							     ASIC_INTERNAL_MEMORY_SS, vco_freq)) {
> +				clk_v = rv6xx_calculate_spread_spectrum_clk_v(vco_freq,
> +									     (ref_clk / (dividers.ref_div + 1)),
> +									     ss.rate,
> +									     ss.percentage,
> +									     pi->fb_div_scale);
> +
> +				clk_s = rv6xx_calculate_spread_spectrum_clk_s(ss.rate,
> +									     (ref_clk / (dividers.ref_div + 1)));
> +
> +				rv6xx_set_memory_spread_spectrum_clk_v(rdev, clk_v);
> +				rv6xx_set_memory_spread_spectrum_clk_s(rdev, clk_s);
> +				rv6xx_enable_memory_spread_spectrum(rdev, true);
> +			}
> +		}
> +	}
> +}
> +
> +static int rv6xx_program_voltage_stepping_entry(struct radeon_device *rdev,
> +						u32 entry, u16 voltage)
> +{
> +	u32 mask, set_pins;
> +	int ret;
> +
> +	ret = radeon_atom_get_voltage_gpio_settings(rdev, voltage,
> +						    SET_VOLTAGE_TYPE_ASIC_VDDC,
> +						    &set_pins, &mask);
> +	if (ret)
> +		return ret;
> +
> +	r600_voltage_control_program_voltages(rdev, entry, set_pins);
> +
> +	return 0;
> +}
> +
> +static void rv6xx_program_voltage_stepping_parameters_except_lowest_entry(struct radeon_device *rdev)
> +{
> +	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
> +	int i;
> +
> +	for (i = 1; i < R600_PM_NUMBER_OF_VOLTAGE_LEVELS; i++)
> +		rv6xx_program_voltage_stepping_entry(rdev, i,
> +						     pi->hw.vddc[i]);
> +
> +}
> +
> +static void rv6xx_program_backbias_stepping_parameters_except_lowest_entry(struct radeon_device *rdev)
> +{
> +	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
> +
> +	if (pi->hw.backbias[1])
> +		WREG32_P(VID_UPPER_GPIO_CNTL, MEDIUM_BACKBIAS_VALUE, ~MEDIUM_BACKBIAS_VALUE);
> +	else
> +		WREG32_P(VID_UPPER_GPIO_CNTL, 0, ~MEDIUM_BACKBIAS_VALUE);
> +
> +	if (pi->hw.backbias[2])
> +		WREG32_P(VID_UPPER_GPIO_CNTL, HIGH_BACKBIAS_VALUE, ~HIGH_BACKBIAS_VALUE);
> +	else
> +		WREG32_P(VID_UPPER_GPIO_CNTL, 0, ~HIGH_BACKBIAS_VALUE);
> +}
> +
> +static void rv6xx_program_sclk_spread_spectrum_parameters_lowest_entry(struct radeon_device *rdev)
> +{
> +	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
> +
> +	rv6xx_program_engine_spread_spectrum(rdev,
> +					     pi->hw.sclks[R600_POWER_LEVEL_LOW],
> +					     R600_POWER_LEVEL_LOW);
> +}
> +
> +static void rv6xx_program_mclk_stepping_parameters_lowest_entry(struct radeon_device *rdev)
> +{
> +	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
> +
> +	if (pi->hw.mclks[0])
> +		rv6xx_program_mclk_stepping_entry(rdev, 0,
> +						  pi->hw.mclks[0]);
> +}
> +
> +static void rv6xx_program_voltage_stepping_parameters_lowest_entry(struct radeon_device *rdev)
> +{
> +	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
> +
> +	rv6xx_program_voltage_stepping_entry(rdev, 0,
> +					     pi->hw.vddc[0]);
> +
> +}
> +
> +static void rv6xx_program_backbias_stepping_parameters_lowest_entry(struct radeon_device *rdev)
> +{
> +	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
> +
> +	if (pi->hw.backbias[0])
> +		WREG32_P(VID_UPPER_GPIO_CNTL, LOW_BACKBIAS_VALUE, ~LOW_BACKBIAS_VALUE);
> +	else
> +		WREG32_P(VID_UPPER_GPIO_CNTL, 0, ~LOW_BACKBIAS_VALUE);
> +}
> +
> +static u32 calculate_memory_refresh_rate(struct radeon_device *rdev,
> +					 u32 engine_clock)
> +{
> +	u32 dram_rows, dram_refresh_rate;
> +	u32 tmp;
> +
> +	tmp = (RREG32(RAMCFG) & NOOFROWS_MASK) >> NOOFROWS_SHIFT;
> +	dram_rows = 1 << (tmp + 10);
> +	dram_refresh_rate = 1 << ((RREG32(MC_SEQ_RESERVE_M) & 0x3) + 3);
> +
> +	return ((engine_clock * 10) * dram_refresh_rate / dram_rows - 32) / 64;
> +}
> +
> +static void rv6xx_program_memory_timing_parameters(struct radeon_device *rdev)
> +{
> +	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
> +	u32 sqm_ratio;
> +	u32 arb_refresh_rate;
> +	u32 high_clock;
> +
> +	if (pi->hw.sclks[R600_POWER_LEVEL_HIGH] <
> +	    (pi->hw.sclks[R600_POWER_LEVEL_LOW] * 0xFF / 0x40))
> +		high_clock = pi->hw.sclks[R600_POWER_LEVEL_HIGH];
> +	else
> +		high_clock =
> +			pi->hw.sclks[R600_POWER_LEVEL_LOW] * 0xFF / 0x40;
> +
> +	radeon_atom_set_engine_dram_timings(rdev, high_clock, 0);
> +
> +	sqm_ratio = (STATE0(64 * high_clock / pi->hw.sclks[R600_POWER_LEVEL_LOW]) |
> +		     STATE1(64 * high_clock / pi->hw.sclks[R600_POWER_LEVEL_MEDIUM]) |
> +		     STATE2(64 * high_clock / pi->hw.sclks[R600_POWER_LEVEL_HIGH]) |
> +		     STATE3(64 * high_clock / pi->hw.sclks[R600_POWER_LEVEL_HIGH]));
> +	WREG32(SQM_RATIO, sqm_ratio);
> +
> +	arb_refresh_rate =
> +		(POWERMODE0(calculate_memory_refresh_rate(rdev,
> +							  pi->hw.sclks[R600_POWER_LEVEL_LOW])) |
> +		 POWERMODE1(calculate_memory_refresh_rate(rdev,
> +							  pi->hw.sclks[R600_POWER_LEVEL_MEDIUM])) |
> +		 POWERMODE2(calculate_memory_refresh_rate(rdev,
> +							  pi->hw.sclks[R600_POWER_LEVEL_MEDIUM])) |
> +		 POWERMODE3(calculate_memory_refresh_rate(rdev,
> +							  pi->hw.sclks[R600_POWER_LEVEL_HIGH])));
> +	WREG32(ARB_RFSH_RATE, arb_refresh_rate);
> +}
> +
> +static void rv6xx_program_mpll_timing_parameters(struct radeon_device *rdev)
> +{
> +	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
> +
> +	r600_set_mpll_lock_time(rdev, R600_MPLLLOCKTIME_DFLT *
> +				pi->mpll_ref_div);
> +	r600_set_mpll_reset_time(rdev, R600_MPLLRESETTIME_DFLT);
> +}
> +
> +static void rv6xx_program_bsp(struct radeon_device *rdev)
> +{
> +	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
> +	u32 ref_clk = rdev->clock.spll.reference_freq;
> +
> +	r600_calculate_u_and_p(R600_ASI_DFLT,
> +			       ref_clk, 16,
> +			       &pi->bsp,
> +			       &pi->bsu);
> +
> +	r600_set_bsp(rdev, pi->bsu, pi->bsp);
> +}
> +
> +static void rv6xx_program_at(struct radeon_device *rdev)
> +{
> +	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
> +
> +	r600_set_at(rdev,
> +		    (pi->hw.rp[0] * pi->bsp) / 200,
> +		    (pi->hw.rp[1] * pi->bsp) / 200,
> +		    (pi->hw.lp[2] * pi->bsp) / 200,
> +		    (pi->hw.lp[1] * pi->bsp) / 200);
> +}
> +
> +static void rv6xx_program_git(struct radeon_device *rdev)
> +{
> +	r600_set_git(rdev, R600_GICST_DFLT);
> +}
> +
> +static void rv6xx_program_tp(struct radeon_device *rdev)
> +{
> +	int i;
> +
> +	for (i = 0; i < R600_PM_NUMBER_OF_TC; i++)
> +		r600_set_tc(rdev, i, r600_utc[i], r600_dtc[i]);
> +
> +	r600_select_td(rdev, R600_TD_DFLT);
> +}
> +
> +static void rv6xx_program_vc(struct radeon_device *rdev)
> +{
> +	r600_set_vrc(rdev, R600_VRC_DFLT);
> +}
> +
> +static void rv6xx_clear_vc(struct radeon_device *rdev)
> +{
> +	r600_set_vrc(rdev, 0);
> +}
> +
> +static void rv6xx_program_tpp(struct radeon_device *rdev)
> +{
> +	r600_set_tpu(rdev, R600_TPU_DFLT);
> +	r600_set_tpc(rdev, R600_TPC_DFLT);
> +}
> +
> +static void rv6xx_program_sstp(struct radeon_device *rdev)
> +{
> +	r600_set_sstu(rdev, R600_SSTU_DFLT);
> +	r600_set_sst(rdev, R600_SST_DFLT);
> +}
> +
> +static void rv6xx_program_fcp(struct radeon_device *rdev)
> +{
> +	r600_set_fctu(rdev, R600_FCTU_DFLT);
> +	r600_set_fct(rdev, R600_FCT_DFLT);
> +}
> +
> +static void rv6xx_program_vddc3d_parameters(struct radeon_device *rdev)
> +{
> +	r600_set_vddc3d_oorsu(rdev, R600_VDDC3DOORSU_DFLT);
> +	r600_set_vddc3d_oorphc(rdev, R600_VDDC3DOORPHC_DFLT);
> +	r600_set_vddc3d_oorsdc(rdev, R600_VDDC3DOORSDC_DFLT);
> +	r600_set_ctxcgtt3d_rphc(rdev, R600_CTXCGTT3DRPHC_DFLT);
> +	r600_set_ctxcgtt3d_rsdc(rdev, R600_CTXCGTT3DRSDC_DFLT);
> +}
> +
> +static void rv6xx_program_voltage_timing_parameters(struct radeon_device *rdev)
> +{
> +	u32 rt;
> +
> +	r600_vid_rt_set_vru(rdev, R600_VRU_DFLT);
> +
> +	r600_vid_rt_set_vrt(rdev,
> +			    rv6xx_compute_count_for_delay(rdev,
> +							  rdev->pm.dpm.voltage_response_time,
> +							  R600_VRU_DFLT));
> +
> +	rt = rv6xx_compute_count_for_delay(rdev,
> +					   rdev->pm.dpm.backbias_response_time,
> +					   R600_VRU_DFLT);
> +
> +	rv6xx_vid_response_set_brt(rdev, (rt + 0x1F) >> 5);
> +}
> +
> +static void rv6xx_program_engine_speed_parameters(struct radeon_device *rdev)
> +{
> +	r600_vid_rt_set_ssu(rdev, R600_SPLLSTEPUNIT_DFLT);
> +	rv6xx_enable_engine_feedback_and_reference_sync(rdev);
> +}
> +
> +static u64 rv6xx_get_master_voltage_mask(struct radeon_device *rdev)
> +{
> +	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
> +	u64 master_mask = 0;
> +	int i;
> +
> +	for (i = 0; i < R600_PM_NUMBER_OF_VOLTAGE_LEVELS; i++) {
> +		u32 tmp_mask, tmp_set_pins;
> +		int ret;
> +
> +		ret = radeon_atom_get_voltage_gpio_settings(rdev,
> +							    pi->hw.vddc[i],
> +							    SET_VOLTAGE_TYPE_ASIC_VDDC,
> +							    &tmp_set_pins, &tmp_mask);
> +
> +		if (ret == 0)
> +			master_mask |= tmp_mask;
> +	}
> +
> +	return master_mask;
> +}
> +
> +static void rv6xx_program_voltage_gpio_pins(struct radeon_device *rdev)
> +{
> +	r600_voltage_control_enable_pins(rdev,
> +					 rv6xx_get_master_voltage_mask(rdev));
> +}
> +
> +static void rv6xx_enable_static_voltage_control(struct radeon_device *rdev, bool enable)
> +{
> +	struct rv6xx_ps *new_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps);
> +
> +	if (enable)
> +		radeon_atom_set_voltage(rdev,
> +					new_state->low.vddc,
> +					SET_VOLTAGE_TYPE_ASIC_VDDC);
> +	else
> +		r600_voltage_control_deactivate_static_control(rdev,
> +							       rv6xx_get_master_voltage_mask(rdev));
> +}
> +
> +static void rv6xx_enable_display_gap(struct radeon_device *rdev, bool enable)
> +{
> +	if (enable) {
> +		u32 tmp = (DISP1_GAP(R600_PM_DISPLAY_GAP_VBLANK_OR_WM) |
> +			   DISP2_GAP(R600_PM_DISPLAY_GAP_VBLANK_OR_WM) |
> +			   DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE) |
> +			   DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE) |
> +			   VBI_TIMER_COUNT(0x3FFF) |
> +			   VBI_TIMER_UNIT(7));
> +		WREG32(CG_DISPLAY_GAP_CNTL, tmp);
> +
> +		WREG32_P(MCLK_PWRMGT_CNTL, USE_DISPLAY_GAP, ~USE_DISPLAY_GAP);
> +	} else
> +		WREG32_P(MCLK_PWRMGT_CNTL, 0, ~USE_DISPLAY_GAP);
> +}
> +
> +static void rv6xx_program_power_level_enter_state(struct radeon_device *rdev)
> +{
> +	r600_power_level_set_enter_index(rdev, R600_POWER_LEVEL_MEDIUM);
> +}
> +
> +static void rv6xx_calculate_t(u32 l_f, u32 h_f, int h,
> +			      int d_l, int d_r, u8 *l, u8 *r)
> +{
> +	int a_n, a_d, h_r, l_r;
> +
> +	h_r = d_l;
> +	l_r = 100 - d_r;
> +
> +	a_n = (int)h_f * d_l + (int)l_f * (h - d_r);
> +	a_d = (int)l_f * l_r + (int)h_f * h_r;
> +
> +	if (a_d != 0) {
> +		*l = d_l - h_r * a_n / a_d;
> +		*r = d_r + l_r * a_n / a_d;
> +	}
> +}
> +
> +static void rv6xx_calculate_ap(struct radeon_device *rdev,
> +			       struct rv6xx_ps *state)
> +{
> +	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
> +
> +	pi->hw.lp[0] = 0;
> +	pi->hw.rp[R600_PM_NUMBER_OF_ACTIVITY_LEVELS - 1]
> +		= 100;
> +
> +	rv6xx_calculate_t(state->low.sclk,
> +			  state->medium.sclk,
> +			  R600_AH_DFLT,
> +			  R600_LMP_DFLT,
> +			  R600_RLP_DFLT,
> +			  &pi->hw.lp[1],
> +			  &pi->hw.rp[0]);
> +
> +	rv6xx_calculate_t(state->medium.sclk,
> +			  state->high.sclk,
> +			  R600_AH_DFLT,
> +			  R600_LHP_DFLT,
> +			  R600_RMP_DFLT,
> +			  &pi->hw.lp[2],
> +			  &pi->hw.rp[1]);
> +
> +}
> +
> +static void rv6xx_calculate_stepping_parameters(struct radeon_device *rdev)
> +{
> +	struct rv6xx_ps *new_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps);
> +
> +	rv6xx_calculate_engine_speed_stepping_parameters(rdev, new_state);
> +	rv6xx_calculate_memory_clock_stepping_parameters(rdev, new_state);
> +	rv6xx_calculate_voltage_stepping_parameters(rdev, new_state);
> +	rv6xx_calculate_ap(rdev, new_state);
> +}
> +
> +static void rv6xx_program_stepping_parameters_except_lowest_entry(struct radeon_device *rdev)
> +{
> +	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
> +
> +	rv6xx_program_mclk_stepping_parameters_except_lowest_entry(rdev);
> +	if (pi->voltage_control)
> +		rv6xx_program_voltage_stepping_parameters_except_lowest_entry(rdev);
> +	rv6xx_program_backbias_stepping_parameters_except_lowest_entry(rdev);
> +	rv6xx_program_sclk_spread_spectrum_parameters_except_lowest_entry(rdev);
> +	rv6xx_program_mclk_spread_spectrum_parameters(rdev);
> +	rv6xx_program_memory_timing_parameters(rdev);
> +}
> +
> +static void rv6xx_program_stepping_parameters_lowest_entry(struct radeon_device *rdev)
> +{
> +	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
> +
> +	rv6xx_program_mclk_stepping_parameters_lowest_entry(rdev);
> +	if (pi->voltage_control)
> +		rv6xx_program_voltage_stepping_parameters_lowest_entry(rdev);
> +	rv6xx_program_backbias_stepping_parameters_lowest_entry(rdev);
> +	rv6xx_program_sclk_spread_spectrum_parameters_lowest_entry(rdev);
> +}
> +
> +static void rv6xx_program_power_level_low(struct radeon_device *rdev)
> +{
> +	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
> +
> +	r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_LOW,
> +					   pi->hw.low_vddc_index);
> +	r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_LOW,
> +					     pi->hw.low_mclk_index);
> +	r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_LOW,
> +					     pi->hw.low_sclk_index);
> +	r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_LOW,
> +					  R600_DISPLAY_WATERMARK_LOW);
> +	r600_power_level_set_pcie_gen2(rdev, R600_POWER_LEVEL_LOW,
> +				       pi->hw.pcie_gen2[R600_POWER_LEVEL_LOW]);
> +}
> +
> +static void rv6xx_program_power_level_low_to_lowest_state(struct radeon_device *rdev)
> +{
> +	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
> +
> +	r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_LOW, 0);
> +	r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_LOW, 0);
> +	r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_LOW, 0);
> +
> +	r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_LOW,
> +					  R600_DISPLAY_WATERMARK_LOW);
> +
> +	r600_power_level_set_pcie_gen2(rdev, R600_POWER_LEVEL_LOW,
> +				       pi->hw.pcie_gen2[R600_POWER_LEVEL_LOW]);
> +
> +}
> +
> +static void rv6xx_program_power_level_medium(struct radeon_device *rdev)
> +{
> +	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
> +
> +	r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_MEDIUM,
> +					  pi->hw.medium_vddc_index);
> +	r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_MEDIUM,
> +					    pi->hw.medium_mclk_index);
> +	r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_MEDIUM,
> +					    pi->hw.medium_sclk_index);
> +	r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_MEDIUM,
> +					 R600_DISPLAY_WATERMARK_LOW);
> +	r600_power_level_set_pcie_gen2(rdev, R600_POWER_LEVEL_MEDIUM,
> +				      pi->hw.pcie_gen2[R600_POWER_LEVEL_MEDIUM]);
> +}
> +
> +static void rv6xx_program_power_level_medium_for_transition(struct radeon_device *rdev)
> +{
> +	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
> +
> +	rv6xx_program_mclk_stepping_entry(rdev,
> +					  R600_POWER_LEVEL_CTXSW,
> +					  pi->hw.mclks[pi->hw.low_mclk_index]);
> +
> +	r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_MEDIUM, 1);
> +
> +	r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_MEDIUM,
> +					     R600_POWER_LEVEL_CTXSW);
> +	r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_MEDIUM,
> +					     pi->hw.medium_sclk_index);
> +
> +	r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_MEDIUM,
> +					  R600_DISPLAY_WATERMARK_LOW);
> +
> +	rv6xx_enable_engine_spread_spectrum(rdev, R600_POWER_LEVEL_MEDIUM, false);
> +
> +	r600_power_level_set_pcie_gen2(rdev, R600_POWER_LEVEL_MEDIUM,
> +				       pi->hw.pcie_gen2[R600_POWER_LEVEL_LOW]);
> +}
> +
> +static void rv6xx_program_power_level_high(struct radeon_device *rdev)
> +{
> +	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
> +
> +	r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_HIGH,
> +					   pi->hw.high_vddc_index);
> +	r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_HIGH,
> +					     pi->hw.high_mclk_index);
> +	r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_HIGH,
> +					     pi->hw.high_sclk_index);
> +
> +	r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_HIGH,
> +					  R600_DISPLAY_WATERMARK_HIGH);
> +
> +	r600_power_level_set_pcie_gen2(rdev, R600_POWER_LEVEL_HIGH,
> +				       pi->hw.pcie_gen2[R600_POWER_LEVEL_HIGH]);
> +}
> +
> +static void rv6xx_enable_backbias(struct radeon_device *rdev, bool enable)
> +{
> +	if (enable)
> +		WREG32_P(GENERAL_PWRMGT, BACKBIAS_PAD_EN | BACKBIAS_DPM_CNTL,
> +			 ~(BACKBIAS_PAD_EN | BACKBIAS_DPM_CNTL));
> +	else
> +		WREG32_P(GENERAL_PWRMGT, 0,
> +			 ~(BACKBIAS_VALUE | BACKBIAS_PAD_EN | BACKBIAS_DPM_CNTL));
> +}
> +
> +static void rv6xx_program_display_gap(struct radeon_device *rdev)
> +{
> +	u32 tmp = RREG32(CG_DISPLAY_GAP_CNTL);
> +
> +	tmp &= ~(DISP1_GAP_MCHG_MASK | DISP2_GAP_MCHG_MASK);
> +	if (RREG32(AVIVO_D1CRTC_CONTROL) & AVIVO_CRTC_EN) {
> +		tmp |= DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK);
> +		tmp |= DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE);
> +	} else if (RREG32(AVIVO_D2CRTC_CONTROL) & AVIVO_CRTC_EN) {
> +		tmp |= DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE);
> +		tmp |= DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK);
> +	} else {
> +		tmp |= DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE);
> +		tmp |= DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE);
> +	}
> +	WREG32(CG_DISPLAY_GAP_CNTL, tmp);
> +}
> +
> +static void rv6xx_set_sw_voltage_to_safe(struct radeon_device *rdev)
> +{
> +	struct rv6xx_ps *new_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps);
> +	struct rv6xx_ps *old_state = rv6xx_get_ps(rdev->pm.dpm.current_ps);
> +	u16 safe_voltage;
> +
> +	safe_voltage = (new_state->low.vddc >= old_state->low.vddc) ?
> +		new_state->low.vddc : old_state->low.vddc;
> +
> +	rv6xx_program_voltage_stepping_entry(rdev, R600_POWER_LEVEL_CTXSW,
> +					     safe_voltage);
> +
> +	WREG32_P(GENERAL_PWRMGT, SW_GPIO_INDEX(R600_POWER_LEVEL_CTXSW),
> +		 ~SW_GPIO_INDEX_MASK);
> +}
> +
> +static void rv6xx_set_sw_voltage_to_low(struct radeon_device *rdev)
> +{
> +	struct rv6xx_ps *old_state = rv6xx_get_ps(rdev->pm.dpm.current_ps);
> +
> +	rv6xx_program_voltage_stepping_entry(rdev, R600_POWER_LEVEL_CTXSW,
> +					     old_state->low.vddc);
> +
> +	WREG32_P(GENERAL_PWRMGT, SW_GPIO_INDEX(R600_POWER_LEVEL_CTXSW),
> +		~SW_GPIO_INDEX_MASK);
> +}
> +
> +static void rv6xx_set_safe_backbias(struct radeon_device *rdev)
> +{
> +	struct rv6xx_ps *new_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps);
> +	struct rv6xx_ps *old_state = rv6xx_get_ps(rdev->pm.dpm.current_ps);
> +
> +	if ((new_state->low.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) &&
> +	    (old_state->low.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE))
> +		WREG32_P(GENERAL_PWRMGT, BACKBIAS_VALUE, ~BACKBIAS_VALUE);
> +	else
> +		WREG32_P(GENERAL_PWRMGT, 0, ~BACKBIAS_VALUE);
> +}
> +
> +static void rv6xx_set_safe_pcie_gen2(struct radeon_device *rdev)
> +{
> +	struct rv6xx_ps *new_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps);
> +	struct rv6xx_ps *old_state = rv6xx_get_ps(rdev->pm.dpm.current_ps);
> +
> +	if ((new_state->low.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) !=
> +	    (old_state->low.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2))
> +		rv6xx_force_pcie_gen1(rdev);
> +}
> +
> +static void rv6xx_enable_dynamic_voltage_control(struct radeon_device *rdev,
> +						 bool enable)
> +{
> +	if (enable)
> +		WREG32_P(GENERAL_PWRMGT, VOLT_PWRMGT_EN, ~VOLT_PWRMGT_EN);
> +	else
> +		WREG32_P(GENERAL_PWRMGT, 0, ~VOLT_PWRMGT_EN);
> +}
> +
> +static void rv6xx_enable_dynamic_backbias_control(struct radeon_device *rdev,
> +						  bool enable)
> +{
> +	if (enable)
> +		WREG32_P(GENERAL_PWRMGT, BACKBIAS_DPM_CNTL, ~BACKBIAS_DPM_CNTL);
> +	else
> +		WREG32_P(GENERAL_PWRMGT, 0, ~BACKBIAS_DPM_CNTL);
> +}
> +
> +static int rv6xx_step_sw_voltage(struct radeon_device *rdev,
> +				 u16 initial_voltage,
> +				 u16 target_voltage)
> +{
> +	u16 current_voltage;
> +	u16 true_target_voltage;
> +	u16 voltage_step;
> +	int signed_voltage_step;
> +
> +	if ((radeon_atom_get_voltage_step(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC,
> +					  &voltage_step)) ||
> +	    (radeon_atom_round_to_true_voltage(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC,
> +					       initial_voltage, &current_voltage)) ||
> +	    (radeon_atom_round_to_true_voltage(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC,
> +					       target_voltage, &true_target_voltage)))
> +		return -EINVAL;
> +
> +	if (true_target_voltage < current_voltage)
> +		signed_voltage_step = -(int)voltage_step;
> +	else
> +		signed_voltage_step = voltage_step;
> +
> +	while (current_voltage != true_target_voltage) {
> +		current_voltage += signed_voltage_step;
> +		rv6xx_program_voltage_stepping_entry(rdev, R600_POWER_LEVEL_CTXSW,
> +						     current_voltage);
> +		msleep((rdev->pm.dpm.voltage_response_time + 999) / 1000);
> +	}
> +
> +	return 0;
> +}
> +
> +static int rv6xx_step_voltage_if_increasing(struct radeon_device *rdev)
> +{
> +	struct rv6xx_ps *new_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps);
> +	struct rv6xx_ps *old_state = rv6xx_get_ps(rdev->pm.dpm.current_ps);
> +
> +	if (new_state->low.vddc > old_state->low.vddc)
> +		return rv6xx_step_sw_voltage(rdev,
> +					     old_state->low.vddc,
> +					     new_state->low.vddc);
> +
> +	return 0;
> +}
> +
> +static int rv6xx_step_voltage_if_decreasing(struct radeon_device *rdev)
> +{
> +	struct rv6xx_ps *new_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps);
> +	struct rv6xx_ps *old_state = rv6xx_get_ps(rdev->pm.dpm.current_ps);
> +
> +	if (new_state->low.vddc < old_state->low.vddc)
> +		return rv6xx_step_sw_voltage(rdev,
> +					     old_state->low.vddc,
> +					     new_state->low.vddc);
> +	else
> +		return 0;
> +}
> +
> +static void rv6xx_enable_high(struct radeon_device *rdev)
> +{
> +	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
> +
> +	if ((pi->restricted_levels < 1) ||
> +	    (pi->restricted_levels == 3))
> +		r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, true);
> +}
> +
> +static void rv6xx_enable_medium(struct radeon_device *rdev)
> +{
> +	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
> +
> +	if (pi->restricted_levels < 2)
> +		r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, true);
> +}
> +
> +static void rv6xx_set_dpm_event_sources(struct radeon_device *rdev, u32 sources)
> +{
> +	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
> +	bool want_thermal_protection;
> +	enum radeon_dpm_event_src dpm_event_src;
> +
> +	switch (sources) {
> +        case 0:
> +        default:
> +		want_thermal_protection = false;
> +		break;
> +        case (1 << RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL):
> +		want_thermal_protection = true;
> +		dpm_event_src = RADEON_DPM_EVENT_SRC_DIGITAL;
> +		break;
> +
> +        case (1 << RADEON_DPM_AUTO_THROTTLE_SRC_EXTERNAL):
> +		want_thermal_protection = true;
> +		dpm_event_src = RADEON_DPM_EVENT_SRC_EXTERNAL;
> +		break;
> +
> +        case ((1 << RADEON_DPM_AUTO_THROTTLE_SRC_EXTERNAL) |
> +	      (1 << RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL)):
> +		want_thermal_protection = true;
> +		dpm_event_src = RADEON_DPM_EVENT_SRC_DIGIAL_OR_EXTERNAL;
> +		break;
> +	}
> +
> +	if (want_thermal_protection) {
> +		WREG32_P(CG_THERMAL_CTRL, DPM_EVENT_SRC(dpm_event_src), ~DPM_EVENT_SRC_MASK);
> +		if (pi->thermal_protection)
> +			WREG32_P(GENERAL_PWRMGT, 0, ~THERMAL_PROTECTION_DIS);
> +	} else {
> +		WREG32_P(GENERAL_PWRMGT, THERMAL_PROTECTION_DIS, ~THERMAL_PROTECTION_DIS);
> +	}
> +}
> +
> +static void rv6xx_enable_auto_throttle_source(struct radeon_device *rdev,
> +					      enum radeon_dpm_auto_throttle_src source,
> +					      bool enable)
> +{
> +	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
> +
> +	if (enable) {
> +		if (!(pi->active_auto_throttle_sources & (1 << source))) {
> +			pi->active_auto_throttle_sources |= 1 << source;
> +			rv6xx_set_dpm_event_sources(rdev, pi->active_auto_throttle_sources);
> +		}
> +	} else {
> +		if (pi->active_auto_throttle_sources & (1 << source)) {
> +			pi->active_auto_throttle_sources &= ~(1 << source);
> +			rv6xx_set_dpm_event_sources(rdev, pi->active_auto_throttle_sources);
> +		}
> +	}
> +}
> +
> +
> +static void rv6xx_enable_thermal_protection(struct radeon_device *rdev,
> +					    bool enable)
> +{
> +	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
> +
> +	if (pi->active_auto_throttle_sources)
> +		r600_enable_thermal_protection(rdev, enable);
> +}
> +
> +static void rv6xx_generate_transition_stepping(struct radeon_device *rdev)
> +{
> +	struct rv6xx_ps *new_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps);
> +	struct rv6xx_ps *old_state = rv6xx_get_ps(rdev->pm.dpm.current_ps);
> +	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
> +
> +	rv6xx_generate_steps(rdev,
> +			     old_state->low.sclk,
> +			     new_state->low.sclk,
> +			     0, &pi->hw.medium_sclk_index);
> +}
> +
> +static void rv6xx_generate_low_step(struct radeon_device *rdev)
> +{
> +	struct rv6xx_ps *new_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps);
> +	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
> +
> +	pi->hw.low_sclk_index = 0;
> +	rv6xx_generate_single_step(rdev,
> +				   new_state->low.sclk,
> +				   0);
> +}
> +
> +static void rv6xx_invalidate_intermediate_steps(struct radeon_device *rdev)
> +{
> +	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
> +
> +	rv6xx_invalidate_intermediate_steps_range(rdev, 0,
> +						  pi->hw.medium_sclk_index);
> +}
> +
> +static void rv6xx_generate_stepping_table(struct radeon_device *rdev)
> +{
> +	struct rv6xx_ps *new_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps);
> +	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
> +
> +	pi->hw.low_sclk_index = 0;
> +
> +	rv6xx_generate_steps(rdev,
> +			     new_state->low.sclk,
> +			     new_state->medium.sclk,
> +			     0,
> +			     &pi->hw.medium_sclk_index);
> +	rv6xx_generate_steps(rdev,
> +			     new_state->medium.sclk,
> +			     new_state->high.sclk,
> +			     pi->hw.medium_sclk_index,
> +			     &pi->hw.high_sclk_index);
> +}
> +
> +static void rv6xx_enable_spread_spectrum(struct radeon_device *rdev,
> +					 bool enable)
> +{
> +	if (enable)
> +		rv6xx_enable_dynamic_spread_spectrum(rdev, true);
> +	else {
> +		rv6xx_enable_engine_spread_spectrum(rdev, R600_POWER_LEVEL_LOW, false);
> +		rv6xx_enable_engine_spread_spectrum(rdev, R600_POWER_LEVEL_MEDIUM, false);
> +		rv6xx_enable_engine_spread_spectrum(rdev, R600_POWER_LEVEL_HIGH, false);
> +		rv6xx_enable_dynamic_spread_spectrum(rdev, false);
> +		rv6xx_enable_memory_spread_spectrum(rdev, false);
> +	}
> +}
> +
> +static void rv6xx_reset_lvtm_data_sync(struct radeon_device *rdev)
> +{
> +	if (ASIC_IS_DCE3(rdev))
> +		WREG32_P(DCE3_LVTMA_DATA_SYNCHRONIZATION, LVTMA_PFREQCHG, ~LVTMA_PFREQCHG);
> +	else
> +		WREG32_P(LVTMA_DATA_SYNCHRONIZATION, LVTMA_PFREQCHG, ~LVTMA_PFREQCHG);
> +}
> +
> +static void rv6xx_enable_dynamic_pcie_gen2(struct radeon_device *rdev,
> +					   bool enable)
> +{
> +	struct rv6xx_ps *new_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps);
> +
> +	if (enable) {
> +		rv6xx_enable_bif_dynamic_pcie_gen2(rdev, true);
> +		rv6xx_enable_pcie_gen2_support(rdev);
> +		r600_enable_dynamic_pcie_gen2(rdev, true);
> +	} else {
> +		if (!(new_state->low.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2))
> +			rv6xx_force_pcie_gen1(rdev);
> +		rv6xx_enable_bif_dynamic_pcie_gen2(rdev, false);
> +		r600_enable_dynamic_pcie_gen2(rdev, false);
> +	}
> +}
> +
> +int rv6xx_dpm_enable(struct radeon_device *rdev)
> +{
> +	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
> +
> +	if (r600_dynamicpm_enabled(rdev))
> +		return -EINVAL;
> +
> +	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS)
> +		rv6xx_enable_backbias(rdev, true);
> +
> +	if (pi->dynamic_ss)
> +		rv6xx_enable_spread_spectrum(rdev, true);
> +
> +	rv6xx_program_mpll_timing_parameters(rdev);
> +	rv6xx_program_bsp(rdev);
> +	rv6xx_program_git(rdev);
> +	rv6xx_program_tp(rdev);
> +	rv6xx_program_tpp(rdev);
> +	rv6xx_program_sstp(rdev);
> +	rv6xx_program_fcp(rdev);
> +	rv6xx_program_vddc3d_parameters(rdev);
> +	rv6xx_program_voltage_timing_parameters(rdev);
> +	rv6xx_program_engine_speed_parameters(rdev);
> +
> +	rv6xx_enable_display_gap(rdev, true);
> +	if (pi->display_gap == false)
> +		rv6xx_enable_display_gap(rdev, false);
> +
> +	rv6xx_program_power_level_enter_state(rdev);
> +
> +	rv6xx_calculate_stepping_parameters(rdev);
> +
> +	if (pi->voltage_control)
> +		rv6xx_program_voltage_gpio_pins(rdev);
> +
> +	rv6xx_generate_stepping_table(rdev);
> +
> +	rv6xx_program_stepping_parameters_except_lowest_entry(rdev);
> +	rv6xx_program_stepping_parameters_lowest_entry(rdev);
> +
> +	rv6xx_program_power_level_low(rdev);
> +	rv6xx_program_power_level_medium(rdev);
> +	rv6xx_program_power_level_high(rdev);
> +	rv6xx_program_vc(rdev);
> +	rv6xx_program_at(rdev);
> +
> +	r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true);
> +	r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, true);
> +	r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, true);
> +
> +	if (rdev->irq.installed &&
> +	    r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
> +		r600_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
> +		rdev->irq.dpm_thermal = true;
> +		radeon_irq_set(rdev);
> +	}
> +
> +	rv6xx_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true);
> +
> +	r600_start_dpm(rdev);
> +
> +	if (pi->voltage_control)
> +		rv6xx_enable_static_voltage_control(rdev, false);
> +
> +	if (pi->dynamic_pcie_gen2)
> +		rv6xx_enable_dynamic_pcie_gen2(rdev, true);
> +
> +	if (pi->gfx_clock_gating)
> +		r600_gfx_clockgating_enable(rdev, true);
> +
> +	return 0;
> +}
> +
> +void rv6xx_dpm_disable(struct radeon_device *rdev)
> +{
> +	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
> +
> +	if (!r600_dynamicpm_enabled(rdev))
> +		return;
> +
> +	r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true);
> +	r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, true);
> +	rv6xx_enable_display_gap(rdev, false);
> +	rv6xx_clear_vc(rdev);
> +	r600_set_at(rdev, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF);
> +
> +	if (pi->thermal_protection)
> +		r600_enable_thermal_protection(rdev, false);
> +
> +	r600_wait_for_power_level(rdev, R600_POWER_LEVEL_LOW);
> +	r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, false);
> +	r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, false);
> +
> +	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS)
> +		rv6xx_enable_backbias(rdev, false);
> +
> +	rv6xx_enable_spread_spectrum(rdev, false);
> +
> +	if (pi->voltage_control)
> +		rv6xx_enable_static_voltage_control(rdev, true);
> +
> +	if (pi->dynamic_pcie_gen2)
> +		rv6xx_enable_dynamic_pcie_gen2(rdev, false);
> +
> +	if (rdev->irq.installed &&
> +	    r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
> +		rdev->irq.dpm_thermal = false;
> +		radeon_irq_set(rdev);
> +	}
> +
> +	if (pi->gfx_clock_gating)
> +		r600_gfx_clockgating_enable(rdev, false);
> +
> +	r600_stop_dpm(rdev);
> +}
> +
> +int rv6xx_dpm_set_power_state(struct radeon_device *rdev)
> +{
> +	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
> +
> +	rv6xx_clear_vc(rdev);
> +	r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true);
> +	r600_set_at(rdev, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF);
> +
> +	if (pi->thermal_protection)
> +		r600_enable_thermal_protection(rdev, false);
> +
> +	r600_wait_for_power_level(rdev, R600_POWER_LEVEL_LOW);
> +	r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, false);
> +	r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, false);
> +
> +	rv6xx_generate_transition_stepping(rdev);
> +	rv6xx_program_power_level_medium_for_transition(rdev);
> +
> +	if (pi->voltage_control) {
> +		rv6xx_set_sw_voltage_to_safe(rdev);
> +		if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC)
> +			rv6xx_set_sw_voltage_to_low(rdev);
> +	}
> +
> +	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS)
> +		rv6xx_set_safe_backbias(rdev);
> +
> +	if (pi->dynamic_pcie_gen2)
> +		rv6xx_set_safe_pcie_gen2(rdev);
> +
> +	if (pi->voltage_control)
> +		rv6xx_enable_dynamic_voltage_control(rdev, false);
> +
> +	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS)
> +		rv6xx_enable_dynamic_backbias_control(rdev, false);
> +
> +	if (pi->voltage_control) {
> +		if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC)
> +			rv6xx_step_voltage_if_increasing(rdev);
> +		msleep((rdev->pm.dpm.voltage_response_time + 999) / 1000);
> +	}
> +
> +	r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, true);
> +	r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, false);
> +	r600_wait_for_power_level_unequal(rdev, R600_POWER_LEVEL_LOW);
> +
> +	rv6xx_generate_low_step(rdev);
> +	rv6xx_invalidate_intermediate_steps(rdev);
> +	rv6xx_calculate_stepping_parameters(rdev);
> +	rv6xx_program_stepping_parameters_lowest_entry(rdev);
> +	rv6xx_program_power_level_low_to_lowest_state(rdev);
> +
> +	r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true);
> +	r600_wait_for_power_level(rdev, R600_POWER_LEVEL_LOW);
> +	r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, false);
> +
> +	if (pi->voltage_control) {
> +		if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC)
> +			rv6xx_step_voltage_if_decreasing(rdev);
> +		rv6xx_enable_dynamic_voltage_control(rdev, true);
> +	}
> +
> +	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS)
> +		rv6xx_enable_dynamic_backbias_control(rdev, true);
> +
> +	if (pi->dynamic_pcie_gen2)
> +		rv6xx_enable_dynamic_pcie_gen2(rdev, true);
> +
> +	rv6xx_reset_lvtm_data_sync(rdev);
> +
> +	rv6xx_generate_stepping_table(rdev);
> +	rv6xx_program_stepping_parameters_except_lowest_entry(rdev);
> +	rv6xx_program_power_level_low(rdev);
> +	rv6xx_program_power_level_medium(rdev);
> +	rv6xx_program_power_level_high(rdev);
> +	rv6xx_enable_medium(rdev);
> +	rv6xx_enable_high(rdev);
> +
> +	if (pi->thermal_protection)
> +		rv6xx_enable_thermal_protection(rdev, true);
> +	rv6xx_program_vc(rdev);
> +	rv6xx_program_at(rdev);
> +
> +	return 0;
> +}
> +
> +void rv6xx_setup_asic(struct radeon_device *rdev)
> +{
> +	r600_enable_acpi_pm(rdev);
> +
> +	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L0s)
> +		rv6xx_enable_l0s(rdev);
> +	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L1)
> +		rv6xx_enable_l1(rdev);
> +	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_TURNOFFPLL_ASPML1)
> +		rv6xx_enable_pll_sleep_in_l1(rdev);
> +}
> +
> +void rv6xx_dpm_display_configuration_changed(struct radeon_device *rdev)
> +{
> +	rv6xx_program_display_gap(rdev);
> +}
> +
> +union power_info {
> +	struct _ATOM_POWERPLAY_INFO info;
> +	struct _ATOM_POWERPLAY_INFO_V2 info_2;
> +	struct _ATOM_POWERPLAY_INFO_V3 info_3;
> +	struct _ATOM_PPLIB_POWERPLAYTABLE pplib;
> +	struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2;
> +	struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3;
> +};
> +
> +union pplib_clock_info {
> +	struct _ATOM_PPLIB_R600_CLOCK_INFO r600;
> +	struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780;
> +	struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen;
> +	struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo;
> +};
> +
> +union pplib_power_state {
> +	struct _ATOM_PPLIB_STATE v1;
> +	struct _ATOM_PPLIB_STATE_V2 v2;
> +};
> +
> +static void rv6xx_parse_pplib_non_clock_info(struct radeon_device *rdev,
> +					     struct radeon_ps *rps,
> +					     struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info)
> +{
> +	rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings);
> +	rps->class = le16_to_cpu(non_clock_info->usClassification);
> +	rps->class2 = le16_to_cpu(non_clock_info->usClassification2);
> +
> +	if (r600_is_uvd_state(rps->class, rps->class2)) {
> +		rps->vclk = RV6XX_DEFAULT_VCLK_FREQ;
> +		rps->dclk = RV6XX_DEFAULT_DCLK_FREQ;
> +	} else {
> +		rps->vclk = 0;
> +		rps->dclk = 0;
> +	}
> +
> +	if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT)
> +		rdev->pm.dpm.boot_ps = rps;
> +	if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
> +		rdev->pm.dpm.uvd_ps = rps;
> +}
> +
> +static void rv6xx_parse_pplib_clock_info(struct radeon_device *rdev,
> +					 struct radeon_ps *rps, int index,
> +					 union pplib_clock_info *clock_info)
> +{
> +	struct rv6xx_ps *ps = rv6xx_get_ps(rps);
> +	u32 sclk, mclk;
> +	u16 vddc;
> +	struct rv6xx_pl *pl;
> +
> +	switch (index) {
> +	case 0:
> +		pl = &ps->low;
> +		break;
> +	case 1:
> +		pl = &ps->medium;
> +		break;
> +	case 2:
> +	default:
> +		pl = &ps->high;
> +		break;
> +	}
> +
> +	sclk = le16_to_cpu(clock_info->r600.usEngineClockLow);
> +	sclk |= clock_info->r600.ucEngineClockHigh << 16;
> +	mclk = le16_to_cpu(clock_info->r600.usMemoryClockLow);
> +	mclk |= clock_info->r600.ucMemoryClockHigh << 16;
> +
> +	pl->mclk = mclk;
> +	pl->sclk = sclk;
> +	pl->vddc = le16_to_cpu(clock_info->r600.usVDDC);
> +	pl->flags = le32_to_cpu(clock_info->r600.ulFlags);
> +
> +	/* patch up vddc if necessary */
> +	if (pl->vddc == 0xff01) {
> +		if (radeon_atom_get_max_vddc(rdev, 0, 0, &vddc) == 0)
> +			pl->vddc = vddc;
> +	}
> +
> +	/* fix up pcie gen2 */
> +	if (pl->flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) {
> +		if ((rdev->family == CHIP_RV610) || (rdev->family == CHIP_RV630)) {
> +			if (pl->vddc < 1100)
> +				pl->flags &= ~ATOM_PPLIB_R600_FLAGS_PCIEGEN2;
> +		}
> +	}
> +
> +	/* patch up boot state */
> +	if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) {
> +		u16 vddc, vddci;
> +		radeon_atombios_get_default_voltages(rdev, &vddc, &vddci);
> +		pl->mclk = rdev->clock.default_mclk;
> +		pl->sclk = rdev->clock.default_sclk;
> +		pl->vddc = vddc;
> +	}
> +}
> +
> +static int rv6xx_parse_power_table(struct radeon_device *rdev)
> +{
> +	struct radeon_mode_info *mode_info = &rdev->mode_info;
> +	struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
> +	union pplib_power_state *power_state;
> +	int i, j;
> +	union pplib_clock_info *clock_info;
> +	union power_info *power_info;
> +	int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
> +        u16 data_offset;
> +	u8 frev, crev;
> +	struct rv6xx_ps *ps;
> +
> +	if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
> +				   &frev, &crev, &data_offset))
> +		return -EINVAL;
> +	power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
> +
> +	rdev->pm.dpm.ps = kzalloc(sizeof(struct radeon_ps) *
> +				  power_info->pplib.ucNumStates, GFP_KERNEL);
> +	if (!rdev->pm.dpm.ps)
> +		return -ENOMEM;
> +	rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps);
> +	rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime);
> +	rdev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime);
> +
> +	for (i = 0; i < power_info->pplib.ucNumStates; i++) {
> +		power_state = (union pplib_power_state *)
> +			(mode_info->atom_context->bios + data_offset +
> +			 le16_to_cpu(power_info->pplib.usStateArrayOffset) +
> +			 i * power_info->pplib.ucStateEntrySize);
> +		non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
> +			(mode_info->atom_context->bios + data_offset +
> +			 le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset) +
> +			 (power_state->v1.ucNonClockStateIndex *
> +			  power_info->pplib.ucNonClockSize));
> +		if (power_info->pplib.ucStateEntrySize - 1) {
> +			ps = kzalloc(sizeof(struct rv6xx_ps), GFP_KERNEL);
> +			if (ps == NULL) {
> +				kfree(rdev->pm.dpm.ps);
> +				return -ENOMEM;
> +			}
> +			rdev->pm.dpm.ps[i].ps_priv = ps;
> +			rv6xx_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i],
> +							 non_clock_info);
> +			for (j = 0; j < (power_info->pplib.ucStateEntrySize - 1); j++) {
> +				clock_info = (union pplib_clock_info *)
> +					(mode_info->atom_context->bios + data_offset +
> +					 le16_to_cpu(power_info->pplib.usClockInfoArrayOffset) +
> +					 (power_state->v1.ucClockStateIndices[j] *
> +					  power_info->pplib.ucClockInfoSize));
> +				rv6xx_parse_pplib_clock_info(rdev,
> +							     &rdev->pm.dpm.ps[i], j,
> +							     clock_info);
> +			}
> +		}
> +	}
> +	rdev->pm.dpm.num_ps = power_info->pplib.ucNumStates;
> +	return 0;
> +}
> +
> +int rv6xx_dpm_init(struct radeon_device *rdev)
> +{
> +	int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info);
> +	uint16_t data_offset, size;
> +	uint8_t frev, crev;
> +	struct atom_clock_dividers dividers;
> +	struct rv6xx_power_info *pi;
> +	int ret;
> +
> +	pi = kzalloc(sizeof(struct rv6xx_power_info), GFP_KERNEL);
> +	if (pi == NULL)
> +		return -ENOMEM;
> +	rdev->pm.dpm.priv = pi;
> +
> +	ret = rv6xx_parse_power_table(rdev);
> +	if (ret)
> +		return ret;
> +
> +	if (rdev->pm.dpm.voltage_response_time == 0)
> +		rdev->pm.dpm.voltage_response_time = R600_VOLTAGERESPONSETIME_DFLT;
> +	if (rdev->pm.dpm.backbias_response_time == 0)
> +		rdev->pm.dpm.backbias_response_time = R600_BACKBIASRESPONSETIME_DFLT;
> +
> +	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
> +					     0, false, &dividers);
> +	if (ret)
> +		pi->spll_ref_div = dividers.ref_div + 1;
> +	else
> +		pi->spll_ref_div = R600_REFERENCEDIVIDER_DFLT;
> +
> +	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_MEMORY_PLL_PARAM,
> +					     0, false, &dividers);
> +	if (ret)
> +		pi->mpll_ref_div = dividers.ref_div + 1;
> +	else
> +		pi->mpll_ref_div = R600_REFERENCEDIVIDER_DFLT;
> +
> +	if (rdev->family >= CHIP_RV670)
> +		pi->fb_div_scale = 1;
> +	else
> +		pi->fb_div_scale = 0;
> +
> +	pi->voltage_control =
> +		radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC);
> +
> +	pi->gfx_clock_gating = true;
> +
> +	if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
> +                                   &frev, &crev, &data_offset)) {
> +		pi->sclk_ss = true;
> +		pi->mclk_ss = true;
> +		pi->dynamic_ss = true;
> +	} else {
> +		pi->sclk_ss = false;
> +		pi->mclk_ss = false;
> +		pi->dynamic_ss = false;
> +	}
> +
> +	pi->dynamic_pcie_gen2 = true;
> +
> +	if (pi->gfx_clock_gating &&
> +	    (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE))
> +		pi->thermal_protection = true;
> +	else
> +		pi->thermal_protection = false;
> +
> +	pi->display_gap = true;
> +
> +	return 0;
> +}
> +
> +void rv6xx_dpm_print_power_state(struct radeon_device *rdev,
> +				 struct radeon_ps *rps)
> +{
> +	struct rv6xx_ps *ps = rv6xx_get_ps(rps);
> +	struct rv6xx_pl *pl;
> +
> +	r600_dpm_print_class_info(rps->class, rps->class2);
> +	r600_dpm_print_cap_info(rps->caps);
> +	printk("\tuvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
> +	pl = &ps->low;
> +	printk("\t\tpower level 0    sclk: %u mclk: %u vddc: %u\n",
> +	       pl->sclk, pl->mclk, pl->vddc);
> +	pl = &ps->medium;
> +	printk("\t\tpower level 1    sclk: %u mclk: %u vddc: %u\n",
> +	       pl->sclk, pl->mclk, pl->vddc);
> +	pl = &ps->high;
> +	printk("\t\tpower level 2    sclk: %u mclk: %u vddc: %u\n",
> +	       pl->sclk, pl->mclk, pl->vddc);
> +	r600_dpm_print_ps_status(rdev, rps);
> +}
> +
> +void rv6xx_dpm_fini(struct radeon_device *rdev)
> +{
> +	int i;
> +
> +	for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
> +		kfree(rdev->pm.dpm.ps[i].ps_priv);
> +	}
> +	kfree(rdev->pm.dpm.ps);
> +	kfree(rdev->pm.dpm.priv);
> +}
> +
> +u32 rv6xx_dpm_get_sclk(struct radeon_device *rdev, bool low)
> +{
> +	struct rv6xx_ps *requested_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps);
> +
> +	if (low)
> +		return requested_state->low.sclk;
> +	else
> +		return requested_state->high.sclk;
> +}
> +
> +u32 rv6xx_dpm_get_mclk(struct radeon_device *rdev, bool low)
> +{
> +	struct rv6xx_ps *requested_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps);
> +
> +	if (low)
> +		return requested_state->low.mclk;
> +	else
> +		return requested_state->high.mclk;
> +}
> diff --git a/drivers/gpu/drm/radeon/rv6xx_dpm.h b/drivers/gpu/drm/radeon/rv6xx_dpm.h
> new file mode 100644
> index 0000000..8035d53
> --- /dev/null
> +++ b/drivers/gpu/drm/radeon/rv6xx_dpm.h
> @@ -0,0 +1,95 @@
> +/*
> + * Copyright 2011 Advanced Micro Devices, Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + *
> + * Authors: Alex Deucher
> + */
> +
> +#ifndef __RV6XX_DPM_H__
> +#define __RV6XX_DPM_H__
> +
> +#include "r600_dpm.h"
> +
> +/* Represents a single SCLK step. */
> +struct rv6xx_sclk_stepping
> +{
> +    u32 vco_frequency;
> +    u32 post_divider;
> +};
> +
> +struct rv6xx_pm_hw_state {
> +	u32 sclks[R600_PM_NUMBER_OF_ACTIVITY_LEVELS];
> +	u32 mclks[R600_PM_NUMBER_OF_MCLKS];
> +	u16 vddc[R600_PM_NUMBER_OF_VOLTAGE_LEVELS];
> +	bool backbias[R600_PM_NUMBER_OF_VOLTAGE_LEVELS];
> +	bool pcie_gen2[R600_PM_NUMBER_OF_ACTIVITY_LEVELS];
> +	u8 high_sclk_index;
> +	u8 medium_sclk_index;
> +	u8 low_sclk_index;
> +	u8 high_mclk_index;
> +	u8 medium_mclk_index;
> +	u8 low_mclk_index;
> +	u8 high_vddc_index;
> +	u8 medium_vddc_index;
> +	u8 low_vddc_index;
> +	u8 rp[R600_PM_NUMBER_OF_ACTIVITY_LEVELS];
> +	u8 lp[R600_PM_NUMBER_OF_ACTIVITY_LEVELS];
> +};
> +
> +struct rv6xx_power_info {
> +	/* flags */
> +	bool voltage_control;
> +	bool sclk_ss;
> +	bool mclk_ss;
> +	bool dynamic_ss;
> +	bool dynamic_pcie_gen2;
> +	bool thermal_protection;
> +	bool display_gap;
> +	bool gfx_clock_gating;
> +	/* clk values */
> +	u32 fb_div_scale;
> +	u32 spll_ref_div;
> +	u32 mpll_ref_div;
> +	u32 bsu;
> +	u32 bsp;
> +	/* */
> +	u32 active_auto_throttle_sources;
> +	/* current power state */
> +	u32 restricted_levels;
> +	struct rv6xx_pm_hw_state hw;
> +};
> +
> +struct rv6xx_pl {
> +	u32 sclk;
> +	u32 mclk;
> +	u16 vddc;
> +	u32 flags;
> +};
> +
> +struct rv6xx_ps {
> +	struct rv6xx_pl high;
> +	struct rv6xx_pl medium;
> +	struct rv6xx_pl low;
> +};
> +
> +#define RV6XX_DEFAULT_VCLK_FREQ  40000 /* 10 khz */
> +#define RV6XX_DEFAULT_DCLK_FREQ  30000 /* 10 khz */
> +
> +#endif
> diff --git a/drivers/gpu/drm/radeon/rv6xxd.h b/drivers/gpu/drm/radeon/rv6xxd.h
> new file mode 100644
> index 0000000..34e86f9
> --- /dev/null
> +++ b/drivers/gpu/drm/radeon/rv6xxd.h
> @@ -0,0 +1,246 @@
> +/*
> + * Copyright 2011 Advanced Micro Devices, Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + *
> + */
> +#ifndef RV6XXD_H
> +#define RV6XXD_H
> +
> +/* RV6xx power management */
> +#define SPLL_CNTL_MODE                                    0x60c
> +#       define SPLL_DIV_SYNC                              (1 << 5)
> +
> +#define GENERAL_PWRMGT                                    0x618
> +#       define GLOBAL_PWRMGT_EN                           (1 << 0)
> +#       define STATIC_PM_EN                               (1 << 1)
> +#       define MOBILE_SU                                  (1 << 2)
> +#       define THERMAL_PROTECTION_DIS                     (1 << 3)
> +#       define THERMAL_PROTECTION_TYPE                    (1 << 4)
> +#       define ENABLE_GEN2PCIE                            (1 << 5)
> +#       define SW_GPIO_INDEX(x)                           ((x) << 6)
> +#       define SW_GPIO_INDEX_MASK                         (3 << 6)
> +#       define LOW_VOLT_D2_ACPI                           (1 << 8)
> +#       define LOW_VOLT_D3_ACPI                           (1 << 9)
> +#       define VOLT_PWRMGT_EN                             (1 << 10)
> +#       define BACKBIAS_PAD_EN                            (1 << 16)
> +#       define BACKBIAS_VALUE                             (1 << 17)
> +#       define BACKBIAS_DPM_CNTL                          (1 << 18)
> +#       define DYN_SPREAD_SPECTRUM_EN                     (1 << 21)
> +
> +#define MCLK_PWRMGT_CNTL                                  0x624
> +#       define MPLL_PWRMGT_OFF                            (1 << 0)
> +#       define YCLK_TURNOFF                               (1 << 1)
> +#       define MPLL_TURNOFF                               (1 << 2)
> +#       define SU_MCLK_USE_BCLK                           (1 << 3)
> +#       define DLL_READY                                  (1 << 4)
> +#       define MC_BUSY                                    (1 << 5)
> +#       define MC_INT_CNTL                                (1 << 7)
> +#       define MRDCKA_SLEEP                               (1 << 8)
> +#       define MRDCKB_SLEEP                               (1 << 9)
> +#       define MRDCKC_SLEEP                               (1 << 10)
> +#       define MRDCKD_SLEEP                               (1 << 11)
> +#       define MRDCKE_SLEEP                               (1 << 12)
> +#       define MRDCKF_SLEEP                               (1 << 13)
> +#       define MRDCKG_SLEEP                               (1 << 14)
> +#       define MRDCKH_SLEEP                               (1 << 15)
> +#       define MRDCKA_RESET                               (1 << 16)
> +#       define MRDCKB_RESET                               (1 << 17)
> +#       define MRDCKC_RESET                               (1 << 18)
> +#       define MRDCKD_RESET                               (1 << 19)
> +#       define MRDCKE_RESET                               (1 << 20)
> +#       define MRDCKF_RESET                               (1 << 21)
> +#       define MRDCKG_RESET                               (1 << 22)
> +#       define MRDCKH_RESET                               (1 << 23)
> +#       define DLL_READY_READ                             (1 << 24)
> +#       define USE_DISPLAY_GAP                            (1 << 25)
> +#       define USE_DISPLAY_URGENT_NORMAL                  (1 << 26)
> +#       define USE_DISPLAY_GAP_CTXSW                      (1 << 27)
> +#       define MPLL_TURNOFF_D2                            (1 << 28)
> +#       define USE_DISPLAY_URGENT_CTXSW                   (1 << 29)
> +
> +#define MPLL_FREQ_LEVEL_0                                 0x6e8
> +#       define LEVEL0_MPLL_POST_DIV(x)                    ((x) << 0)
> +#       define LEVEL0_MPLL_POST_DIV_MASK                  (0xff << 0)
> +#       define LEVEL0_MPLL_FB_DIV(x)                      ((x) << 8)
> +#       define LEVEL0_MPLL_FB_DIV_MASK                    (0xfff << 8)
> +#       define LEVEL0_MPLL_REF_DIV(x)                     ((x) << 20)
> +#       define LEVEL0_MPLL_REF_DIV_MASK                   (0x3f << 20)
> +#       define LEVEL0_MPLL_DIV_EN                         (1 << 28)
> +#       define LEVEL0_DLL_BYPASS                          (1 << 29)
> +#       define LEVEL0_DLL_RESET                           (1 << 30)
> +
> +#define VID_RT                                            0x6f8
> +#       define VID_CRT(x)                                 ((x) << 0)
> +#       define VID_CRT_MASK                               (0x1fff << 0)
> +#       define VID_CRTU(x)                                ((x) << 13)
> +#       define VID_CRTU_MASK                              (7 << 13)
> +#       define SSTU(x)                                    ((x) << 16)
> +#       define SSTU_MASK                                  (7 << 16)
> +#       define VID_SWT(x)                                 ((x) << 19)
> +#       define VID_SWT_MASK                               (0x1f << 19)
> +#       define BRT(x)                                     ((x) << 24)
> +#       define BRT_MASK                                   (0xff << 24)
> +
> +#define TARGET_AND_CURRENT_PROFILE_INDEX                  0x70c
> +#       define TARGET_PROFILE_INDEX_MASK                  (3 << 0)
> +#       define TARGET_PROFILE_INDEX_SHIFT                 0
> +#       define CURRENT_PROFILE_INDEX_MASK                 (3 << 2)
> +#       define CURRENT_PROFILE_INDEX_SHIFT                2
> +#       define DYN_PWR_ENTER_INDEX(x)                     ((x) << 4)
> +#       define DYN_PWR_ENTER_INDEX_MASK                   (3 << 4)
> +#       define DYN_PWR_ENTER_INDEX_SHIFT                  4
> +#       define CURR_MCLK_INDEX_MASK                       (3 << 6)
> +#       define CURR_MCLK_INDEX_SHIFT                      6
> +#       define CURR_SCLK_INDEX_MASK                       (0x1f << 8)
> +#       define CURR_SCLK_INDEX_SHIFT                      8
> +#       define CURR_VID_INDEX_MASK                        (3 << 13)
> +#       define CURR_VID_INDEX_SHIFT                       13
> +
> +#define VID_UPPER_GPIO_CNTL                               0x740
> +#       define CTXSW_UPPER_GPIO_VALUES(x)                 ((x) << 0)
> +#       define CTXSW_UPPER_GPIO_VALUES_MASK               (7 << 0)
> +#       define HIGH_UPPER_GPIO_VALUES(x)                  ((x) << 3)
> +#       define HIGH_UPPER_GPIO_VALUES_MASK                (7 << 3)
> +#       define MEDIUM_UPPER_GPIO_VALUES(x)                ((x) << 6)
> +#       define MEDIUM_UPPER_GPIO_VALUES_MASK              (7 << 6)
> +#       define LOW_UPPER_GPIO_VALUES(x)                   ((x) << 9)
> +#       define LOW_UPPER_GPIO_VALUES_MASK                 (7 << 9)
> +#       define CTXSW_BACKBIAS_VALUE                       (1 << 12)
> +#       define HIGH_BACKBIAS_VALUE                        (1 << 13)
> +#       define MEDIUM_BACKBIAS_VALUE                      (1 << 14)
> +#       define LOW_BACKBIAS_VALUE                         (1 << 15)
> +
> +#define CG_DISPLAY_GAP_CNTL                               0x7dc
> +#       define DISP1_GAP(x)                               ((x) << 0)
> +#       define DISP1_GAP_MASK                             (3 << 0)
> +#       define DISP2_GAP(x)                               ((x) << 2)
> +#       define DISP2_GAP_MASK                             (3 << 2)
> +#       define VBI_TIMER_COUNT(x)                         ((x) << 4)
> +#       define VBI_TIMER_COUNT_MASK                       (0x3fff << 4)
> +#       define VBI_TIMER_UNIT(x)                          ((x) << 20)
> +#       define VBI_TIMER_UNIT_MASK                        (7 << 20)
> +#       define DISP1_GAP_MCHG(x)                          ((x) << 24)
> +#       define DISP1_GAP_MCHG_MASK                        (3 << 24)
> +#       define DISP2_GAP_MCHG(x)                          ((x) << 26)
> +#       define DISP2_GAP_MCHG_MASK                        (3 << 26)
> +
> +#define CG_THERMAL_CTRL                                   0x7f0
> +#       define DPM_EVENT_SRC(x)                           ((x) << 0)
> +#       define DPM_EVENT_SRC_MASK                         (7 << 0)
> +#       define THERM_INC_CLK                              (1 << 3)
> +#       define TOFFSET(x)                                 ((x) << 4)
> +#       define TOFFSET_MASK                               (0xff << 4)
> +#       define DIG_THERM_DPM(x)                           ((x) << 12)
> +#       define DIG_THERM_DPM_MASK                         (0xff << 12)
> +#       define CTF_SEL(x)                                 ((x) << 20)
> +#       define CTF_SEL_MASK                               (7 << 20)
> +#       define CTF_PAD_POLARITY                           (1 << 23)
> +#       define CTF_PAD_EN                                 (1 << 24)
> +
> +#define CG_SPLL_SPREAD_SPECTRUM_LOW                       0x820
> +#       define SSEN                                       (1 << 0)
> +#       define CLKS(x)                                    ((x) << 3)
> +#       define CLKS_MASK                                  (0xff << 3)
> +#       define CLKS_SHIFT                                 3
> +#       define CLKV(x)                                    ((x) << 11)
> +#       define CLKV_MASK                                  (0x7ff << 11)
> +#       define CLKV_SHIFT                                 11
> +#define CG_MPLL_SPREAD_SPECTRUM                           0x830
> +
> +#define CITF_CNTL					0x200c
> +#       define BLACKOUT_RD                              (1 << 0)
> +#       define BLACKOUT_WR                              (1 << 1)
> +
> +#define RAMCFG						0x2408
> +#define		NOOFBANK_SHIFT					0
> +#define		NOOFBANK_MASK					0x00000001
> +#define		NOOFRANK_SHIFT					1
> +#define		NOOFRANK_MASK					0x00000002
> +#define		NOOFROWS_SHIFT					2
> +#define		NOOFROWS_MASK					0x0000001C
> +#define		NOOFCOLS_SHIFT					5
> +#define		NOOFCOLS_MASK					0x00000060
> +#define		CHANSIZE_SHIFT					7
> +#define		CHANSIZE_MASK					0x00000080
> +#define		BURSTLENGTH_SHIFT				8
> +#define		BURSTLENGTH_MASK				0x00000100
> +#define		CHANSIZE_OVERRIDE				(1 << 10)
> +
> +#define SQM_RATIO					0x2424
> +#       define STATE0(x)                                ((x) << 0)
> +#       define STATE0_MASK                              (0xff << 0)
> +#       define STATE1(x)                                ((x) << 8)
> +#       define STATE1_MASK                              (0xff << 8)
> +#       define STATE2(x)                                ((x) << 16)
> +#       define STATE2_MASK                              (0xff << 16)
> +#       define STATE3(x)                                ((x) << 24)
> +#       define STATE3_MASK                              (0xff << 24)
> +
> +#define ARB_RFSH_CNTL					0x2460
> +#       define ENABLE                                   (1 << 0)
> +#define ARB_RFSH_RATE					0x2464
> +#       define POWERMODE0(x)                            ((x) << 0)
> +#       define POWERMODE0_MASK                          (0xff << 0)
> +#       define POWERMODE1(x)                            ((x) << 8)
> +#       define POWERMODE1_MASK                          (0xff << 8)
> +#       define POWERMODE2(x)                            ((x) << 16)
> +#       define POWERMODE2_MASK                          (0xff << 16)
> +#       define POWERMODE3(x)                            ((x) << 24)
> +#       define POWERMODE3_MASK                          (0xff << 24)
> +
> +#define MC_SEQ_DRAM					0x2608
> +#       define CKE_DYN                                  (1 << 12)
> +
> +#define MC_SEQ_CMD					0x26c4
> +
> +#define MC_SEQ_RESERVE_S				0x2890
> +#define MC_SEQ_RESERVE_M				0x2894
> +
> +#define LVTMA_DATA_SYNCHRONIZATION                      0x7adc
> +#       define LVTMA_PFREQCHG                           (1 << 8)
> +#define DCE3_LVTMA_DATA_SYNCHRONIZATION                 0x7f98
> +
> +/* PCIE indirect regs */
> +#define PCIE_P_CNTL                                       0x40
> +#       define P_PLL_PWRDN_IN_L1L23                       (1 << 3)
> +#       define P_PLL_BUF_PDNB                             (1 << 4)
> +#       define P_PLL_PDNB                                 (1 << 9)
> +#       define P_ALLOW_PRX_FRONTEND_SHUTOFF               (1 << 12)
> +/* PCIE PORT indirect regs */
> +#define PCIE_LC_CNTL                                      0xa0
> +#       define LC_L0S_INACTIVITY(x)                       ((x) << 8)
> +#       define LC_L0S_INACTIVITY_MASK                     (0xf << 8)
> +#       define LC_L0S_INACTIVITY_SHIFT                    8
> +#       define LC_L1_INACTIVITY(x)                        ((x) << 12)
> +#       define LC_L1_INACTIVITY_MASK                      (0xf << 12)
> +#       define LC_L1_INACTIVITY_SHIFT                     12
> +#       define LC_PMI_TO_L1_DIS                           (1 << 16)
> +#       define LC_ASPM_TO_L1_DIS                          (1 << 24)
> +#define PCIE_LC_SPEED_CNTL                                0xa4
> +#       define LC_GEN2_EN                                 (1 << 0)
> +#       define LC_INITIATE_LINK_SPEED_CHANGE              (1 << 7)
> +#       define LC_CURRENT_DATA_RATE                       (1 << 11)
> +#       define LC_HW_VOLTAGE_IF_CONTROL(x)                ((x) << 12)
> +#       define LC_HW_VOLTAGE_IF_CONTROL_MASK              (3 << 12)
> +#       define LC_HW_VOLTAGE_IF_CONTROL_SHIFT             12
> +#       define LC_OTHER_SIDE_EVER_SENT_GEN2               (1 << 23)
> +#       define LC_OTHER_SIDE_SUPPORTS_GEN2                (1 << 24)
> +
> +#endif

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 075/165] drm/radeon/kms: add dpm support for rs780/rs880
  2013-06-26 10:46   ` Jerome Glisse
@ 2013-06-26 18:19     ` Alex Deucher
  2013-06-26 13:18       ` Jerome Glisse
  0 siblings, 1 reply; 142+ messages in thread
From: Alex Deucher @ 2013-06-26 18:19 UTC (permalink / raw)
  To: Jerome Glisse; +Cc: Alex Deucher, dri-devel

On Wed, Jun 26, 2013 at 6:46 AM, Jerome Glisse <j.glisse@gmail.com> wrote:
> On Wed, Jun 26, 2013 at 09:22:35AM -0400, alexdeucher@gmail.com wrote:
>> From: Alex Deucher <alexander.deucher@amd.com>
>>
>> This adds dpm support for rs780/rs880 asics.  This includes:
>> - clockgating
>> - dynamic engine clock scaling
>> - dynamic voltage scaling
>>
>> set radeon.dpm=1 to enable it.
>>
>> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
>
> Depending on the answer to inline question :
>
> Reviewed-by: Jerome Glisse <jglisse@redhat.com>
>
>> ---
>>  drivers/gpu/drm/radeon/Makefile      |    2 +-
>>  drivers/gpu/drm/radeon/radeon_asic.c |   12 +
>>  drivers/gpu/drm/radeon/radeon_asic.h |   12 +
>>  drivers/gpu/drm/radeon/radeon_pm.c   |    7 +
>>  drivers/gpu/drm/radeon/rs780_dpm.c   |  894 ++++++++++++++++++++++++++++++++++
>>  drivers/gpu/drm/radeon/rs780_dpm.h   |  109 ++++
>>  drivers/gpu/drm/radeon/rs780d.h      |  168 +++++++
>>  7 files changed, 1203 insertions(+), 1 deletions(-)
>>  create mode 100644 drivers/gpu/drm/radeon/rs780_dpm.c
>>  create mode 100644 drivers/gpu/drm/radeon/rs780_dpm.h
>>  create mode 100644 drivers/gpu/drm/radeon/rs780d.h
>>
>> diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile
>> index a131a13..e44b046 100644
>> --- a/drivers/gpu/drm/radeon/Makefile
>> +++ b/drivers/gpu/drm/radeon/Makefile
>> @@ -77,7 +77,7 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \
>>       evergreen_hdmi.o radeon_trace_points.o ni.o cayman_blit_shaders.o \
>>       atombios_encoders.o radeon_semaphore.o radeon_sa.o atombios_i2c.o si.o \
>>       si_blit_shaders.o radeon_prime.o radeon_uvd.o cik.o cik_blit_shaders.o \
>> -     r600_dpm.o
>> +     r600_dpm.o rs780_dpm.o
>>
>>  radeon-$(CONFIG_COMPAT) += radeon_ioc32.o
>>  radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o
>> diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c
>> index d9c8e9a..db3c930 100644
>> --- a/drivers/gpu/drm/radeon/radeon_asic.c
>> +++ b/drivers/gpu/drm/radeon/radeon_asic.c
>> @@ -1194,6 +1194,18 @@ static struct radeon_asic rs780_asic = {
>>               .set_clock_gating = NULL,
>>               .get_temperature = &rv6xx_get_temp,
>>       },
>> +     .dpm = {
>> +             .init = &rs780_dpm_init,
>> +             .setup_asic = &rs780_dpm_setup_asic,
>> +             .enable = &rs780_dpm_enable,
>> +             .disable = &rs780_dpm_disable,
>> +             .set_power_state = &rs780_dpm_set_power_state,
>> +             .display_configuration_changed = &rs780_dpm_display_configuration_changed,
>> +             .fini = &rs780_dpm_fini,
>> +             .get_sclk = &rs780_dpm_get_sclk,
>> +             .get_mclk = &rs780_dpm_get_mclk,
>> +             .print_power_state = &rs780_dpm_print_power_state,
>> +     },
>>       .pflip = {
>>               .pre_page_flip = &rs600_pre_page_flip,
>>               .page_flip = &rs600_page_flip,
>> diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
>> index 8507cae..134bf57 100644
>> --- a/drivers/gpu/drm/radeon/radeon_asic.h
>> +++ b/drivers/gpu/drm/radeon/radeon_asic.h
>> @@ -396,6 +396,18 @@ int r600_mc_wait_for_idle(struct radeon_device *rdev);
>>  u32 r600_get_xclk(struct radeon_device *rdev);
>>  uint64_t r600_get_gpu_clock_counter(struct radeon_device *rdev);
>>  int rv6xx_get_temp(struct radeon_device *rdev);
>> +/* rs780 dpm */
>> +int rs780_dpm_init(struct radeon_device *rdev);
>> +int rs780_dpm_enable(struct radeon_device *rdev);
>> +void rs780_dpm_disable(struct radeon_device *rdev);
>> +int rs780_dpm_set_power_state(struct radeon_device *rdev);
>> +void rs780_dpm_setup_asic(struct radeon_device *rdev);
>> +void rs780_dpm_display_configuration_changed(struct radeon_device *rdev);
>> +void rs780_dpm_fini(struct radeon_device *rdev);
>> +u32 rs780_dpm_get_sclk(struct radeon_device *rdev, bool low);
>> +u32 rs780_dpm_get_mclk(struct radeon_device *rdev, bool low);
>> +void rs780_dpm_print_power_state(struct radeon_device *rdev,
>> +                              struct radeon_ps *ps);
>>
>>  /* uvd */
>>  int r600_uvd_init(struct radeon_device *rdev);
>> diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
>> index 4f5422e..853a8a2 100644
>> --- a/drivers/gpu/drm/radeon/radeon_pm.c
>> +++ b/drivers/gpu/drm/radeon/radeon_pm.c
>> @@ -1030,6 +1030,13 @@ int radeon_pm_init(struct radeon_device *rdev)
>>  {
>>       /* enable dpm on rv6xx+ */
>>       switch (rdev->family) {
>> +     case CHIP_RS780:
>> +     case CHIP_RS880:
>> +             if (radeon_dpm == 1)
>> +                     rdev->pm.pm_method = PM_METHOD_DPM;
>> +             else
>> +                     rdev->pm.pm_method = PM_METHOD_PROFILE;
>> +             break;
>>       default:
>>               /* default to profile method */
>>               rdev->pm.pm_method = PM_METHOD_PROFILE;
>> diff --git a/drivers/gpu/drm/radeon/rs780_dpm.c b/drivers/gpu/drm/radeon/rs780_dpm.c
>> new file mode 100644
>> index 0000000..f594900
>> --- /dev/null
>> +++ b/drivers/gpu/drm/radeon/rs780_dpm.c
>> @@ -0,0 +1,894 @@
>> +/*
>> + * Copyright 2011 Advanced Micro Devices, Inc.
>> + *
>> + * Permission is hereby granted, free of charge, to any person obtaining a
>> + * copy of this software and associated documentation files (the "Software"),
>> + * to deal in the Software without restriction, including without limitation
>> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
>> + * and/or sell copies of the Software, and to permit persons to whom the
>> + * Software is furnished to do so, subject to the following conditions:
>> + *
>> + * The above copyright notice and this permission notice shall be included in
>> + * all copies or substantial portions of the Software.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
>> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
>> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
>> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
>> + * OTHER DEALINGS IN THE SOFTWARE.
>> + *
>> + * Authors: Alex Deucher
>> + */
>> +
>> +#include "drmP.h"
>> +#include "radeon.h"
>> +#include "rs780d.h"
>> +#include "r600_dpm.h"
>> +#include "rs780_dpm.h"
>> +#include "atom.h"
>> +
>> +static struct igp_ps *rs780_get_ps(struct radeon_ps *rps)
>> +{
>> +     struct igp_ps *ps = rps->ps_priv;
>> +
>> +     return ps;
>> +}
>> +
>> +static struct igp_power_info *rs780_get_pi(struct radeon_device *rdev)
>> +{
>> +     struct igp_power_info *pi = rdev->pm.dpm.priv;
>> +
>> +     return pi;
>> +}
>> +
>> +static void rs780_get_pm_mode_parameters(struct radeon_device *rdev)
>> +{
>> +     struct igp_power_info *pi = rs780_get_pi(rdev);
>> +     struct radeon_mode_info *minfo = &rdev->mode_info;
>> +     struct drm_crtc *crtc;
>> +     struct radeon_crtc *radeon_crtc;
>> +     int i;
>> +
>> +     /* defaults */
>> +     pi->crtc_id = 0;
>> +     pi->refresh_rate = 60;
>> +
>> +     for (i = 0; i < rdev->num_crtc; i++) {
>> +             crtc = (struct drm_crtc *)minfo->crtcs[i];
>> +             if (crtc && crtc->enabled) {
>> +                     radeon_crtc = to_radeon_crtc(crtc);
>> +                     pi->crtc_id = radeon_crtc->crtc_id;
>> +                     if (crtc->mode.htotal && crtc->mode.vtotal)
>> +                             pi->refresh_rate =
>> +                                     (crtc->mode.clock * 1000) /
>> +                                     (crtc->mode.htotal * crtc->mode.vtotal);
>> +                     break;
>> +             }
>> +     }
>
> Ok this looks wrong to me you look for the first enabled crtc but on those iirc
> there could be 2 so first one might be a low refresh rate and second one an higher
> one. Thus returning the first one might lead to PM decision that are wrong.
>

On RS780/RS880, the hardware can only synchronize with a single crtc,
so it doesn't really matter which one we pick as long as it's active.


>> +}
>> +
>> +static void rs780_voltage_scaling_enable(struct radeon_device *rdev, bool enable);
>> +
>> +static int rs780_initialize_dpm_power_state(struct radeon_device *rdev)
>> +{
>> +     struct atom_clock_dividers dividers;
>> +     struct igp_ps *default_state = rs780_get_ps(rdev->pm.dpm.boot_ps);
>> +     int i, ret;
>> +
>> +     ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
>> +                                          default_state->sclk_low, false, &dividers);
>> +     if (ret)
>> +             return ret;
>> +
>> +     r600_engine_clock_entry_set_reference_divider(rdev, 0, dividers.ref_div);
>> +     r600_engine_clock_entry_set_feedback_divider(rdev, 0, dividers.fb_div);
>> +     r600_engine_clock_entry_set_post_divider(rdev, 0, dividers.post_div);
>> +
>> +     if (dividers.enable_post_div)
>> +             r600_engine_clock_entry_enable_post_divider(rdev, 0, true);
>> +     else
>> +             r600_engine_clock_entry_enable_post_divider(rdev, 0, false);
>> +
>> +     r600_engine_clock_entry_set_step_time(rdev, 0, R600_SST_DFLT);
>> +     r600_engine_clock_entry_enable_pulse_skipping(rdev, 0, false);
>> +
>> +     r600_engine_clock_entry_enable(rdev, 0, true);
>> +     for (i = 1; i < R600_PM_NUMBER_OF_SCLKS; i++)
>> +             r600_engine_clock_entry_enable(rdev, i, false);
>> +
>> +     r600_enable_mclk_control(rdev, false);
>> +     r600_voltage_control_enable_pins(rdev, 0);
>> +
>> +     return 0;
>> +}
>> +
>> +static int rs780_initialize_dpm_parameters(struct radeon_device *rdev)
>> +{
>> +     int ret = 0;
>> +     int i;
>> +
>> +     r600_set_bsp(rdev, R600_BSU_DFLT, R600_BSP_DFLT);
>> +
>> +     r600_set_at(rdev, 0, 0, 0, 0);
>> +
>> +     r600_set_git(rdev, R600_GICST_DFLT);
>> +
>> +     for (i = 0; i < R600_PM_NUMBER_OF_TC; i++)
>> +             r600_set_tc(rdev, i, 0, 0);
>> +
>> +     r600_select_td(rdev, R600_TD_DFLT);
>> +     r600_set_vrc(rdev, 0);
>> +
>> +     r600_set_tpu(rdev, R600_TPU_DFLT);
>> +     r600_set_tpc(rdev, R600_TPC_DFLT);
>> +
>> +     r600_set_sstu(rdev, R600_SSTU_DFLT);
>> +     r600_set_sst(rdev, R600_SST_DFLT);
>> +
>> +     r600_set_fctu(rdev, R600_FCTU_DFLT);
>> +     r600_set_fct(rdev, R600_FCT_DFLT);
>> +
>> +     r600_set_vddc3d_oorsu(rdev, R600_VDDC3DOORSU_DFLT);
>> +     r600_set_vddc3d_oorphc(rdev, R600_VDDC3DOORPHC_DFLT);
>> +     r600_set_vddc3d_oorsdc(rdev, R600_VDDC3DOORSDC_DFLT);
>> +     r600_set_ctxcgtt3d_rphc(rdev, R600_CTXCGTT3DRPHC_DFLT);
>> +     r600_set_ctxcgtt3d_rsdc(rdev, R600_CTXCGTT3DRSDC_DFLT);
>> +
>> +     r600_vid_rt_set_vru(rdev, R600_VRU_DFLT);
>> +     r600_vid_rt_set_vrt(rdev, R600_VOLTAGERESPONSETIME_DFLT);
>> +     r600_vid_rt_set_ssu(rdev, R600_SPLLSTEPUNIT_DFLT);
>> +
>> +     ret = rs780_initialize_dpm_power_state(rdev);
>> +
>> +     r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_LOW,     0);
>> +     r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_MEDIUM,  0);
>> +     r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_HIGH,    0);
>> +
>> +     r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_LOW,    0);
>> +     r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_MEDIUM, 0);
>> +     r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_HIGH,   0);
>> +
>> +     r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_LOW,    0);
>> +     r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_MEDIUM, 0);
>> +     r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_HIGH,   0);
>> +
>> +     r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_LOW,    R600_DISPLAY_WATERMARK_HIGH);
>> +     r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_MEDIUM, R600_DISPLAY_WATERMARK_HIGH);
>> +     r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_HIGH,   R600_DISPLAY_WATERMARK_HIGH);
>> +
>> +     r600_power_level_enable(rdev, R600_POWER_LEVEL_CTXSW, false);
>> +     r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, false);
>> +     r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, false);
>> +     r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true);
>> +
>> +     r600_power_level_set_enter_index(rdev, R600_POWER_LEVEL_LOW);
>> +
>> +     r600_set_vrc(rdev, RS780_CGFTV_DFLT);
>> +
>> +     return ret;
>> +}
>> +
>> +static void rs780_start_dpm(struct radeon_device *rdev)
>> +{
>> +     r600_enable_sclk_control(rdev, false);
>> +     r600_enable_mclk_control(rdev, false);
>> +
>> +     r600_dynamicpm_enable(rdev, true);
>> +
>> +     radeon_wait_for_vblank(rdev, 0);
>> +     radeon_wait_for_vblank(rdev, 1);
>> +
>> +     r600_enable_spll_bypass(rdev, true);
>> +     r600_wait_for_spll_change(rdev);
>> +     r600_enable_spll_bypass(rdev, false);
>> +     r600_wait_for_spll_change(rdev);
>> +
>> +     r600_enable_spll_bypass(rdev, true);
>> +     r600_wait_for_spll_change(rdev);
>> +     r600_enable_spll_bypass(rdev, false);
>> +     r600_wait_for_spll_change(rdev);
>> +
>> +     r600_enable_sclk_control(rdev, true);
>> +}
>> +
>> +
>> +static void rs780_preset_ranges_slow_clk_fbdiv_en(struct radeon_device *rdev)
>> +{
>> +     WREG32_P(FVTHROT_SLOW_CLK_FEEDBACK_DIV_REG1, RANGE_SLOW_CLK_FEEDBACK_DIV_EN,
>> +              ~RANGE_SLOW_CLK_FEEDBACK_DIV_EN);
>> +
>> +     WREG32_P(FVTHROT_SLOW_CLK_FEEDBACK_DIV_REG1,
>> +              RANGE0_SLOW_CLK_FEEDBACK_DIV(RS780_SLOWCLKFEEDBACKDIV_DFLT),
>> +              ~RANGE0_SLOW_CLK_FEEDBACK_DIV_MASK);
>> +}
>> +
>> +static void rs780_preset_starting_fbdiv(struct radeon_device *rdev)
>> +{
>> +     u32 fbdiv = (RREG32(CG_SPLL_FUNC_CNTL) & SPLL_FB_DIV_MASK) >> SPLL_FB_DIV_SHIFT;
>> +
>> +     WREG32_P(FVTHROT_FBDIV_REG1, STARTING_FEEDBACK_DIV(fbdiv),
>> +              ~STARTING_FEEDBACK_DIV_MASK);
>> +
>> +     WREG32_P(FVTHROT_FBDIV_REG2, FORCED_FEEDBACK_DIV(fbdiv),
>> +              ~FORCED_FEEDBACK_DIV_MASK);
>> +
>> +     WREG32_P(FVTHROT_FBDIV_REG1, FORCE_FEEDBACK_DIV, ~FORCE_FEEDBACK_DIV);
>> +}
>> +
>> +static void rs780_voltage_scaling_init(struct radeon_device *rdev)
>> +{
>> +     struct igp_power_info *pi = rs780_get_pi(rdev);
>> +     struct drm_device *dev = rdev->ddev;
>> +     u32 fv_throt_pwm_fb_div_range[3];
>> +     u32 fv_throt_pwm_range[4];
>> +
>> +     if (dev->pdev->device == 0x9614) {
>> +             fv_throt_pwm_fb_div_range[0] = RS780D_FVTHROTPWMFBDIVRANGEREG0_DFLT;
>> +             fv_throt_pwm_fb_div_range[1] = RS780D_FVTHROTPWMFBDIVRANGEREG1_DFLT;
>> +             fv_throt_pwm_fb_div_range[2] = RS780D_FVTHROTPWMFBDIVRANGEREG2_DFLT;
>> +     } else if ((dev->pdev->device == 0x9714) ||
>> +                (dev->pdev->device == 0x9715)) {
>> +             fv_throt_pwm_fb_div_range[0] = RS880D_FVTHROTPWMFBDIVRANGEREG0_DFLT;
>> +             fv_throt_pwm_fb_div_range[1] = RS880D_FVTHROTPWMFBDIVRANGEREG1_DFLT;
>> +             fv_throt_pwm_fb_div_range[2] = RS880D_FVTHROTPWMFBDIVRANGEREG2_DFLT;
>> +     } else {
>> +             fv_throt_pwm_fb_div_range[0] = RS780_FVTHROTPWMFBDIVRANGEREG0_DFLT;
>> +             fv_throt_pwm_fb_div_range[1] = RS780_FVTHROTPWMFBDIVRANGEREG1_DFLT;
>> +             fv_throt_pwm_fb_div_range[2] = RS780_FVTHROTPWMFBDIVRANGEREG2_DFLT;
>> +     }
>> +
>> +     if (pi->pwm_voltage_control) {
>> +             fv_throt_pwm_range[0] = pi->min_voltage;
>> +             fv_throt_pwm_range[1] = pi->min_voltage;
>> +             fv_throt_pwm_range[2] = pi->max_voltage;
>> +             fv_throt_pwm_range[3] = pi->max_voltage;
>> +     } else {
>> +             fv_throt_pwm_range[0] = pi->invert_pwm_required ?
>> +                     RS780_FVTHROTPWMRANGE3_GPIO_DFLT : RS780_FVTHROTPWMRANGE0_GPIO_DFLT;
>> +             fv_throt_pwm_range[1] = pi->invert_pwm_required ?
>> +                     RS780_FVTHROTPWMRANGE2_GPIO_DFLT : RS780_FVTHROTPWMRANGE1_GPIO_DFLT;
>> +             fv_throt_pwm_range[2] = pi->invert_pwm_required ?
>> +                     RS780_FVTHROTPWMRANGE1_GPIO_DFLT : RS780_FVTHROTPWMRANGE2_GPIO_DFLT;
>> +             fv_throt_pwm_range[3] = pi->invert_pwm_required ?
>> +                     RS780_FVTHROTPWMRANGE0_GPIO_DFLT : RS780_FVTHROTPWMRANGE3_GPIO_DFLT;
>> +     }
>> +
>> +     WREG32_P(FVTHROT_PWM_CTRL_REG0,
>> +              STARTING_PWM_HIGHTIME(pi->max_voltage),
>> +              ~STARTING_PWM_HIGHTIME_MASK);
>> +
>> +     WREG32_P(FVTHROT_PWM_CTRL_REG0,
>> +              NUMBER_OF_CYCLES_IN_PERIOD(pi->num_of_cycles_in_period),
>> +              ~NUMBER_OF_CYCLES_IN_PERIOD_MASK);
>> +
>> +     WREG32_P(FVTHROT_PWM_CTRL_REG0, FORCE_STARTING_PWM_HIGHTIME,
>> +              ~FORCE_STARTING_PWM_HIGHTIME);
>> +
>> +     if (pi->invert_pwm_required)
>> +             WREG32_P(FVTHROT_PWM_CTRL_REG0, INVERT_PWM_WAVEFORM, ~INVERT_PWM_WAVEFORM);
>> +     else
>> +             WREG32_P(FVTHROT_PWM_CTRL_REG0, 0, ~INVERT_PWM_WAVEFORM);
>> +
>> +     rs780_voltage_scaling_enable(rdev, true);
>> +
>> +     WREG32(FVTHROT_PWM_CTRL_REG1,
>> +            (MIN_PWM_HIGHTIME(pi->min_voltage) |
>> +             MAX_PWM_HIGHTIME(pi->max_voltage)));
>> +
>> +     WREG32(FVTHROT_PWM_US_REG0, RS780_FVTHROTPWMUSREG0_DFLT);
>> +     WREG32(FVTHROT_PWM_US_REG1, RS780_FVTHROTPWMUSREG1_DFLT);
>> +     WREG32(FVTHROT_PWM_DS_REG0, RS780_FVTHROTPWMDSREG0_DFLT);
>> +     WREG32(FVTHROT_PWM_DS_REG1, RS780_FVTHROTPWMDSREG1_DFLT);
>> +
>> +     WREG32_P(FVTHROT_PWM_FEEDBACK_DIV_REG1,
>> +              RANGE0_PWM_FEEDBACK_DIV(fv_throt_pwm_fb_div_range[0]),
>> +              ~RANGE0_PWM_FEEDBACK_DIV_MASK);
>> +
>> +     WREG32(FVTHROT_PWM_FEEDBACK_DIV_REG2,
>> +            (RANGE1_PWM_FEEDBACK_DIV(fv_throt_pwm_fb_div_range[1]) |
>> +             RANGE2_PWM_FEEDBACK_DIV(fv_throt_pwm_fb_div_range[2])));
>> +
>> +     WREG32(FVTHROT_PWM_FEEDBACK_DIV_REG3,
>> +            (RANGE0_PWM(fv_throt_pwm_range[1]) |
>> +             RANGE1_PWM(fv_throt_pwm_range[2])));
>> +     WREG32(FVTHROT_PWM_FEEDBACK_DIV_REG4,
>> +            (RANGE2_PWM(fv_throt_pwm_range[1]) |
>> +             RANGE3_PWM(fv_throt_pwm_range[2])));
>> +}
>> +
>> +static void rs780_clk_scaling_enable(struct radeon_device *rdev, bool enable)
>> +{
>> +     if (enable)
>> +             WREG32_P(FVTHROT_CNTRL_REG, ENABLE_FV_THROT | ENABLE_FV_UPDATE,
>> +                      ~(ENABLE_FV_THROT | ENABLE_FV_UPDATE));
>> +     else
>> +             WREG32_P(FVTHROT_CNTRL_REG, 0,
>> +                      ~(ENABLE_FV_THROT | ENABLE_FV_UPDATE));
>> +}
>> +
>> +static void rs780_voltage_scaling_enable(struct radeon_device *rdev, bool enable)
>> +{
>> +     if (enable)
>> +             WREG32_P(FVTHROT_CNTRL_REG, ENABLE_FV_THROT_IO, ~ENABLE_FV_THROT_IO);
>> +     else
>> +             WREG32_P(FVTHROT_CNTRL_REG, 0, ~ENABLE_FV_THROT_IO);
>> +}
>> +
>> +static void rs780_set_engine_clock_wfc(struct radeon_device *rdev)
>> +{
>> +     WREG32(FVTHROT_UTC0, RS780_FVTHROTUTC0_DFLT);
>> +     WREG32(FVTHROT_UTC1, RS780_FVTHROTUTC1_DFLT);
>> +     WREG32(FVTHROT_UTC2, RS780_FVTHROTUTC2_DFLT);
>> +     WREG32(FVTHROT_UTC3, RS780_FVTHROTUTC3_DFLT);
>> +     WREG32(FVTHROT_UTC4, RS780_FVTHROTUTC4_DFLT);
>> +
>> +     WREG32(FVTHROT_DTC0, RS780_FVTHROTDTC0_DFLT);
>> +     WREG32(FVTHROT_DTC1, RS780_FVTHROTDTC1_DFLT);
>> +     WREG32(FVTHROT_DTC2, RS780_FVTHROTDTC2_DFLT);
>> +     WREG32(FVTHROT_DTC3, RS780_FVTHROTDTC3_DFLT);
>> +     WREG32(FVTHROT_DTC4, RS780_FVTHROTDTC4_DFLT);
>> +}
>> +
>> +static void rs780_set_engine_clock_sc(struct radeon_device *rdev)
>> +{
>> +     WREG32_P(FVTHROT_FBDIV_REG2,
>> +              FB_DIV_TIMER_VAL(RS780_FBDIVTIMERVAL_DFLT),
>> +              ~FB_DIV_TIMER_VAL_MASK);
>> +
>> +     WREG32_P(FVTHROT_CNTRL_REG,
>> +              REFRESH_RATE_DIVISOR(0) | MINIMUM_CIP(0xf),
>> +              ~(REFRESH_RATE_DIVISOR_MASK | MINIMUM_CIP_MASK));
>> +}
>> +
>> +static void rs780_set_engine_clock_tdc(struct radeon_device *rdev)
>> +{
>> +     WREG32_P(FVTHROT_CNTRL_REG, 0, ~(FORCE_TREND_SEL | TREND_SEL_MODE));
>> +}
>> +
>> +static void rs780_set_engine_clock_ssc(struct radeon_device *rdev)
>> +{
>> +     WREG32(FVTHROT_FB_US_REG0, RS780_FVTHROTFBUSREG0_DFLT);
>> +     WREG32(FVTHROT_FB_US_REG1, RS780_FVTHROTFBUSREG1_DFLT);
>> +     WREG32(FVTHROT_FB_DS_REG0, RS780_FVTHROTFBDSREG0_DFLT);
>> +     WREG32(FVTHROT_FB_DS_REG1, RS780_FVTHROTFBDSREG1_DFLT);
>> +
>> +     WREG32_P(FVTHROT_FBDIV_REG1, MAX_FEEDBACK_STEP(1), ~MAX_FEEDBACK_STEP_MASK);
>> +}
>> +
>> +static void rs780_program_at(struct radeon_device *rdev)
>> +{
>> +     struct igp_power_info *pi = rs780_get_pi(rdev);
>> +
>> +     WREG32(FVTHROT_TARGET_REG, 30000000 / pi->refresh_rate);
>> +     WREG32(FVTHROT_CB1, 1000000 * 5 / pi->refresh_rate);
>> +     WREG32(FVTHROT_CB2, 1000000 * 10 / pi->refresh_rate);
>> +     WREG32(FVTHROT_CB3, 1000000 * 30 / pi->refresh_rate);
>> +     WREG32(FVTHROT_CB4, 1000000 * 50 / pi->refresh_rate);
>> +}
>> +
>> +static void rs780_disable_vbios_powersaving(struct radeon_device *rdev)
>> +{
>> +     WREG32_P(CG_INTGFX_MISC, 0, ~0xFFF00000);
>> +}
>> +
>> +static void rs780_force_voltage_to_high(struct radeon_device *rdev)
>> +{
>> +     struct igp_power_info *pi = rs780_get_pi(rdev);
>> +     struct igp_ps *current_state = rs780_get_ps(rdev->pm.dpm.current_ps);
>> +
>> +     if ((current_state->max_voltage == RS780_VDDC_LEVEL_HIGH) &&
>> +         (current_state->min_voltage == RS780_VDDC_LEVEL_HIGH))
>> +             return;
>> +
>> +     WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL);
>> +
>> +     udelay(1);
>> +
>> +     WREG32_P(FVTHROT_PWM_CTRL_REG0,
>> +              STARTING_PWM_HIGHTIME(pi->max_voltage),
>> +              ~STARTING_PWM_HIGHTIME_MASK);
>> +
>> +     WREG32_P(FVTHROT_PWM_CTRL_REG0,
>> +              FORCE_STARTING_PWM_HIGHTIME, ~FORCE_STARTING_PWM_HIGHTIME);
>> +
>> +     WREG32_P(FVTHROT_PWM_FEEDBACK_DIV_REG1, 0,
>> +             ~RANGE_PWM_FEEDBACK_DIV_EN);
>> +
>> +     udelay(1);
>> +
>> +     WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
>> +}
>> +
>> +static int rs780_set_engine_clock_scaling(struct radeon_device *rdev)
>> +{
>> +     struct atom_clock_dividers min_dividers, max_dividers, current_max_dividers;
>> +     struct igp_ps *new_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
>> +     struct igp_ps *old_state = rs780_get_ps(rdev->pm.dpm.current_ps);
>> +     int ret;
>> +
>> +     if ((new_state->sclk_high == old_state->sclk_high) &&
>> +         (new_state->sclk_low == old_state->sclk_low))
>> +             return 0;
>> +
>> +     ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
>> +                                          new_state->sclk_low, false, &min_dividers);
>> +     if (ret)
>> +             return ret;
>> +
>> +     ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
>> +                                          new_state->sclk_high, false, &max_dividers);
>> +     if (ret)
>> +             return ret;
>> +
>> +     ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
>> +                                          old_state->sclk_high, false, &current_max_dividers);
>> +     if (ret)
>> +             return ret;
>> +
>> +     WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL);
>> +
>> +     WREG32_P(FVTHROT_FBDIV_REG2, FORCED_FEEDBACK_DIV(max_dividers.fb_div),
>> +              ~FORCED_FEEDBACK_DIV_MASK);
>> +     WREG32_P(FVTHROT_FBDIV_REG1, STARTING_FEEDBACK_DIV(max_dividers.fb_div),
>> +              ~STARTING_FEEDBACK_DIV_MASK);
>> +     WREG32_P(FVTHROT_FBDIV_REG1, FORCE_FEEDBACK_DIV, ~FORCE_FEEDBACK_DIV);
>> +
>> +     udelay(100);
>> +
>> +     WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
>> +
>> +     if (max_dividers.fb_div > min_dividers.fb_div) {
>> +             WREG32_P(FVTHROT_FBDIV_REG0,
>> +                      MIN_FEEDBACK_DIV(min_dividers.fb_div) |
>> +                      MAX_FEEDBACK_DIV(max_dividers.fb_div),
>> +                      ~(MIN_FEEDBACK_DIV_MASK | MAX_FEEDBACK_DIV_MASK));
>> +
>> +             WREG32_P(FVTHROT_FBDIV_REG1, 0, ~FORCE_FEEDBACK_DIV);
>> +     }
>> +
>> +     return 0;
>> +}
>> +
>> +static void rs780_set_engine_clock_spc(struct radeon_device *rdev)
>> +{
>> +     struct igp_ps *new_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
>> +     struct igp_ps *old_state = rs780_get_ps(rdev->pm.dpm.current_ps);
>> +     struct igp_power_info *pi = rs780_get_pi(rdev);
>> +
>> +     if ((new_state->sclk_high == old_state->sclk_high) &&
>> +         (new_state->sclk_low == old_state->sclk_low))
>> +             return;
>> +
>> +     if (pi->crtc_id == 0)
>> +             WREG32_P(CG_INTGFX_MISC, 0, ~FVTHROT_VBLANK_SEL);
>> +     else
>> +             WREG32_P(CG_INTGFX_MISC, FVTHROT_VBLANK_SEL, ~FVTHROT_VBLANK_SEL);
>> +
>> +}
>> +
>> +static void rs780_activate_engine_clk_scaling(struct radeon_device *rdev)
>> +{
>> +     struct igp_ps *new_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
>> +     struct igp_ps *old_state = rs780_get_ps(rdev->pm.dpm.current_ps);
>> +
>> +     if ((new_state->sclk_high == old_state->sclk_high) &&
>> +         (new_state->sclk_low == old_state->sclk_low))
>> +             return;
>> +
>> +     rs780_clk_scaling_enable(rdev, true);
>> +}
>> +
>> +static u32 rs780_get_voltage_for_vddc_level(struct radeon_device *rdev,
>> +                                         enum rs780_vddc_level vddc)
>> +{
>> +     struct igp_power_info *pi = rs780_get_pi(rdev);
>> +
>> +     if (vddc == RS780_VDDC_LEVEL_HIGH)
>> +             return pi->max_voltage;
>> +     else if (vddc == RS780_VDDC_LEVEL_LOW)
>> +             return pi->min_voltage;
>> +     else
>> +             return pi->max_voltage;
>> +}
>> +
>> +static void rs780_enable_voltage_scaling(struct radeon_device *rdev)
>> +{
>> +     struct igp_ps *new_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
>> +     struct igp_power_info *pi = rs780_get_pi(rdev);
>> +     enum rs780_vddc_level vddc_high, vddc_low;
>> +
>> +     udelay(100);
>> +
>> +     if ((new_state->max_voltage == RS780_VDDC_LEVEL_HIGH) &&
>> +         (new_state->min_voltage == RS780_VDDC_LEVEL_HIGH))
>> +             return;
>> +
>> +     vddc_high = rs780_get_voltage_for_vddc_level(rdev,
>> +                                                  new_state->max_voltage);
>> +     vddc_low = rs780_get_voltage_for_vddc_level(rdev,
>> +                                                 new_state->min_voltage);
>> +
>> +     WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL);
>> +
>> +     udelay(1);
>> +     if (vddc_high > vddc_low) {
>> +             WREG32_P(FVTHROT_PWM_FEEDBACK_DIV_REG1,
>> +                      RANGE_PWM_FEEDBACK_DIV_EN, ~RANGE_PWM_FEEDBACK_DIV_EN);
>> +
>> +             WREG32_P(FVTHROT_PWM_CTRL_REG0, 0, ~FORCE_STARTING_PWM_HIGHTIME);
>> +     } else if (vddc_high == vddc_low) {
>> +             if (pi->max_voltage != vddc_high) {
>> +                     WREG32_P(FVTHROT_PWM_CTRL_REG0,
>> +                              STARTING_PWM_HIGHTIME(vddc_high),
>> +                              ~STARTING_PWM_HIGHTIME_MASK);
>> +
>> +                     WREG32_P(FVTHROT_PWM_CTRL_REG0,
>> +                              FORCE_STARTING_PWM_HIGHTIME,
>> +                              ~FORCE_STARTING_PWM_HIGHTIME);
>> +             }
>> +     }
>> +
>> +     WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
>> +}
>> +
>> +int rs780_dpm_enable(struct radeon_device *rdev)
>> +{
>> +     struct igp_power_info *pi = rs780_get_pi(rdev);
>> +
>> +     rs780_get_pm_mode_parameters(rdev);
>> +     rs780_disable_vbios_powersaving(rdev);
>> +
>> +     if (r600_dynamicpm_enabled(rdev))
>> +             return -EINVAL;
>> +     if (rs780_initialize_dpm_parameters(rdev))
>> +             return -EINVAL;
>> +     rs780_start_dpm(rdev);
>> +
>> +     rs780_preset_ranges_slow_clk_fbdiv_en(rdev);
>> +     rs780_preset_starting_fbdiv(rdev);
>> +     if (pi->voltage_control)
>> +             rs780_voltage_scaling_init(rdev);
>> +     rs780_clk_scaling_enable(rdev, true);
>> +     rs780_set_engine_clock_sc(rdev);
>> +     rs780_set_engine_clock_wfc(rdev);
>> +     rs780_program_at(rdev);
>> +     rs780_set_engine_clock_tdc(rdev);
>> +     rs780_set_engine_clock_ssc(rdev);
>> +
>> +     if (pi->gfx_clock_gating)
>> +             r600_gfx_clockgating_enable(rdev, true);
>> +
>> +     return 0;
>> +}
>> +
>> +void rs780_dpm_disable(struct radeon_device *rdev)
>> +{
>> +     struct igp_power_info *pi = rs780_get_pi(rdev);
>> +
>> +     r600_dynamicpm_enable(rdev, false);
>> +
>> +     rs780_clk_scaling_enable(rdev, false);
>> +     rs780_voltage_scaling_enable(rdev, false);
>> +
>> +     if (pi->gfx_clock_gating)
>> +             r600_gfx_clockgating_enable(rdev, false);
>> +}
>> +
>> +int rs780_dpm_set_power_state(struct radeon_device *rdev)
>> +{
>> +     struct igp_power_info *pi = rs780_get_pi(rdev);
>> +
>> +     rs780_get_pm_mode_parameters(rdev);
>> +
>> +     if (pi->voltage_control) {
>> +             rs780_force_voltage_to_high(rdev);
>> +             mdelay(5);
>> +     }
>> +
>> +     rs780_set_engine_clock_scaling(rdev);
>> +     rs780_set_engine_clock_spc(rdev);
>> +
>> +     rs780_activate_engine_clk_scaling(rdev);
>> +
>> +     if (pi->voltage_control)
>> +             rs780_enable_voltage_scaling(rdev);
>> +
>> +     return 0;
>> +}
>> +
>> +void rs780_dpm_setup_asic(struct radeon_device *rdev)
>> +{
>> +
>> +}
>> +
>> +void rs780_dpm_display_configuration_changed(struct radeon_device *rdev)
>> +{
>> +     rs780_get_pm_mode_parameters(rdev);
>> +     rs780_program_at(rdev);
>> +}
>> +
>> +union igp_info {
>> +     struct _ATOM_INTEGRATED_SYSTEM_INFO info;
>> +     struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2;
>> +};
>> +
>> +union power_info {
>> +     struct _ATOM_POWERPLAY_INFO info;
>> +     struct _ATOM_POWERPLAY_INFO_V2 info_2;
>> +     struct _ATOM_POWERPLAY_INFO_V3 info_3;
>> +     struct _ATOM_PPLIB_POWERPLAYTABLE pplib;
>> +     struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2;
>> +     struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3;
>> +};
>> +
>> +union pplib_clock_info {
>> +     struct _ATOM_PPLIB_R600_CLOCK_INFO r600;
>> +     struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780;
>> +     struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen;
>> +     struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo;
>> +};
>> +
>> +union pplib_power_state {
>> +     struct _ATOM_PPLIB_STATE v1;
>> +     struct _ATOM_PPLIB_STATE_V2 v2;
>> +};
>> +
>> +static void rs780_parse_pplib_non_clock_info(struct radeon_device *rdev,
>> +                                          struct radeon_ps *rps,
>> +                                          struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info,
>> +                                          u8 table_rev)
>> +{
>> +     rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings);
>> +     rps->class = le16_to_cpu(non_clock_info->usClassification);
>> +     rps->class2 = le16_to_cpu(non_clock_info->usClassification2);
>> +
>> +     if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) {
>> +             rps->vclk = le32_to_cpu(non_clock_info->ulVCLK);
>> +             rps->dclk = le32_to_cpu(non_clock_info->ulDCLK);
>> +     } else if (r600_is_uvd_state(rps->class, rps->class2)) {
>> +             rps->vclk = RS780_DEFAULT_VCLK_FREQ;
>> +             rps->dclk = RS780_DEFAULT_DCLK_FREQ;
>> +     } else {
>> +             rps->vclk = 0;
>> +             rps->dclk = 0;
>> +     }
>> +
>> +     if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT)
>> +             rdev->pm.dpm.boot_ps = rps;
>> +     if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
>> +             rdev->pm.dpm.uvd_ps = rps;
>> +}
>> +
>> +static void rs780_parse_pplib_clock_info(struct radeon_device *rdev,
>> +                                      struct radeon_ps *rps,
>> +                                      union pplib_clock_info *clock_info)
>> +{
>> +     struct igp_ps *ps = rs780_get_ps(rps);
>> +     u32 sclk;
>> +
>> +     sclk = le16_to_cpu(clock_info->rs780.usLowEngineClockLow);
>> +     sclk |= clock_info->rs780.ucLowEngineClockHigh << 16;
>> +     ps->sclk_low = sclk;
>> +     sclk = le16_to_cpu(clock_info->rs780.usHighEngineClockLow);
>> +     sclk |= clock_info->rs780.ucHighEngineClockHigh << 16;
>> +     ps->sclk_high = sclk;
>> +     switch (le16_to_cpu(clock_info->rs780.usVDDC)) {
>> +     case ATOM_PPLIB_RS780_VOLTAGE_NONE:
>> +     default:
>> +             ps->min_voltage = RS780_VDDC_LEVEL_UNKNOWN;
>> +             ps->max_voltage = RS780_VDDC_LEVEL_UNKNOWN;
>> +             break;
>> +     case ATOM_PPLIB_RS780_VOLTAGE_LOW:
>> +             ps->min_voltage = RS780_VDDC_LEVEL_LOW;
>> +             ps->max_voltage = RS780_VDDC_LEVEL_LOW;
>> +             break;
>> +     case ATOM_PPLIB_RS780_VOLTAGE_HIGH:
>> +             ps->min_voltage = RS780_VDDC_LEVEL_HIGH;
>> +             ps->max_voltage = RS780_VDDC_LEVEL_HIGH;
>> +             break;
>> +     case ATOM_PPLIB_RS780_VOLTAGE_VARIABLE:
>> +             ps->min_voltage = RS780_VDDC_LEVEL_LOW;
>> +             ps->max_voltage = RS780_VDDC_LEVEL_HIGH;
>> +             break;
>> +     }
>> +     ps->flags = le32_to_cpu(clock_info->rs780.ulFlags);
>> +
>> +     if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) {
>> +             ps->sclk_low = rdev->clock.default_sclk;
>> +             ps->sclk_high = rdev->clock.default_sclk;
>> +             ps->min_voltage = RS780_VDDC_LEVEL_HIGH;
>> +             ps->max_voltage = RS780_VDDC_LEVEL_HIGH;
>> +     }
>> +}
>> +
>> +static int rs780_parse_power_table(struct radeon_device *rdev)
>> +{
>> +     struct radeon_mode_info *mode_info = &rdev->mode_info;
>> +     struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
>> +     union pplib_power_state *power_state;
>> +     int i;
>> +     union pplib_clock_info *clock_info;
>> +     union power_info *power_info;
>> +     int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
>> +        u16 data_offset;
>> +     u8 frev, crev;
>> +     struct igp_ps *ps;
>> +
>> +     if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
>> +                                &frev, &crev, &data_offset))
>> +             return -EINVAL;
>> +     power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
>> +
>> +     rdev->pm.dpm.ps = kzalloc(sizeof(struct radeon_ps) *
>> +                               power_info->pplib.ucNumStates, GFP_KERNEL);
>> +     if (!rdev->pm.dpm.ps)
>> +             return -ENOMEM;
>> +     rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps);
>> +     rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime);
>> +     rdev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime);
>> +
>> +     for (i = 0; i < power_info->pplib.ucNumStates; i++) {
>> +             power_state = (union pplib_power_state *)
>> +                     (mode_info->atom_context->bios + data_offset +
>> +                      le16_to_cpu(power_info->pplib.usStateArrayOffset) +
>> +                      i * power_info->pplib.ucStateEntrySize);
>> +             non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
>> +                     (mode_info->atom_context->bios + data_offset +
>> +                      le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset) +
>> +                      (power_state->v1.ucNonClockStateIndex *
>> +                       power_info->pplib.ucNonClockSize));
>> +             if (power_info->pplib.ucStateEntrySize - 1) {
>> +                     clock_info = (union pplib_clock_info *)
>> +                             (mode_info->atom_context->bios + data_offset +
>> +                              le16_to_cpu(power_info->pplib.usClockInfoArrayOffset) +
>> +                              (power_state->v1.ucClockStateIndices[0] *
>> +                               power_info->pplib.ucClockInfoSize));
>> +                     ps = kzalloc(sizeof(struct igp_ps), GFP_KERNEL);
>> +                     if (ps == NULL) {
>> +                             kfree(rdev->pm.dpm.ps);
>> +                             return -ENOMEM;
>> +                     }
>> +                     rdev->pm.dpm.ps[i].ps_priv = ps;
>> +                     rs780_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i],
>> +                                                      non_clock_info,
>> +                                                      power_info->pplib.ucNonClockSize);
>> +                     rs780_parse_pplib_clock_info(rdev,
>> +                                                  &rdev->pm.dpm.ps[i],
>> +                                                  clock_info);
>> +             }
>> +     }
>> +     rdev->pm.dpm.num_ps = power_info->pplib.ucNumStates;
>> +     return 0;
>> +}
>> +
>> +int rs780_dpm_init(struct radeon_device *rdev)
>> +{
>> +     struct igp_power_info *pi;
>> +     int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);
>> +     union igp_info *info;
>> +     u16 data_offset;
>> +     u8 frev, crev;
>> +     int ret;
>> +
>> +     pi = kzalloc(sizeof(struct igp_power_info), GFP_KERNEL);
>> +     if (pi == NULL)
>> +             return -ENOMEM;
>> +     rdev->pm.dpm.priv = pi;
>> +
>> +     ret = rs780_parse_power_table(rdev);
>> +     if (ret)
>> +             return ret;
>> +
>> +     pi->voltage_control = false;
>> +     pi->gfx_clock_gating = true;
>> +
>> +     if (atom_parse_data_header(rdev->mode_info.atom_context, index, NULL,
>> +                                &frev, &crev, &data_offset)) {
>> +             info = (union igp_info *)(rdev->mode_info.atom_context->bios + data_offset);
>> +
>> +             /* Get various system informations from bios */
>> +             switch (crev) {
>> +             case 1:
>> +                     pi->num_of_cycles_in_period =
>> +                             info->info.ucNumberOfCyclesInPeriod;
>> +                     pi->num_of_cycles_in_period |=
>> +                             info->info.ucNumberOfCyclesInPeriodHi << 8;
>> +                     pi->invert_pwm_required =
>> +                             (pi->num_of_cycles_in_period & 0x8000) ? true : false;
>> +                     pi->boot_voltage = info->info.ucStartingPWM_HighTime;
>> +                     pi->max_voltage = info->info.ucMaxNBVoltage;
>> +                     pi->max_voltage |= info->info.ucMaxNBVoltageHigh << 8;
>> +                     pi->min_voltage = info->info.ucMinNBVoltage;
>> +                     pi->min_voltage |= info->info.ucMinNBVoltageHigh << 8;
>> +                     pi->inter_voltage_low =
>> +                             le16_to_cpu(info->info.usInterNBVoltageLow);
>> +                     pi->inter_voltage_high =
>> +                             le16_to_cpu(info->info.usInterNBVoltageHigh);
>> +                     pi->voltage_control = true;
>> +                     pi->bootup_uma_clk = info->info.usK8MemoryClock * 100;
>> +                     break;
>> +             case 2:
>> +                     pi->num_of_cycles_in_period =
>> +                             le16_to_cpu(info->info_2.usNumberOfCyclesInPeriod);
>> +                     pi->invert_pwm_required =
>> +                             (pi->num_of_cycles_in_period & 0x8000) ? true : false;
>> +                     pi->boot_voltage =
>> +                             le16_to_cpu(info->info_2.usBootUpNBVoltage);
>> +                     pi->max_voltage =
>> +                             le16_to_cpu(info->info_2.usMaxNBVoltage);
>> +                     pi->min_voltage =
>> +                             le16_to_cpu(info->info_2.usMinNBVoltage);
>> +                     pi->system_config =
>> +                             le32_to_cpu(info->info_2.ulSystemConfig);
>> +                     pi->pwm_voltage_control =
>> +                             (pi->system_config & 0x4) ? true : false;
>> +                     pi->voltage_control = true;
>> +                     pi->bootup_uma_clk = le32_to_cpu(info->info_2.ulBootUpUMAClock);
>> +                     break;
>> +             default:
>> +                     DRM_ERROR("No integrated system info for your GPU\n");
>> +                     return -EINVAL;
>> +             }
>> +             if (pi->min_voltage > pi->max_voltage)
>> +                     pi->voltage_control = false;
>> +             if (pi->pwm_voltage_control) {
>> +                     if ((pi->num_of_cycles_in_period == 0) ||
>> +                         (pi->max_voltage == 0) ||
>> +                         (pi->min_voltage == 0))
>> +                             pi->voltage_control = false;
>> +             } else {
>> +                     if ((pi->num_of_cycles_in_period == 0) ||
>> +                         (pi->max_voltage == 0))
>> +                             pi->voltage_control = false;
>> +             }
>> +
>> +             return 0;
>> +     }
>> +     radeon_dpm_fini(rdev);
>> +     return -EINVAL;
>> +}
>> +
>> +void rs780_dpm_print_power_state(struct radeon_device *rdev,
>> +                              struct radeon_ps *rps)
>> +{
>> +     struct igp_ps *ps = rs780_get_ps(rps);
>> +
>> +     r600_dpm_print_class_info(rps->class, rps->class2);
>> +     r600_dpm_print_cap_info(rps->caps);
>> +     printk("\tuvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
>> +     printk("\t\tpower level 0    sclk: %u vddc_index: %d\n",
>> +            ps->sclk_low, ps->min_voltage);
>> +     printk("\t\tpower level 1    sclk: %u vddc_index: %d\n",
>> +            ps->sclk_high, ps->max_voltage);
>> +     r600_dpm_print_ps_status(rdev, rps);
>> +}
>> +
>> +void rs780_dpm_fini(struct radeon_device *rdev)
>> +{
>> +     int i;
>> +
>> +     for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
>> +             kfree(rdev->pm.dpm.ps[i].ps_priv);
>> +     }
>> +     kfree(rdev->pm.dpm.ps);
>> +     kfree(rdev->pm.dpm.priv);
>> +}
>> +
>> +u32 rs780_dpm_get_sclk(struct radeon_device *rdev, bool low)
>> +{
>> +     struct igp_ps *requested_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
>> +
>> +     if (low)
>> +             return requested_state->sclk_low;
>> +     else
>> +             return requested_state->sclk_high;
>> +}
>> +
>> +u32 rs780_dpm_get_mclk(struct radeon_device *rdev, bool low)
>> +{
>> +     struct igp_power_info *pi = rs780_get_pi(rdev);
>> +
>> +     return pi->bootup_uma_clk;
>> +}
>> diff --git a/drivers/gpu/drm/radeon/rs780_dpm.h b/drivers/gpu/drm/radeon/rs780_dpm.h
>> new file mode 100644
>> index 0000000..47a40b1
>> --- /dev/null
>> +++ b/drivers/gpu/drm/radeon/rs780_dpm.h
>> @@ -0,0 +1,109 @@
>> +/*
>> + * Copyright 2011 Advanced Micro Devices, Inc.
>> + *
>> + * Permission is hereby granted, free of charge, to any person obtaining a
>> + * copy of this software and associated documentation files (the "Software"),
>> + * to deal in the Software without restriction, including without limitation
>> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
>> + * and/or sell copies of the Software, and to permit persons to whom the
>> + * Software is furnished to do so, subject to the following conditions:
>> + *
>> + * The above copyright notice and this permission notice shall be included in
>> + * all copies or substantial portions of the Software.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
>> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
>> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
>> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
>> + * OTHER DEALINGS IN THE SOFTWARE.
>> + *
>> + */
>> +#ifndef __RS780_DPM_H__
>> +#define __RS780_DPM_H__
>> +
>> +enum rs780_vddc_level {
>> +     RS780_VDDC_LEVEL_UNKNOWN = 0,
>> +     RS780_VDDC_LEVEL_LOW = 1,
>> +     RS780_VDDC_LEVEL_HIGH = 2,
>> +};
>> +
>> +struct igp_power_info {
>> +     /* flags */
>> +     bool invert_pwm_required;
>> +     bool pwm_voltage_control;
>> +     bool voltage_control;
>> +     bool gfx_clock_gating;
>> +     /* stored values */
>> +     u32 system_config;
>> +     u32 bootup_uma_clk;
>> +     u16 max_voltage;
>> +     u16 min_voltage;
>> +     u16 boot_voltage;
>> +     u16 inter_voltage_low;
>> +     u16 inter_voltage_high;
>> +     u16 num_of_cycles_in_period;
>> +     /* variable */
>> +     int crtc_id;
>> +     int refresh_rate;
>> +};
>> +
>> +struct igp_ps {
>> +     enum rs780_vddc_level min_voltage;
>> +     enum rs780_vddc_level max_voltage;
>> +     u32 sclk_low;
>> +     u32 sclk_high;
>> +     u32 flags;
>> +};
>> +
>> +#define RS780_CGFTV_DFLT                 0x0303000f
>> +#define RS780_FBDIVTIMERVAL_DFLT         0x2710
>> +
>> +#define RS780_FVTHROTUTC0_DFLT   0x04010040
>> +#define RS780_FVTHROTUTC1_DFLT   0x04010040
>> +#define RS780_FVTHROTUTC2_DFLT   0x04010040
>> +#define RS780_FVTHROTUTC3_DFLT   0x04010040
>> +#define RS780_FVTHROTUTC4_DFLT   0x04010040
>> +
>> +#define RS780_FVTHROTDTC0_DFLT 0x04010040
>> +#define RS780_FVTHROTDTC1_DFLT 0x04010040
>> +#define RS780_FVTHROTDTC2_DFLT 0x04010040
>> +#define RS780_FVTHROTDTC3_DFLT 0x04010040
>> +#define RS780_FVTHROTDTC4_DFLT 0x04010040
>> +
>> +#define RS780_FVTHROTFBUSREG0_DFLT       0x00001001
>> +#define RS780_FVTHROTFBUSREG1_DFLT       0x00002002
>> +#define RS780_FVTHROTFBDSREG0_DFLT       0x00004001
>> +#define RS780_FVTHROTFBDSREG1_DFLT       0x00020010
>> +
>> +#define RS780_FVTHROTPWMUSREG0_DFLT      0x00002001
>> +#define RS780_FVTHROTPWMUSREG1_DFLT      0x00004003
>> +#define RS780_FVTHROTPWMDSREG0_DFLT      0x00002001
>> +#define RS780_FVTHROTPWMDSREG1_DFLT      0x00004003
>> +
>> +#define RS780_FVTHROTPWMFBDIVRANGEREG0_DFLT  0x37
>> +#define RS780_FVTHROTPWMFBDIVRANGEREG1_DFLT  0x4b
>> +#define RS780_FVTHROTPWMFBDIVRANGEREG2_DFLT  0x8b
>> +
>> +#define RS780D_FVTHROTPWMFBDIVRANGEREG0_DFLT  0x8b
>> +#define RS780D_FVTHROTPWMFBDIVRANGEREG1_DFLT  0x8c
>> +#define RS780D_FVTHROTPWMFBDIVRANGEREG2_DFLT  0xb5
>> +
>> +#define RS880D_FVTHROTPWMFBDIVRANGEREG0_DFLT  0x8d
>> +#define RS880D_FVTHROTPWMFBDIVRANGEREG1_DFLT  0x8e
>> +#define RS880D_FVTHROTPWMFBDIVRANGEREG2_DFLT  0xBa
>> +
>> +#define RS780_FVTHROTPWMRANGE0_GPIO_DFLT  0x1a
>> +#define RS780_FVTHROTPWMRANGE1_GPIO_DFLT  0x1a
>> +#define RS780_FVTHROTPWMRANGE2_GPIO_DFLT  0x0
>> +#define RS780_FVTHROTPWMRANGE3_GPIO_DFLT  0x0
>> +
>> +#define RS780_SLOWCLKFEEDBACKDIV_DFLT 110
>> +
>> +#define RS780_CGCLKGATING_DFLT           0x0000E204
>> +
>> +#define RS780_DEFAULT_VCLK_FREQ  53300 /* 10 khz */
>> +#define RS780_DEFAULT_DCLK_FREQ  40000 /* 10 khz */
>> +
>> +#endif
>> diff --git a/drivers/gpu/drm/radeon/rs780d.h b/drivers/gpu/drm/radeon/rs780d.h
>> new file mode 100644
>> index 0000000..b1142ed
>> --- /dev/null
>> +++ b/drivers/gpu/drm/radeon/rs780d.h
>> @@ -0,0 +1,168 @@
>> +/*
>> + * Copyright 2011 Advanced Micro Devices, Inc.
>> + *
>> + * Permission is hereby granted, free of charge, to any person obtaining a
>> + * copy of this software and associated documentation files (the "Software"),
>> + * to deal in the Software without restriction, including without limitation
>> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
>> + * and/or sell copies of the Software, and to permit persons to whom the
>> + * Software is furnished to do so, subject to the following conditions:
>> + *
>> + * The above copyright notice and this permission notice shall be included in
>> + * all copies or substantial portions of the Software.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
>> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
>> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
>> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
>> + * OTHER DEALINGS IN THE SOFTWARE.
>> + *
>> + */
>> +#ifndef __RS780D_H__
>> +#define __RS780D_H__
>> +
>> +#define CG_SPLL_FUNC_CNTL                                 0x600
>> +#       define SPLL_RESET                                (1 << 0)
>> +#       define SPLL_SLEEP                                (1 << 1)
>> +#       define SPLL_REF_DIV(x)                           ((x) << 2)
>> +#       define SPLL_REF_DIV_MASK                         (7 << 2)
>> +#       define SPLL_FB_DIV(x)                            ((x) << 5)
>> +#       define SPLL_FB_DIV_MASK                          (0xff << 2)
>> +#       define SPLL_FB_DIV_SHIFT                         2
>> +#       define SPLL_PULSEEN                              (1 << 13)
>> +#       define SPLL_PULSENUM(x)                          ((x) << 14)
>> +#       define SPLL_PULSENUM_MASK                        (3 << 14)
>> +#       define SPLL_SW_HILEN(x)                          ((x) << 16)
>> +#       define SPLL_SW_HILEN_MASK                        (0xf << 16)
>> +#       define SPLL_SW_LOLEN(x)                          ((x) << 20)
>> +#       define SPLL_SW_LOLEN_MASK                        (0xf << 20)
>> +#       define SPLL_DIVEN                                (1 << 24)
>> +#       define SPLL_BYPASS_EN                            (1 << 25)
>> +#       define SPLL_CHG_STATUS                           (1 << 29)
>> +#       define SPLL_CTLREQ                               (1 << 30)
>> +#       define SPLL_CTLACK                               (1 << 31)
>> +
>> +/* RS780/RS880 PM */
>> +#define      FVTHROT_CNTRL_REG                               0x3000
>> +#define              DONT_WAIT_FOR_FBDIV_WRAP                (1 << 0)
>> +#define              MINIMUM_CIP(x)                          ((x) << 1)
>> +#define              MINIMUM_CIP_SHIFT                       1
>> +#define              MINIMUM_CIP_MASK                        0x1fffffe
>> +#define              REFRESH_RATE_DIVISOR(x)                 ((x) << 25)
>> +#define              REFRESH_RATE_DIVISOR_SHIFT              25
>> +#define              REFRESH_RATE_DIVISOR_MASK               (0x3 << 25)
>> +#define              ENABLE_FV_THROT                         (1 << 27)
>> +#define              ENABLE_FV_UPDATE                        (1 << 28)
>> +#define              TREND_SEL_MODE                          (1 << 29)
>> +#define              FORCE_TREND_SEL                         (1 << 30)
>> +#define              ENABLE_FV_THROT_IO                      (1 << 31)
>> +#define      FVTHROT_TARGET_REG                              0x3004
>> +#define              TARGET_IDLE_COUNT(x)                    ((x) << 0)
>> +#define              TARGET_IDLE_COUNT_MASK                  0xffffff
>> +#define              TARGET_IDLE_COUNT_SHIFT                 0
>> +#define      FVTHROT_CB1                                     0x3008
>> +#define      FVTHROT_CB2                                     0x300c
>> +#define      FVTHROT_CB3                                     0x3010
>> +#define      FVTHROT_CB4                                     0x3014
>> +#define      FVTHROT_UTC0                                    0x3018
>> +#define      FVTHROT_UTC1                                    0x301c
>> +#define      FVTHROT_UTC2                                    0x3020
>> +#define      FVTHROT_UTC3                                    0x3024
>> +#define      FVTHROT_UTC4                                    0x3028
>> +#define      FVTHROT_DTC0                                    0x302c
>> +#define      FVTHROT_DTC1                                    0x3030
>> +#define      FVTHROT_DTC2                                    0x3034
>> +#define      FVTHROT_DTC3                                    0x3038
>> +#define      FVTHROT_DTC4                                    0x303c
>> +#define      FVTHROT_FBDIV_REG0                              0x3040
>> +#define              MIN_FEEDBACK_DIV(x)                     ((x) << 0)
>> +#define              MIN_FEEDBACK_DIV_MASK                   0xfff
>> +#define              MIN_FEEDBACK_DIV_SHIFT                  0
>> +#define              MAX_FEEDBACK_DIV(x)                     ((x) << 12)
>> +#define              MAX_FEEDBACK_DIV_MASK                   (0xfff << 12)
>> +#define              MAX_FEEDBACK_DIV_SHIFT                  12
>> +#define      FVTHROT_FBDIV_REG1                              0x3044
>> +#define              MAX_FEEDBACK_STEP(x)                    ((x) << 0)
>> +#define              MAX_FEEDBACK_STEP_MASK                  0xfff
>> +#define              MAX_FEEDBACK_STEP_SHIFT                 0
>> +#define              STARTING_FEEDBACK_DIV(x)                ((x) << 12)
>> +#define              STARTING_FEEDBACK_DIV_MASK              (0xfff << 12)
>> +#define              STARTING_FEEDBACK_DIV_SHIFT             12
>> +#define              FORCE_FEEDBACK_DIV                      (1 << 24)
>> +#define      FVTHROT_FBDIV_REG2                              0x3048
>> +#define              FORCED_FEEDBACK_DIV(x)                  ((x) << 0)
>> +#define              FORCED_FEEDBACK_DIV_MASK                0xfff
>> +#define              FORCED_FEEDBACK_DIV_SHIFT               0
>> +#define              FB_DIV_TIMER_VAL(x)                     ((x) << 12)
>> +#define              FB_DIV_TIMER_VAL_MASK                   (0xffff << 12)
>> +#define              FB_DIV_TIMER_VAL_SHIFT                  12
>> +#define      FVTHROT_FB_US_REG0                              0x304c
>> +#define      FVTHROT_FB_US_REG1                              0x3050
>> +#define      FVTHROT_FB_DS_REG0                              0x3054
>> +#define      FVTHROT_FB_DS_REG1                              0x3058
>> +#define      FVTHROT_PWM_CTRL_REG0                           0x305c
>> +#define              STARTING_PWM_HIGHTIME(x)                ((x) << 0)
>> +#define              STARTING_PWM_HIGHTIME_MASK              0xfff
>> +#define              STARTING_PWM_HIGHTIME_SHIFT             0
>> +#define              NUMBER_OF_CYCLES_IN_PERIOD(x)           ((x) << 12)
>> +#define              NUMBER_OF_CYCLES_IN_PERIOD_MASK         (0xfff << 12)
>> +#define              NUMBER_OF_CYCLES_IN_PERIOD_SHIFT        12
>> +#define              FORCE_STARTING_PWM_HIGHTIME             (1 << 24)
>> +#define              INVERT_PWM_WAVEFORM                     (1 << 25)
>> +#define      FVTHROT_PWM_CTRL_REG1                           0x3060
>> +#define              MIN_PWM_HIGHTIME(x)                     ((x) << 0)
>> +#define              MIN_PWM_HIGHTIME_MASK                   0xfff
>> +#define              MIN_PWM_HIGHTIME_SHIFT                  0
>> +#define              MAX_PWM_HIGHTIME(x)                     ((x) << 12)
>> +#define              MAX_PWM_HIGHTIME_MASK                   (0xfff << 12)
>> +#define              MAX_PWM_HIGHTIME_SHIFT                  12
>> +#define      FVTHROT_PWM_US_REG0                             0x3064
>> +#define      FVTHROT_PWM_US_REG1                             0x3068
>> +#define      FVTHROT_PWM_DS_REG0                             0x306c
>> +#define      FVTHROT_PWM_DS_REG1                             0x3070
>> +#define      FVTHROT_STATUS_REG0                             0x3074
>> +#define              CURRENT_FEEDBACK_DIV_MASK               0xfff
>> +#define              CURRENT_FEEDBACK_DIV_SHIFT              0
>> +#define      FVTHROT_STATUS_REG1                             0x3078
>> +#define      FVTHROT_STATUS_REG2                             0x307c
>> +#define      CG_INTGFX_MISC                                  0x3080
>> +#define              FVTHROT_VBLANK_SEL                      (1 << 9)
>> +#define      FVTHROT_PWM_FEEDBACK_DIV_REG1                   0x308c
>> +#define              RANGE0_PWM_FEEDBACK_DIV(x)              ((x) << 0)
>> +#define              RANGE0_PWM_FEEDBACK_DIV_MASK            0xfff
>> +#define              RANGE0_PWM_FEEDBACK_DIV_SHIFT           0
>> +#define              RANGE_PWM_FEEDBACK_DIV_EN               (1 << 12)
>> +#define      FVTHROT_PWM_FEEDBACK_DIV_REG2                   0x3090
>> +#define              RANGE1_PWM_FEEDBACK_DIV(x)              ((x) << 0)
>> +#define              RANGE1_PWM_FEEDBACK_DIV_MASK            0xfff
>> +#define              RANGE1_PWM_FEEDBACK_DIV_SHIFT           0
>> +#define              RANGE2_PWM_FEEDBACK_DIV(x)              ((x) << 12)
>> +#define              RANGE2_PWM_FEEDBACK_DIV_MASK            (0xfff << 12)
>> +#define              RANGE2_PWM_FEEDBACK_DIV_SHIFT           12
>> +#define      FVTHROT_PWM_FEEDBACK_DIV_REG3                   0x3094
>> +#define              RANGE0_PWM(x)                           ((x) << 0)
>> +#define              RANGE0_PWM_MASK                         0xfff
>> +#define              RANGE0_PWM_SHIFT                        0
>> +#define              RANGE1_PWM(x)                           ((x) << 12)
>> +#define              RANGE1_PWM_MASK                         (0xfff << 12)
>> +#define              RANGE1_PWM_SHIFT                        12
>> +#define      FVTHROT_PWM_FEEDBACK_DIV_REG4                   0x3098
>> +#define              RANGE2_PWM(x)                           ((x) << 0)
>> +#define              RANGE2_PWM_MASK                         0xfff
>> +#define              RANGE2_PWM_SHIFT                        0
>> +#define              RANGE3_PWM(x)                           ((x) << 12)
>> +#define              RANGE3_PWM_MASK                         (0xfff << 12)
>> +#define              RANGE3_PWM_SHIFT                        12
>> +#define      FVTHROT_SLOW_CLK_FEEDBACK_DIV_REG1              0x30ac
>> +#define              RANGE0_SLOW_CLK_FEEDBACK_DIV(x)         ((x) << 0)
>> +#define              RANGE0_SLOW_CLK_FEEDBACK_DIV_MASK       0xfff
>> +#define              RANGE0_SLOW_CLK_FEEDBACK_DIV_SHIFT      0
>> +#define              RANGE_SLOW_CLK_FEEDBACK_DIV_EN          (1 << 12)
>> +
>> +#define      GFX_MACRO_BYPASS_CNTL                           0x30c0
>> +#define              SPLL_BYPASS_CNTL                        (1 << 0)
>> +#define              UPLL_BYPASS_CNTL                        (1 << 1)
>> +
>> +#endif
>> --
>> 1.7.7.5
>>
>> _______________________________________________
>> dri-devel mailing list
>> dri-devel@lists.freedesktop.org
>> http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 051/165] drm/radeon: implement simple doorbell page allocator
  2013-06-26 12:57   ` Jerome Glisse
@ 2013-06-26 18:38     ` Alex Deucher
  0 siblings, 0 replies; 142+ messages in thread
From: Alex Deucher @ 2013-06-26 18:38 UTC (permalink / raw)
  To: Jerome Glisse; +Cc: Alex Deucher, dri-devel

On Wed, Jun 26, 2013 at 8:57 AM, Jerome Glisse <j.glisse@gmail.com> wrote:
> On Wed, Jun 26, 2013 at 09:22:11AM -0400, alexdeucher@gmail.com wrote:
>> From: Alex Deucher <alexander.deucher@amd.com>
>>
>> The doorbell aperture is a PCI BAR whose pages can be
>> mapped to compute resources for things like wptrs
>> for userspace queues.
>>
>> This patch maps the BAR and sets up a simple allocator
>> to allocate pages from the BAR.
>
> This doorbell stuff is cryptic, is that some memory on the GPU ? Or is it
> more like a register file ? ie what is backing the pci bar.
>

There's no memory backing it.  It's just an aperture that the GPU can
selectively listens to.  You assign dw offsets from the doorbell
aperture for things like the wrptr for compute rings.  When the driver
or process write a new wtpr value to the offset assigned to it's
specific ring, the GPU starts processing it.  Like ringing a doorbell.

Alex

> Also probably want to use bitmap as i dont think gcc will turn bool array
> into a bitmap.
>
> Cheers,
> Jerome
>
>>
>> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
>> ---
>>  drivers/gpu/drm/radeon/cik.c           |   38 +++++++++++++
>>  drivers/gpu/drm/radeon/radeon.h        |   21 +++++++
>>  drivers/gpu/drm/radeon/radeon_device.c |   94 ++++++++++++++++++++++++++++++++
>>  3 files changed, 153 insertions(+), 0 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
>> index bb7dbc4..5c28fa5 100644
>> --- a/drivers/gpu/drm/radeon/cik.c
>> +++ b/drivers/gpu/drm/radeon/cik.c
>> @@ -121,6 +121,44 @@ u32 cik_get_xclk(struct radeon_device *rdev)
>>       return reference_clock;
>>  }
>>
>> +/**
>> + * cik_mm_rdoorbell - read a doorbell dword
>> + *
>> + * @rdev: radeon_device pointer
>> + * @offset: byte offset into the aperture
>> + *
>> + * Returns the value in the doorbell aperture at the
>> + * requested offset (CIK).
>> + */
>> +u32 cik_mm_rdoorbell(struct radeon_device *rdev, u32 offset)
>> +{
>> +     if (offset < rdev->doorbell.size) {
>> +             return readl(((void __iomem *)rdev->doorbell.ptr) + offset);
>> +     } else {
>> +             DRM_ERROR("reading beyond doorbell aperture: 0x%08x!\n", offset);
>> +             return 0;
>> +     }
>> +}
>> +
>> +/**
>> + * cik_mm_wdoorbell - write a doorbell dword
>> + *
>> + * @rdev: radeon_device pointer
>> + * @offset: byte offset into the aperture
>> + * @v: value to write
>> + *
>> + * Writes @v to the doorbell aperture at the
>> + * requested offset (CIK).
>> + */
>> +void cik_mm_wdoorbell(struct radeon_device *rdev, u32 offset, u32 v)
>> +{
>> +     if (offset < rdev->doorbell.size) {
>> +             writel(v, ((void __iomem *)rdev->doorbell.ptr) + offset);
>> +     } else {
>> +             DRM_ERROR("writing beyond doorbell aperture: 0x%08x!\n", offset);
>> +     }
>> +}
>> +
>>  #define BONAIRE_IO_MC_REGS_SIZE 36
>>
>>  static const u32 bonaire_io_mc_regs[BONAIRE_IO_MC_REGS_SIZE][2] =
>> diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
>> index ad4e68a..a2a3430 100644
>> --- a/drivers/gpu/drm/radeon/radeon.h
>> +++ b/drivers/gpu/drm/radeon/radeon.h
>> @@ -556,6 +556,20 @@ struct radeon_scratch {
>>  int radeon_scratch_get(struct radeon_device *rdev, uint32_t *reg);
>>  void radeon_scratch_free(struct radeon_device *rdev, uint32_t reg);
>>
>> +/*
>> + * GPU doorbell structures, functions & helpers
>> + */
>> +struct radeon_doorbell {
>> +     u32                     num_pages;
>> +     bool                    free[1024];
>> +     /* doorbell mmio */
>> +     resource_size_t                 base;
>> +     resource_size_t                 size;
>> +     void __iomem                    *ptr;
>> +};
>> +
>> +int radeon_doorbell_get(struct radeon_device *rdev, u32 *page);
>> +void radeon_doorbell_free(struct radeon_device *rdev, u32 doorbell);
>>
>>  /*
>>   * IRQS.
>> @@ -1711,6 +1725,7 @@ struct radeon_device {
>>       struct radeon_gart              gart;
>>       struct radeon_mode_info         mode_info;
>>       struct radeon_scratch           scratch;
>> +     struct radeon_doorbell          doorbell;
>>       struct radeon_mman              mman;
>>       struct radeon_fence_driver      fence_drv[RADEON_NUM_RINGS];
>>       wait_queue_head_t               fence_queue;
>> @@ -1784,6 +1799,9 @@ void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v,
>>  u32 r100_io_rreg(struct radeon_device *rdev, u32 reg);
>>  void r100_io_wreg(struct radeon_device *rdev, u32 reg, u32 v);
>>
>> +u32 cik_mm_rdoorbell(struct radeon_device *rdev, u32 offset);
>> +void cik_mm_wdoorbell(struct radeon_device *rdev, u32 offset, u32 v);
>> +
>>  /*
>>   * Cast helper
>>   */
>> @@ -1833,6 +1851,9 @@ void r100_io_wreg(struct radeon_device *rdev, u32 reg, u32 v);
>>  #define RREG32_IO(reg) r100_io_rreg(rdev, (reg))
>>  #define WREG32_IO(reg, v) r100_io_wreg(rdev, (reg), (v))
>>
>> +#define RDOORBELL32(offset) cik_mm_rdoorbell(rdev, (offset))
>> +#define WDOORBELL32(offset, v) cik_mm_wdoorbell(rdev, (offset), (v))
>> +
>>  /*
>>   * Indirect registers accessor
>>   */
>> diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
>> index 4e97ff7..82335e3 100644
>> --- a/drivers/gpu/drm/radeon/radeon_device.c
>> +++ b/drivers/gpu/drm/radeon/radeon_device.c
>> @@ -232,6 +232,94 @@ void radeon_scratch_free(struct radeon_device *rdev, uint32_t reg)
>>  }
>>
>>  /*
>> + * GPU doorbell aperture helpers function.
>> + */
>> +/**
>> + * radeon_doorbell_init - Init doorbell driver information.
>> + *
>> + * @rdev: radeon_device pointer
>> + *
>> + * Init doorbell driver information (CIK)
>> + * Returns 0 on success, error on failure.
>> + */
>> +int radeon_doorbell_init(struct radeon_device *rdev)
>> +{
>> +     int i;
>> +
>> +     /* doorbell bar mapping */
>> +     rdev->doorbell.base = pci_resource_start(rdev->pdev, 2);
>> +     rdev->doorbell.size = pci_resource_len(rdev->pdev, 2);
>> +
>> +     /* limit to 4 MB for now */
>> +     if (rdev->doorbell.size > (4 * 1024 * 1024))
>> +             rdev->doorbell.size = 4 * 1024 * 1024;
>> +
>> +     rdev->doorbell.ptr = ioremap(rdev->doorbell.base, rdev->doorbell.size);
>> +     if (rdev->doorbell.ptr == NULL) {
>> +             return -ENOMEM;
>> +     }
>> +     DRM_INFO("doorbell mmio base: 0x%08X\n", (uint32_t)rdev->doorbell.base);
>> +     DRM_INFO("doorbell mmio size: %u\n", (unsigned)rdev->doorbell.size);
>> +
>> +     rdev->doorbell.num_pages = rdev->doorbell.size / PAGE_SIZE;
>> +
>> +     for (i = 0; i < rdev->doorbell.num_pages; i++) {
>> +             rdev->doorbell.free[i] = true;
>> +     }
>> +     return 0;
>> +}
>> +
>> +/**
>> + * radeon_doorbell_fini - Tear down doorbell driver information.
>> + *
>> + * @rdev: radeon_device pointer
>> + *
>> + * Tear down doorbell driver information (CIK)
>> + */
>> +void radeon_doorbell_fini(struct radeon_device *rdev)
>> +{
>> +     iounmap(rdev->doorbell.ptr);
>> +     rdev->doorbell.ptr = NULL;
>> +}
>> +
>> +/**
>> + * radeon_doorbell_get - Allocate a doorbell page
>> + *
>> + * @rdev: radeon_device pointer
>> + * @doorbell: doorbell page number
>> + *
>> + * Allocate a doorbell page for use by the driver (all asics).
>> + * Returns 0 on success or -EINVAL on failure.
>> + */
>> +int radeon_doorbell_get(struct radeon_device *rdev, u32 *doorbell)
>> +{
>> +     int i;
>> +
>> +     for (i = 0; i < rdev->doorbell.num_pages; i++) {
>> +             if (rdev->doorbell.free[i]) {
>> +                     rdev->doorbell.free[i] = false;
>> +                     *doorbell = i;
>> +                     return 0;
>> +             }
>> +     }
>> +     return -EINVAL;
>> +}
>> +
>> +/**
>> + * radeon_doorbell_free - Free a doorbell page
>> + *
>> + * @rdev: radeon_device pointer
>> + * @doorbell: doorbell page number
>> + *
>> + * Free a doorbell page allocated for use by the driver (all asics)
>> + */
>> +void radeon_doorbell_free(struct radeon_device *rdev, u32 doorbell)
>> +{
>> +     if (doorbell < rdev->doorbell.num_pages)
>> +             rdev->doorbell.free[doorbell] = true;
>> +}
>> +
>> +/*
>>   * radeon_wb_*()
>>   * Writeback is the the method by which the the GPU updates special pages
>>   * in memory with the status of certain GPU events (fences, ring pointers,
>> @@ -1162,6 +1250,10 @@ int radeon_device_init(struct radeon_device *rdev,
>>       DRM_INFO("register mmio base: 0x%08X\n", (uint32_t)rdev->rmmio_base);
>>       DRM_INFO("register mmio size: %u\n", (unsigned)rdev->rmmio_size);
>>
>> +     /* doorbell bar mapping */
>> +     if (rdev->family >= CHIP_BONAIRE)
>> +             radeon_doorbell_init(rdev);
>> +
>>       /* io port mapping */
>>       for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
>>               if (pci_resource_flags(rdev->pdev, i) & IORESOURCE_IO) {
>> @@ -1239,6 +1331,8 @@ void radeon_device_fini(struct radeon_device *rdev)
>>       rdev->rio_mem = NULL;
>>       iounmap(rdev->rmmio);
>>       rdev->rmmio = NULL;
>> +     if (rdev->family >= CHIP_BONAIRE)
>> +             radeon_doorbell_fini(rdev);
>>       radeon_debugfs_remove_files(rdev);
>>  }
>>
>> --
>> 1.7.7.5
>>
>> _______________________________________________
>> dri-devel mailing list
>> dri-devel@lists.freedesktop.org
>> http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 075/165] drm/radeon/kms: add dpm support for rs780/rs880
  2013-06-26 13:18       ` Jerome Glisse
@ 2013-06-26 18:41         ` Alex Deucher
  0 siblings, 0 replies; 142+ messages in thread
From: Alex Deucher @ 2013-06-26 18:41 UTC (permalink / raw)
  To: Jerome Glisse; +Cc: Alex Deucher, dri-devel

On Wed, Jun 26, 2013 at 9:18 AM, Jerome Glisse <j.glisse@gmail.com> wrote:
> On Wed, Jun 26, 2013 at 02:19:23PM -0400, Alex Deucher wrote:
>> On Wed, Jun 26, 2013 at 6:46 AM, Jerome Glisse <j.glisse@gmail.com> wrote:
>> > On Wed, Jun 26, 2013 at 09:22:35AM -0400, alexdeucher@gmail.com wrote:
>> >> From: Alex Deucher <alexander.deucher@amd.com>
>> >>
>> >> This adds dpm support for rs780/rs880 asics.  This includes:
>> >> - clockgating
>> >> - dynamic engine clock scaling
>> >> - dynamic voltage scaling
>> >>
>> >> set radeon.dpm=1 to enable it.
>> >>
>> >> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
>> >
>> > Depending on the answer to inline question :
>> >
>> > Reviewed-by: Jerome Glisse <jglisse@redhat.com>
>> >
>> >> ---
>> >>  drivers/gpu/drm/radeon/Makefile      |    2 +-
>> >>  drivers/gpu/drm/radeon/radeon_asic.c |   12 +
>> >>  drivers/gpu/drm/radeon/radeon_asic.h |   12 +
>> >>  drivers/gpu/drm/radeon/radeon_pm.c   |    7 +
>> >>  drivers/gpu/drm/radeon/rs780_dpm.c   |  894 ++++++++++++++++++++++++++++++++++
>> >>  drivers/gpu/drm/radeon/rs780_dpm.h   |  109 ++++
>> >>  drivers/gpu/drm/radeon/rs780d.h      |  168 +++++++
>> >>  7 files changed, 1203 insertions(+), 1 deletions(-)
>> >>  create mode 100644 drivers/gpu/drm/radeon/rs780_dpm.c
>> >>  create mode 100644 drivers/gpu/drm/radeon/rs780_dpm.h
>> >>  create mode 100644 drivers/gpu/drm/radeon/rs780d.h
>> >>
>> >> diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile
>> >> index a131a13..e44b046 100644
>> >> --- a/drivers/gpu/drm/radeon/Makefile
>> >> +++ b/drivers/gpu/drm/radeon/Makefile
>> >> @@ -77,7 +77,7 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \
>> >>       evergreen_hdmi.o radeon_trace_points.o ni.o cayman_blit_shaders.o \
>> >>       atombios_encoders.o radeon_semaphore.o radeon_sa.o atombios_i2c.o si.o \
>> >>       si_blit_shaders.o radeon_prime.o radeon_uvd.o cik.o cik_blit_shaders.o \
>> >> -     r600_dpm.o
>> >> +     r600_dpm.o rs780_dpm.o
>> >>
>> >>  radeon-$(CONFIG_COMPAT) += radeon_ioc32.o
>> >>  radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o
>> >> diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c
>> >> index d9c8e9a..db3c930 100644
>> >> --- a/drivers/gpu/drm/radeon/radeon_asic.c
>> >> +++ b/drivers/gpu/drm/radeon/radeon_asic.c
>> >> @@ -1194,6 +1194,18 @@ static struct radeon_asic rs780_asic = {
>> >>               .set_clock_gating = NULL,
>> >>               .get_temperature = &rv6xx_get_temp,
>> >>       },
>> >> +     .dpm = {
>> >> +             .init = &rs780_dpm_init,
>> >> +             .setup_asic = &rs780_dpm_setup_asic,
>> >> +             .enable = &rs780_dpm_enable,
>> >> +             .disable = &rs780_dpm_disable,
>> >> +             .set_power_state = &rs780_dpm_set_power_state,
>> >> +             .display_configuration_changed = &rs780_dpm_display_configuration_changed,
>> >> +             .fini = &rs780_dpm_fini,
>> >> +             .get_sclk = &rs780_dpm_get_sclk,
>> >> +             .get_mclk = &rs780_dpm_get_mclk,
>> >> +             .print_power_state = &rs780_dpm_print_power_state,
>> >> +     },
>> >>       .pflip = {
>> >>               .pre_page_flip = &rs600_pre_page_flip,
>> >>               .page_flip = &rs600_page_flip,
>> >> diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
>> >> index 8507cae..134bf57 100644
>> >> --- a/drivers/gpu/drm/radeon/radeon_asic.h
>> >> +++ b/drivers/gpu/drm/radeon/radeon_asic.h
>> >> @@ -396,6 +396,18 @@ int r600_mc_wait_for_idle(struct radeon_device *rdev);
>> >>  u32 r600_get_xclk(struct radeon_device *rdev);
>> >>  uint64_t r600_get_gpu_clock_counter(struct radeon_device *rdev);
>> >>  int rv6xx_get_temp(struct radeon_device *rdev);
>> >> +/* rs780 dpm */
>> >> +int rs780_dpm_init(struct radeon_device *rdev);
>> >> +int rs780_dpm_enable(struct radeon_device *rdev);
>> >> +void rs780_dpm_disable(struct radeon_device *rdev);
>> >> +int rs780_dpm_set_power_state(struct radeon_device *rdev);
>> >> +void rs780_dpm_setup_asic(struct radeon_device *rdev);
>> >> +void rs780_dpm_display_configuration_changed(struct radeon_device *rdev);
>> >> +void rs780_dpm_fini(struct radeon_device *rdev);
>> >> +u32 rs780_dpm_get_sclk(struct radeon_device *rdev, bool low);
>> >> +u32 rs780_dpm_get_mclk(struct radeon_device *rdev, bool low);
>> >> +void rs780_dpm_print_power_state(struct radeon_device *rdev,
>> >> +                              struct radeon_ps *ps);
>> >>
>> >>  /* uvd */
>> >>  int r600_uvd_init(struct radeon_device *rdev);
>> >> diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
>> >> index 4f5422e..853a8a2 100644
>> >> --- a/drivers/gpu/drm/radeon/radeon_pm.c
>> >> +++ b/drivers/gpu/drm/radeon/radeon_pm.c
>> >> @@ -1030,6 +1030,13 @@ int radeon_pm_init(struct radeon_device *rdev)
>> >>  {
>> >>       /* enable dpm on rv6xx+ */
>> >>       switch (rdev->family) {
>> >> +     case CHIP_RS780:
>> >> +     case CHIP_RS880:
>> >> +             if (radeon_dpm == 1)
>> >> +                     rdev->pm.pm_method = PM_METHOD_DPM;
>> >> +             else
>> >> +                     rdev->pm.pm_method = PM_METHOD_PROFILE;
>> >> +             break;
>> >>       default:
>> >>               /* default to profile method */
>> >>               rdev->pm.pm_method = PM_METHOD_PROFILE;
>> >> diff --git a/drivers/gpu/drm/radeon/rs780_dpm.c b/drivers/gpu/drm/radeon/rs780_dpm.c
>> >> new file mode 100644
>> >> index 0000000..f594900
>> >> --- /dev/null
>> >> +++ b/drivers/gpu/drm/radeon/rs780_dpm.c
>> >> @@ -0,0 +1,894 @@
>> >> +/*
>> >> + * Copyright 2011 Advanced Micro Devices, Inc.
>> >> + *
>> >> + * Permission is hereby granted, free of charge, to any person obtaining a
>> >> + * copy of this software and associated documentation files (the "Software"),
>> >> + * to deal in the Software without restriction, including without limitation
>> >> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
>> >> + * and/or sell copies of the Software, and to permit persons to whom the
>> >> + * Software is furnished to do so, subject to the following conditions:
>> >> + *
>> >> + * The above copyright notice and this permission notice shall be included in
>> >> + * all copies or substantial portions of the Software.
>> >> + *
>> >> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>> >> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>> >> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
>> >> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
>> >> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
>> >> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
>> >> + * OTHER DEALINGS IN THE SOFTWARE.
>> >> + *
>> >> + * Authors: Alex Deucher
>> >> + */
>> >> +
>> >> +#include "drmP.h"
>> >> +#include "radeon.h"
>> >> +#include "rs780d.h"
>> >> +#include "r600_dpm.h"
>> >> +#include "rs780_dpm.h"
>> >> +#include "atom.h"
>> >> +
>> >> +static struct igp_ps *rs780_get_ps(struct radeon_ps *rps)
>> >> +{
>> >> +     struct igp_ps *ps = rps->ps_priv;
>> >> +
>> >> +     return ps;
>> >> +}
>> >> +
>> >> +static struct igp_power_info *rs780_get_pi(struct radeon_device *rdev)
>> >> +{
>> >> +     struct igp_power_info *pi = rdev->pm.dpm.priv;
>> >> +
>> >> +     return pi;
>> >> +}
>> >> +
>> >> +static void rs780_get_pm_mode_parameters(struct radeon_device *rdev)
>> >> +{
>> >> +     struct igp_power_info *pi = rs780_get_pi(rdev);
>> >> +     struct radeon_mode_info *minfo = &rdev->mode_info;
>> >> +     struct drm_crtc *crtc;
>> >> +     struct radeon_crtc *radeon_crtc;
>> >> +     int i;
>> >> +
>> >> +     /* defaults */
>> >> +     pi->crtc_id = 0;
>> >> +     pi->refresh_rate = 60;
>> >> +
>> >> +     for (i = 0; i < rdev->num_crtc; i++) {
>> >> +             crtc = (struct drm_crtc *)minfo->crtcs[i];
>> >> +             if (crtc && crtc->enabled) {
>> >> +                     radeon_crtc = to_radeon_crtc(crtc);
>> >> +                     pi->crtc_id = radeon_crtc->crtc_id;
>> >> +                     if (crtc->mode.htotal && crtc->mode.vtotal)
>> >> +                             pi->refresh_rate =
>> >> +                                     (crtc->mode.clock * 1000) /
>> >> +                                     (crtc->mode.htotal * crtc->mode.vtotal);
>> >> +                     break;
>> >> +             }
>> >> +     }
>> >
>> > Ok this looks wrong to me you look for the first enabled crtc but on those iirc
>> > there could be 2 so first one might be a low refresh rate and second one an higher
>> > one. Thus returning the first one might lead to PM decision that are wrong.
>> >
>
> So what happens when 2 are active ? Flickering on the unsync one ?

In theory, although changing sclk and voltage can be done outside of
the vblank period on most asics.  vblank is mainly needed for memory
related operations.  I'm not sure what exactly is affected on rs780.
Too old.  Hard to find docs on it.

Alex

>
> Cheers,
> Jerome
>
>>
>> On RS780/RS880, the hardware can only synchronize with a single crtc,
>> so it doesn't really matter which one we pick as long as it's active.
>>
>>
>> >> +}
>> >> +
>> >> +static void rs780_voltage_scaling_enable(struct radeon_device *rdev, bool enable);
>> >> +
>> >> +static int rs780_initialize_dpm_power_state(struct radeon_device *rdev)
>> >> +{
>> >> +     struct atom_clock_dividers dividers;
>> >> +     struct igp_ps *default_state = rs780_get_ps(rdev->pm.dpm.boot_ps);
>> >> +     int i, ret;
>> >> +
>> >> +     ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
>> >> +                                          default_state->sclk_low, false, &dividers);
>> >> +     if (ret)
>> >> +             return ret;
>> >> +
>> >> +     r600_engine_clock_entry_set_reference_divider(rdev, 0, dividers.ref_div);
>> >> +     r600_engine_clock_entry_set_feedback_divider(rdev, 0, dividers.fb_div);
>> >> +     r600_engine_clock_entry_set_post_divider(rdev, 0, dividers.post_div);
>> >> +
>> >> +     if (dividers.enable_post_div)
>> >> +             r600_engine_clock_entry_enable_post_divider(rdev, 0, true);
>> >> +     else
>> >> +             r600_engine_clock_entry_enable_post_divider(rdev, 0, false);
>> >> +
>> >> +     r600_engine_clock_entry_set_step_time(rdev, 0, R600_SST_DFLT);
>> >> +     r600_engine_clock_entry_enable_pulse_skipping(rdev, 0, false);
>> >> +
>> >> +     r600_engine_clock_entry_enable(rdev, 0, true);
>> >> +     for (i = 1; i < R600_PM_NUMBER_OF_SCLKS; i++)
>> >> +             r600_engine_clock_entry_enable(rdev, i, false);
>> >> +
>> >> +     r600_enable_mclk_control(rdev, false);
>> >> +     r600_voltage_control_enable_pins(rdev, 0);
>> >> +
>> >> +     return 0;
>> >> +}
>> >> +
>> >> +static int rs780_initialize_dpm_parameters(struct radeon_device *rdev)
>> >> +{
>> >> +     int ret = 0;
>> >> +     int i;
>> >> +
>> >> +     r600_set_bsp(rdev, R600_BSU_DFLT, R600_BSP_DFLT);
>> >> +
>> >> +     r600_set_at(rdev, 0, 0, 0, 0);
>> >> +
>> >> +     r600_set_git(rdev, R600_GICST_DFLT);
>> >> +
>> >> +     for (i = 0; i < R600_PM_NUMBER_OF_TC; i++)
>> >> +             r600_set_tc(rdev, i, 0, 0);
>> >> +
>> >> +     r600_select_td(rdev, R600_TD_DFLT);
>> >> +     r600_set_vrc(rdev, 0);
>> >> +
>> >> +     r600_set_tpu(rdev, R600_TPU_DFLT);
>> >> +     r600_set_tpc(rdev, R600_TPC_DFLT);
>> >> +
>> >> +     r600_set_sstu(rdev, R600_SSTU_DFLT);
>> >> +     r600_set_sst(rdev, R600_SST_DFLT);
>> >> +
>> >> +     r600_set_fctu(rdev, R600_FCTU_DFLT);
>> >> +     r600_set_fct(rdev, R600_FCT_DFLT);
>> >> +
>> >> +     r600_set_vddc3d_oorsu(rdev, R600_VDDC3DOORSU_DFLT);
>> >> +     r600_set_vddc3d_oorphc(rdev, R600_VDDC3DOORPHC_DFLT);
>> >> +     r600_set_vddc3d_oorsdc(rdev, R600_VDDC3DOORSDC_DFLT);
>> >> +     r600_set_ctxcgtt3d_rphc(rdev, R600_CTXCGTT3DRPHC_DFLT);
>> >> +     r600_set_ctxcgtt3d_rsdc(rdev, R600_CTXCGTT3DRSDC_DFLT);
>> >> +
>> >> +     r600_vid_rt_set_vru(rdev, R600_VRU_DFLT);
>> >> +     r600_vid_rt_set_vrt(rdev, R600_VOLTAGERESPONSETIME_DFLT);
>> >> +     r600_vid_rt_set_ssu(rdev, R600_SPLLSTEPUNIT_DFLT);
>> >> +
>> >> +     ret = rs780_initialize_dpm_power_state(rdev);
>> >> +
>> >> +     r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_LOW,     0);
>> >> +     r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_MEDIUM,  0);
>> >> +     r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_HIGH,    0);
>> >> +
>> >> +     r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_LOW,    0);
>> >> +     r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_MEDIUM, 0);
>> >> +     r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_HIGH,   0);
>> >> +
>> >> +     r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_LOW,    0);
>> >> +     r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_MEDIUM, 0);
>> >> +     r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_HIGH,   0);
>> >> +
>> >> +     r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_LOW,    R600_DISPLAY_WATERMARK_HIGH);
>> >> +     r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_MEDIUM, R600_DISPLAY_WATERMARK_HIGH);
>> >> +     r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_HIGH,   R600_DISPLAY_WATERMARK_HIGH);
>> >> +
>> >> +     r600_power_level_enable(rdev, R600_POWER_LEVEL_CTXSW, false);
>> >> +     r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, false);
>> >> +     r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, false);
>> >> +     r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true);
>> >> +
>> >> +     r600_power_level_set_enter_index(rdev, R600_POWER_LEVEL_LOW);
>> >> +
>> >> +     r600_set_vrc(rdev, RS780_CGFTV_DFLT);
>> >> +
>> >> +     return ret;
>> >> +}
>> >> +
>> >> +static void rs780_start_dpm(struct radeon_device *rdev)
>> >> +{
>> >> +     r600_enable_sclk_control(rdev, false);
>> >> +     r600_enable_mclk_control(rdev, false);
>> >> +
>> >> +     r600_dynamicpm_enable(rdev, true);
>> >> +
>> >> +     radeon_wait_for_vblank(rdev, 0);
>> >> +     radeon_wait_for_vblank(rdev, 1);
>> >> +
>> >> +     r600_enable_spll_bypass(rdev, true);
>> >> +     r600_wait_for_spll_change(rdev);
>> >> +     r600_enable_spll_bypass(rdev, false);
>> >> +     r600_wait_for_spll_change(rdev);
>> >> +
>> >> +     r600_enable_spll_bypass(rdev, true);
>> >> +     r600_wait_for_spll_change(rdev);
>> >> +     r600_enable_spll_bypass(rdev, false);
>> >> +     r600_wait_for_spll_change(rdev);
>> >> +
>> >> +     r600_enable_sclk_control(rdev, true);
>> >> +}
>> >> +
>> >> +
>> >> +static void rs780_preset_ranges_slow_clk_fbdiv_en(struct radeon_device *rdev)
>> >> +{
>> >> +     WREG32_P(FVTHROT_SLOW_CLK_FEEDBACK_DIV_REG1, RANGE_SLOW_CLK_FEEDBACK_DIV_EN,
>> >> +              ~RANGE_SLOW_CLK_FEEDBACK_DIV_EN);
>> >> +
>> >> +     WREG32_P(FVTHROT_SLOW_CLK_FEEDBACK_DIV_REG1,
>> >> +              RANGE0_SLOW_CLK_FEEDBACK_DIV(RS780_SLOWCLKFEEDBACKDIV_DFLT),
>> >> +              ~RANGE0_SLOW_CLK_FEEDBACK_DIV_MASK);
>> >> +}
>> >> +
>> >> +static void rs780_preset_starting_fbdiv(struct radeon_device *rdev)
>> >> +{
>> >> +     u32 fbdiv = (RREG32(CG_SPLL_FUNC_CNTL) & SPLL_FB_DIV_MASK) >> SPLL_FB_DIV_SHIFT;
>> >> +
>> >> +     WREG32_P(FVTHROT_FBDIV_REG1, STARTING_FEEDBACK_DIV(fbdiv),
>> >> +              ~STARTING_FEEDBACK_DIV_MASK);
>> >> +
>> >> +     WREG32_P(FVTHROT_FBDIV_REG2, FORCED_FEEDBACK_DIV(fbdiv),
>> >> +              ~FORCED_FEEDBACK_DIV_MASK);
>> >> +
>> >> +     WREG32_P(FVTHROT_FBDIV_REG1, FORCE_FEEDBACK_DIV, ~FORCE_FEEDBACK_DIV);
>> >> +}
>> >> +
>> >> +static void rs780_voltage_scaling_init(struct radeon_device *rdev)
>> >> +{
>> >> +     struct igp_power_info *pi = rs780_get_pi(rdev);
>> >> +     struct drm_device *dev = rdev->ddev;
>> >> +     u32 fv_throt_pwm_fb_div_range[3];
>> >> +     u32 fv_throt_pwm_range[4];
>> >> +
>> >> +     if (dev->pdev->device == 0x9614) {
>> >> +             fv_throt_pwm_fb_div_range[0] = RS780D_FVTHROTPWMFBDIVRANGEREG0_DFLT;
>> >> +             fv_throt_pwm_fb_div_range[1] = RS780D_FVTHROTPWMFBDIVRANGEREG1_DFLT;
>> >> +             fv_throt_pwm_fb_div_range[2] = RS780D_FVTHROTPWMFBDIVRANGEREG2_DFLT;
>> >> +     } else if ((dev->pdev->device == 0x9714) ||
>> >> +                (dev->pdev->device == 0x9715)) {
>> >> +             fv_throt_pwm_fb_div_range[0] = RS880D_FVTHROTPWMFBDIVRANGEREG0_DFLT;
>> >> +             fv_throt_pwm_fb_div_range[1] = RS880D_FVTHROTPWMFBDIVRANGEREG1_DFLT;
>> >> +             fv_throt_pwm_fb_div_range[2] = RS880D_FVTHROTPWMFBDIVRANGEREG2_DFLT;
>> >> +     } else {
>> >> +             fv_throt_pwm_fb_div_range[0] = RS780_FVTHROTPWMFBDIVRANGEREG0_DFLT;
>> >> +             fv_throt_pwm_fb_div_range[1] = RS780_FVTHROTPWMFBDIVRANGEREG1_DFLT;
>> >> +             fv_throt_pwm_fb_div_range[2] = RS780_FVTHROTPWMFBDIVRANGEREG2_DFLT;
>> >> +     }
>> >> +
>> >> +     if (pi->pwm_voltage_control) {
>> >> +             fv_throt_pwm_range[0] = pi->min_voltage;
>> >> +             fv_throt_pwm_range[1] = pi->min_voltage;
>> >> +             fv_throt_pwm_range[2] = pi->max_voltage;
>> >> +             fv_throt_pwm_range[3] = pi->max_voltage;
>> >> +     } else {
>> >> +             fv_throt_pwm_range[0] = pi->invert_pwm_required ?
>> >> +                     RS780_FVTHROTPWMRANGE3_GPIO_DFLT : RS780_FVTHROTPWMRANGE0_GPIO_DFLT;
>> >> +             fv_throt_pwm_range[1] = pi->invert_pwm_required ?
>> >> +                     RS780_FVTHROTPWMRANGE2_GPIO_DFLT : RS780_FVTHROTPWMRANGE1_GPIO_DFLT;
>> >> +             fv_throt_pwm_range[2] = pi->invert_pwm_required ?
>> >> +                     RS780_FVTHROTPWMRANGE1_GPIO_DFLT : RS780_FVTHROTPWMRANGE2_GPIO_DFLT;
>> >> +             fv_throt_pwm_range[3] = pi->invert_pwm_required ?
>> >> +                     RS780_FVTHROTPWMRANGE0_GPIO_DFLT : RS780_FVTHROTPWMRANGE3_GPIO_DFLT;
>> >> +     }
>> >> +
>> >> +     WREG32_P(FVTHROT_PWM_CTRL_REG0,
>> >> +              STARTING_PWM_HIGHTIME(pi->max_voltage),
>> >> +              ~STARTING_PWM_HIGHTIME_MASK);
>> >> +
>> >> +     WREG32_P(FVTHROT_PWM_CTRL_REG0,
>> >> +              NUMBER_OF_CYCLES_IN_PERIOD(pi->num_of_cycles_in_period),
>> >> +              ~NUMBER_OF_CYCLES_IN_PERIOD_MASK);
>> >> +
>> >> +     WREG32_P(FVTHROT_PWM_CTRL_REG0, FORCE_STARTING_PWM_HIGHTIME,
>> >> +              ~FORCE_STARTING_PWM_HIGHTIME);
>> >> +
>> >> +     if (pi->invert_pwm_required)
>> >> +             WREG32_P(FVTHROT_PWM_CTRL_REG0, INVERT_PWM_WAVEFORM, ~INVERT_PWM_WAVEFORM);
>> >> +     else
>> >> +             WREG32_P(FVTHROT_PWM_CTRL_REG0, 0, ~INVERT_PWM_WAVEFORM);
>> >> +
>> >> +     rs780_voltage_scaling_enable(rdev, true);
>> >> +
>> >> +     WREG32(FVTHROT_PWM_CTRL_REG1,
>> >> +            (MIN_PWM_HIGHTIME(pi->min_voltage) |
>> >> +             MAX_PWM_HIGHTIME(pi->max_voltage)));
>> >> +
>> >> +     WREG32(FVTHROT_PWM_US_REG0, RS780_FVTHROTPWMUSREG0_DFLT);
>> >> +     WREG32(FVTHROT_PWM_US_REG1, RS780_FVTHROTPWMUSREG1_DFLT);
>> >> +     WREG32(FVTHROT_PWM_DS_REG0, RS780_FVTHROTPWMDSREG0_DFLT);
>> >> +     WREG32(FVTHROT_PWM_DS_REG1, RS780_FVTHROTPWMDSREG1_DFLT);
>> >> +
>> >> +     WREG32_P(FVTHROT_PWM_FEEDBACK_DIV_REG1,
>> >> +              RANGE0_PWM_FEEDBACK_DIV(fv_throt_pwm_fb_div_range[0]),
>> >> +              ~RANGE0_PWM_FEEDBACK_DIV_MASK);
>> >> +
>> >> +     WREG32(FVTHROT_PWM_FEEDBACK_DIV_REG2,
>> >> +            (RANGE1_PWM_FEEDBACK_DIV(fv_throt_pwm_fb_div_range[1]) |
>> >> +             RANGE2_PWM_FEEDBACK_DIV(fv_throt_pwm_fb_div_range[2])));
>> >> +
>> >> +     WREG32(FVTHROT_PWM_FEEDBACK_DIV_REG3,
>> >> +            (RANGE0_PWM(fv_throt_pwm_range[1]) |
>> >> +             RANGE1_PWM(fv_throt_pwm_range[2])));
>> >> +     WREG32(FVTHROT_PWM_FEEDBACK_DIV_REG4,
>> >> +            (RANGE2_PWM(fv_throt_pwm_range[1]) |
>> >> +             RANGE3_PWM(fv_throt_pwm_range[2])));
>> >> +}
>> >> +
>> >> +static void rs780_clk_scaling_enable(struct radeon_device *rdev, bool enable)
>> >> +{
>> >> +     if (enable)
>> >> +             WREG32_P(FVTHROT_CNTRL_REG, ENABLE_FV_THROT | ENABLE_FV_UPDATE,
>> >> +                      ~(ENABLE_FV_THROT | ENABLE_FV_UPDATE));
>> >> +     else
>> >> +             WREG32_P(FVTHROT_CNTRL_REG, 0,
>> >> +                      ~(ENABLE_FV_THROT | ENABLE_FV_UPDATE));
>> >> +}
>> >> +
>> >> +static void rs780_voltage_scaling_enable(struct radeon_device *rdev, bool enable)
>> >> +{
>> >> +     if (enable)
>> >> +             WREG32_P(FVTHROT_CNTRL_REG, ENABLE_FV_THROT_IO, ~ENABLE_FV_THROT_IO);
>> >> +     else
>> >> +             WREG32_P(FVTHROT_CNTRL_REG, 0, ~ENABLE_FV_THROT_IO);
>> >> +}
>> >> +
>> >> +static void rs780_set_engine_clock_wfc(struct radeon_device *rdev)
>> >> +{
>> >> +     WREG32(FVTHROT_UTC0, RS780_FVTHROTUTC0_DFLT);
>> >> +     WREG32(FVTHROT_UTC1, RS780_FVTHROTUTC1_DFLT);
>> >> +     WREG32(FVTHROT_UTC2, RS780_FVTHROTUTC2_DFLT);
>> >> +     WREG32(FVTHROT_UTC3, RS780_FVTHROTUTC3_DFLT);
>> >> +     WREG32(FVTHROT_UTC4, RS780_FVTHROTUTC4_DFLT);
>> >> +
>> >> +     WREG32(FVTHROT_DTC0, RS780_FVTHROTDTC0_DFLT);
>> >> +     WREG32(FVTHROT_DTC1, RS780_FVTHROTDTC1_DFLT);
>> >> +     WREG32(FVTHROT_DTC2, RS780_FVTHROTDTC2_DFLT);
>> >> +     WREG32(FVTHROT_DTC3, RS780_FVTHROTDTC3_DFLT);
>> >> +     WREG32(FVTHROT_DTC4, RS780_FVTHROTDTC4_DFLT);
>> >> +}
>> >> +
>> >> +static void rs780_set_engine_clock_sc(struct radeon_device *rdev)
>> >> +{
>> >> +     WREG32_P(FVTHROT_FBDIV_REG2,
>> >> +              FB_DIV_TIMER_VAL(RS780_FBDIVTIMERVAL_DFLT),
>> >> +              ~FB_DIV_TIMER_VAL_MASK);
>> >> +
>> >> +     WREG32_P(FVTHROT_CNTRL_REG,
>> >> +              REFRESH_RATE_DIVISOR(0) | MINIMUM_CIP(0xf),
>> >> +              ~(REFRESH_RATE_DIVISOR_MASK | MINIMUM_CIP_MASK));
>> >> +}
>> >> +
>> >> +static void rs780_set_engine_clock_tdc(struct radeon_device *rdev)
>> >> +{
>> >> +     WREG32_P(FVTHROT_CNTRL_REG, 0, ~(FORCE_TREND_SEL | TREND_SEL_MODE));
>> >> +}
>> >> +
>> >> +static void rs780_set_engine_clock_ssc(struct radeon_device *rdev)
>> >> +{
>> >> +     WREG32(FVTHROT_FB_US_REG0, RS780_FVTHROTFBUSREG0_DFLT);
>> >> +     WREG32(FVTHROT_FB_US_REG1, RS780_FVTHROTFBUSREG1_DFLT);
>> >> +     WREG32(FVTHROT_FB_DS_REG0, RS780_FVTHROTFBDSREG0_DFLT);
>> >> +     WREG32(FVTHROT_FB_DS_REG1, RS780_FVTHROTFBDSREG1_DFLT);
>> >> +
>> >> +     WREG32_P(FVTHROT_FBDIV_REG1, MAX_FEEDBACK_STEP(1), ~MAX_FEEDBACK_STEP_MASK);
>> >> +}
>> >> +
>> >> +static void rs780_program_at(struct radeon_device *rdev)
>> >> +{
>> >> +     struct igp_power_info *pi = rs780_get_pi(rdev);
>> >> +
>> >> +     WREG32(FVTHROT_TARGET_REG, 30000000 / pi->refresh_rate);
>> >> +     WREG32(FVTHROT_CB1, 1000000 * 5 / pi->refresh_rate);
>> >> +     WREG32(FVTHROT_CB2, 1000000 * 10 / pi->refresh_rate);
>> >> +     WREG32(FVTHROT_CB3, 1000000 * 30 / pi->refresh_rate);
>> >> +     WREG32(FVTHROT_CB4, 1000000 * 50 / pi->refresh_rate);
>> >> +}
>> >> +
>> >> +static void rs780_disable_vbios_powersaving(struct radeon_device *rdev)
>> >> +{
>> >> +     WREG32_P(CG_INTGFX_MISC, 0, ~0xFFF00000);
>> >> +}
>> >> +
>> >> +static void rs780_force_voltage_to_high(struct radeon_device *rdev)
>> >> +{
>> >> +     struct igp_power_info *pi = rs780_get_pi(rdev);
>> >> +     struct igp_ps *current_state = rs780_get_ps(rdev->pm.dpm.current_ps);
>> >> +
>> >> +     if ((current_state->max_voltage == RS780_VDDC_LEVEL_HIGH) &&
>> >> +         (current_state->min_voltage == RS780_VDDC_LEVEL_HIGH))
>> >> +             return;
>> >> +
>> >> +     WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL);
>> >> +
>> >> +     udelay(1);
>> >> +
>> >> +     WREG32_P(FVTHROT_PWM_CTRL_REG0,
>> >> +              STARTING_PWM_HIGHTIME(pi->max_voltage),
>> >> +              ~STARTING_PWM_HIGHTIME_MASK);
>> >> +
>> >> +     WREG32_P(FVTHROT_PWM_CTRL_REG0,
>> >> +              FORCE_STARTING_PWM_HIGHTIME, ~FORCE_STARTING_PWM_HIGHTIME);
>> >> +
>> >> +     WREG32_P(FVTHROT_PWM_FEEDBACK_DIV_REG1, 0,
>> >> +             ~RANGE_PWM_FEEDBACK_DIV_EN);
>> >> +
>> >> +     udelay(1);
>> >> +
>> >> +     WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
>> >> +}
>> >> +
>> >> +static int rs780_set_engine_clock_scaling(struct radeon_device *rdev)
>> >> +{
>> >> +     struct atom_clock_dividers min_dividers, max_dividers, current_max_dividers;
>> >> +     struct igp_ps *new_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
>> >> +     struct igp_ps *old_state = rs780_get_ps(rdev->pm.dpm.current_ps);
>> >> +     int ret;
>> >> +
>> >> +     if ((new_state->sclk_high == old_state->sclk_high) &&
>> >> +         (new_state->sclk_low == old_state->sclk_low))
>> >> +             return 0;
>> >> +
>> >> +     ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
>> >> +                                          new_state->sclk_low, false, &min_dividers);
>> >> +     if (ret)
>> >> +             return ret;
>> >> +
>> >> +     ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
>> >> +                                          new_state->sclk_high, false, &max_dividers);
>> >> +     if (ret)
>> >> +             return ret;
>> >> +
>> >> +     ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
>> >> +                                          old_state->sclk_high, false, &current_max_dividers);
>> >> +     if (ret)
>> >> +             return ret;
>> >> +
>> >> +     WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL);
>> >> +
>> >> +     WREG32_P(FVTHROT_FBDIV_REG2, FORCED_FEEDBACK_DIV(max_dividers.fb_div),
>> >> +              ~FORCED_FEEDBACK_DIV_MASK);
>> >> +     WREG32_P(FVTHROT_FBDIV_REG1, STARTING_FEEDBACK_DIV(max_dividers.fb_div),
>> >> +              ~STARTING_FEEDBACK_DIV_MASK);
>> >> +     WREG32_P(FVTHROT_FBDIV_REG1, FORCE_FEEDBACK_DIV, ~FORCE_FEEDBACK_DIV);
>> >> +
>> >> +     udelay(100);
>> >> +
>> >> +     WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
>> >> +
>> >> +     if (max_dividers.fb_div > min_dividers.fb_div) {
>> >> +             WREG32_P(FVTHROT_FBDIV_REG0,
>> >> +                      MIN_FEEDBACK_DIV(min_dividers.fb_div) |
>> >> +                      MAX_FEEDBACK_DIV(max_dividers.fb_div),
>> >> +                      ~(MIN_FEEDBACK_DIV_MASK | MAX_FEEDBACK_DIV_MASK));
>> >> +
>> >> +             WREG32_P(FVTHROT_FBDIV_REG1, 0, ~FORCE_FEEDBACK_DIV);
>> >> +     }
>> >> +
>> >> +     return 0;
>> >> +}
>> >> +
>> >> +static void rs780_set_engine_clock_spc(struct radeon_device *rdev)
>> >> +{
>> >> +     struct igp_ps *new_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
>> >> +     struct igp_ps *old_state = rs780_get_ps(rdev->pm.dpm.current_ps);
>> >> +     struct igp_power_info *pi = rs780_get_pi(rdev);
>> >> +
>> >> +     if ((new_state->sclk_high == old_state->sclk_high) &&
>> >> +         (new_state->sclk_low == old_state->sclk_low))
>> >> +             return;
>> >> +
>> >> +     if (pi->crtc_id == 0)
>> >> +             WREG32_P(CG_INTGFX_MISC, 0, ~FVTHROT_VBLANK_SEL);
>> >> +     else
>> >> +             WREG32_P(CG_INTGFX_MISC, FVTHROT_VBLANK_SEL, ~FVTHROT_VBLANK_SEL);
>> >> +
>> >> +}
>> >> +
>> >> +static void rs780_activate_engine_clk_scaling(struct radeon_device *rdev)
>> >> +{
>> >> +     struct igp_ps *new_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
>> >> +     struct igp_ps *old_state = rs780_get_ps(rdev->pm.dpm.current_ps);
>> >> +
>> >> +     if ((new_state->sclk_high == old_state->sclk_high) &&
>> >> +         (new_state->sclk_low == old_state->sclk_low))
>> >> +             return;
>> >> +
>> >> +     rs780_clk_scaling_enable(rdev, true);
>> >> +}
>> >> +
>> >> +static u32 rs780_get_voltage_for_vddc_level(struct radeon_device *rdev,
>> >> +                                         enum rs780_vddc_level vddc)
>> >> +{
>> >> +     struct igp_power_info *pi = rs780_get_pi(rdev);
>> >> +
>> >> +     if (vddc == RS780_VDDC_LEVEL_HIGH)
>> >> +             return pi->max_voltage;
>> >> +     else if (vddc == RS780_VDDC_LEVEL_LOW)
>> >> +             return pi->min_voltage;
>> >> +     else
>> >> +             return pi->max_voltage;
>> >> +}
>> >> +
>> >> +static void rs780_enable_voltage_scaling(struct radeon_device *rdev)
>> >> +{
>> >> +     struct igp_ps *new_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
>> >> +     struct igp_power_info *pi = rs780_get_pi(rdev);
>> >> +     enum rs780_vddc_level vddc_high, vddc_low;
>> >> +
>> >> +     udelay(100);
>> >> +
>> >> +     if ((new_state->max_voltage == RS780_VDDC_LEVEL_HIGH) &&
>> >> +         (new_state->min_voltage == RS780_VDDC_LEVEL_HIGH))
>> >> +             return;
>> >> +
>> >> +     vddc_high = rs780_get_voltage_for_vddc_level(rdev,
>> >> +                                                  new_state->max_voltage);
>> >> +     vddc_low = rs780_get_voltage_for_vddc_level(rdev,
>> >> +                                                 new_state->min_voltage);
>> >> +
>> >> +     WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL);
>> >> +
>> >> +     udelay(1);
>> >> +     if (vddc_high > vddc_low) {
>> >> +             WREG32_P(FVTHROT_PWM_FEEDBACK_DIV_REG1,
>> >> +                      RANGE_PWM_FEEDBACK_DIV_EN, ~RANGE_PWM_FEEDBACK_DIV_EN);
>> >> +
>> >> +             WREG32_P(FVTHROT_PWM_CTRL_REG0, 0, ~FORCE_STARTING_PWM_HIGHTIME);
>> >> +     } else if (vddc_high == vddc_low) {
>> >> +             if (pi->max_voltage != vddc_high) {
>> >> +                     WREG32_P(FVTHROT_PWM_CTRL_REG0,
>> >> +                              STARTING_PWM_HIGHTIME(vddc_high),
>> >> +                              ~STARTING_PWM_HIGHTIME_MASK);
>> >> +
>> >> +                     WREG32_P(FVTHROT_PWM_CTRL_REG0,
>> >> +                              FORCE_STARTING_PWM_HIGHTIME,
>> >> +                              ~FORCE_STARTING_PWM_HIGHTIME);
>> >> +             }
>> >> +     }
>> >> +
>> >> +     WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
>> >> +}
>> >> +
>> >> +int rs780_dpm_enable(struct radeon_device *rdev)
>> >> +{
>> >> +     struct igp_power_info *pi = rs780_get_pi(rdev);
>> >> +
>> >> +     rs780_get_pm_mode_parameters(rdev);
>> >> +     rs780_disable_vbios_powersaving(rdev);
>> >> +
>> >> +     if (r600_dynamicpm_enabled(rdev))
>> >> +             return -EINVAL;
>> >> +     if (rs780_initialize_dpm_parameters(rdev))
>> >> +             return -EINVAL;
>> >> +     rs780_start_dpm(rdev);
>> >> +
>> >> +     rs780_preset_ranges_slow_clk_fbdiv_en(rdev);
>> >> +     rs780_preset_starting_fbdiv(rdev);
>> >> +     if (pi->voltage_control)
>> >> +             rs780_voltage_scaling_init(rdev);
>> >> +     rs780_clk_scaling_enable(rdev, true);
>> >> +     rs780_set_engine_clock_sc(rdev);
>> >> +     rs780_set_engine_clock_wfc(rdev);
>> >> +     rs780_program_at(rdev);
>> >> +     rs780_set_engine_clock_tdc(rdev);
>> >> +     rs780_set_engine_clock_ssc(rdev);
>> >> +
>> >> +     if (pi->gfx_clock_gating)
>> >> +             r600_gfx_clockgating_enable(rdev, true);
>> >> +
>> >> +     return 0;
>> >> +}
>> >> +
>> >> +void rs780_dpm_disable(struct radeon_device *rdev)
>> >> +{
>> >> +     struct igp_power_info *pi = rs780_get_pi(rdev);
>> >> +
>> >> +     r600_dynamicpm_enable(rdev, false);
>> >> +
>> >> +     rs780_clk_scaling_enable(rdev, false);
>> >> +     rs780_voltage_scaling_enable(rdev, false);
>> >> +
>> >> +     if (pi->gfx_clock_gating)
>> >> +             r600_gfx_clockgating_enable(rdev, false);
>> >> +}
>> >> +
>> >> +int rs780_dpm_set_power_state(struct radeon_device *rdev)
>> >> +{
>> >> +     struct igp_power_info *pi = rs780_get_pi(rdev);
>> >> +
>> >> +     rs780_get_pm_mode_parameters(rdev);
>> >> +
>> >> +     if (pi->voltage_control) {
>> >> +             rs780_force_voltage_to_high(rdev);
>> >> +             mdelay(5);
>> >> +     }
>> >> +
>> >> +     rs780_set_engine_clock_scaling(rdev);
>> >> +     rs780_set_engine_clock_spc(rdev);
>> >> +
>> >> +     rs780_activate_engine_clk_scaling(rdev);
>> >> +
>> >> +     if (pi->voltage_control)
>> >> +             rs780_enable_voltage_scaling(rdev);
>> >> +
>> >> +     return 0;
>> >> +}
>> >> +
>> >> +void rs780_dpm_setup_asic(struct radeon_device *rdev)
>> >> +{
>> >> +
>> >> +}
>> >> +
>> >> +void rs780_dpm_display_configuration_changed(struct radeon_device *rdev)
>> >> +{
>> >> +     rs780_get_pm_mode_parameters(rdev);
>> >> +     rs780_program_at(rdev);
>> >> +}
>> >> +
>> >> +union igp_info {
>> >> +     struct _ATOM_INTEGRATED_SYSTEM_INFO info;
>> >> +     struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2;
>> >> +};
>> >> +
>> >> +union power_info {
>> >> +     struct _ATOM_POWERPLAY_INFO info;
>> >> +     struct _ATOM_POWERPLAY_INFO_V2 info_2;
>> >> +     struct _ATOM_POWERPLAY_INFO_V3 info_3;
>> >> +     struct _ATOM_PPLIB_POWERPLAYTABLE pplib;
>> >> +     struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2;
>> >> +     struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3;
>> >> +};
>> >> +
>> >> +union pplib_clock_info {
>> >> +     struct _ATOM_PPLIB_R600_CLOCK_INFO r600;
>> >> +     struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780;
>> >> +     struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen;
>> >> +     struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo;
>> >> +};
>> >> +
>> >> +union pplib_power_state {
>> >> +     struct _ATOM_PPLIB_STATE v1;
>> >> +     struct _ATOM_PPLIB_STATE_V2 v2;
>> >> +};
>> >> +
>> >> +static void rs780_parse_pplib_non_clock_info(struct radeon_device *rdev,
>> >> +                                          struct radeon_ps *rps,
>> >> +                                          struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info,
>> >> +                                          u8 table_rev)
>> >> +{
>> >> +     rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings);
>> >> +     rps->class = le16_to_cpu(non_clock_info->usClassification);
>> >> +     rps->class2 = le16_to_cpu(non_clock_info->usClassification2);
>> >> +
>> >> +     if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) {
>> >> +             rps->vclk = le32_to_cpu(non_clock_info->ulVCLK);
>> >> +             rps->dclk = le32_to_cpu(non_clock_info->ulDCLK);
>> >> +     } else if (r600_is_uvd_state(rps->class, rps->class2)) {
>> >> +             rps->vclk = RS780_DEFAULT_VCLK_FREQ;
>> >> +             rps->dclk = RS780_DEFAULT_DCLK_FREQ;
>> >> +     } else {
>> >> +             rps->vclk = 0;
>> >> +             rps->dclk = 0;
>> >> +     }
>> >> +
>> >> +     if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT)
>> >> +             rdev->pm.dpm.boot_ps = rps;
>> >> +     if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
>> >> +             rdev->pm.dpm.uvd_ps = rps;
>> >> +}
>> >> +
>> >> +static void rs780_parse_pplib_clock_info(struct radeon_device *rdev,
>> >> +                                      struct radeon_ps *rps,
>> >> +                                      union pplib_clock_info *clock_info)
>> >> +{
>> >> +     struct igp_ps *ps = rs780_get_ps(rps);
>> >> +     u32 sclk;
>> >> +
>> >> +     sclk = le16_to_cpu(clock_info->rs780.usLowEngineClockLow);
>> >> +     sclk |= clock_info->rs780.ucLowEngineClockHigh << 16;
>> >> +     ps->sclk_low = sclk;
>> >> +     sclk = le16_to_cpu(clock_info->rs780.usHighEngineClockLow);
>> >> +     sclk |= clock_info->rs780.ucHighEngineClockHigh << 16;
>> >> +     ps->sclk_high = sclk;
>> >> +     switch (le16_to_cpu(clock_info->rs780.usVDDC)) {
>> >> +     case ATOM_PPLIB_RS780_VOLTAGE_NONE:
>> >> +     default:
>> >> +             ps->min_voltage = RS780_VDDC_LEVEL_UNKNOWN;
>> >> +             ps->max_voltage = RS780_VDDC_LEVEL_UNKNOWN;
>> >> +             break;
>> >> +     case ATOM_PPLIB_RS780_VOLTAGE_LOW:
>> >> +             ps->min_voltage = RS780_VDDC_LEVEL_LOW;
>> >> +             ps->max_voltage = RS780_VDDC_LEVEL_LOW;
>> >> +             break;
>> >> +     case ATOM_PPLIB_RS780_VOLTAGE_HIGH:
>> >> +             ps->min_voltage = RS780_VDDC_LEVEL_HIGH;
>> >> +             ps->max_voltage = RS780_VDDC_LEVEL_HIGH;
>> >> +             break;
>> >> +     case ATOM_PPLIB_RS780_VOLTAGE_VARIABLE:
>> >> +             ps->min_voltage = RS780_VDDC_LEVEL_LOW;
>> >> +             ps->max_voltage = RS780_VDDC_LEVEL_HIGH;
>> >> +             break;
>> >> +     }
>> >> +     ps->flags = le32_to_cpu(clock_info->rs780.ulFlags);
>> >> +
>> >> +     if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) {
>> >> +             ps->sclk_low = rdev->clock.default_sclk;
>> >> +             ps->sclk_high = rdev->clock.default_sclk;
>> >> +             ps->min_voltage = RS780_VDDC_LEVEL_HIGH;
>> >> +             ps->max_voltage = RS780_VDDC_LEVEL_HIGH;
>> >> +     }
>> >> +}
>> >> +
>> >> +static int rs780_parse_power_table(struct radeon_device *rdev)
>> >> +{
>> >> +     struct radeon_mode_info *mode_info = &rdev->mode_info;
>> >> +     struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
>> >> +     union pplib_power_state *power_state;
>> >> +     int i;
>> >> +     union pplib_clock_info *clock_info;
>> >> +     union power_info *power_info;
>> >> +     int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
>> >> +        u16 data_offset;
>> >> +     u8 frev, crev;
>> >> +     struct igp_ps *ps;
>> >> +
>> >> +     if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
>> >> +                                &frev, &crev, &data_offset))
>> >> +             return -EINVAL;
>> >> +     power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
>> >> +
>> >> +     rdev->pm.dpm.ps = kzalloc(sizeof(struct radeon_ps) *
>> >> +                               power_info->pplib.ucNumStates, GFP_KERNEL);
>> >> +     if (!rdev->pm.dpm.ps)
>> >> +             return -ENOMEM;
>> >> +     rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps);
>> >> +     rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime);
>> >> +     rdev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime);
>> >> +
>> >> +     for (i = 0; i < power_info->pplib.ucNumStates; i++) {
>> >> +             power_state = (union pplib_power_state *)
>> >> +                     (mode_info->atom_context->bios + data_offset +
>> >> +                      le16_to_cpu(power_info->pplib.usStateArrayOffset) +
>> >> +                      i * power_info->pplib.ucStateEntrySize);
>> >> +             non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
>> >> +                     (mode_info->atom_context->bios + data_offset +
>> >> +                      le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset) +
>> >> +                      (power_state->v1.ucNonClockStateIndex *
>> >> +                       power_info->pplib.ucNonClockSize));
>> >> +             if (power_info->pplib.ucStateEntrySize - 1) {
>> >> +                     clock_info = (union pplib_clock_info *)
>> >> +                             (mode_info->atom_context->bios + data_offset +
>> >> +                              le16_to_cpu(power_info->pplib.usClockInfoArrayOffset) +
>> >> +                              (power_state->v1.ucClockStateIndices[0] *
>> >> +                               power_info->pplib.ucClockInfoSize));
>> >> +                     ps = kzalloc(sizeof(struct igp_ps), GFP_KERNEL);
>> >> +                     if (ps == NULL) {
>> >> +                             kfree(rdev->pm.dpm.ps);
>> >> +                             return -ENOMEM;
>> >> +                     }
>> >> +                     rdev->pm.dpm.ps[i].ps_priv = ps;
>> >> +                     rs780_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i],
>> >> +                                                      non_clock_info,
>> >> +                                                      power_info->pplib.ucNonClockSize);
>> >> +                     rs780_parse_pplib_clock_info(rdev,
>> >> +                                                  &rdev->pm.dpm.ps[i],
>> >> +                                                  clock_info);
>> >> +             }
>> >> +     }
>> >> +     rdev->pm.dpm.num_ps = power_info->pplib.ucNumStates;
>> >> +     return 0;
>> >> +}
>> >> +
>> >> +int rs780_dpm_init(struct radeon_device *rdev)
>> >> +{
>> >> +     struct igp_power_info *pi;
>> >> +     int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);
>> >> +     union igp_info *info;
>> >> +     u16 data_offset;
>> >> +     u8 frev, crev;
>> >> +     int ret;
>> >> +
>> >> +     pi = kzalloc(sizeof(struct igp_power_info), GFP_KERNEL);
>> >> +     if (pi == NULL)
>> >> +             return -ENOMEM;
>> >> +     rdev->pm.dpm.priv = pi;
>> >> +
>> >> +     ret = rs780_parse_power_table(rdev);
>> >> +     if (ret)
>> >> +             return ret;
>> >> +
>> >> +     pi->voltage_control = false;
>> >> +     pi->gfx_clock_gating = true;
>> >> +
>> >> +     if (atom_parse_data_header(rdev->mode_info.atom_context, index, NULL,
>> >> +                                &frev, &crev, &data_offset)) {
>> >> +             info = (union igp_info *)(rdev->mode_info.atom_context->bios + data_offset);
>> >> +
>> >> +             /* Get various system informations from bios */
>> >> +             switch (crev) {
>> >> +             case 1:
>> >> +                     pi->num_of_cycles_in_period =
>> >> +                             info->info.ucNumberOfCyclesInPeriod;
>> >> +                     pi->num_of_cycles_in_period |=
>> >> +                             info->info.ucNumberOfCyclesInPeriodHi << 8;
>> >> +                     pi->invert_pwm_required =
>> >> +                             (pi->num_of_cycles_in_period & 0x8000) ? true : false;
>> >> +                     pi->boot_voltage = info->info.ucStartingPWM_HighTime;
>> >> +                     pi->max_voltage = info->info.ucMaxNBVoltage;
>> >> +                     pi->max_voltage |= info->info.ucMaxNBVoltageHigh << 8;
>> >> +                     pi->min_voltage = info->info.ucMinNBVoltage;
>> >> +                     pi->min_voltage |= info->info.ucMinNBVoltageHigh << 8;
>> >> +                     pi->inter_voltage_low =
>> >> +                             le16_to_cpu(info->info.usInterNBVoltageLow);
>> >> +                     pi->inter_voltage_high =
>> >> +                             le16_to_cpu(info->info.usInterNBVoltageHigh);
>> >> +                     pi->voltage_control = true;
>> >> +                     pi->bootup_uma_clk = info->info.usK8MemoryClock * 100;
>> >> +                     break;
>> >> +             case 2:
>> >> +                     pi->num_of_cycles_in_period =
>> >> +                             le16_to_cpu(info->info_2.usNumberOfCyclesInPeriod);
>> >> +                     pi->invert_pwm_required =
>> >> +                             (pi->num_of_cycles_in_period & 0x8000) ? true : false;
>> >> +                     pi->boot_voltage =
>> >> +                             le16_to_cpu(info->info_2.usBootUpNBVoltage);
>> >> +                     pi->max_voltage =
>> >> +                             le16_to_cpu(info->info_2.usMaxNBVoltage);
>> >> +                     pi->min_voltage =
>> >> +                             le16_to_cpu(info->info_2.usMinNBVoltage);
>> >> +                     pi->system_config =
>> >> +                             le32_to_cpu(info->info_2.ulSystemConfig);
>> >> +                     pi->pwm_voltage_control =
>> >> +                             (pi->system_config & 0x4) ? true : false;
>> >> +                     pi->voltage_control = true;
>> >> +                     pi->bootup_uma_clk = le32_to_cpu(info->info_2.ulBootUpUMAClock);
>> >> +                     break;
>> >> +             default:
>> >> +                     DRM_ERROR("No integrated system info for your GPU\n");
>> >> +                     return -EINVAL;
>> >> +             }
>> >> +             if (pi->min_voltage > pi->max_voltage)
>> >> +                     pi->voltage_control = false;
>> >> +             if (pi->pwm_voltage_control) {
>> >> +                     if ((pi->num_of_cycles_in_period == 0) ||
>> >> +                         (pi->max_voltage == 0) ||
>> >> +                         (pi->min_voltage == 0))
>> >> +                             pi->voltage_control = false;
>> >> +             } else {
>> >> +                     if ((pi->num_of_cycles_in_period == 0) ||
>> >> +                         (pi->max_voltage == 0))
>> >> +                             pi->voltage_control = false;
>> >> +             }
>> >> +
>> >> +             return 0;
>> >> +     }
>> >> +     radeon_dpm_fini(rdev);
>> >> +     return -EINVAL;
>> >> +}
>> >> +
>> >> +void rs780_dpm_print_power_state(struct radeon_device *rdev,
>> >> +                              struct radeon_ps *rps)
>> >> +{
>> >> +     struct igp_ps *ps = rs780_get_ps(rps);
>> >> +
>> >> +     r600_dpm_print_class_info(rps->class, rps->class2);
>> >> +     r600_dpm_print_cap_info(rps->caps);
>> >> +     printk("\tuvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
>> >> +     printk("\t\tpower level 0    sclk: %u vddc_index: %d\n",
>> >> +            ps->sclk_low, ps->min_voltage);
>> >> +     printk("\t\tpower level 1    sclk: %u vddc_index: %d\n",
>> >> +            ps->sclk_high, ps->max_voltage);
>> >> +     r600_dpm_print_ps_status(rdev, rps);
>> >> +}
>> >> +
>> >> +void rs780_dpm_fini(struct radeon_device *rdev)
>> >> +{
>> >> +     int i;
>> >> +
>> >> +     for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
>> >> +             kfree(rdev->pm.dpm.ps[i].ps_priv);
>> >> +     }
>> >> +     kfree(rdev->pm.dpm.ps);
>> >> +     kfree(rdev->pm.dpm.priv);
>> >> +}
>> >> +
>> >> +u32 rs780_dpm_get_sclk(struct radeon_device *rdev, bool low)
>> >> +{
>> >> +     struct igp_ps *requested_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
>> >> +
>> >> +     if (low)
>> >> +             return requested_state->sclk_low;
>> >> +     else
>> >> +             return requested_state->sclk_high;
>> >> +}
>> >> +
>> >> +u32 rs780_dpm_get_mclk(struct radeon_device *rdev, bool low)
>> >> +{
>> >> +     struct igp_power_info *pi = rs780_get_pi(rdev);
>> >> +
>> >> +     return pi->bootup_uma_clk;
>> >> +}
>> >> diff --git a/drivers/gpu/drm/radeon/rs780_dpm.h b/drivers/gpu/drm/radeon/rs780_dpm.h
>> >> new file mode 100644
>> >> index 0000000..47a40b1
>> >> --- /dev/null
>> >> +++ b/drivers/gpu/drm/radeon/rs780_dpm.h
>> >> @@ -0,0 +1,109 @@
>> >> +/*
>> >> + * Copyright 2011 Advanced Micro Devices, Inc.
>> >> + *
>> >> + * Permission is hereby granted, free of charge, to any person obtaining a
>> >> + * copy of this software and associated documentation files (the "Software"),
>> >> + * to deal in the Software without restriction, including without limitation
>> >> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
>> >> + * and/or sell copies of the Software, and to permit persons to whom the
>> >> + * Software is furnished to do so, subject to the following conditions:
>> >> + *
>> >> + * The above copyright notice and this permission notice shall be included in
>> >> + * all copies or substantial portions of the Software.
>> >> + *
>> >> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>> >> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>> >> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
>> >> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
>> >> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
>> >> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
>> >> + * OTHER DEALINGS IN THE SOFTWARE.
>> >> + *
>> >> + */
>> >> +#ifndef __RS780_DPM_H__
>> >> +#define __RS780_DPM_H__
>> >> +
>> >> +enum rs780_vddc_level {
>> >> +     RS780_VDDC_LEVEL_UNKNOWN = 0,
>> >> +     RS780_VDDC_LEVEL_LOW = 1,
>> >> +     RS780_VDDC_LEVEL_HIGH = 2,
>> >> +};
>> >> +
>> >> +struct igp_power_info {
>> >> +     /* flags */
>> >> +     bool invert_pwm_required;
>> >> +     bool pwm_voltage_control;
>> >> +     bool voltage_control;
>> >> +     bool gfx_clock_gating;
>> >> +     /* stored values */
>> >> +     u32 system_config;
>> >> +     u32 bootup_uma_clk;
>> >> +     u16 max_voltage;
>> >> +     u16 min_voltage;
>> >> +     u16 boot_voltage;
>> >> +     u16 inter_voltage_low;
>> >> +     u16 inter_voltage_high;
>> >> +     u16 num_of_cycles_in_period;
>> >> +     /* variable */
>> >> +     int crtc_id;
>> >> +     int refresh_rate;
>> >> +};
>> >> +
>> >> +struct igp_ps {
>> >> +     enum rs780_vddc_level min_voltage;
>> >> +     enum rs780_vddc_level max_voltage;
>> >> +     u32 sclk_low;
>> >> +     u32 sclk_high;
>> >> +     u32 flags;
>> >> +};
>> >> +
>> >> +#define RS780_CGFTV_DFLT                 0x0303000f
>> >> +#define RS780_FBDIVTIMERVAL_DFLT         0x2710
>> >> +
>> >> +#define RS780_FVTHROTUTC0_DFLT   0x04010040
>> >> +#define RS780_FVTHROTUTC1_DFLT   0x04010040
>> >> +#define RS780_FVTHROTUTC2_DFLT   0x04010040
>> >> +#define RS780_FVTHROTUTC3_DFLT   0x04010040
>> >> +#define RS780_FVTHROTUTC4_DFLT   0x04010040
>> >> +
>> >> +#define RS780_FVTHROTDTC0_DFLT 0x04010040
>> >> +#define RS780_FVTHROTDTC1_DFLT 0x04010040
>> >> +#define RS780_FVTHROTDTC2_DFLT 0x04010040
>> >> +#define RS780_FVTHROTDTC3_DFLT 0x04010040
>> >> +#define RS780_FVTHROTDTC4_DFLT 0x04010040
>> >> +
>> >> +#define RS780_FVTHROTFBUSREG0_DFLT       0x00001001
>> >> +#define RS780_FVTHROTFBUSREG1_DFLT       0x00002002
>> >> +#define RS780_FVTHROTFBDSREG0_DFLT       0x00004001
>> >> +#define RS780_FVTHROTFBDSREG1_DFLT       0x00020010
>> >> +
>> >> +#define RS780_FVTHROTPWMUSREG0_DFLT      0x00002001
>> >> +#define RS780_FVTHROTPWMUSREG1_DFLT      0x00004003
>> >> +#define RS780_FVTHROTPWMDSREG0_DFLT      0x00002001
>> >> +#define RS780_FVTHROTPWMDSREG1_DFLT      0x00004003
>> >> +
>> >> +#define RS780_FVTHROTPWMFBDIVRANGEREG0_DFLT  0x37
>> >> +#define RS780_FVTHROTPWMFBDIVRANGEREG1_DFLT  0x4b
>> >> +#define RS780_FVTHROTPWMFBDIVRANGEREG2_DFLT  0x8b
>> >> +
>> >> +#define RS780D_FVTHROTPWMFBDIVRANGEREG0_DFLT  0x8b
>> >> +#define RS780D_FVTHROTPWMFBDIVRANGEREG1_DFLT  0x8c
>> >> +#define RS780D_FVTHROTPWMFBDIVRANGEREG2_DFLT  0xb5
>> >> +
>> >> +#define RS880D_FVTHROTPWMFBDIVRANGEREG0_DFLT  0x8d
>> >> +#define RS880D_FVTHROTPWMFBDIVRANGEREG1_DFLT  0x8e
>> >> +#define RS880D_FVTHROTPWMFBDIVRANGEREG2_DFLT  0xBa
>> >> +
>> >> +#define RS780_FVTHROTPWMRANGE0_GPIO_DFLT  0x1a
>> >> +#define RS780_FVTHROTPWMRANGE1_GPIO_DFLT  0x1a
>> >> +#define RS780_FVTHROTPWMRANGE2_GPIO_DFLT  0x0
>> >> +#define RS780_FVTHROTPWMRANGE3_GPIO_DFLT  0x0
>> >> +
>> >> +#define RS780_SLOWCLKFEEDBACKDIV_DFLT 110
>> >> +
>> >> +#define RS780_CGCLKGATING_DFLT           0x0000E204
>> >> +
>> >> +#define RS780_DEFAULT_VCLK_FREQ  53300 /* 10 khz */
>> >> +#define RS780_DEFAULT_DCLK_FREQ  40000 /* 10 khz */
>> >> +
>> >> +#endif
>> >> diff --git a/drivers/gpu/drm/radeon/rs780d.h b/drivers/gpu/drm/radeon/rs780d.h
>> >> new file mode 100644
>> >> index 0000000..b1142ed
>> >> --- /dev/null
>> >> +++ b/drivers/gpu/drm/radeon/rs780d.h
>> >> @@ -0,0 +1,168 @@
>> >> +/*
>> >> + * Copyright 2011 Advanced Micro Devices, Inc.
>> >> + *
>> >> + * Permission is hereby granted, free of charge, to any person obtaining a
>> >> + * copy of this software and associated documentation files (the "Software"),
>> >> + * to deal in the Software without restriction, including without limitation
>> >> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
>> >> + * and/or sell copies of the Software, and to permit persons to whom the
>> >> + * Software is furnished to do so, subject to the following conditions:
>> >> + *
>> >> + * The above copyright notice and this permission notice shall be included in
>> >> + * all copies or substantial portions of the Software.
>> >> + *
>> >> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>> >> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>> >> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
>> >> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
>> >> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
>> >> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
>> >> + * OTHER DEALINGS IN THE SOFTWARE.
>> >> + *
>> >> + */
>> >> +#ifndef __RS780D_H__
>> >> +#define __RS780D_H__
>> >> +
>> >> +#define CG_SPLL_FUNC_CNTL                                 0x600
>> >> +#       define SPLL_RESET                                (1 << 0)
>> >> +#       define SPLL_SLEEP                                (1 << 1)
>> >> +#       define SPLL_REF_DIV(x)                           ((x) << 2)
>> >> +#       define SPLL_REF_DIV_MASK                         (7 << 2)
>> >> +#       define SPLL_FB_DIV(x)                            ((x) << 5)
>> >> +#       define SPLL_FB_DIV_MASK                          (0xff << 2)
>> >> +#       define SPLL_FB_DIV_SHIFT                         2
>> >> +#       define SPLL_PULSEEN                              (1 << 13)
>> >> +#       define SPLL_PULSENUM(x)                          ((x) << 14)
>> >> +#       define SPLL_PULSENUM_MASK                        (3 << 14)
>> >> +#       define SPLL_SW_HILEN(x)                          ((x) << 16)
>> >> +#       define SPLL_SW_HILEN_MASK                        (0xf << 16)
>> >> +#       define SPLL_SW_LOLEN(x)                          ((x) << 20)
>> >> +#       define SPLL_SW_LOLEN_MASK                        (0xf << 20)
>> >> +#       define SPLL_DIVEN                                (1 << 24)
>> >> +#       define SPLL_BYPASS_EN                            (1 << 25)
>> >> +#       define SPLL_CHG_STATUS                           (1 << 29)
>> >> +#       define SPLL_CTLREQ                               (1 << 30)
>> >> +#       define SPLL_CTLACK                               (1 << 31)
>> >> +
>> >> +/* RS780/RS880 PM */
>> >> +#define      FVTHROT_CNTRL_REG                               0x3000
>> >> +#define              DONT_WAIT_FOR_FBDIV_WRAP                (1 << 0)
>> >> +#define              MINIMUM_CIP(x)                          ((x) << 1)
>> >> +#define              MINIMUM_CIP_SHIFT                       1
>> >> +#define              MINIMUM_CIP_MASK                        0x1fffffe
>> >> +#define              REFRESH_RATE_DIVISOR(x)                 ((x) << 25)
>> >> +#define              REFRESH_RATE_DIVISOR_SHIFT              25
>> >> +#define              REFRESH_RATE_DIVISOR_MASK               (0x3 << 25)
>> >> +#define              ENABLE_FV_THROT                         (1 << 27)
>> >> +#define              ENABLE_FV_UPDATE                        (1 << 28)
>> >> +#define              TREND_SEL_MODE                          (1 << 29)
>> >> +#define              FORCE_TREND_SEL                         (1 << 30)
>> >> +#define              ENABLE_FV_THROT_IO                      (1 << 31)
>> >> +#define      FVTHROT_TARGET_REG                              0x3004
>> >> +#define              TARGET_IDLE_COUNT(x)                    ((x) << 0)
>> >> +#define              TARGET_IDLE_COUNT_MASK                  0xffffff
>> >> +#define              TARGET_IDLE_COUNT_SHIFT                 0
>> >> +#define      FVTHROT_CB1                                     0x3008
>> >> +#define      FVTHROT_CB2                                     0x300c
>> >> +#define      FVTHROT_CB3                                     0x3010
>> >> +#define      FVTHROT_CB4                                     0x3014
>> >> +#define      FVTHROT_UTC0                                    0x3018
>> >> +#define      FVTHROT_UTC1                                    0x301c
>> >> +#define      FVTHROT_UTC2                                    0x3020
>> >> +#define      FVTHROT_UTC3                                    0x3024
>> >> +#define      FVTHROT_UTC4                                    0x3028
>> >> +#define      FVTHROT_DTC0                                    0x302c
>> >> +#define      FVTHROT_DTC1                                    0x3030
>> >> +#define      FVTHROT_DTC2                                    0x3034
>> >> +#define      FVTHROT_DTC3                                    0x3038
>> >> +#define      FVTHROT_DTC4                                    0x303c
>> >> +#define      FVTHROT_FBDIV_REG0                              0x3040
>> >> +#define              MIN_FEEDBACK_DIV(x)                     ((x) << 0)
>> >> +#define              MIN_FEEDBACK_DIV_MASK                   0xfff
>> >> +#define              MIN_FEEDBACK_DIV_SHIFT                  0
>> >> +#define              MAX_FEEDBACK_DIV(x)                     ((x) << 12)
>> >> +#define              MAX_FEEDBACK_DIV_MASK                   (0xfff << 12)
>> >> +#define              MAX_FEEDBACK_DIV_SHIFT                  12
>> >> +#define      FVTHROT_FBDIV_REG1                              0x3044
>> >> +#define              MAX_FEEDBACK_STEP(x)                    ((x) << 0)
>> >> +#define              MAX_FEEDBACK_STEP_MASK                  0xfff
>> >> +#define              MAX_FEEDBACK_STEP_SHIFT                 0
>> >> +#define              STARTING_FEEDBACK_DIV(x)                ((x) << 12)
>> >> +#define              STARTING_FEEDBACK_DIV_MASK              (0xfff << 12)
>> >> +#define              STARTING_FEEDBACK_DIV_SHIFT             12
>> >> +#define              FORCE_FEEDBACK_DIV                      (1 << 24)
>> >> +#define      FVTHROT_FBDIV_REG2                              0x3048
>> >> +#define              FORCED_FEEDBACK_DIV(x)                  ((x) << 0)
>> >> +#define              FORCED_FEEDBACK_DIV_MASK                0xfff
>> >> +#define              FORCED_FEEDBACK_DIV_SHIFT               0
>> >> +#define              FB_DIV_TIMER_VAL(x)                     ((x) << 12)
>> >> +#define              FB_DIV_TIMER_VAL_MASK                   (0xffff << 12)
>> >> +#define              FB_DIV_TIMER_VAL_SHIFT                  12
>> >> +#define      FVTHROT_FB_US_REG0                              0x304c
>> >> +#define      FVTHROT_FB_US_REG1                              0x3050
>> >> +#define      FVTHROT_FB_DS_REG0                              0x3054
>> >> +#define      FVTHROT_FB_DS_REG1                              0x3058
>> >> +#define      FVTHROT_PWM_CTRL_REG0                           0x305c
>> >> +#define              STARTING_PWM_HIGHTIME(x)                ((x) << 0)
>> >> +#define              STARTING_PWM_HIGHTIME_MASK              0xfff
>> >> +#define              STARTING_PWM_HIGHTIME_SHIFT             0
>> >> +#define              NUMBER_OF_CYCLES_IN_PERIOD(x)           ((x) << 12)
>> >> +#define              NUMBER_OF_CYCLES_IN_PERIOD_MASK         (0xfff << 12)
>> >> +#define              NUMBER_OF_CYCLES_IN_PERIOD_SHIFT        12
>> >> +#define              FORCE_STARTING_PWM_HIGHTIME             (1 << 24)
>> >> +#define              INVERT_PWM_WAVEFORM                     (1 << 25)
>> >> +#define      FVTHROT_PWM_CTRL_REG1                           0x3060
>> >> +#define              MIN_PWM_HIGHTIME(x)                     ((x) << 0)
>> >> +#define              MIN_PWM_HIGHTIME_MASK                   0xfff
>> >> +#define              MIN_PWM_HIGHTIME_SHIFT                  0
>> >> +#define              MAX_PWM_HIGHTIME(x)                     ((x) << 12)
>> >> +#define              MAX_PWM_HIGHTIME_MASK                   (0xfff << 12)
>> >> +#define              MAX_PWM_HIGHTIME_SHIFT                  12
>> >> +#define      FVTHROT_PWM_US_REG0                             0x3064
>> >> +#define      FVTHROT_PWM_US_REG1                             0x3068
>> >> +#define      FVTHROT_PWM_DS_REG0                             0x306c
>> >> +#define      FVTHROT_PWM_DS_REG1                             0x3070
>> >> +#define      FVTHROT_STATUS_REG0                             0x3074
>> >> +#define              CURRENT_FEEDBACK_DIV_MASK               0xfff
>> >> +#define              CURRENT_FEEDBACK_DIV_SHIFT              0
>> >> +#define      FVTHROT_STATUS_REG1                             0x3078
>> >> +#define      FVTHROT_STATUS_REG2                             0x307c
>> >> +#define      CG_INTGFX_MISC                                  0x3080
>> >> +#define              FVTHROT_VBLANK_SEL                      (1 << 9)
>> >> +#define      FVTHROT_PWM_FEEDBACK_DIV_REG1                   0x308c
>> >> +#define              RANGE0_PWM_FEEDBACK_DIV(x)              ((x) << 0)
>> >> +#define              RANGE0_PWM_FEEDBACK_DIV_MASK            0xfff
>> >> +#define              RANGE0_PWM_FEEDBACK_DIV_SHIFT           0
>> >> +#define              RANGE_PWM_FEEDBACK_DIV_EN               (1 << 12)
>> >> +#define      FVTHROT_PWM_FEEDBACK_DIV_REG2                   0x3090
>> >> +#define              RANGE1_PWM_FEEDBACK_DIV(x)              ((x) << 0)
>> >> +#define              RANGE1_PWM_FEEDBACK_DIV_MASK            0xfff
>> >> +#define              RANGE1_PWM_FEEDBACK_DIV_SHIFT           0
>> >> +#define              RANGE2_PWM_FEEDBACK_DIV(x)              ((x) << 12)
>> >> +#define              RANGE2_PWM_FEEDBACK_DIV_MASK            (0xfff << 12)
>> >> +#define              RANGE2_PWM_FEEDBACK_DIV_SHIFT           12
>> >> +#define      FVTHROT_PWM_FEEDBACK_DIV_REG3                   0x3094
>> >> +#define              RANGE0_PWM(x)                           ((x) << 0)
>> >> +#define              RANGE0_PWM_MASK                         0xfff
>> >> +#define              RANGE0_PWM_SHIFT                        0
>> >> +#define              RANGE1_PWM(x)                           ((x) << 12)
>> >> +#define              RANGE1_PWM_MASK                         (0xfff << 12)
>> >> +#define              RANGE1_PWM_SHIFT                        12
>> >> +#define      FVTHROT_PWM_FEEDBACK_DIV_REG4                   0x3098
>> >> +#define              RANGE2_PWM(x)                           ((x) << 0)
>> >> +#define              RANGE2_PWM_MASK                         0xfff
>> >> +#define              RANGE2_PWM_SHIFT                        0
>> >> +#define              RANGE3_PWM(x)                           ((x) << 12)
>> >> +#define              RANGE3_PWM_MASK                         (0xfff << 12)
>> >> +#define              RANGE3_PWM_SHIFT                        12
>> >> +#define      FVTHROT_SLOW_CLK_FEEDBACK_DIV_REG1              0x30ac
>> >> +#define              RANGE0_SLOW_CLK_FEEDBACK_DIV(x)         ((x) << 0)
>> >> +#define              RANGE0_SLOW_CLK_FEEDBACK_DIV_MASK       0xfff
>> >> +#define              RANGE0_SLOW_CLK_FEEDBACK_DIV_SHIFT      0
>> >> +#define              RANGE_SLOW_CLK_FEEDBACK_DIV_EN          (1 << 12)
>> >> +
>> >> +#define      GFX_MACRO_BYPASS_CNTL                           0x30c0
>> >> +#define              SPLL_BYPASS_CNTL                        (1 << 0)
>> >> +#define              UPLL_BYPASS_CNTL                        (1 << 1)
>> >> +
>> >> +#endif
>> >> --
>> >> 1.7.7.5
>> >>
>> >> _______________________________________________
>> >> dri-devel mailing list
>> >> dri-devel@lists.freedesktop.org
>> >> http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 000/165] radeon drm-next patches
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (111 preceding siblings ...)
  2013-06-26 13:23 ` [PATCH 111/165] drm/radeon/dpm: remove local sumo_get_xclk() alexdeucher
@ 2013-06-26 21:57 ` Julian Wollrath
  2013-06-26 22:51   ` Julian Wollrath
  2013-06-29 17:37   ` Grigori Goronzy
  2013-06-26 22:23 ` Alex Deucher
  113 siblings, 2 replies; 142+ messages in thread
From: Julian Wollrath @ 2013-06-26 21:57 UTC (permalink / raw)
  To: alexdeucher; +Cc: dri-devel

Hi,

I just tried the DPM support out on a E-450 APU (HD6320) and it did not
work like expected. In the terminal everything seemed ok but when I
started a display manager, the screen showed garbage and the system
basically locked up. The radeon and drm related parts of the syslog are
below.

If you need further information, feel free to ask.


Best regards,
Julian Wollrath

[   14.926970] [drm] Initialized drm 1.1.0 20060810
[   15.607011] [drm] radeon kernel modesetting enabled.
[   15.608158] [drm] initializing kernel modesetting (PALM 0x1002:0x9806 0x17AA:0x21EC).
[   15.608242] [drm] register mmio base: 0xF0300000
[   15.608247] [drm] register mmio size: 262144
[   15.608438] ATOM BIOS: Lenovo
[   15.608544] radeon 0000:00:01.0: VRAM: 384M 0x0000000000000000 - 0x0000000017FFFFFF (384M used)
[   15.608554] radeon 0000:00:01.0: GTT: 512M 0x0000000018000000 - 0x0000000037FFFFFF
[   15.609062] [drm] Detected VRAM RAM=384M, BAR=256M
[   15.609077] [drm] RAM width 32bits DDR
[   15.609442] [TTM] Zone  kernel: Available graphics memory: 1821260 kiB
[   15.609453] [TTM] Initializing pool allocator
[   15.609469] [TTM] Initializing DMA pool allocator
[   15.609553] [drm] radeon: 384M of VRAM memory ready
[   15.609560] [drm] radeon: 512M of GTT memory ready.
[   15.785368] radeon 0000:00:01.0: ffff880119401000 unpin not necessary
[   15.911347] radeon 0000:00:01.0: fence driver on ring 5 use gpu addr 0x0000000000072118 and cpu addr 0xffffc90002ce6118
[   15.911374] [drm] GART: num cpu pages 131072, num gpu pages 131072
[   15.915577] [drm] Loading PALM Microcode
[   16.354967] [drm] PCIE GART of 512M enabled (table at 0x0000000000040000).
[   16.355272] radeon 0000:00:01.0: WB enabled
[   16.355287] radeon 0000:00:01.0: fence driver on ring 0 use gpu addr 0x0000000018000c00 and cpu addr 0xffff880115f44c00
[   16.355297] radeon 0000:00:01.0: fence driver on ring 3 use gpu addr 0x0000000018000c0c and cpu addr 0xffff880115f44c0c
[   16.359306] radeon 0000:00:01.0: fence driver on ring 5 use gpu addr 0x0000000000177118 and cpu addr 0xffffc90003032118
[   16.359326] [drm] Supports vblank timestamp caching Rev 1 (10.10.2010).
[   16.359330] [drm] Driver supports precise vblank timestamp query.
[   16.359391] radeon 0000:00:01.0: irq 46 for MSI/MSI-X
[   16.359432] radeon 0000:00:01.0: radeon: using MSI.
[   16.359528] [drm] radeon: irq initialized.
[   16.379053] [drm] ring test on 0 succeeded in 1 usecs
[   16.379120] [drm] ring test on 3 succeeded in 1 usecs
[   16.434367] [drm] ring test on 5 succeeded in 1 usecs
[   16.434384] [drm] UVD initialized successfully.
[   16.455934] [drm] ib test on ring 0 succeeded in 0 usecs
[   16.455984] [drm] ib test on ring 3 succeeded in 0 usecs
[   16.476866] [drm] ib test on ring 5 succeeded
[   16.549696] [drm] radeon atom DIG backlight initialized
[   16.549718] [drm] Radeon Display Connectors
[   16.549724] [drm] Connector 0:
[   16.549731] [drm]   LVDS-1
[   16.549736] [drm]   HPD1
[   16.549744] [drm]   DDC: 0x6430 0x6430 0x6434 0x6434 0x6438 0x6438 0x643c 0x643c
[   16.549748] [drm]   Encoders:
[   16.549753] [drm]     LCD1: INTERNAL_UNIPHY
[   16.549757] [drm] Connector 1:
[   16.549762] [drm]   HDMI-A-1
[   16.549766] [drm]   HPD2
[   16.549773] [drm]   DDC: 0x6440 0x6440 0x6444 0x6444 0x6448 0x6448 0x644c 0x644c
[   16.549776] [drm]   Encoders:
[   16.549780] [drm]     DFP1: INTERNAL_UNIPHY
[   16.549784] [drm] Connector 2:
[   16.549788] [drm]   VGA-1
[   16.549795] [drm]   DDC: 0x64d8 0x64d8 0x64dc 0x64dc 0x64e0 0x64e0 0x64e4 0x64e4
[   16.549799] [drm]   Encoders:
[   16.549803] [drm]     CRT1: INTERNAL_KLDSCP_DAC1
[   16.549900] [drm] Internal thermal controller without fan control
[   16.550073] == power state 0 ==
[   16.550079] 	ui class: none
[   16.550085] 	internal class: uvd_hd 
[   16.550091] 	caps: 
[   16.550096] 	uvd    vclk: 38824 dclk: 30000
[   16.550102] 		power level 0    sclk: 27500 vddc: 875
[   16.550106] 	status: 
[   16.550110] == power state 1 ==
[   16.550113] 	ui class: none
[   16.550117] 	internal class: uvd 
[   16.550122] 	caps: 
[   16.550127] 	uvd    vclk: 55000 dclk: 41250
[   16.550132] 		power level 0    sclk: 50770 vddc: 950
[   16.550135] 	status: 
[   16.550139] == power state 2 ==
[   16.550142] 	ui class: battery
[   16.550146] 	internal class: none
[   16.550151] 	caps: 
[   16.550155] 	uvd    vclk: 0 dclk: 0
[   16.550160] 		power level 0    sclk: 27500 vddc: 875
[   16.550163] 	status: 
[   16.550167] == power state 3 ==
[   16.550170] 	ui class: performance
[   16.550174] 	internal class: none
[   16.550179] 	caps: 
[   16.550184] 	uvd    vclk: 0 dclk: 0
[   16.550188] 		power level 0    sclk: 27500 vddc: 875
[   16.550193] 		power level 1    sclk: 50770 vddc: 950
[   16.550196] 	status: 
[   16.550200] == power state 4 ==
[   16.550203] 	ui class: none
[   16.550207] 	internal class: boot 
[   16.550212] 	caps: 
[   16.550216] 	uvd    vclk: 0 dclk: 0
[   16.550221] 		power level 0    sclk: 20000 vddc: 975
[   16.550224] 	status: c r b 
[   16.550232] == power state 5 ==
[   16.550235] 	ui class: none
[   16.550239] 	internal class: thermal 
[   16.550243] 	caps: 
[   16.550248] 	uvd    vclk: 0 dclk: 0
[   16.550252] 		power level 0    sclk: 17369 vddc: 875
[   16.550255] 	status: 
[   16.550263] [drm] Found smc ucode version: 0x00010601
[   16.576523] switching from power state:
[   16.576539] 	ui class: none
[   16.576545] 	internal class: boot 
[   16.576551] 	caps: 
[   16.576557] 	uvd    vclk: 0 dclk: 0
[   16.576565] 		power level 0    sclk: 20000 vddc: 975
[   16.576569] 	status: c b 
[   16.576575] switching to power state:
[   16.576578] 	ui class: performance
[   16.576582] 	internal class: none
[   16.576588] 	caps: 
[   16.576592] 	uvd    vclk: 0 dclk: 0
[   16.576598] 		power level 0    sclk: 27500 vddc: 875
[   16.576603] 		power level 1    sclk: 50770 vddc: 950
[   16.576606] 	status: r 
[   16.576735] [drm] radeon: dpm initialized
[   17.000309] [drm] fb mappable at 0xE0378000
[   17.000317] [drm] vram apper at 0xE0000000
[   17.000319] [drm] size 4325376
[   17.000322] [drm] fb depth is 24
[   17.000324] [drm]    pitch is 5632
[   17.000438] fbcon: radeondrmfb (fb0) is primary device
[   17.563999] Console: switching to colour frame buffer device 170x48
[   17.577133] radeon 0000:00:01.0: fb0: radeondrmfb frame buffer device
[   17.577141] radeon 0000:00:01.0: registered panic notifier
[   17.577820] [drm] Initialized radeon 2.34.0 20080528 for 0000:00:01.0 on minor 0

[  159.318231] radeon 0000:00:01.0: GPU lockup CP stall for more than 10000msec
[  159.318252] radeon 0000:00:01.0: GPU lockup (waiting for 0x0000000000000004 last fence id 0x0000000000000001)
[  159.369796] radeon 0000:00:01.0: fence driver on ring 5 use gpu addr 0x0000000000177118 and cpu addr 0xffffc9000301b118
[  159.370844] radeon 0000:00:01.0: Saved 87 dwords of commands on ring 0.
[  159.370856] radeon 0000:00:01.0: GPU softreset: 0x00000009
[  159.370861] radeon 0000:00:01.0:   GRBM_STATUS               = 0xB2433828
[  159.370865] radeon 0000:00:01.0:   GRBM_STATUS_SE0           = 0x08000007
[  159.370869] radeon 0000:00:01.0:   GRBM_STATUS_SE1           = 0x00000007
[  159.370872] radeon 0000:00:01.0:   SRBM_STATUS               = 0x20000040
[  159.370876] radeon 0000:00:01.0:   SRBM_STATUS2              = 0x00000000
[  159.370880] radeon 0000:00:01.0:   R_008674_CP_STALLED_STAT1 = 0x00000000
[  159.370884] radeon 0000:00:01.0:   R_008678_CP_STALLED_STAT2 = 0x40000000
[  159.370888] radeon 0000:00:01.0:   R_00867C_CP_BUSY_STAT     = 0x00008000
[  159.370891] radeon 0000:00:01.0:   R_008680_CP_STAT          = 0x80228643
[  159.370895] radeon 0000:00:01.0:   R_00D034_DMA_STATUS_REG   = 0x44C83D57
[  159.386016] radeon 0000:00:01.0: GRBM_SOFT_RESET=0x00007F6B
[  159.386093] radeon 0000:00:01.0: SRBM_SOFT_RESET=0x00000100
[  159.387279] radeon 0000:00:01.0:   GRBM_STATUS               = 0x00003828
[  159.387282] radeon 0000:00:01.0:   GRBM_STATUS_SE0           = 0x00000007
[  159.387286] radeon 0000:00:01.0:   GRBM_STATUS_SE1           = 0x00000007
[  159.387289] radeon 0000:00:01.0:   SRBM_STATUS               = 0x20000040
[  159.387293] radeon 0000:00:01.0:   SRBM_STATUS2              = 0x00000000
[  159.387296] radeon 0000:00:01.0:   R_008674_CP_STALLED_STAT1 = 0x00000000
[  159.387300] radeon 0000:00:01.0:   R_008678_CP_STALLED_STAT2 = 0x00000000
[  159.387303] radeon 0000:00:01.0:   R_00867C_CP_BUSY_STAT     = 0x00000000
[  159.387307] radeon 0000:00:01.0:   R_008680_CP_STAT          = 0x00000000
[  159.387310] radeon 0000:00:01.0:   R_00D034_DMA_STATUS_REG   = 0x44C83D57
[  159.387316] radeon 0000:00:01.0: GPU reset succeeded, trying to resume
[  159.407287] [drm] PCIE GART of 512M enabled (table at 0x0000000000040000).
[  159.407562] radeon 0000:00:01.0: WB enabled
[  159.407576] radeon 0000:00:01.0: fence driver on ring 0 use gpu addr 0x0000000018000c00 and cpu addr 0xffff880115f44c00
[  159.407587] radeon 0000:00:01.0: fence driver on ring 3 use gpu addr 0x0000000018000c0c and cpu addr 0xffff880115f44c0c
[  159.410849] radeon 0000:00:01.0: fence driver on ring 5 use gpu addr 0x0000000000177118 and cpu addr 0xffffc90003eb2118
[  159.427563] [drm] ring test on 0 succeeded in 1 usecs
[  159.427634] [drm] ring test on 3 succeeded in 1 usecs
[  159.472928] [drm] ring test on 5 succeeded in 1 usecs
[  159.472958] [drm] UVD initialized successfully.
[  164.422044] SysRq : Keyboard mode set to system default
[  164.646822] SysRq : Terminate All Tasks

[   14.301299] [drm] Initialized drm 1.1.0 20060810
[   14.906930] [drm] radeon kernel modesetting enabled.
[   14.975218] [drm] initializing kernel modesetting (PALM 0x1002:0x9806 0x17AA:0x21EC).
[   14.975271] [drm] register mmio base: 0xF0300000
[   14.975273] [drm] register mmio size: 262144
[   14.975377] ATOM BIOS: Lenovo
[   14.975453] radeon 0000:00:01.0: VRAM: 384M 0x0000000000000000 - 0x0000000017FFFFFF (384M used)
[   14.975459] radeon 0000:00:01.0: GTT: 512M 0x0000000018000000 - 0x0000000037FFFFFF
[   14.975657] [drm] Detected VRAM RAM=384M, BAR=256M
[   14.975667] [drm] RAM width 32bits DDR
[   14.976352] [TTM] Zone  kernel: Available graphics memory: 1821260 kiB
[   14.976356] [TTM] Initializing pool allocator
[   14.976364] [TTM] Initializing DMA pool allocator
[   14.976404] [drm] radeon: 384M of VRAM memory ready
[   14.976408] [drm] radeon: 512M of GTT memory ready.
[   15.719064] radeon 0000:00:01.0: ffff8801196f1800 unpin not necessary
[   15.856057] radeon 0000:00:01.0: fence driver on ring 5 use gpu addr 0x0000000000072118 and cpu addr 0xffffc90002ce6118
[   15.856075] [drm] GART: num cpu pages 131072, num gpu pages 131072
[   15.858815] [drm] Loading PALM Microcode
[   16.363243] [drm] PCIE GART of 512M enabled (table at 0x0000000000040000).
[   16.363537] radeon 0000:00:01.0: WB enabled
[   16.363545] radeon 0000:00:01.0: fence driver on ring 0 use gpu addr 0x0000000018000c00 and cpu addr 0xffff880115f8bc00
[   16.363550] radeon 0000:00:01.0: fence driver on ring 3 use gpu addr 0x0000000018000c0c and cpu addr 0xffff880115f8bc0c
[   16.365611] radeon 0000:00:01.0: fence driver on ring 5 use gpu addr 0x0000000000177118 and cpu addr 0xffffc90002ab2118
[   16.365623] [drm] Supports vblank timestamp caching Rev 1 (10.10.2010).
[   16.365626] [drm] Driver supports precise vblank timestamp query.
[   16.365666] radeon 0000:00:01.0: irq 46 for MSI/MSI-X
[   16.365692] radeon 0000:00:01.0: radeon: using MSI.
[   16.365733] [drm] radeon: irq initialized.
[   16.383123] [drm] ring test on 0 succeeded in 1 usecs
[   16.383199] [drm] ring test on 3 succeeded in 1 usecs
[   16.438468] [drm] ring test on 5 succeeded in 1 usecs
[   16.438479] [drm] UVD initialized successfully.
[   16.459644] [drm] ib test on ring 0 succeeded in 0 usecs
[   16.459693] [drm] ib test on ring 3 succeeded in 0 usecs
[   16.480537] [drm] ib test on ring 5 succeeded
[   16.556037] [drm] radeon atom DIG backlight initialized
[   16.556058] [drm] Radeon Display Connectors
[   16.556064] [drm] Connector 0:
[   16.556072] [drm]   LVDS-1
[   16.556077] [drm]   HPD1
[   16.556085] [drm]   DDC: 0x6430 0x6430 0x6434 0x6434 0x6438 0x6438 0x643c 0x643c
[   16.556089] [drm]   Encoders:
[   16.556094] [drm]     LCD1: INTERNAL_UNIPHY
[   16.556099] [drm] Connector 1:
[   16.556104] [drm]   HDMI-A-1
[   16.556107] [drm]   HPD2
[   16.556114] [drm]   DDC: 0x6440 0x6440 0x6444 0x6444 0x6448 0x6448 0x644c 0x644c
[   16.556118] [drm]   Encoders:
[   16.556122] [drm]     DFP1: INTERNAL_UNIPHY
[   16.556126] [drm] Connector 2:
[   16.556131] [drm]   VGA-1
[   16.556137] [drm]   DDC: 0x64d8 0x64d8 0x64dc 0x64dc 0x64e0 0x64e0 0x64e4 0x64e4
[   16.556141] [drm]   Encoders:
[   16.556145] [drm]     CRT1: INTERNAL_KLDSCP_DAC1
[   16.556242] [drm] Internal thermal controller without fan control
[   16.556392] == power state 0 ==
[   16.556398] 	ui class: none
[   16.556404] 	internal class: uvd_hd 
[   16.556410] 	caps: 
[   16.556416] 	uvd    vclk: 38824 dclk: 30000
[   16.556422] 		power level 0    sclk: 27500 vddc: 875
[   16.556425] 	status: 
[   16.556430] == power state 1 ==
[   16.556433] 	ui class: none
[   16.556437] 	internal class: uvd 
[   16.556442] 	caps: 
[   16.556447] 	uvd    vclk: 55000 dclk: 41250
[   16.556452] 		power level 0    sclk: 50770 vddc: 950
[   16.556455] 	status: 
[   16.556459] == power state 2 ==
[   16.556462] 	ui class: battery
[   16.556466] 	internal class: none
[   16.556471] 	caps: 
[   16.556475] 	uvd    vclk: 0 dclk: 0
[   16.556480] 		power level 0    sclk: 27500 vddc: 875
[   16.556483] 	status: 
[   16.556487] == power state 3 ==
[   16.556491] 	ui class: performance
[   16.556494] 	internal class: none
[   16.556499] 	caps: 
[   16.556504] 	uvd    vclk: 0 dclk: 0
[   16.556509] 		power level 0    sclk: 27500 vddc: 875
[   16.556514] 		power level 1    sclk: 50770 vddc: 950
[   16.556517] 	status: 
[   16.556521] == power state 4 ==
[   16.556524] 	ui class: none
[   16.556528] 	internal class: boot 
[   16.556533] 	caps: 
[   16.556537] 	uvd    vclk: 0 dclk: 0
[   16.556542] 		power level 0    sclk: 20000 vddc: 975
[   16.556545] 	status: c r b 
[   16.556553] == power state 5 ==
[   16.556556] 	ui class: none
[   16.556560] 	internal class: thermal 
[   16.556564] 	caps: 
[   16.556569] 	uvd    vclk: 0 dclk: 0
[   16.556574] 		power level 0    sclk: 17369 vddc: 875
[   16.556577] 	status: 
[   16.556584] [drm] Found smc ucode version: 0x00010601
[   16.577725] switching from power state:
[   16.577737] 	ui class: none
[   16.577740] 	internal class: boot 
[   16.577744] 	caps: 
[   16.577747] 	uvd    vclk: 0 dclk: 0
[   16.577751] 		power level 0    sclk: 20000 vddc: 975
[   16.577753] 	status: c b 
[   16.577757] switching to power state:
[   16.577758] 	ui class: performance
[   16.577760] 	internal class: none
[   16.577763] 	caps: 
[   16.577765] 	uvd    vclk: 0 dclk: 0
[   16.577768] 		power level 0    sclk: 27500 vddc: 875
[   16.577771] 		power level 1    sclk: 50770 vddc: 950
[   16.577772] 	status: r 
[   16.577868] [drm] radeon: dpm initialized
[   16.694706] ieee80211 phy0: Selected rate control algorithm 'iwl-agn-rs'
[   16.997044] [drm] fb mappable at 0xE0378000
[   16.997057] [drm] vram apper at 0xE0000000
[   16.997062] [drm] size 4325376
[   16.997067] [drm] fb depth is 24
[   16.997072] [drm]    pitch is 5632
[   16.997267] fbcon: radeondrmfb (fb0) is primary device
[   17.565597] Console: switching to colour frame buffer device 170x48
[   17.578692] radeon 0000:00:01.0: fb0: radeondrmfb frame buffer device
[   17.578701] radeon 0000:00:01.0: registered panic notifier
[   17.579385] [drm] Initialized radeon 2.34.0 20080528 for 0000:00:01.0 on minor 0

[  195.823063] radeon 0000:00:01.0: GPU lockup CP stall for more than 10000msec
[  195.827260] radeon 0000:00:01.0: GPU lockup (waiting for 0x0000000000000004 last fence id 0x0000000000000001)
[  195.879857] radeon 0000:00:01.0: fence driver on ring 5 use gpu addr 0x0000000000177118 and cpu addr 0xffffc90002832118
[  195.880922] radeon 0000:00:01.0: Saved 87 dwords of commands on ring 0.
[  195.880935] radeon 0000:00:01.0: GPU softreset: 0x00000009
[  195.880941] radeon 0000:00:01.0:   GRBM_STATUS               = 0xB2433828
[  195.880946] radeon 0000:00:01.0:   GRBM_STATUS_SE0           = 0x08000007
[  195.880951] radeon 0000:00:01.0:   GRBM_STATUS_SE1           = 0x00000007
[  195.880956] radeon 0000:00:01.0:   SRBM_STATUS               = 0x20000040
[  195.880960] radeon 0000:00:01.0:   SRBM_STATUS2              = 0x00000000
[  195.880965] radeon 0000:00:01.0:   R_008674_CP_STALLED_STAT1 = 0x00000000
[  195.880970] radeon 0000:00:01.0:   R_008678_CP_STALLED_STAT2 = 0x40000000
[  195.880974] radeon 0000:00:01.0:   R_00867C_CP_BUSY_STAT     = 0x00008000
[  195.880979] radeon 0000:00:01.0:   R_008680_CP_STAT          = 0x80228643
[  195.880983] radeon 0000:00:01.0:   R_00D034_DMA_STATUS_REG   = 0x44C83D57
[  195.895865] radeon 0000:00:01.0: GRBM_SOFT_RESET=0x00007F6B
[  195.895921] radeon 0000:00:01.0: SRBM_SOFT_RESET=0x00000100
[  195.897108] radeon 0000:00:01.0:   GRBM_STATUS               = 0x00003828
[  195.897113] radeon 0000:00:01.0:   GRBM_STATUS_SE0           = 0x00000007
[  195.897117] radeon 0000:00:01.0:   GRBM_STATUS_SE1           = 0x00000007
[  195.897121] radeon 0000:00:01.0:   SRBM_STATUS               = 0x20000040
[  195.897126] radeon 0000:00:01.0:   SRBM_STATUS2              = 0x00000000
[  195.897130] radeon 0000:00:01.0:   R_008674_CP_STALLED_STAT1 = 0x00000000
[  195.897134] radeon 0000:00:01.0:   R_008678_CP_STALLED_STAT2 = 0x00000000
[  195.897138] radeon 0000:00:01.0:   R_00867C_CP_BUSY_STAT     = 0x00000000
[  195.897143] radeon 0000:00:01.0:   R_008680_CP_STAT          = 0x00000000
[  195.897147] radeon 0000:00:01.0:   R_00D034_DMA_STATUS_REG   = 0x44C83D57
[  195.897154] radeon 0000:00:01.0: GPU reset succeeded, trying to resume
[  195.917323] [drm] PCIE GART of 512M enabled (table at 0x0000000000040000).
[  195.917553] radeon 0000:00:01.0: WB enabled
[  195.917567] radeon 0000:00:01.0: fence driver on ring 0 use gpu addr 0x0000000018000c00 and cpu addr 0xffff880115f8bc00
[  195.917578] radeon 0000:00:01.0: fence driver on ring 3 use gpu addr 0x0000000018000c0c and cpu addr 0xffff880115f8bc0c
[  195.920890] radeon 0000:00:01.0: fence driver on ring 5 use gpu addr 0x0000000000177118 and cpu addr 0xffffc90003c32118
[  195.937779] [drm] ring test on 0 succeeded in 1 usecs
[  195.937858] [drm] ring test on 3 succeeded in 1 usecs
[  195.983131] [drm] ring test on 5 succeeded in 1 usecs
[  195.983148] [drm] UVD initialized successfully.
[  206.009333] radeon 0000:00:01.0: GPU lockup CP stall for more than 10000msec
[  206.013681] radeon 0000:00:01.0: GPU lockup (waiting for 0x0000000000000005 last fence id 0x0000000000000001)
[  206.013692] [drm:r600_ib_test] *ERROR* radeon: fence wait failed (-35).
[  206.018028] [drm:radeon_ib_ring_tests] *ERROR* radeon: failed testing IB on GFX ring (-35).
[  206.022364] radeon 0000:00:01.0: ib ring test failed (-35).
[  206.075249] radeon 0000:00:01.0: fence driver on ring 5 use gpu addr 0x0000000000177118 and cpu addr 0xffffc90002832118
[  206.076352] radeon 0000:00:01.0: GPU softreset: 0x00000009
[  206.076362] radeon 0000:00:01.0:   GRBM_STATUS               = 0xB3533828
[  206.076370] radeon 0000:00:01.0:   GRBM_STATUS_SE0           = 0x2C000007
[  206.076378] radeon 0000:00:01.0:   GRBM_STATUS_SE1           = 0x00000007
[  206.076386] radeon 0000:00:01.0:   SRBM_STATUS               = 0x20000040
[  206.076393] radeon 0000:00:01.0:   SRBM_STATUS2              = 0x00000000
[  206.076401] radeon 0000:00:01.0:   R_008674_CP_STALLED_STAT1 = 0x00000000
[  206.076408] radeon 0000:00:01.0:   R_008678_CP_STALLED_STAT2 = 0x400C0000
[  206.076415] radeon 0000:00:01.0:   R_00867C_CP_BUSY_STAT     = 0x00048000
[  206.076422] radeon 0000:00:01.0:   R_008680_CP_STAT          = 0x80268643
[  206.076429] radeon 0000:00:01.0:   R_00D034_DMA_STATUS_REG   = 0x44C83D57
[  206.076620] radeon 0000:00:01.0: GRBM_SOFT_RESET=0x00007F6B
[  206.076678] radeon 0000:00:01.0: SRBM_SOFT_RESET=0x00000100
[  206.077871] radeon 0000:00:01.0:   GRBM_STATUS               = 0x00003828
[  206.077878] radeon 0000:00:01.0:   GRBM_STATUS_SE0           = 0x00000007
[  206.077885] radeon 0000:00:01.0:   GRBM_STATUS_SE1           = 0x00000007
[  206.077892] radeon 0000:00:01.0:   SRBM_STATUS               = 0x20000040
[  206.077899] radeon 0000:00:01.0:   SRBM_STATUS2              = 0x00000000
[  206.077905] radeon 0000:00:01.0:   R_008674_CP_STALLED_STAT1 = 0x00000000
[  206.077912] radeon 0000:00:01.0:   R_008678_CP_STALLED_STAT2 = 0x00000000
[  206.077919] radeon 0000:00:01.0:   R_00867C_CP_BUSY_STAT     = 0x00000000
[  206.077926] radeon 0000:00:01.0:   R_008680_CP_STAT          = 0x00000000
[  206.077932] radeon 0000:00:01.0:   R_00D034_DMA_STATUS_REG   = 0x44C83D57
[  206.077943] radeon 0000:00:01.0: GPU reset succeeded, trying to resume
[  206.082896] [drm] PCIE GART of 512M enabled (table at 0x0000000000040000).
[  206.083120] radeon 0000:00:01.0: WB enabled
[  206.083134] radeon 0000:00:01.0: fence driver on ring 0 use gpu addr 0x0000000018000c00 and cpu addr 0xffff880115f8bc00
[  206.083143] radeon 0000:00:01.0: fence driver on ring 3 use gpu addr 0x0000000018000c0c and cpu addr 0xffff880115f8bc0c
[  206.086489] radeon 0000:00:01.0: fence driver on ring 5 use gpu addr 0x0000000000177118 and cpu addr 0xffffc90003c32118
[  206.103118] [drm] ring test on 0 succeeded in 1 usecs
[  206.103188] [drm] ring test on 3 succeeded in 1 usecs
[  206.148514] [drm] ring test on 5 succeeded in 1 usecs
[  206.148531] [drm] UVD initialized successfully.
[  206.867862] SysRq : Keyboard mode set to system default
[  207.151608] SysRq : Terminate All Tasks

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 000/165] radeon drm-next patches
  2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
                   ` (112 preceding siblings ...)
  2013-06-26 21:57 ` [PATCH 000/165] radeon drm-next patches Julian Wollrath
@ 2013-06-26 22:23 ` Alex Deucher
  2013-06-27 13:12   ` Andy Furniss
  113 siblings, 1 reply; 142+ messages in thread
From: Alex Deucher @ 2013-06-26 22:23 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

On Wed, Jun 26, 2013 at 9:21 AM,  <alexdeucher@gmail.com> wrote:
> From: Alex Deucher <alexander.deucher@amd.com>
>
> These are the radeon patches for 3.11.  Some of these patches
> are huge so, it might be easier to review things here:
> http://cgit.freedesktop.org/~agd5f/linux/log/?h=drm-next-3.11-wip

Updated branch:
http://cgit.freedesktop.org/~agd5f/linux/log/?h=drm-next-3.11-wip-2
Takes into account comments from Jerome a Christian and contains a few
DPM fixes.

Alex

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 000/165] radeon drm-next patches
  2013-06-26 21:57 ` [PATCH 000/165] radeon drm-next patches Julian Wollrath
@ 2013-06-26 22:51   ` Julian Wollrath
  2013-06-27 14:21     ` Jerome Glisse
  2013-06-29 17:37   ` Grigori Goronzy
  1 sibling, 1 reply; 142+ messages in thread
From: Julian Wollrath @ 2013-06-26 22:51 UTC (permalink / raw)
  To: alexdeucher; +Cc: dri-devel

Hi,

> I just tried the DPM support out on a E-450 APU (HD6320) and it did
> not work like expected. In the terminal everything seemed ok but when
> I started a display manager, the screen showed garbage and the system
> basically locked up. The radeon and drm related parts of the syslog
> are below.
I saw, that you updated the patches, therefore I tried out the branch
drm-next-3.11-wip-2 and I got, additionally to the problem mentioned in
my first e-mail, the following warning:

[   14.274349] ------------[ cut here ]------------
[   14.274369] WARNING: at kernel/workqueue.c:1365 __queue_work+0x260/0x2c0()
[   14.274374] Modules linked in: bluetooth crc16 acpi_cpufreq snd_hda_codec_hdmi iwlwifi uvcvideo mperf radeon(+) videobuf2_vmalloc cfg80211 snd_hda_intel(+) battery processor button thinkpad_acpi video nvram rfkill videobuf2_memops videobuf2_core videodev snd_hda_codec kvm_amd i2c_algo_bit kvm snd_hwdep snd_pcm snd_timer snd_page_alloc ac drm_kms_helper ttm snd drm soundcore wmi i2c_piix4 agpgart pcspkr i2c_core evdev k10temp psmouse serio_raw sha256_ssse3 sha256_generic twofish_x86_64_3way glue_helper xts lrw gf128mul twofish_x86_64 twofish_common cbc dm_crypt dm_mod sd_mod crc_t10dif rtsx_pci_sdmmc mmc_core microcode thermal thermal_sys ahci libahci ohci_hcd ehci_pci ehci_hcd rtsx_pci mfd_core usbcore usb_common libata scsi_mod
[   14.274517] CPU: 1 PID: 497 Comm: modprobe Not tainted 3.10.0-rc7-wl+ #3
[   14.274524] Hardware name: LENOVO 30515YG/30515YG, BIOS 8RET52WW (1.15 ) 11/15/2011
[   14.274530]  ffffffff813fc83e ffffffff81037a7a ffff88011ec12540 ffff88011ed15d00
[   14.274539]  ffff8801164a5bc8 0000000000000002 ffff88011e060a00 ffffffff81053590
[   14.274548]  0000000000000002 ffff8801164a5e9c 0000000000000001 0000000000000010
[   14.274558] Call Trace:
[   14.274563]  <IRQ>  [<ffffffff813fc83e>] ? dump_stack+0xc/0x15
[   14.274582]  [<ffffffff81037a7a>] ? warn_slowpath_common+0x6a/0xa0
[   14.274594]  [<ffffffff81053590>] ? __queue_work+0x260/0x2c0
[   14.274605]  [<ffffffff8105360d>] ? queue_work_on+0x1d/0x30
[   14.274703]  [<ffffffffa045ac26>] ? evergreen_irq_process+0x906/0xd20 [radeon]
[   14.274715]  [<ffffffff810a0a2d>] ? handle_irq_event_percpu+0x2d/0x1a0
[   14.274724]  [<ffffffff810a0bd6>] ? handle_irq_event+0x36/0x60
[   14.274734]  [<ffffffff810a3487>] ? handle_edge_irq+0x67/0x110
[   14.274743]  [<ffffffff810045d5>] ? handle_irq+0x15/0x20
[   14.274751]  [<ffffffff81004261>] ? do_IRQ+0x51/0xd0
[   14.274761]  [<ffffffff814009ea>] ? common_interrupt+0x6a/0x6a
[   14.274765]  <EOI>  [<ffffffff812369a9>] ? delay_tsc+0x29/0x60
[   14.274850]  [<ffffffffa0455cda>] ? sumo_set_uvd_clock+0x8a/0xb0 [radeon]
[   14.274926]  [<ffffffffa0455dfd>] ? sumo_set_uvd_clocks+0x4d/0xe0 [radeon]
[   14.274999]  [<ffffffffa043f775>] ? r600_uvd_init+0x25/0x390 [radeon]
[   14.275073]  [<ffffffffa045d652>] ? evergreen_startup+0x1952/0x1960 [radeon]
[   14.275146]  [<ffffffffa045d85b>] ? evergreen_init+0x17b/0x2c0 [radeon]
[   14.275208]  [<ffffffffa03f96a5>] ? radeon_device_init+0x5b5/0x6d0 [radeon]
[   14.275219]  [<ffffffff8124d975>] ? pci_find_capability+0x45/0x60
[   14.275279]  [<ffffffffa03fb234>] ? radeon_driver_load_kms+0x84/0x140 [radeon]
[   14.275303]  [<ffffffffa01d84ad>] ? drm_get_pci_dev+0x17d/0x290 [drm]
[   14.275314]  [<ffffffff812521b8>] ? pci_device_probe+0x98/0xe0
[   14.275325]  [<ffffffff812d9ed8>] ? driver_probe_device+0x68/0x210
[   14.275333]  [<ffffffff812da173>] ? __driver_attach+0x93/0xa0
[   14.275341]  [<ffffffff812da0e0>] ? __device_attach+0x60/0x60
[   14.275351]  [<ffffffff812d81b3>] ? bus_for_each_dev+0x53/0x90
[   14.275359]  [<ffffffff812d96a0>] ? bus_add_driver+0x1c0/0x250
[   14.275367]  [<ffffffff812da709>] ? driver_register+0x69/0x140
[   14.275380]  [<ffffffffa050b000>] ? 0xffffffffa050afff
[   14.275390]  [<ffffffffa050b000>] ? 0xffffffffa050afff
[   14.275399]  [<ffffffff810002da>] ? do_one_initcall+0x10a/0x160
[   14.275408]  [<ffffffff8108e508>] ? load_module+0x1cd8/0x2390
[   14.275416]  [<ffffffff8108a540>] ? store_uevent+0x50/0x50
[   14.275427]  [<ffffffff8108ec78>] ? SyS_init_module+0xb8/0xe0
[   14.275438]  [<ffffffff81401112>] ? system_call_fastpath+0x16/0x1b
[   14.275444] ---[ end trace 1f1cbf85b14e84a1 ]---

With best regards,
Julian Wollrath

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 000/165] radeon drm-next patches
  2013-06-26 22:23 ` Alex Deucher
@ 2013-06-27 13:12   ` Andy Furniss
  2013-06-27 14:55     ` Alex Deucher
  2013-06-27 23:55     ` Alex Deucher
  0 siblings, 2 replies; 142+ messages in thread
From: Andy Furniss @ 2013-06-27 13:12 UTC (permalink / raw)
  To: Alex Deucher; +Cc: Alex Deucher, dri-devel

Alex Deucher wrote:
> On Wed, Jun 26, 2013 at 9:21 AM,  <alexdeucher@gmail.com> wrote:
>> From: Alex Deucher <alexander.deucher@amd.com>
>>
>> These are the radeon patches for 3.11.  Some of these patches
>> are huge so, it might be easier to review things here:
>> http://cgit.freedesktop.org/~agd5f/linux/log/?h=drm-next-3.11-wip
>
> Updated branch:
> http://cgit.freedesktop.org/~agd5f/linux/log/?h=drm-next-3.11-wip-2
> Takes into account comments from Jerome a Christian and contains a few
> DPM fixes.

I see there's a 3 now - I tested that (I guess currently it's the same 
as 2 anyway).

On my rv790 there are no regressions so far, but whatever I do it stays low.

echo profile > /sys/class/drm/card0/device/power_method = write error, 
is there a way to go back to manual setting with dpm?

I haven't tried rv670 yet - I couldn't see a new firmware for that, does 
it just not need one?

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 069/165] drm/radeon/kms: add common dpm infrastructure
  2013-06-26 13:22 ` [PATCH 069/165] drm/radeon/kms: add common dpm infrastructure alexdeucher
  2013-06-26 10:27   ` Jerome Glisse
@ 2013-06-27 13:52   ` K. Schnass
  1 sibling, 0 replies; 142+ messages in thread
From: K. Schnass @ 2013-06-27 13:52 UTC (permalink / raw)
  To: dri-devel

Thanks for the work the whole thing seems to work fine on my RV770, although I 
cannot really say if does anything as I found no way to query the current clk 
or voltage?! There is one little gripe though, the rest of the code uses 
DRM_INFO() for printing whereas this series uses plain printk() resulting in 
some weird looking dmesg output:

Jun 27 14:41:54 my-little-devil kernel: [drm]   VGA-1
Jun 27 14:41:54 my-little-devil kernel: [drm]   DDC: 0x7e60 0x7e60 0x7e64 
0x7e64 0x7e68 0x7e68 0x7e6c 0x7e6c
Jun 27 14:41:54 my-little-devil kernel: [drm]   Encoders:
Jun 27 14:41:54 my-little-devil kernel: [drm]     CRT2: INTERNAL_KLDSCP_DAC2
Jun 27 14:41:54 my-little-devil kernel: [drm] Internal thermal controller with 
fan control
Jun 27 14:41:54 my-little-devil kernel: == power state 0 ==
Jun 27 14:41:54 my-little-devil kernel:         ui class: none
Jun 27 14:41:54 my-little-devil kernel:         internal class: boot 
Jun 27 14:41:54 my-little-devil kernel:         caps: video 
Jun 27 14:41:54 my-little-devil kernel:         uvd    vclk: 0 dclk: 0
Jun 27 14:41:54 my-little-devil kernel:                 power level 0    sclk: 
62500 mclk: 99300 vddc: 1123
Jun 27 14:41:54 my-little-devil kernel:                 power level 1    sclk: 
62500 mclk: 99300 vddc: 1123
Jun 27 14:41:54 my-little-devil kernel:                 power level 2    sclk: 
62500 mclk: 99300 vddc: 1123

best regards
K. Schnass

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 000/165] radeon drm-next patches
  2013-06-26 22:51   ` Julian Wollrath
@ 2013-06-27 14:21     ` Jerome Glisse
  2013-06-27 21:26       ` Julian Wollrath
  0 siblings, 1 reply; 142+ messages in thread
From: Jerome Glisse @ 2013-06-27 14:21 UTC (permalink / raw)
  To: Julian Wollrath; +Cc: dri-devel

On Wed, Jun 26, 2013 at 6:51 PM, Julian Wollrath <jwollrath@web.de> wrote:
> Hi,
>
>> I just tried the DPM support out on a E-450 APU (HD6320) and it did
>> not work like expected. In the terminal everything seemed ok but when
>> I started a display manager, the screen showed garbage and the system
>> basically locked up. The radeon and drm related parts of the syslog
>> are below.
> I saw, that you updated the patches, therefore I tried out the branch
> drm-next-3.11-wip-2 and I got, additionally to the problem mentioned in
> my first e-mail, the following warning:
>
> [   14.274349] ------------[ cut here ]------------
> [   14.274369] WARNING: at kernel/workqueue.c:1365 __queue_work+0x260/0x2c0()
> [   14.274374] Modules linked in: bluetooth crc16 acpi_cpufreq snd_hda_codec_hdmi iwlwifi uvcvideo mperf radeon(+) videobuf2_vmalloc cfg80211 snd_hda_intel(+) battery processor button thinkpad_acpi video nvram rfkill videobuf2_memops videobuf2_core videodev snd_hda_codec kvm_amd i2c_algo_bit kvm snd_hwdep snd_pcm snd_timer snd_page_alloc ac drm_kms_helper ttm snd drm soundcore wmi i2c_piix4 agpgart pcspkr i2c_core evdev k10temp psmouse serio_raw sha256_ssse3 sha256_generic twofish_x86_64_3way glue_helper xts lrw gf128mul twofish_x86_64 twofish_common cbc dm_crypt dm_mod sd_mod crc_t10dif rtsx_pci_sdmmc mmc_core microcode thermal thermal_sys ahci libahci ohci_hcd ehci_pci ehci_hcd rtsx_pci mfd_core usbcore usb_common libata scsi_mod
> [   14.274517] CPU: 1 PID: 497 Comm: modprobe Not tainted 3.10.0-rc7-wl+ #3
> [   14.274524] Hardware name: LENOVO 30515YG/30515YG, BIOS 8RET52WW (1.15 ) 11/15/2011
> [   14.274530]  ffffffff813fc83e ffffffff81037a7a ffff88011ec12540 ffff88011ed15d00
> [   14.274539]  ffff8801164a5bc8 0000000000000002 ffff88011e060a00 ffffffff81053590
> [   14.274548]  0000000000000002 ffff8801164a5e9c 0000000000000001 0000000000000010
> [   14.274558] Call Trace:
> [   14.274563]  <IRQ>  [<ffffffff813fc83e>] ? dump_stack+0xc/0x15
> [   14.274582]  [<ffffffff81037a7a>] ? warn_slowpath_common+0x6a/0xa0
> [   14.274594]  [<ffffffff81053590>] ? __queue_work+0x260/0x2c0
> [   14.274605]  [<ffffffff8105360d>] ? queue_work_on+0x1d/0x30
> [   14.274703]  [<ffffffffa045ac26>] ? evergreen_irq_process+0x906/0xd20 [radeon]
> [   14.274715]  [<ffffffff810a0a2d>] ? handle_irq_event_percpu+0x2d/0x1a0
> [   14.274724]  [<ffffffff810a0bd6>] ? handle_irq_event+0x36/0x60
> [   14.274734]  [<ffffffff810a3487>] ? handle_edge_irq+0x67/0x110
> [   14.274743]  [<ffffffff810045d5>] ? handle_irq+0x15/0x20
> [   14.274751]  [<ffffffff81004261>] ? do_IRQ+0x51/0xd0
> [   14.274761]  [<ffffffff814009ea>] ? common_interrupt+0x6a/0x6a
> [   14.274765]  <EOI>  [<ffffffff812369a9>] ? delay_tsc+0x29/0x60
> [   14.274850]  [<ffffffffa0455cda>] ? sumo_set_uvd_clock+0x8a/0xb0 [radeon]
> [   14.274926]  [<ffffffffa0455dfd>] ? sumo_set_uvd_clocks+0x4d/0xe0 [radeon]
> [   14.274999]  [<ffffffffa043f775>] ? r600_uvd_init+0x25/0x390 [radeon]
> [   14.275073]  [<ffffffffa045d652>] ? evergreen_startup+0x1952/0x1960 [radeon]
> [   14.275146]  [<ffffffffa045d85b>] ? evergreen_init+0x17b/0x2c0 [radeon]
> [   14.275208]  [<ffffffffa03f96a5>] ? radeon_device_init+0x5b5/0x6d0 [radeon]
> [   14.275219]  [<ffffffff8124d975>] ? pci_find_capability+0x45/0x60
> [   14.275279]  [<ffffffffa03fb234>] ? radeon_driver_load_kms+0x84/0x140 [radeon]
> [   14.275303]  [<ffffffffa01d84ad>] ? drm_get_pci_dev+0x17d/0x290 [drm]
> [   14.275314]  [<ffffffff812521b8>] ? pci_device_probe+0x98/0xe0
> [   14.275325]  [<ffffffff812d9ed8>] ? driver_probe_device+0x68/0x210
> [   14.275333]  [<ffffffff812da173>] ? __driver_attach+0x93/0xa0
> [   14.275341]  [<ffffffff812da0e0>] ? __device_attach+0x60/0x60
> [   14.275351]  [<ffffffff812d81b3>] ? bus_for_each_dev+0x53/0x90
> [   14.275359]  [<ffffffff812d96a0>] ? bus_add_driver+0x1c0/0x250
> [   14.275367]  [<ffffffff812da709>] ? driver_register+0x69/0x140
> [   14.275380]  [<ffffffffa050b000>] ? 0xffffffffa050afff
> [   14.275390]  [<ffffffffa050b000>] ? 0xffffffffa050afff
> [   14.275399]  [<ffffffff810002da>] ? do_one_initcall+0x10a/0x160
> [   14.275408]  [<ffffffff8108e508>] ? load_module+0x1cd8/0x2390
> [   14.275416]  [<ffffffff8108a540>] ? store_uevent+0x50/0x50
> [   14.275427]  [<ffffffff8108ec78>] ? SyS_init_module+0xb8/0xe0
> [   14.275438]  [<ffffffff81401112>] ? system_call_fastpath+0x16/0x1b
> [   14.275444] ---[ end trace 1f1cbf85b14e84a1 ]---
>
> With best regards,
> Julian Wollrath


This patch should fix your issue :

http://people.freedesktop.org/~glisse/0001-radeon-do-no-schedule-thermal-work-if-dpm-is-not-ena.patch

Cheers,
Jerome

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 000/165] radeon drm-next patches
  2013-06-27 13:12   ` Andy Furniss
@ 2013-06-27 14:55     ` Alex Deucher
  2013-06-27 22:19       ` James Cloos
  2013-06-27 23:55     ` Alex Deucher
  1 sibling, 1 reply; 142+ messages in thread
From: Alex Deucher @ 2013-06-27 14:55 UTC (permalink / raw)
  To: Andy Furniss; +Cc: Alex Deucher, dri-devel

On Thu, Jun 27, 2013 at 9:12 AM, Andy Furniss <adf.lists@gmail.com> wrote:
> Alex Deucher wrote:
>>
>> On Wed, Jun 26, 2013 at 9:21 AM,  <alexdeucher@gmail.com> wrote:
>>>
>>> From: Alex Deucher <alexander.deucher@amd.com>
>>>
>>> These are the radeon patches for 3.11.  Some of these patches
>>> are huge so, it might be easier to review things here:
>>> http://cgit.freedesktop.org/~agd5f/linux/log/?h=drm-next-3.11-wip
>>
>>
>> Updated branch:
>> http://cgit.freedesktop.org/~agd5f/linux/log/?h=drm-next-3.11-wip-2
>> Takes into account comments from Jerome a Christian and contains a few
>> DPM fixes.
>
>
> I see there's a 3 now - I tested that (I guess currently it's the same as 2
> anyway).
>
> On my rv790 there are no regressions so far, but whatever I do it stays low.
>

We may need to tweak the scaling parameters a bit to force higher
states more readily.  They are pretty conservative right now.

> echo profile > /sys/class/drm/card0/device/power_method = write error, is
> there a way to go back to manual setting with dpm?

Not yet.  I'm working on an infrastructure to force DPM modes, but
it's not ready yet.

>
> I haven't tried rv670 yet - I couldn't see a new firmware for that, does it
> just not need one?
>

Nope.  6xx and APUs do not require ucode.  only 7xx+ dGPUs.

Alex

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 000/165] radeon drm-next patches
  2013-06-27 14:21     ` Jerome Glisse
@ 2013-06-27 21:26       ` Julian Wollrath
  0 siblings, 0 replies; 142+ messages in thread
From: Julian Wollrath @ 2013-06-27 21:26 UTC (permalink / raw)
  To: Jerome Glisse; +Cc: dri-devel

Hi,

> This patch should fix your issue :
> 
> http://people.freedesktop.org/~glisse/0001-radeon-do-no-schedule-thermal-work-if-dpm-is-not-ena.patch  
yes, that seems to do the trick (but I can not be 100% sure, since I
only saw the warning once).

> 
> Cheers,
> Jerome  
Best regards,
Julian

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 000/165] radeon drm-next patches
  2013-06-27 14:55     ` Alex Deucher
@ 2013-06-27 22:19       ` James Cloos
  2013-06-27 22:52         ` Jerome Glisse
  0 siblings, 1 reply; 142+ messages in thread
From: James Cloos @ 2013-06-27 22:19 UTC (permalink / raw)
  To: Alex Deucher; +Cc: Alex Deucher, dri-devel

>>>>> "AD" == Alex Deucher <alexdeucher@gmail.com> writes:

AD> Nope.  6xx and APUs do not require ucode.  only 7xx+ dGPUs.

Does that mean that APUs do not require *any* ucode blobs?

Or just that they do not require updated or additional blobs
for the new functionality like DPM?

-JimC
-- 
James Cloos <cloos@jhcloos.com>         OpenPGP: 1024D/ED7DAEA6

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 000/165] radeon drm-next patches
  2013-06-27 22:19       ` James Cloos
@ 2013-06-27 22:52         ` Jerome Glisse
  0 siblings, 0 replies; 142+ messages in thread
From: Jerome Glisse @ 2013-06-27 22:52 UTC (permalink / raw)
  To: James Cloos; +Cc: Alex Deucher, dri-devel

On Thu, Jun 27, 2013 at 6:19 PM, James Cloos <cloos@jhcloos.com> wrote:
>>>>>> "AD" == Alex Deucher <alexdeucher@gmail.com> writes:
>
> AD> Nope.  6xx and APUs do not require ucode.  only 7xx+ dGPUs.
>
> Does that mean that APUs do not require *any* ucode blobs?
>
> Or just that they do not require updated or additional blobs
> for the new functionality like DPM?
>
> -JimC
> --

They don't require any ucode blob for the power management. They do
require ucode blob for 3d acceleration, compute, well anything that
want to use the gpu really.

Cheers,
Jerome

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 000/165] radeon drm-next patches
  2013-06-27 13:12   ` Andy Furniss
  2013-06-27 14:55     ` Alex Deucher
@ 2013-06-27 23:55     ` Alex Deucher
  2013-06-28 13:00       ` Laurent Carlier
  2013-06-29  9:28       ` Andy Furniss
  1 sibling, 2 replies; 142+ messages in thread
From: Alex Deucher @ 2013-06-27 23:55 UTC (permalink / raw)
  To: Andy Furniss; +Cc: Alex Deucher, dri-devel

On Thu, Jun 27, 2013 at 9:12 AM, Andy Furniss <adf.lists@gmail.com> wrote:
> Alex Deucher wrote:
>>
>> On Wed, Jun 26, 2013 at 9:21 AM,  <alexdeucher@gmail.com> wrote:
>>>
>>> From: Alex Deucher <alexander.deucher@amd.com>
>>>
>>> These are the radeon patches for 3.11.  Some of these patches
>>> are huge so, it might be easier to review things here:
>>> http://cgit.freedesktop.org/~agd5f/linux/log/?h=drm-next-3.11-wip
>>
>>
>> Updated branch:
>> http://cgit.freedesktop.org/~agd5f/linux/log/?h=drm-next-3.11-wip-2
>> Takes into account comments from Jerome a Christian and contains a few
>> DPM fixes.
>
>
> I see there's a 3 now - I tested that (I guess currently it's the same as 2
> anyway).
>
> On my rv790 there are no regressions so far, but whatever I do it stays low.

This should work much better with with wip-5.

Alex

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 000/165] radeon drm-next patches
  2013-06-27 23:55     ` Alex Deucher
@ 2013-06-28 13:00       ` Laurent Carlier
  2013-06-29  9:28       ` Andy Furniss
  1 sibling, 0 replies; 142+ messages in thread
From: Laurent Carlier @ 2013-06-28 13:00 UTC (permalink / raw)
  To: dri-devel


[-- Attachment #1.1: Type: text/plain, Size: 1287 bytes --]

Le 28/06/2013 01:55, Alex Deucher a écrit :
> On Thu, Jun 27, 2013 at 9:12 AM, Andy Furniss <adf.lists@gmail.com> wrote:
>> Alex Deucher wrote:
>>>
>>> On Wed, Jun 26, 2013 at 9:21 AM,  <alexdeucher@gmail.com> wrote:
>>>>
>>>> From: Alex Deucher <alexander.deucher@amd.com>
>>>>
>>>> These are the radeon patches for 3.11.  Some of these patches
>>>> are huge so, it might be easier to review things here:
>>>> http://cgit.freedesktop.org/~agd5f/linux/log/?h=drm-next-3.11-wip
>>>
>>>
>>> Updated branch:
>>> http://cgit.freedesktop.org/~agd5f/linux/log/?h=drm-next-3.11-wip-2
>>> Takes into account comments from Jerome a Christian and contains a few
>>> DPM fixes.
>>
>>
>> I see there's a 3 now - I tested that (I guess currently it's the same as 2
>> anyway).
>>
>> On my rv790 there are no regressions so far, but whatever I do it stays low.
> 
> This should work much better with with wip-5.
> 
> Alex
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
> 

Just tested, and my card (HD6870) is still stuck at low.

(tested with HL2 and wine/furmark)

++

-- 
Laurent Carlier
ArchLinux Developer
http://www.archlinux.org


[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 555 bytes --]

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 000/165] radeon drm-next patches
  2013-06-27 23:55     ` Alex Deucher
  2013-06-28 13:00       ` Laurent Carlier
@ 2013-06-29  9:28       ` Andy Furniss
  2013-06-29 10:23         ` Ilyes Gouta
  1 sibling, 1 reply; 142+ messages in thread
From: Andy Furniss @ 2013-06-29  9:28 UTC (permalink / raw)
  To: Alex Deucher; +Cc: Alex Deucher, dri-devel

Alex Deucher wrote:
> On Thu, Jun 27, 2013 at 9:12 AM, Andy Furniss <adf.lists@gmail.com> wrote:
>> Alex Deucher wrote:
>>>
>>> On Wed, Jun 26, 2013 at 9:21 AM,  <alexdeucher@gmail.com> wrote:
>>>>
>>>> From: Alex Deucher <alexander.deucher@amd.com>
>>>>
>>>> These are the radeon patches for 3.11.  Some of these patches
>>>> are huge so, it might be easier to review things here:
>>>> http://cgit.freedesktop.org/~agd5f/linux/log/?h=drm-next-3.11-wip
>>>
>>>
>>> Updated branch:
>>> http://cgit.freedesktop.org/~agd5f/linux/log/?h=drm-next-3.11-wip-2
>>> Takes into account comments from Jerome a Christian and contains a few
>>> DPM fixes.
>>
>>
>> I see there's a 3 now - I tested that (I guess currently it's the same as 2
>> anyway).
>>
>> On my rv790 there are no regressions so far, but whatever I do it stays low.
>
> This should work much better with with wip-5.

Yes, this works on my rv790 games get high and using vdpau/gl for video 
stays low (which is nice as the fan on my card is too noisy on high).

One thing which I guess 99.999% of people won't notice is that doing any 
thing with plain X + fluxbox (so no compositing) very briefly ramps up 
the speed.

As my fan is just audible on low but very quick to respond I can hear 
every time the screen gets updated eg. switching desktops, 
browsing+scrolling or switching tabs, even typing dmesg in an xterm 
which time shows as taking < 0.1 sec results in a fan change.

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 000/165] radeon drm-next patches
  2013-06-29  9:28       ` Andy Furniss
@ 2013-06-29 10:23         ` Ilyes Gouta
  0 siblings, 0 replies; 142+ messages in thread
From: Ilyes Gouta @ 2013-06-29 10:23 UTC (permalink / raw)
  To: Andy Furniss; +Cc: Alex Deucher, dri-devel


[-- Attachment #1.1: Type: text/plain, Size: 849 bytes --]

Hi,

> Yes, this works on my rv790 games get high and using vdpau/gl for video
stays low (which is nice as the fan on my card is too noisy on high).
>
> One thing which I guess 99.999% of people won't notice is that doing any
thing with plain X + fluxbox (so no compositing) very briefly ramps up the
speed.
>
> As my fan is just audible on low but very quick to respond I can hear
every time the screen gets updated eg. switching desktops,
browsing+scrolling or switching tabs, even typing dmesg in an xterm which
time shows as taking < 0.1 sec results in a fan change.

Probably a low-pass filter is needed/has to be configured in front of the
freq. scaling engine?

Ilyes

>
>
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

[-- Attachment #1.2: Type: text/html, Size: 1109 bytes --]

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 000/165] radeon drm-next patches
  2013-06-26 21:57 ` [PATCH 000/165] radeon drm-next patches Julian Wollrath
  2013-06-26 22:51   ` Julian Wollrath
@ 2013-06-29 17:37   ` Grigori Goronzy
  1 sibling, 0 replies; 142+ messages in thread
From: Grigori Goronzy @ 2013-06-29 17:37 UTC (permalink / raw)
  To: Julian Wollrath; +Cc: dri-devel

On 26.06.2013 23:57, Julian Wollrath wrote:
> Hi,
>
> I just tried the DPM support out on a E-450 APU (HD6320) and it did not
> work like expected. In the terminal everything seemed ok but when I
> started a display manager, the screen showed garbage and the system
> basically locked up. The radeon and drm related parts of the syslog are
> below.
>
> If you need further information, feel free to ask.
>

I have the same problem with the same APU. Disabling power gating (set 
enable_gfx_power_gating to false in sumo_dpm.c:sumo_dpm_init) fixes it. 
So this problem may related to power gating.

The difference in power consumption seems to be small, but I'd still 
prefer it working.

By the way, the "disable_gfx_power_gating_in_uvd" quirk is not actually 
used, seems to be some leftover from debugging or such.

Best regards
Grigori

^ permalink raw reply	[flat|nested] 142+ messages in thread

end of thread, other threads:[~2013-06-29 17:47 UTC | newest]

Thread overview: 142+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-06-26 13:21 [PATCH 000/165] radeon drm-next patches alexdeucher
2013-06-26 12:55 ` Jerome Glisse
2013-06-26 13:21 ` [PATCH 001/165] drm/radeon: fix AVI infoframe generation alexdeucher
2013-06-26 13:21 ` [PATCH 002/165] drm/radeon: add backlight quirk for hybrid mac alexdeucher
2013-06-26 13:21 ` [PATCH 003/165] drm/radeon: add a reset work handler alexdeucher
2013-06-26 13:21 ` [PATCH 004/165] drm/radeon: add CIK chip families alexdeucher
2013-06-26 13:21 ` [PATCH 005/165] drm/radeon: add DCE8 macro for CIK alexdeucher
2013-06-26 13:21 ` [PATCH 006/165] drm/radeon: adapt to PCI BAR changes on CIK alexdeucher
2013-06-26 13:21 ` [PATCH 007/165] drm/radeon: add gpu init support for CIK (v9) alexdeucher
2013-06-26 13:21 ` [PATCH 008/165] drm/radeon: Add support for CIK GPU reset (v2) alexdeucher
2013-06-26 13:21 ` [PATCH 009/165] drm/radeon: add support for MC/VM setup on CIK (v6) alexdeucher
2013-06-26 13:21 ` [PATCH 010/165] drm/radeon/cik: stop page faults from hanging the system (v2) alexdeucher
2013-06-26 13:21 ` [PATCH 011/165] drm/radeon: add initial ucode loading for CIK (v5) alexdeucher
2013-06-26 13:21 ` [PATCH 012/165] drm/radeon: add support mc ucode loading on CIK (v2) alexdeucher
2013-06-26 13:21 ` [PATCH 013/165] drm/radeon: Add CP init for CIK (v7) alexdeucher
2013-06-26 13:21 ` [PATCH 014/165] drm/radeon: add IB and fence dispatch functions for CIK gfx (v7) alexdeucher
2013-06-26 13:21 ` [PATCH 015/165] drm/radeon: add ring and IB tests for CIK (v3) alexdeucher
2013-06-26 13:21 ` [PATCH 016/165] drm/radeon: implement async vm_flush for the CP (v7) alexdeucher
2013-06-26 13:21 ` [PATCH 017/165] drm/radeon: Add support for RLC init on CIK (v4) alexdeucher
2013-06-26 13:21 ` [PATCH 018/165] drm/radeon: add support for interrupts on CIK (v5) alexdeucher
2013-06-26 13:21 ` [PATCH 019/165] drm/radeon/cik: log and handle VM page fault interrupts alexdeucher
2013-06-26 13:21 ` [PATCH 020/165] drm/radeon/cik: add support for sDMA dma engines (v8) alexdeucher
2013-06-26 13:21 ` [PATCH 021/165] drm/radeon: implement async vm_flush for the sDMA (v6) alexdeucher
2013-06-26 13:21 ` [PATCH 022/165] drm/radeon/cik: add support for doing async VM pt updates (v5) alexdeucher
2013-06-26 13:21 ` [PATCH 023/165] drm/radeon/cik: fill in startup/shutdown callbacks (v4) alexdeucher
2013-06-26 15:03   ` Christian König
2013-06-26 13:21 ` [PATCH 024/165] drm/radeon: upstream ObjectID.h updates (v2) alexdeucher
2013-06-26 13:21 ` [PATCH 025/165] drm/radeon: upstream atombios.h " alexdeucher
2013-06-26 13:21 ` [PATCH 026/165] drm/radeon: atombios power table " alexdeucher
2013-06-26 13:21 ` [PATCH 027/165] drm/radeon: handle the integrated thermal controller on CI alexdeucher
2013-06-26 13:21 ` [PATCH 028/165] drm/radeon: update power state parsing for CI alexdeucher
2013-06-26 13:21 ` [PATCH 029/165] drm/radeon/dce8: add support for display watermark setup alexdeucher
2013-06-26 13:21 ` [PATCH 030/165] drm/radeon/cik: add hw cursor support (v2) alexdeucher
2013-06-26 13:21 ` [PATCH 031/165] drm/radeon/dce8: properly handle interlaced timing alexdeucher
2013-06-26 13:21 ` [PATCH 032/165] drm/radeon/dce8: crtc_set_base updates alexdeucher
2013-06-26 13:21 ` [PATCH 033/165] drm/radeon/atom: add DCE8 encoder support alexdeucher
2013-06-26 13:21 ` [PATCH 034/165] drm/radeon/atom: add support for new DVO tables alexdeucher
2013-06-26 13:21 ` [PATCH 035/165] drm/radeon: update DISPCLK programming for DCE8 alexdeucher
2013-06-26 13:21 ` [PATCH 036/165] drm/radeon: add support pll selection for DCE8 (v4) alexdeucher
2013-06-26 13:21 ` [PATCH 037/165] drm/radeon: Handle PPLL0 powerdown on DCE8 alexdeucher
2013-06-26 13:21 ` [PATCH 038/165] drm/radeon: use frac fb div " alexdeucher
2013-06-26 13:21 ` [PATCH 039/165] drm/radeon: add SS override support for KB/KV alexdeucher
2013-06-26 13:22 ` [PATCH 040/165] drm/radeon: Update radeon_info_ioctl for CIK (v2) alexdeucher
2013-06-26 13:22 ` [PATCH 041/165] drm/radeon: add get_gpu_clock_counter() callback for cik alexdeucher
2013-06-26 13:22 ` [PATCH 042/165] drm/radeon: update CIK soft reset alexdeucher
2013-06-26 13:22 ` [PATCH 043/165] drm/radeon: add indirect register accessors for SMC registers alexdeucher
2013-06-26 13:22 ` [PATCH 044/165] drm/radeon: add get_xclk() callback for CIK alexdeucher
2013-06-26 13:22 ` [PATCH 045/165] drm/radeon/cik: add pcie_port indirect register accessors alexdeucher
2013-06-26 13:22 ` [PATCH 046/165] drm/radeon: update radeon_atom_get_clock_dividers() for SI alexdeucher
2013-06-26 13:22 ` [PATCH 047/165] drm/radeon: update radeon_atom_get_clock_dividers for CIK alexdeucher
2013-06-26 13:22 ` [PATCH 048/165] drm/radeon: add UVD support for CIK (v3) alexdeucher
2013-06-26 13:22 ` [PATCH 049/165] drm/radeon/cik: add srbm_select function alexdeucher
2013-06-26 13:22 ` [PATCH 050/165] drm/radeon: use callbacks for ring pointer handling alexdeucher
2013-06-26 15:31   ` Christian König
2013-06-26 13:22 ` [PATCH 051/165] drm/radeon: implement simple doorbell page allocator alexdeucher
2013-06-26 12:57   ` Jerome Glisse
2013-06-26 18:38     ` Alex Deucher
2013-06-26 13:22 ` [PATCH 052/165] drm/radeon/cik: Add support for compute queues (v2) alexdeucher
2013-06-26 10:08   ` Jerome Glisse
2013-06-26 13:22 ` [PATCH 053/165] drm/radeon/cik: switch to type3 nop packet for compute rings alexdeucher
2013-06-26 10:10   ` Jerome Glisse
2013-06-26 13:22 ` [PATCH 054/165] drm/radeon: fix up ring functions " alexdeucher
2013-06-26 13:22 ` [PATCH 055/165] drm/radeon/cik: add support for compute interrupts alexdeucher
2013-06-26 13:22 ` [PATCH 056/165] drm/radeon/cik: add support for golden register init alexdeucher
2013-06-26 13:22 ` [PATCH 057/165] drm/radeon: add radeon_asic struct for CIK (v11) alexdeucher
2013-06-26 13:22 ` [PATCH 058/165] drm/radeon: add cik tile mode array query alexdeucher
2013-06-26 13:22 ` [PATCH 059/165] drm/radeon: add current Bonaire PCI ids alexdeucher
2013-06-26 13:22 ` [PATCH 060/165] drm/radeon: add current KB pci ids alexdeucher
2013-06-26 13:22 ` [PATCH 061/165] drm/radeon/kms: add accessors for RCU indirect space alexdeucher
2013-06-26 13:22 ` [PATCH 062/165] drm/radeon/evergreen: add indirect register accessors for CG registers alexdeucher
2013-06-26 13:22 ` [PATCH 063/165] drm/radeon: make get_temperature functions a callback alexdeucher
2013-06-26 13:22 ` [PATCH 064/165] drm/radeon: add support for thermal sensor on tn alexdeucher
2013-06-26 13:22 ` [PATCH 065/165] drm/radeon/kms: move ucode defines to a separate header alexdeucher
2013-06-26 13:22 ` [PATCH 066/165] drm/radeon: properly set up the RLC on ON/LN/TN (v3) alexdeucher
2013-06-26 13:22 ` [PATCH 067/165] drm/radeon/kms: add atom helper functions for dpm (v3) alexdeucher
2013-06-26 13:22 ` [PATCH 068/165] drm/radeon/kms: add new asic struct for rv6xx (v3) alexdeucher
2013-06-26 13:22 ` [PATCH 069/165] drm/radeon/kms: add common dpm infrastructure alexdeucher
2013-06-26 10:27   ` Jerome Glisse
2013-06-27 13:52   ` K. Schnass
2013-06-26 13:22 ` [PATCH 070/165] drm/radeon/kms: fix up rs780/rs880 display watermark calc for dpm alexdeucher
2013-06-26 13:22 ` [PATCH 071/165] drm/radeon/kms: fix up 6xx/7xx " alexdeucher
2013-06-26 13:22 ` [PATCH 072/165] drm/radeon/kms: fix up dce4/5 " alexdeucher
2013-06-26 13:22 ` [PATCH 073/165] drm/radeon/kms: fix up dce6 " alexdeucher
2013-06-26 13:22 ` [PATCH 074/165] drm/radeon/kms: add common r600 dpm functions alexdeucher
2013-06-26 13:22 ` [PATCH 075/165] drm/radeon/kms: add dpm support for rs780/rs880 alexdeucher
2013-06-26 10:46   ` Jerome Glisse
2013-06-26 18:19     ` Alex Deucher
2013-06-26 13:18       ` Jerome Glisse
2013-06-26 18:41         ` Alex Deucher
2013-06-26 13:22 ` [PATCH 076/165] drm/radeon/kms: add dpm support for rv6xx alexdeucher
2013-06-26 16:45   ` Christian König
2013-06-26 13:22 ` [PATCH 077/165] drm/radeon/kms: add dpm support for rv7xx (v2) alexdeucher
2013-06-26 13:22 ` [PATCH 078/165] drm/radeon/kms: add dpm support for evergreen (v2) alexdeucher
2013-06-26 13:22 ` [PATCH 079/165] drm/radeon/kms: add dpm support for btc (v2) alexdeucher
2013-06-26 13:22 ` [PATCH 080/165] drm/radeon/kms: add dpm support for sumo asics alexdeucher
2013-06-26 11:19   ` Jerome Glisse
2013-06-26 13:22 ` [PATCH 081/165] drm/radeon/kms: add dpm support for trinity asics alexdeucher
2013-06-26 13:22 ` [PATCH 082/165] drm/radeon/dpm: let atom control display phy powergating alexdeucher
2013-06-26 13:22 ` [PATCH 083/165] drm/radeon: add dpm UVD handling for r7xx asics alexdeucher
2013-06-26 13:22 ` [PATCH 084/165] drm/radeon: add dpm UVD handling for evergreen/btc asics alexdeucher
2013-06-26 13:22 ` [PATCH 085/165] drm/radeon: add dpm UVD handling for sumo asics alexdeucher
2013-06-26 13:22 ` [PATCH 086/165] drm/radeon: add dpm UVD handling for TN asics (v2) alexdeucher
2013-06-26 13:22 ` [PATCH 087/165] drm/radeon/kms: enable UVD as needed (v9) alexdeucher
2013-06-26 13:22 ` [PATCH 088/165] drm/radeon/dpm: add helpers for extended power tables (v2) alexdeucher
2013-06-26 13:22 ` [PATCH 089/165] drm/radeon/dpm: track whether we are on AC or battery alexdeucher
2013-06-26 13:22 ` [PATCH 090/165] drm/radeon/dpm: fixup dynamic state adjust for sumo alexdeucher
2013-06-26 13:22 ` [PATCH 091/165] drm/radeon/dpm: fixup dynamic state adjust for TN alexdeucher
2013-06-26 13:22 ` [PATCH 092/165] drm/radeon/dpm: fixup dynamic state adjust for btc (v2) alexdeucher
2013-06-26 13:22 ` [PATCH 093/165] drm/radeon/kms: add dpm support for cayman alexdeucher
2013-06-26 11:29   ` Jerome Glisse
2013-06-26 13:22 ` [PATCH 094/165] drm/radeon/cayman: update tdp limits in set_power_state alexdeucher
2013-06-26 13:22 ` [PATCH 095/165] drm/radeon/dpm/rs780: restructure code alexdeucher
2013-06-26 13:22 ` [PATCH 096/165] drm/radeon/dpm/rv6xx: " alexdeucher
2013-06-26 13:22 ` [PATCH 097/165] drm/radeon/dpm/rv7xx: " alexdeucher
2013-06-26 13:22 ` [PATCH 098/165] drm/radeon/dpm/evergreen: " alexdeucher
2013-06-26 13:22 ` [PATCH 099/165] drm/radeon/dpm/btc: " alexdeucher
2013-06-26 13:23 ` [PATCH 100/165] drm/radeon/dpm/cayman: " alexdeucher
2013-06-26 13:23 ` [PATCH 101/165] drm/radeon/dpm/sumo: " alexdeucher
2013-06-26 13:23 ` [PATCH 102/165] drm/radeon/dpm/tn: " alexdeucher
2013-06-26 13:23 ` [PATCH 103/165] drm/radeon/dpm: add new pre/post_set_power_state callbacks alexdeucher
2013-06-26 13:23 ` [PATCH 104/165] drm/radeon/dpm: add pre/post_set_power_state callbacks (6xx-eg) alexdeucher
2013-06-26 13:23 ` [PATCH 105/165] drm/radeon/dpm: add pre/post_set_power_state callback (sumo) alexdeucher
2013-06-26 13:23 ` [PATCH 106/165] drm/radeon/dpm: add pre/post_set_power_state callback (TN) alexdeucher
2013-06-26 13:23 ` [PATCH 107/165] drm/radeon/dpm: add pre/post_set_power_state callback (BTC) alexdeucher
2013-06-26 13:23 ` [PATCH 108/165] drm/radeon/dpm: add pre/post_set_power_state callback (cayman) alexdeucher
2013-06-26 13:23 ` [PATCH 109/165] drm/radeon/dpm: remove broken dyn state remnants alexdeucher
2013-06-26 13:23 ` [PATCH 110/165] drm/radeon: add missing UVD clock set in cayman dpm code alexdeucher
2013-06-26 13:23 ` [PATCH 111/165] drm/radeon/dpm: remove local sumo_get_xclk() alexdeucher
2013-06-26 21:57 ` [PATCH 000/165] radeon drm-next patches Julian Wollrath
2013-06-26 22:51   ` Julian Wollrath
2013-06-27 14:21     ` Jerome Glisse
2013-06-27 21:26       ` Julian Wollrath
2013-06-29 17:37   ` Grigori Goronzy
2013-06-26 22:23 ` Alex Deucher
2013-06-27 13:12   ` Andy Furniss
2013-06-27 14:55     ` Alex Deucher
2013-06-27 22:19       ` James Cloos
2013-06-27 22:52         ` Jerome Glisse
2013-06-27 23:55     ` Alex Deucher
2013-06-28 13:00       ` Laurent Carlier
2013-06-29  9:28       ` Andy Furniss
2013-06-29 10:23         ` Ilyes Gouta

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.