Commit 14b27d5d authored by Connor Abbott's avatar Connor Abbott Committed by Rob Clark

drm/msm/a7xx: Initialize a750 "software fuse"

On all Qualcomm platforms with a7xx GPUs, qcom_scm provides a method to
initialize cx_mem. Copy this from downstream (minus BCL which we
currently don't support). On a750, this includes a new "fuse" register
which can be used by qcom_scm to fuse off certain features like
raytracing in software. The fuse is default off, and is initialized by
calling the method. Afterwards we have to read it to find out which
features were enabled.
Reviewed-by: default avatarDmitry Baryshkov <dmitry.baryshkov@linaro.org>
Signed-off-by: default avatarConnor Abbott <cwabbott0@gmail.com>
Reviewed-by: default avatarKonrad Dybcio <konrad.dybcio@linaro.org>
Patchwork: https://patchwork.freedesktop.org/patch/592042/Signed-off-by: default avatarRob Clark <robdclark@chromium.org>
parent 90c3e2bc
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <linux/bitfield.h> #include <linux/bitfield.h>
#include <linux/devfreq.h> #include <linux/devfreq.h>
#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/pm_domain.h> #include <linux/pm_domain.h>
#include <linux/soc/qcom/llcc-qcom.h> #include <linux/soc/qcom/llcc-qcom.h>
...@@ -824,7 +825,8 @@ static int a6xx_zap_shader_init(struct msm_gpu *gpu) ...@@ -824,7 +825,8 @@ static int a6xx_zap_shader_init(struct msm_gpu *gpu)
A6XX_RBBM_INT_0_MASK_RBBM_HANG_DETECT | \ A6XX_RBBM_INT_0_MASK_RBBM_HANG_DETECT | \
A6XX_RBBM_INT_0_MASK_UCHE_OOB_ACCESS | \ A6XX_RBBM_INT_0_MASK_UCHE_OOB_ACCESS | \
A6XX_RBBM_INT_0_MASK_UCHE_TRAP_INTR | \ A6XX_RBBM_INT_0_MASK_UCHE_TRAP_INTR | \
A6XX_RBBM_INT_0_MASK_TSBWRITEERROR) A6XX_RBBM_INT_0_MASK_TSBWRITEERROR | \
A6XX_RBBM_INT_0_MASK_SWFUSEVIOLATION)
#define A7XX_APRIV_MASK (A6XX_CP_APRIV_CNTL_ICACHE | \ #define A7XX_APRIV_MASK (A6XX_CP_APRIV_CNTL_ICACHE | \
A6XX_CP_APRIV_CNTL_RBFETCH | \ A6XX_CP_APRIV_CNTL_RBFETCH | \
...@@ -1494,6 +1496,27 @@ static void a6xx_fault_detect_irq(struct msm_gpu *gpu) ...@@ -1494,6 +1496,27 @@ static void a6xx_fault_detect_irq(struct msm_gpu *gpu)
kthread_queue_work(gpu->worker, &gpu->recover_work); kthread_queue_work(gpu->worker, &gpu->recover_work);
} }
static void a7xx_sw_fuse_violation_irq(struct msm_gpu *gpu)
{
u32 status;
status = gpu_read(gpu, REG_A7XX_RBBM_SW_FUSE_INT_STATUS);
gpu_write(gpu, REG_A7XX_RBBM_SW_FUSE_INT_MASK, 0);
dev_err_ratelimited(&gpu->pdev->dev, "SW fuse violation status=%8.8x\n", status);
/*
* Ignore FASTBLEND violations, because the HW will silently fall back
* to legacy blending.
*/
if (status & (A7XX_CX_MISC_SW_FUSE_VALUE_RAYTRACING |
A7XX_CX_MISC_SW_FUSE_VALUE_LPAC)) {
del_timer(&gpu->hangcheck_timer);
kthread_queue_work(gpu->worker, &gpu->recover_work);
}
}
static irqreturn_t a6xx_irq(struct msm_gpu *gpu) static irqreturn_t a6xx_irq(struct msm_gpu *gpu)
{ {
struct msm_drm_private *priv = gpu->dev->dev_private; struct msm_drm_private *priv = gpu->dev->dev_private;
...@@ -1522,6 +1545,9 @@ static irqreturn_t a6xx_irq(struct msm_gpu *gpu) ...@@ -1522,6 +1545,9 @@ static irqreturn_t a6xx_irq(struct msm_gpu *gpu)
if (status & A6XX_RBBM_INT_0_MASK_UCHE_OOB_ACCESS) if (status & A6XX_RBBM_INT_0_MASK_UCHE_OOB_ACCESS)
dev_err_ratelimited(&gpu->pdev->dev, "UCHE | Out of bounds access\n"); dev_err_ratelimited(&gpu->pdev->dev, "UCHE | Out of bounds access\n");
if (status & A6XX_RBBM_INT_0_MASK_SWFUSEVIOLATION)
a7xx_sw_fuse_violation_irq(gpu);
if (status & A6XX_RBBM_INT_0_MASK_CP_CACHE_FLUSH_TS) if (status & A6XX_RBBM_INT_0_MASK_CP_CACHE_FLUSH_TS)
msm_gpu_retire(gpu); msm_gpu_retire(gpu);
...@@ -1663,6 +1689,61 @@ static void a6xx_llc_slices_init(struct platform_device *pdev, ...@@ -1663,6 +1689,61 @@ static void a6xx_llc_slices_init(struct platform_device *pdev,
a6xx_gpu->llc_mmio = ERR_PTR(-EINVAL); a6xx_gpu->llc_mmio = ERR_PTR(-EINVAL);
} }
static int a7xx_cx_mem_init(struct a6xx_gpu *a6xx_gpu)
{
struct adreno_gpu *adreno_gpu = &a6xx_gpu->base;
struct msm_gpu *gpu = &adreno_gpu->base;
u32 fuse_val;
int ret;
if (adreno_is_a750(adreno_gpu)) {
/*
* Assume that if qcom scm isn't available, that whatever
* replacement allows writing the fuse register ourselves.
* Users of alternative firmware need to make sure this
* register is writeable or indicate that it's not somehow.
* Print a warning because if you mess this up you're about to
* crash horribly.
*/
if (!qcom_scm_is_available()) {
dev_warn_once(gpu->dev->dev,
"SCM is not available, poking fuse register\n");
a6xx_llc_write(a6xx_gpu, REG_A7XX_CX_MISC_SW_FUSE_VALUE,
A7XX_CX_MISC_SW_FUSE_VALUE_RAYTRACING |
A7XX_CX_MISC_SW_FUSE_VALUE_FASTBLEND |
A7XX_CX_MISC_SW_FUSE_VALUE_LPAC);
adreno_gpu->has_ray_tracing = true;
return 0;
}
ret = qcom_scm_gpu_init_regs(QCOM_SCM_GPU_ALWAYS_EN_REQ |
QCOM_SCM_GPU_TSENSE_EN_REQ);
if (ret)
return ret;
/*
* On a750 raytracing may be disabled by the firmware, find out
* whether that's the case. The scm call above sets the fuse
* register.
*/
fuse_val = a6xx_llc_read(a6xx_gpu,
REG_A7XX_CX_MISC_SW_FUSE_VALUE);
adreno_gpu->has_ray_tracing =
!!(fuse_val & A7XX_CX_MISC_SW_FUSE_VALUE_RAYTRACING);
} else {
if (adreno_is_a740(adreno_gpu)) {
/* Raytracing is always enabled on a740 */
adreno_gpu->has_ray_tracing = true;
}
if (qcom_scm_is_available())
return qcom_scm_gpu_init_regs(QCOM_SCM_GPU_ALWAYS_EN_REQ);
}
return 0;
}
#define GBIF_CLIENT_HALT_MASK BIT(0) #define GBIF_CLIENT_HALT_MASK BIT(0)
#define GBIF_ARB_HALT_MASK BIT(1) #define GBIF_ARB_HALT_MASK BIT(1)
#define VBIF_XIN_HALT_CTRL0_MASK GENMASK(3, 0) #define VBIF_XIN_HALT_CTRL0_MASK GENMASK(3, 0)
...@@ -2233,6 +2314,14 @@ struct msm_gpu *a6xx_gpu_init(struct drm_device *dev) ...@@ -2233,6 +2314,14 @@ struct msm_gpu *a6xx_gpu_init(struct drm_device *dev)
return ERR_PTR(ret); return ERR_PTR(ret);
} }
if (adreno_is_a7xx(adreno_gpu)) {
ret = a7xx_cx_mem_init(a6xx_gpu);
if (ret) {
a6xx_destroy(&(a6xx_gpu->base.base));
return ERR_PTR(ret);
}
}
if (gpu->aspace) if (gpu->aspace)
msm_mmu_set_fault_handler(gpu->aspace->mmu, gpu, msm_mmu_set_fault_handler(gpu->aspace->mmu, gpu,
a6xx_fault_handler); a6xx_fault_handler);
......
...@@ -206,6 +206,8 @@ struct adreno_gpu { ...@@ -206,6 +206,8 @@ struct adreno_gpu {
*/ */
const unsigned int *reg_offsets; const unsigned int *reg_offsets;
bool gmu_is_wrapper; bool gmu_is_wrapper;
bool has_ray_tracing;
}; };
#define to_adreno_gpu(x) container_of(x, struct adreno_gpu, base) #define to_adreno_gpu(x) container_of(x, struct adreno_gpu, base)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment