From 6918f9ffa9893419d75dcd795ecdc80538e315b8 Mon Sep 17 00:00:00 2001 From: Pankaj Gupta Date: Wed, 22 Jul 2020 18:59:06 +0530 Subject: [PATCH] msm: kgsl: Add support for gmu wrapper memory region In some targets, SMMU memory region mapped in middle of GPU region. Due to this overlapping, when we try to map full memory region of GPU, request_mem_region will be failed. To avoid that issue, split GPU memory region and program it in gmu_wrapper. Change-Id: I735fde1b47161abe690a018c8642e4211a4c12a7 Signed-off-by: Pankaj Gupta --- drivers/gpu/msm/adreno.c | 43 +++++++++++++++++++-- drivers/gpu/msm/adreno.h | 27 +++++++++++++ drivers/gpu/msm/adreno_a6xx.c | 45 ++++++++++++++++++++-- drivers/gpu/msm/adreno_a6xx_gmu.c | 64 ++++++++++++++++++++++++++++++- 4 files changed, 171 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index 514865058377..85cb92343c66 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -2993,6 +2993,33 @@ static void adreno_regwrite(struct kgsl_device *device, __raw_writel(value, reg); } +void adreno_read_gmu_wrapper(struct adreno_device *adreno_dev, + u32 offsetwords, u32 *val) +{ + if (!adreno_dev->gmu_wrapper_virt) + return; + + *val = __raw_readl(adreno_dev->gmu_wrapper_virt + + (offsetwords << 2) - adreno_dev->gmu_wrapper_base); + /* Order this read with respect to the following memory accesses */ + rmb(); +} + +void adreno_write_gmu_wrapper(struct adreno_device *adreno_dev, + u32 offsetwords, u32 value) +{ + if (!adreno_dev->gmu_wrapper_virt) + return; + + /* + * ensure previous writes post before this one, + * i.e. act like normal writel() + */ + wmb(); + __raw_writel(value, adreno_dev->gmu_wrapper_virt + + (offsetwords << 2) - adreno_dev->gmu_wrapper_base); +} + /* * adreno_gmu_fenced_write() - Check if there is a GMU and it is enabled * @adreno_dev: Pointer to the Adreno device that owns the GMU @@ -3367,12 +3394,22 @@ static void adreno_power_stats(struct kgsl_device *device, struct kgsl_pwrctrl *pwr = &device->pwrctrl; struct adreno_busy_data *busy = &adreno_dev->busy_data; int64_t adj = 0; - u64 gpu_busy; + u64 gpu_busy = 0; + unsigned int val; memset(stats, 0, sizeof(*stats)); - gpu_busy = counter_delta(device, adreno_dev->perfctr_pwr_lo, - &busy->gpu_busy); + if (adreno_is_a619_holi(adreno_dev)) + adreno_read_gmu_wrapper(adreno_dev, + adreno_dev->perfctr_pwr_lo, &val); + else + kgsl_regread(device, adreno_dev->perfctr_pwr_lo, &val); + + if (busy->gpu_busy) + gpu_busy = (val >= busy->gpu_busy) ? val - busy->gpu_busy : + (~0UL - busy->gpu_busy) + val; + + busy->gpu_busy = val; if (gpudev->read_throttling_counters) { adj = gpudev->read_throttling_counters(adreno_dev); diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index 7ee2dbc8e4d0..c5ad9d41038d 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -5,6 +5,7 @@ #ifndef __ADRENO_H #define __ADRENO_H +#include #include "adreno_coresight.h" #include "adreno_dispatch.h" #include "adreno_drawctxt.h" @@ -487,6 +488,8 @@ struct adreno_device { unsigned long isense_base; unsigned int isense_len; void __iomem *isense_virt; + unsigned long gmu_wrapper_base; + void __iomem *gmu_wrapper_virt; const struct adreno_gpu_core *gpucore; struct adreno_firmware fw[2]; size_t gpmu_cmds_size; @@ -1124,6 +1127,12 @@ static inline int adreno_is_a650_family(struct adreno_device *adreno_dev) rev == ADRENO_REV_A660); } +static inline int adreno_is_a619_holi(struct adreno_device *adreno_dev) +{ + return of_device_is_compatible(adreno_dev->dev.pdev->dev.of_node, + "qcom,adreno-gpu-a619-holi"); +} + static inline int adreno_is_a620v1(struct adreno_device *adreno_dev) { return (ADRENO_GPUREV(adreno_dev) == ADRENO_REV_A620) && @@ -1252,6 +1261,24 @@ static inline void adreno_write_gmureg(struct adreno_device *adreno_dev, gpudev->reg_offsets[offset_name], val); } +/** + * adreno_read_gmu_wrapper() - Read a GMU wrapper register + * @adreno_dev: Pointer to the the adreno device + * @offsetwords: Offset of the wrapper register + * @val: Register value read is placed here + */ +void adreno_read_gmu_wrapper(struct adreno_device *adreno_dev, + u32 offsetwords, u32 *val); + +/** + * adreno_write_gmu_wrapper() - write on a GMU wrapper register + * @adreno_dev: Pointer to the the adreno device + * @offsetwords: Offset of the wrapper register + * @val: value to write on wrapper register + */ +void adreno_write_gmu_wrapper(struct adreno_device *adreno_dev, + u32 offsetwords, u32 value); + /** * adreno_gpu_fault() - Return the current state of the GPU * @adreno_dev: A pointer to the adreno_device to query diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c index 0c9990ef5823..308e1dcae750 100644 --- a/drivers/gpu/msm/adreno_a6xx.c +++ b/drivers/gpu/msm/adreno_a6xx.c @@ -121,10 +121,32 @@ static u32 a615_pwrup_reglist[] = { static int a6xx_get_cp_init_cmds(struct adreno_device *adreno_dev); +static void a6xx_gmu_wrapper_init(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct resource *res; + + if (adreno_dev->gmu_wrapper_virt) + return; + + res = platform_get_resource_byname(device->pdev, + IORESOURCE_MEM, "gmu_wrapper"); + if (!res) + return; + + adreno_dev->gmu_wrapper_base = res->start - device->reg_phys; + adreno_dev->gmu_wrapper_virt = devm_ioremap(&device->pdev->dev, + res->start, resource_size(res)); + + if (!adreno_dev->gmu_wrapper_virt) + dev_warn(device->dev, "gmu_wrapper ioremap failed\n"); +} + int a6xx_init(struct adreno_device *adreno_dev) { const struct adreno_a6xx_core *a6xx_core = to_a6xx_core(adreno_dev); + a6xx_gmu_wrapper_init(adreno_dev); adreno_dev->highest_bank_bit = a6xx_core->highest_bank_bit; /* If the memory type is DDR 4, override the existing configuration */ @@ -605,10 +627,27 @@ void a6xx_start(struct adreno_device *adreno_dev) * Enable GMU power counter 0 to count GPU busy. This is applicable to * all a6xx targets */ - kgsl_regwrite(device, A6XX_GPU_GMU_AO_GPU_CX_BUSY_MASK, 0xff000000); - kgsl_regrmw(device, A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_0, 0xff, 0x20); - kgsl_regwrite(device, A6XX_GMU_CX_GMU_POWER_COUNTER_ENABLE, 0x1); + if (adreno_is_a619_holi(adreno_dev)) { + unsigned int val; + adreno_write_gmu_wrapper(adreno_dev, + A6XX_GPU_GMU_AO_GPU_CX_BUSY_MASK, 0xff000000); + adreno_read_gmu_wrapper(adreno_dev, + A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_0, &val); + adreno_write_gmu_wrapper(adreno_dev, + A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_0, + (val & 0xff) | 0x20); + adreno_write_gmu_wrapper(adreno_dev, + A6XX_GMU_CX_GMU_POWER_COUNTER_ENABLE, 0x1); + + } else { + kgsl_regwrite(device, A6XX_GPU_GMU_AO_GPU_CX_BUSY_MASK, + 0xff000000); + kgsl_regrmw(device, A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_0, + 0xff, 0x20); + kgsl_regwrite(device, A6XX_GMU_CX_GMU_POWER_COUNTER_ENABLE, + 0x1); + } a6xx_protect_init(adreno_dev); /* * We start LM here because we want all the following to be up diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.c b/drivers/gpu/msm/adreno_a6xx_gmu.c index ecc5461e2ee7..b85e80da3f3e 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu.c +++ b/drivers/gpu/msm/adreno_a6xx_gmu.c @@ -923,6 +923,32 @@ int a6xx_gmu_sptprac_enable(struct adreno_device *adreno_dev) struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); + if (adreno_is_a619_holi(adreno_dev)) { + u32 val; + void __iomem *addr = adreno_dev->gmu_wrapper_virt + + (A6XX_GMU_SPTPRAC_PWR_CLK_STATUS << 2) - + adreno_dev->gmu_wrapper_base; + + if (!adreno_dev->gmu_wrapper_virt) { + dev_err(device->dev, + "invalid gmu_wrapper addr, power on SPTPRAC fail\n"); + return -EINVAL; + } + + adreno_write_gmu_wrapper(adreno_dev, + A6XX_GMU_GX_SPTPRAC_POWER_CONTROL, + SPTPRAC_POWERON_CTRL_MASK); + + if (readl_poll_timeout(addr, val, + (val & SPTPRAC_POWERON_STATUS_MASK) == + SPTPRAC_POWERON_STATUS_MASK, 10, + 10 * 1000)) { + dev_err(device->dev, "power on SPTPRAC fail\n"); + return -EINVAL; + } + return 0; + } + if (!gmu_core_gpmu_isenabled(device) || !adreno_has_sptprac_gdsc(adreno_dev)) return 0; @@ -952,6 +978,35 @@ void a6xx_gmu_sptprac_disable(struct adreno_device *adreno_dev) struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); + if (adreno_is_a619_holi(adreno_dev)) { + u32 val; + void __iomem *addr = adreno_dev->gmu_wrapper_virt + + (A6XX_GMU_SPTPRAC_PWR_CLK_STATUS << 2) - + adreno_dev->gmu_wrapper_base; + + if (!adreno_dev->gmu_wrapper_virt) { + dev_err(device->dev, + "invalid gmu_wrapper addr, power off SPTPRAC fail\n"); + return; + } + + /* Ensure that retention is on */ + adreno_read_gmu_wrapper(adreno_dev, + A6XX_GPU_CC_GX_GDSCR, &val); + adreno_write_gmu_wrapper(adreno_dev, + A6XX_GPU_CC_GX_GDSCR, + (val | A6XX_RETAIN_FF_ENABLE_ENABLE_MASK)); + adreno_write_gmu_wrapper(adreno_dev, + A6XX_GMU_GX_SPTPRAC_POWER_CONTROL, + SPTPRAC_POWEROFF_CTRL_MASK); + if (readl_poll_timeout(addr, val, + (val & SPTPRAC_POWEROFF_STATUS_MASK) == + SPTPRAC_POWEROFF_STATUS_MASK, 10, + 10 * 1000)) + dev_err(device->dev, "power off SPTPRAC fail\n"); + return; + } + if (!gmu_core_gpmu_isenabled(device) || !adreno_has_sptprac_gdsc(adreno_dev)) return; @@ -996,10 +1051,15 @@ bool a6xx_gmu_sptprac_is_on(struct adreno_device *adreno_dev) struct kgsl_device *device = KGSL_DEVICE(adreno_dev); unsigned int val; - if (!gmu_core_isenabled(device)) + if (gmu_core_isenabled(device)) + gmu_core_regread(device, A6XX_GMU_SPTPRAC_PWR_CLK_STATUS, + &val); + else if (adreno_is_a619_holi(adreno_dev)) + adreno_read_gmu_wrapper(adreno_dev, + A6XX_GMU_SPTPRAC_PWR_CLK_STATUS, &val); + else return true; - gmu_core_regread(device, A6XX_GMU_SPTPRAC_PWR_CLK_STATUS, &val); return !(val & (SPTPRAC_POWER_OFF | SP_CLK_OFF)); }