Program all the register needed to start up LPAC and send initialization sequence.
Additionally, now that the LPAC ring is live, make the code aware of it. Signed-off-by: Anna Maniscalco <[email protected]> --- drivers/gpu/drm/msm/adreno/a6xx_catalog.c | 1 + drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 98 ++++++++++++++++++++++++++++-- drivers/gpu/drm/msm/adreno/adreno_device.c | 6 ++ drivers/gpu/drm/msm/adreno/adreno_gpu.c | 32 ++++++---- drivers/gpu/drm/msm/msm_gpu.c | 21 ++++++- drivers/gpu/drm/msm/msm_gpu.h | 9 +++ 6 files changed, 148 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/a6xx_catalog.c b/drivers/gpu/drm/msm/adreno/a6xx_catalog.c index 3e6f409d13a2..5ee00eead14c 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_catalog.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_catalog.c @@ -1394,6 +1394,7 @@ static const u32 a750_ifpc_reglist_regs[] = { REG_A6XX_SP_NC_MODE_CNTL, REG_A6XX_CP_DBG_ECO_CNTL, REG_A6XX_CP_PROTECT_CNTL, + REG_A6XX_CP_LPAC_PROTECT_CNTL, REG_A6XX_CP_PROTECT(0), REG_A6XX_CP_PROTECT(1), REG_A6XX_CP_PROTECT(2), diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c index 8b3bb2fd433b..9f69aada9b7b 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c @@ -168,6 +168,18 @@ void a6xx_flush(struct msm_gpu *gpu, struct msm_ringbuffer *ring) update_shadow_rptr(gpu, ring); + if (ring == gpu->lpac_rb) { + /* Copy the shadow to the actual register */ + ring->cur = ring->next; + + /* Make sure to wrap wptr if we need to */ + wptr = get_wptr(ring); + + a6xx_fenced_write(a6xx_gpu, REG_A7XX_CP_LPAC_RB_WPTR, wptr, BIT(3), false); + + return; + } + spin_lock_irqsave(&ring->preempt_lock, flags); /* Copy the shadow to the actual register */ @@ -730,6 +742,12 @@ static void a6xx_set_cp_protect(struct msm_gpu *gpu) A6XX_CP_PROTECT_CNTL_ACCESS_FAULT_ON_VIOL_EN | A6XX_CP_PROTECT_CNTL_LAST_SPAN_INF_RANGE); + //TODO if LPAC + gpu_write(gpu, REG_A6XX_CP_LPAC_PROTECT_CNTL, + A6XX_CP_PROTECT_CNTL_ACCESS_PROT_EN | + A6XX_CP_PROTECT_CNTL_ACCESS_FAULT_ON_VIOL_EN | + A6XX_CP_PROTECT_CNTL_LAST_SPAN_INF_RANGE); + for (i = 0; i < protect->count - 1; i++) { /* Intentionally skip writing to some registers */ if (protect->regs[i]) @@ -972,6 +990,53 @@ static int a7xx_cp_init(struct msm_gpu *gpu) return a6xx_idle(gpu, ring) ? 0 : -EINVAL; } +static int lpac_cp_init(struct msm_gpu *gpu) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); + struct msm_ringbuffer *ring = gpu->lpac_rb; + u32 mask; + + OUT_PKT7(ring, CP_ME_INIT, 7); + + /* Use multiple HW contexts */ + mask = BIT(0); + + /* Enable error detection */ + mask |= BIT(1); + + /* Set default reset state */ + mask |= BIT(3); + + /* Disable save/restore of performance counters across preemption */ + mask |= BIT(6); + + /* Enable the register init list with the spinlock */ + mask |= BIT(8); + + OUT_RING(ring, mask); + + /* Enable multiple hardware contexts */ + OUT_RING(ring, 0x00000003); + + /* Enable error detection */ + OUT_RING(ring, 0x20000000); + + /* Operation mode mask */ + OUT_RING(ring, 0x00000002); + + /* *Don't* send a power up reg list for concurrent binning (TODO) */ + /* Lo address */ + OUT_RING(ring, lower_32_bits(a6xx_gpu->pwrup_reglist_iova)); + /* Hi address */ + OUT_RING(ring, upper_32_bits(a6xx_gpu->pwrup_reglist_iova)); + /* BIT(31) set => read the regs from the list */ + OUT_RING(ring, BIT(31)); + + a6xx_flush(gpu, ring); + return a6xx_idle(gpu, ring) ? 0 : -EINVAL; +} + /* * Check that the microcode version is new enough to include several key * security fixes. Return true if the ucode is safe. @@ -1096,7 +1161,7 @@ static int a6xx_ucode_load(struct msm_gpu *gpu) if ((adreno_gpu->base.hw_apriv || a6xx_gpu->has_whereami) && !a6xx_gpu->shadow_bo) { a6xx_gpu->shadow = msm_gem_kernel_new(gpu->dev, - sizeof(u32) * gpu->nr_rings, + sizeof(u32) * (gpu->nr_rings + !!gpu->lpac_rb), MSM_BO_WC | MSM_BO_MAP_PRIV, gpu->vm, &a6xx_gpu->shadow_bo, &a6xx_gpu->shadow_iova); @@ -1289,6 +1354,8 @@ static int hw_init(struct msm_gpu *gpu) gpu_write(gpu, REG_A6XX_UCHE_CACHE_WAYS, 0x4); } + gpu_rmw(gpu, REG_A6XX_UCHE_DEBUG_CNTL_1, BIT(30), BIT(30)); + if (adreno_is_a640_family(adreno_gpu) || adreno_is_a650_family(adreno_gpu)) { gpu_write(gpu, REG_A6XX_CP_ROQ_THRESHOLDS_2, 0x02000140); gpu_write(gpu, REG_A6XX_CP_ROQ_THRESHOLDS_1, 0x8040362c); @@ -1386,6 +1453,11 @@ static int hw_init(struct msm_gpu *gpu) gpu_write(gpu, REG_A6XX_CP_CHICKEN_DBG, BIT(24)); } + gpu_write(gpu, REG_A7XX_CP_LPAC_CHICKEN_DBG, 0x1); + + gpu_write(gpu, REG_A7XX_SP_CHICKEN_BITS_2, BIT(4)); + gpu_write(gpu, REG_A7XX_SP_LPAC_CHICKEN_BITS_2, BIT(4)); + if (adreno_is_a690(adreno_gpu)) gpu_write(gpu, REG_A6XX_UCHE_CMDQ_CONFIG, 0x90); /* Set dualQ + disable afull for A660 GPU */ @@ -1437,13 +1509,17 @@ static int hw_init(struct msm_gpu *gpu) /* Set the ringbuffer address */ gpu_write64(gpu, REG_A6XX_CP_RB_BASE, gpu->rb[0]->iova); + /* Set the ringbuffer address for lpac */ + gpu_write64(gpu, REG_A7XX_CP_LPAC_RB_BASE, gpu->lpac_rb->iova); + /* Targets that support extended APRIV can use the RPTR shadow from * hardware but all the other ones need to disable the feature. Targets * that support the WHERE_AM_I opcode can use that instead */ - if (adreno_gpu->base.hw_apriv) + if (adreno_gpu->base.hw_apriv) { gpu_write(gpu, REG_A6XX_CP_RB_CNTL, MSM_GPU_RB_CNTL_DEFAULT); - else + gpu_write(gpu, REG_A7XX_CP_LPAC_RB_CNTL, MSM_GPU_RB_CNTL_DEFAULT); + } else gpu_write(gpu, REG_A6XX_CP_RB_CNTL, MSM_GPU_RB_CNTL_DEFAULT | AXXX_CP_RB_CNTL_NO_UPDATE); @@ -1451,7 +1527,10 @@ static int hw_init(struct msm_gpu *gpu) if (a6xx_gpu->shadow_bo) { gpu_write64(gpu, REG_A6XX_CP_RB_RPTR_ADDR, shadowptr(a6xx_gpu, gpu->rb[0])); - for (unsigned int i = 0; i < gpu->nr_rings; i++) + if (gpu->lpac_rb) + gpu_write64(gpu, REG_A7XX_CP_LPAC_RB_RPTR_ADDR, + shadowptr(a6xx_gpu, gpu->lpac_rb)); + for (unsigned int i = 0; i < (gpu->nr_rings + !!gpu->lpac_rb); i++) a6xx_gpu->shadow[i] = 0; } @@ -1469,9 +1548,16 @@ static int hw_init(struct msm_gpu *gpu) for (i = 0; i < gpu->nr_rings; i++) gpu->rb[i]->cur_ctx_seqno = 0; + if (gpu->lpac_rb) + gpu->lpac_rb->cur_ctx_seqno = 0; + /* Enable the SQE_to start the CP engine */ gpu_write(gpu, REG_A6XX_CP_SQE_CNTL, 1); + /* Enable the LPAC SQE_to start the CP engine */ + //TODO is this needed? Doesn't fw do this at init? + gpu_write(gpu, REG_A6XX_CP_LPAC_SQE_CNTL, 1); + if (adreno_is_a7xx(adreno_gpu) && !a6xx_gpu->pwrup_reglist_emitted) { a7xx_patch_pwrup_reglist(gpu); a6xx_gpu->pwrup_reglist_emitted = true; @@ -1481,6 +1567,10 @@ static int hw_init(struct msm_gpu *gpu) if (ret) goto out; + ret = lpac_cp_init(gpu); + if (ret) + goto out; + /* * Try to load a zap shader into the secure world. If successful * we can use the CP to switch out of secure mode. If not then we diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c index 7f20320ef66a..881fa09f3943 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_device.c +++ b/drivers/gpu/drm/msm/adreno/adreno_device.c @@ -349,6 +349,9 @@ static void suspend_scheduler(struct msm_gpu *gpu) drm_sched_wqueue_stop(sched); } + + if (gpu->lpac_rb) + drm_sched_wqueue_stop(&gpu->lpac_rb->sched); } static void resume_scheduler(struct msm_gpu *gpu) @@ -360,6 +363,9 @@ static void resume_scheduler(struct msm_gpu *gpu) drm_sched_wqueue_start(sched); } + + if (gpu->lpac_rb) + drm_sched_wqueue_start(&gpu->lpac_rb->sched); } static int adreno_system_suspend(struct device *dev) diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index 6a48e211fa3c..94dbec9464a4 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -655,6 +655,22 @@ struct drm_gem_object *adreno_fw_create_bo(struct msm_gpu *gpu, return bo; } +static inline void init_ring(struct msm_ringbuffer *ring) +{ + ring->cur = ring->start; + ring->next = ring->start; + ring->memptrs->rptr = 0; + ring->memptrs->bv_fence = ring->fctx->completed_fence; + + /* Detect and clean up an impossible fence, ie. if GPU managed + * to scribble something invalid, we don't want that to confuse + * us into mistakingly believing that submits have completed. + */ + if (fence_before(ring->fctx->last_fence, ring->memptrs->fence)) { + ring->memptrs->fence = ring->fctx->last_fence; + } +} + int adreno_hw_init(struct msm_gpu *gpu) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); @@ -679,20 +695,12 @@ int adreno_hw_init(struct msm_gpu *gpu) if (!ring) continue; - ring->cur = ring->start; - ring->next = ring->start; - ring->memptrs->rptr = 0; - ring->memptrs->bv_fence = ring->fctx->completed_fence; - - /* Detect and clean up an impossible fence, ie. if GPU managed - * to scribble something invalid, we don't want that to confuse - * us into mistakingly believing that submits have completed. - */ - if (fence_before(ring->fctx->last_fence, ring->memptrs->fence)) { - ring->memptrs->fence = ring->fctx->last_fence; - } + init_ring(ring); } + if (gpu->lpac_rb) + init_ring(gpu->lpac_rb); + return 0; } diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 18ed00e5f143..932e2a7c24b3 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -739,8 +739,8 @@ static void retire_submits(struct msm_gpu *gpu) int i; /* Retire the commits starting with highest priority */ - for (i = 0; i < gpu->nr_rings; i++) { - struct msm_ringbuffer *ring = gpu->rb[i]; + for (i = 0; i < gpu->nr_rings + !!gpu->lpac_rb; i++) { + struct msm_ringbuffer *ring = i < gpu->nr_rings ? gpu->rb[i] : gpu->lpac_rb; while (true) { struct msm_gem_submit *submit = NULL; @@ -782,6 +782,9 @@ void msm_gpu_retire(struct msm_gpu *gpu) for (i = 0; i < gpu->nr_rings; i++) msm_update_fence(gpu->rb[i]->fctx, gpu->rb[i]->memptrs->fence); + if (gpu->lpac_rb) + msm_update_fence(gpu->lpac_rb->fctx, gpu->lpac_rb->memptrs->fence); + kthread_queue_work(gpu->worker, &gpu->retire_work); } @@ -973,7 +976,7 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev, } memptrs = msm_gem_kernel_new(drm, - sizeof(struct msm_rbmemptrs) * nr_rings, + sizeof(struct msm_rbmemptrs) * (nr_rings + 1), check_apriv(gpu, MSM_BO_WC), gpu->vm, &gpu->memptrs_bo, &memptrs_iova); @@ -1006,6 +1009,15 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev, memptrs_iova += sizeof(struct msm_rbmemptrs); } + gpu->lpac_rb = msm_ringbuffer_new(gpu, nr_rings, memptrs, memptrs_iova); + + if (IS_ERR(gpu->rb[i])) { + ret = PTR_ERR(gpu->rb[i]); + DRM_DEV_ERROR(drm->dev, + "could not create lpac ringbuffer %d\n", ret); + goto fail; + } + gpu->nr_rings = nr_rings; refcount_set(&gpu->sysprof_active, 1); @@ -1046,6 +1058,9 @@ void msm_gpu_cleanup(struct msm_gpu *gpu) gpu->rb[i] = NULL; } + msm_ringbuffer_destroy(gpu->lpac_rb); + gpu->lpac_rb = NULL; + msm_gem_kernel_put(gpu->memptrs_bo, gpu->vm); if (!IS_ERR_OR_NULL(gpu->vm)) { diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h index 271956e7f870..9a213fb65b4f 100644 --- a/drivers/gpu/drm/msm/msm_gpu.h +++ b/drivers/gpu/drm/msm/msm_gpu.h @@ -181,6 +181,8 @@ struct msm_gpu { struct msm_ringbuffer *rb[MSM_GPU_MAX_RINGS]; int nr_rings; + struct msm_ringbuffer *lpac_rb; + /** * sysprof_active: * @@ -323,6 +325,13 @@ static inline bool msm_gpu_active(struct msm_gpu *gpu) return true; } + if (gpu->lpac_rb) { + struct msm_ringbuffer *ring = gpu->lpac_rb; + + if (fence_after(ring->fctx->last_fence, ring->memptrs->fence)) + return true; + } + return false; } -- 2.54.0
