diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index d19d4abd2f72..150f0e672001 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -3004,6 +3004,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 @@ -3378,12 +3405,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 cc7df774a693..acacc69320d2 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)); }