diff options
Diffstat (limited to 'drivers/gpu/drm/msm/adreno/a6xx_gpu.c')
| -rw-r--r-- | drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 132 | 
1 files changed, 124 insertions, 8 deletions
| diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c index 948f3656c20c..130661898546 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c @@ -8,7 +8,9 @@  #include "a6xx_gpu.h"  #include "a6xx_gmu.xml.h" +#include <linux/bitfield.h>  #include <linux/devfreq.h> +#include <linux/soc/qcom/llcc-qcom.h>  #define GPU_PAS_ID 13 @@ -30,7 +32,7 @@ static inline bool _a6xx_check_idle(struct msm_gpu *gpu)  		A6XX_RBBM_INT_0_MASK_RBBM_HANG_DETECT);  } -bool a6xx_idle(struct msm_gpu *gpu, struct msm_ringbuffer *ring) +static bool a6xx_idle(struct msm_gpu *gpu, struct msm_ringbuffer *ring)  {  	/* wait for CP to drain ringbuffer: */  	if (!adreno_idle(gpu, ring)) @@ -65,7 +67,7 @@ static void a6xx_flush(struct msm_gpu *gpu, struct msm_ringbuffer *ring)  		OUT_RING(ring, upper_32_bits(shadowptr(a6xx_gpu, ring)));  	} -	spin_lock_irqsave(&ring->lock, flags); +	spin_lock_irqsave(&ring->preempt_lock, flags);  	/* Copy the shadow to the actual register */  	ring->cur = ring->next; @@ -73,7 +75,7 @@ static void a6xx_flush(struct msm_gpu *gpu, struct msm_ringbuffer *ring)  	/* Make sure to wrap wptr if we need to */  	wptr = get_wptr(ring); -	spin_unlock_irqrestore(&ring->lock, flags); +	spin_unlock_irqrestore(&ring->preempt_lock, flags);  	/* Make sure everything is posted before making a decision */  	mb(); @@ -522,7 +524,7 @@ static int a6xx_cp_init(struct msm_gpu *gpu)  static void a6xx_ucode_check_version(struct a6xx_gpu *a6xx_gpu,  		struct drm_gem_object *obj)  { -	u32 *buf = msm_gem_get_vaddr_active(obj); +	u32 *buf = msm_gem_get_vaddr(obj);  	if (IS_ERR(buf))  		return; @@ -965,8 +967,6 @@ static void a6xx_fault_detect_irq(struct msm_gpu *gpu)  {  	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);  	struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); -	struct drm_device *dev = gpu->dev; -	struct msm_drm_private *priv = dev->dev_private;  	struct msm_ringbuffer *ring = gpu->funcs->active_ring(gpu);  	/* @@ -989,7 +989,7 @@ static void a6xx_fault_detect_irq(struct msm_gpu *gpu)  	/* Turn off the hangcheck timer to keep it from bothering us */  	del_timer(&gpu->hangcheck_timer); -	queue_work(priv->wq, &gpu->recover_work); +	kthread_queue_work(gpu->worker, &gpu->recover_work);  }  static irqreturn_t a6xx_irq(struct msm_gpu *gpu) @@ -1022,6 +1022,105 @@ static irqreturn_t a6xx_irq(struct msm_gpu *gpu)  	return IRQ_HANDLED;  } +static void a6xx_llc_rmw(struct a6xx_gpu *a6xx_gpu, u32 reg, u32 mask, u32 or) +{ +	return msm_rmw(a6xx_gpu->llc_mmio + (reg << 2), mask, or); +} + +static void a6xx_llc_write(struct a6xx_gpu *a6xx_gpu, u32 reg, u32 value) +{ +	return msm_writel(value, a6xx_gpu->llc_mmio + (reg << 2)); +} + +static void a6xx_llc_deactivate(struct a6xx_gpu *a6xx_gpu) +{ +	llcc_slice_deactivate(a6xx_gpu->llc_slice); +	llcc_slice_deactivate(a6xx_gpu->htw_llc_slice); +} + +static void a6xx_llc_activate(struct a6xx_gpu *a6xx_gpu) +{ +	struct adreno_gpu *adreno_gpu = &a6xx_gpu->base; +	struct msm_gpu *gpu = &adreno_gpu->base; +	u32 cntl1_regval = 0; + +	if (IS_ERR(a6xx_gpu->llc_mmio)) +		return; + +	if (!llcc_slice_activate(a6xx_gpu->llc_slice)) { +		u32 gpu_scid = llcc_get_slice_id(a6xx_gpu->llc_slice); + +		gpu_scid &= 0x1f; +		cntl1_regval = (gpu_scid << 0) | (gpu_scid << 5) | (gpu_scid << 10) | +			       (gpu_scid << 15) | (gpu_scid << 20); +	} + +	/* +	 * For targets with a MMU500, activate the slice but don't program the +	 * register.  The XBL will take care of that. +	 */ +	if (!llcc_slice_activate(a6xx_gpu->htw_llc_slice)) { +		if (!a6xx_gpu->have_mmu500) { +			u32 gpuhtw_scid = llcc_get_slice_id(a6xx_gpu->htw_llc_slice); + +			gpuhtw_scid &= 0x1f; +			cntl1_regval |= FIELD_PREP(GENMASK(29, 25), gpuhtw_scid); +		} +	} + +	if (cntl1_regval) { +		/* +		 * Program the slice IDs for the various GPU blocks and GPU MMU +		 * pagetables +		 */ +		if (a6xx_gpu->have_mmu500) +			gpu_rmw(gpu, REG_A6XX_GBIF_SCACHE_CNTL1, GENMASK(24, 0), +				cntl1_regval); +		else { +			a6xx_llc_write(a6xx_gpu, +				REG_A6XX_CX_MISC_SYSTEM_CACHE_CNTL_1, cntl1_regval); + +			/* +			 * Program cacheability overrides to not allocate cache +			 * lines on a write miss +			 */ +			a6xx_llc_rmw(a6xx_gpu, +				REG_A6XX_CX_MISC_SYSTEM_CACHE_CNTL_0, 0xF, 0x03); +		} +	} +} + +static void a6xx_llc_slices_destroy(struct a6xx_gpu *a6xx_gpu) +{ +	llcc_slice_putd(a6xx_gpu->llc_slice); +	llcc_slice_putd(a6xx_gpu->htw_llc_slice); +} + +static void a6xx_llc_slices_init(struct platform_device *pdev, +		struct a6xx_gpu *a6xx_gpu) +{ +	struct device_node *phandle; + +	a6xx_gpu->llc_mmio = msm_ioremap(pdev, "cx_mem", "gpu_cx"); +	if (IS_ERR(a6xx_gpu->llc_mmio)) +		return; + +	/* +	 * There is a different programming path for targets with an mmu500 +	 * attached, so detect if that is the case +	 */ +	phandle = of_parse_phandle(pdev->dev.of_node, "iommus", 0); +	a6xx_gpu->have_mmu500 = (phandle && +		of_device_is_compatible(phandle, "arm,mmu-500")); +	of_node_put(phandle); + +	a6xx_gpu->llc_slice = llcc_slice_getd(LLCC_GPU); +	a6xx_gpu->htw_llc_slice = llcc_slice_getd(LLCC_GPUHTW); + +	if (IS_ERR(a6xx_gpu->llc_slice) && IS_ERR(a6xx_gpu->htw_llc_slice)) +		a6xx_gpu->llc_mmio = ERR_PTR(-EINVAL); +} +  static int a6xx_pm_resume(struct msm_gpu *gpu)  {  	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); @@ -1038,6 +1137,8 @@ static int a6xx_pm_resume(struct msm_gpu *gpu)  	msm_gpu_resume_devfreq(gpu); +	a6xx_llc_activate(a6xx_gpu); +  	return 0;  } @@ -1045,12 +1146,23 @@ static int a6xx_pm_suspend(struct msm_gpu *gpu)  {  	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);  	struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); +	int i, ret;  	trace_msm_gpu_suspend(0); +	a6xx_llc_deactivate(a6xx_gpu); +  	devfreq_suspend_device(gpu->devfreq.devfreq); -	return a6xx_gmu_stop(a6xx_gpu); +	ret = a6xx_gmu_stop(a6xx_gpu); +	if (ret) +		return ret; + +	if (adreno_gpu->base.hw_apriv || a6xx_gpu->has_whereami) +		for (i = 0; i < gpu->nr_rings; i++) +			a6xx_gpu->shadow[i] = 0; + +	return 0;  }  static int a6xx_get_timestamp(struct msm_gpu *gpu, uint64_t *value) @@ -1091,6 +1203,8 @@ static void a6xx_destroy(struct msm_gpu *gpu)  		drm_gem_object_put(a6xx_gpu->shadow_bo);  	} +	a6xx_llc_slices_destroy(a6xx_gpu); +  	a6xx_gmu_remove(a6xx_gpu);  	adreno_gpu_cleanup(adreno_gpu); @@ -1209,6 +1323,8 @@ struct msm_gpu *a6xx_gpu_init(struct drm_device *dev)  	if (info && info->revn == 650)  		adreno_gpu->base.hw_apriv = true; +	a6xx_llc_slices_init(pdev, a6xx_gpu); +  	ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, 1);  	if (ret) {  		a6xx_destroy(&(a6xx_gpu->base.base)); | 
