Loading drivers/gpu/msm/adreno.c +62 −8 Original line number Diff line number Diff line Loading @@ -554,7 +554,13 @@ static int _soft_reset(struct adreno_device *adreno_dev) return 0; } /** * adreno_irqctrl() - Enables/disables the RBBM interrupt mask * @adreno_dev: Pointer to an adreno_device * @state: 1 for masked or 0 for unmasked * Power: The caller of this function must make sure to use OOBs * so that we know that the GPU is powered on */ void adreno_irqctrl(struct adreno_device *adreno_dev, int state) { struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); Loading Loading @@ -599,7 +605,7 @@ static irqreturn_t adreno_irq_handler(struct kgsl_device *device) struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); struct adreno_irq *irq_params = gpudev->irq; irqreturn_t ret = IRQ_NONE; unsigned int status = 0, tmp, int_bit; unsigned int status = 0, fence = 0, tmp, int_bit; int i; atomic_inc(&adreno_dev->pending_irq_refcnt); Loading @@ -614,6 +620,17 @@ static irqreturn_t adreno_irq_handler(struct kgsl_device *device) if (gpudev->gpu_keepalive) gpudev->gpu_keepalive(adreno_dev, true); /* * If the AHB fence is not in ALLOW mode when we receive an RBBM * interrupt, something went wrong. Set a fault and change the * fence to ALLOW so we can clear the interrupt. */ adreno_readreg(adreno_dev, ADRENO_REG_GMU_AO_AHB_FENCE_CTRL, &fence); if (fence != 0) { KGSL_DRV_CRIT_RATELIMIT(device, "AHB fence is stuck in ISR\n"); return ret; } adreno_readreg(adreno_dev, ADRENO_REG_RBBM_INT_0_STATUS, &status); /* Loading Loading @@ -1498,9 +1515,9 @@ static int _adreno_start(struct adreno_device *adreno_dev) /* Send OOB request to turn on the GX */ if (gpudev->oob_set) { status = gpudev->oob_set(adreno_dev, OOB_GPUSTART_SET_MASK, OOB_GPUSTART_CHECK_MASK, OOB_GPUSTART_CLEAR_MASK); status = gpudev->oob_set(adreno_dev, OOB_GPU_SET_MASK, OOB_GPU_CHECK_MASK, OOB_GPU_CLEAR_MASK); if (status) goto error_mmu_off; } Loading Loading @@ -1599,17 +1616,28 @@ static int _adreno_start(struct adreno_device *adreno_dev) pmqos_active_vote); /* Send OOB request to allow IFPC */ if (gpudev->oob_clear) gpudev->oob_clear(adreno_dev, OOB_GPUSTART_CLEAR_MASK); if (gpudev->oob_clear) { gpudev->oob_clear(adreno_dev, OOB_GPU_CLEAR_MASK); /* If we made it this far, the BOOT OOB was sent to the GMU */ if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG)) gpudev->oob_clear(adreno_dev, OOB_BOOT_SLUMBER_CLEAR_MASK); } return 0; error_oob_clear: if (gpudev->oob_clear) gpudev->oob_clear(adreno_dev, OOB_GPUSTART_CLEAR_MASK); gpudev->oob_clear(adreno_dev, OOB_GPU_CLEAR_MASK); error_mmu_off: kgsl_mmu_stop(&device->mmu); if (gpudev->oob_clear && ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG)) { gpudev->oob_clear(adreno_dev, OOB_BOOT_SLUMBER_CLEAR_MASK); } error_pwr_off: /* set the state back to original state */ Loading Loading @@ -1667,10 +1695,23 @@ static void adreno_set_active_ctxs_null(struct adreno_device *adreno_dev) static int adreno_stop(struct kgsl_device *device) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); int error = 0; if (!test_bit(ADRENO_DEVICE_STARTED, &adreno_dev->priv)) return 0; /* Turn the power on one last time before stopping */ if (gpudev->oob_set) { error = gpudev->oob_set(adreno_dev, OOB_GPU_SET_MASK, OOB_GPU_CHECK_MASK, OOB_GPU_CLEAR_MASK); if (error) { gpudev->oob_clear(adreno_dev, OOB_GPU_CLEAR_MASK); return error; } } adreno_set_active_ctxs_null(adreno_dev); adreno_dispatcher_stop(adreno_dev); Loading @@ -1694,6 +1735,19 @@ static int adreno_stop(struct kgsl_device *device) /* Save physical performance counter values before GPU power down*/ adreno_perfcounter_save(adreno_dev); if (gpudev->oob_clear) gpudev->oob_clear(adreno_dev, OOB_GPU_CLEAR_MASK); /* * Saving perfcounters will use an OOB to put the GMU into * active state. Before continuing, we should wait for the * GMU to return to the lowest idle level. This is * because some idle level transitions require VBIF and MMU. */ if (gpudev->wait_for_lowest_idle && gpudev->wait_for_lowest_idle(adreno_dev)) return -EINVAL; adreno_vbif_clear_pending_transactions(device); kgsl_mmu_stop(&device->mmu); Loading drivers/gpu/msm/adreno.h +2 −0 Original line number Diff line number Diff line Loading @@ -638,6 +638,7 @@ enum adreno_regs { ADRENO_REG_VBIF_VERSION, ADRENO_REG_GBIF_HALT, ADRENO_REG_GBIF_HALT_ACK, ADRENO_REG_GMU_AO_AHB_FENCE_CTRL, ADRENO_REG_GMU_AO_INTERRUPT_EN, ADRENO_REG_GMU_AO_HOST_INTERRUPT_CLR, ADRENO_REG_GMU_AO_HOST_INTERRUPT_STATUS, Loading Loading @@ -886,6 +887,7 @@ struct adreno_gpudev { int (*rpmh_gpu_pwrctrl)(struct adreno_device *, unsigned int ops, unsigned int arg1, unsigned int arg2); bool (*hw_isidle)(struct adreno_device *); int (*wait_for_lowest_idle)(struct adreno_device *); int (*wait_for_gmu_idle)(struct adreno_device *); const char *(*iommu_fault_block)(struct adreno_device *adreno_dev, unsigned int fsynr1); Loading drivers/gpu/msm/adreno_a6xx.c +69 −15 Original line number Diff line number Diff line Loading @@ -1025,6 +1025,15 @@ static int timed_poll_check(struct kgsl_device *device, return -EINVAL; } /* * The lowest 16 bits of this value are the number of XO clock cycles * for main hysteresis. This is the first hysteresis. Here we set it * to 0x5DC cycles, or 78.1 us. The highest 16 bits of this value are * the number of XO clock cycles for short hysteresis. This happens * after main hysteresis. Here we set it to 0xA cycles, or 0.5 us. */ #define GMU_PWR_COL_HYST 0x000A05DC /* * a6xx_gmu_power_config() - Configure and enable GMU's low power mode * setting based on ADRENO feature flags. Loading Loading @@ -1056,13 +1065,13 @@ static void a6xx_gmu_power_config(struct kgsl_device *device) /* fall through */ case GPU_HW_IFPC: kgsl_gmu_regwrite(device, A6XX_GMU_PWR_COL_INTER_FRAME_HYST, 0x000A0080); GMU_PWR_COL_HYST); kgsl_gmu_regrmw(device, A6XX_GMU_PWR_COL_INTER_FRAME_CTRL, 0, IFPC_ENABLE_MASK); /* fall through */ case GPU_HW_SPTP_PC: kgsl_gmu_regwrite(device, A6XX_GMU_PWR_COL_SPTPRAC_HYST, 0x000A0080); GMU_PWR_COL_HYST); kgsl_gmu_regrmw(device, A6XX_GMU_PWR_COL_INTER_FRAME_CTRL, 0, SPTP_ENABLE_MASK); /* fall through */ Loading Loading @@ -1281,21 +1290,12 @@ static bool a6xx_gx_is_on(struct adreno_device *adreno_dev) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); unsigned int val; bool state; if (!kgsl_gmu_isenabled(device)) return true; kgsl_gmu_regread(device, A6XX_GMU_SPTPRAC_PWR_CLK_STATUS, &val); state = !(val & (GX_GDSC_POWER_OFF | GX_CLK_OFF)); /* If GMU is holding on to the fence then we cannot dump any GX stuff */ kgsl_gmu_regread(device, A6XX_GMU_AO_AHB_FENCE_CTRL, &val); if (val) return false; return state; return !(val & (GX_GDSC_POWER_OFF | GX_CLK_OFF)); } /* Loading Loading @@ -1366,12 +1366,13 @@ static int a6xx_notify_slumber(struct kgsl_device *device) /* Disable the power counter so that the GMU is not busy */ kgsl_gmu_regwrite(device, A6XX_GMU_CX_GMU_POWER_COUNTER_ENABLE, 0); /* Turn off SPTPRAC before GMU turns off GX */ /* Turn off SPTPRAC if we own it */ if (gmu->idle_level < GPU_HW_SPTP_PC) a6xx_sptprac_disable(adreno_dev); if (!ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG)) { ret = hfi_notify_slumber(gmu, perf_idx, bus_level); return ret; goto out; } kgsl_gmu_regwrite(device, A6XX_GMU_BOOT_SLUMBER_OPTION, Loading @@ -1397,6 +1398,9 @@ static int a6xx_notify_slumber(struct kgsl_device *device) } } out: /* Make sure the fence is in ALLOW mode */ kgsl_gmu_regwrite(device, A6XX_GMU_AO_AHB_FENCE_CTRL, 0); return ret; } Loading Loading @@ -1744,6 +1748,53 @@ static bool a6xx_hw_isidle(struct adreno_device *adreno_dev) return true; } static int a6xx_wait_for_lowest_idle(struct adreno_device *adreno_dev) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct gmu_device *gmu = &device->gmu; struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); unsigned int reg; unsigned long t; if (!kgsl_gmu_isenabled(device)) return 0; t = jiffies + msecs_to_jiffies(GMU_IDLE_TIMEOUT); while (!time_after(jiffies, t)) { adreno_read_gmureg(ADRENO_DEVICE(device), ADRENO_REG_GMU_RPMH_POWER_STATE, ®); /* SPTPRAC PC has the same idle level as IFPC */ if ((reg == gmu->idle_level) || (gmu->idle_level == GPU_HW_SPTP_PC && reg == GPU_HW_IFPC)) { /* IFPC is not complete until GX is off */ if (gmu->idle_level != GPU_HW_IFPC || !gpudev->gx_is_on(adreno_dev)) return 0; } /* Wait 100us to reduce unnecessary AHB bus traffic */ udelay(100); cond_resched(); } /* Check one last time */ adreno_read_gmureg(ADRENO_DEVICE(device), ADRENO_REG_GMU_RPMH_POWER_STATE, ®); if ((reg == gmu->idle_level) || (gmu->idle_level == GPU_HW_SPTP_PC && reg == GPU_HW_IFPC)) { if (gmu->idle_level != GPU_HW_IFPC || !gpudev->gx_is_on(adreno_dev)) return 0; } dev_err(&gmu->pdev->dev, "Timeout waiting for lowest idle level: %d\n", reg); return -ETIMEDOUT; } static int a6xx_wait_for_gmu_idle(struct adreno_device *adreno_dev) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); Loading Loading @@ -2939,6 +2990,8 @@ static unsigned int a6xx_register_offsets[ADRENO_REG_REGISTER_MAX] = { A6XX_GMU_ALWAYS_ON_COUNTER_L), ADRENO_REG_DEFINE(ADRENO_REG_RBBM_ALWAYSON_COUNTER_HI, A6XX_GMU_ALWAYS_ON_COUNTER_H), ADRENO_REG_DEFINE(ADRENO_REG_GMU_AO_AHB_FENCE_CTRL, A6XX_GMU_AO_AHB_FENCE_CTRL), ADRENO_REG_DEFINE(ADRENO_REG_GMU_AO_INTERRUPT_EN, A6XX_GMU_AO_INTERRUPT_EN), ADRENO_REG_DEFINE(ADRENO_REG_GMU_AO_HOST_INTERRUPT_CLR, Loading Loading @@ -3019,6 +3072,7 @@ struct adreno_gpudev adreno_a6xx_gpudev = { .gpu_keepalive = a6xx_gpu_keepalive, .rpmh_gpu_pwrctrl = a6xx_rpmh_gpu_pwrctrl, .hw_isidle = a6xx_hw_isidle, /* Replaced by NULL if GMU is disabled */ .wait_for_lowest_idle = a6xx_wait_for_lowest_idle, .wait_for_gmu_idle = a6xx_wait_for_gmu_idle, .iommu_fault_block = a6xx_iommu_fault_block, .reset = a6xx_reset, Loading drivers/gpu/msm/adreno_a6xx_snapshot.c +6 −0 Original line number Diff line number Diff line Loading @@ -1577,6 +1577,12 @@ void a6xx_snapshot(struct adreno_device *adreno_dev, bool sptprac_on; unsigned int i; /* Make sure the fence is in ALLOW mode so registers can be read */ kgsl_regwrite(device, A6XX_GMU_AO_AHB_FENCE_CTRL, 0); /* GMU TCM data dumped through AHB */ a6xx_snapshot_gmu(adreno_dev, snapshot); sptprac_on = gpudev->sptprac_is_on(adreno_dev); /* Return if the GX is off */ Loading drivers/gpu/msm/adreno_perfcounter.c +7 −0 Original line number Diff line number Diff line Loading @@ -174,10 +174,15 @@ inline void adreno_perfcounter_save(struct adreno_device *adreno_dev) struct adreno_perfcounters *counters = ADRENO_PERFCOUNTERS(adreno_dev); struct adreno_perfcount_group *group; unsigned int counter, groupid; int ret; if (counters == NULL) return; ret = adreno_perfcntr_active_oob_get(adreno_dev); if (ret) return; for (groupid = 0; groupid < counters->group_count; groupid++) { group = &(counters->groups[groupid]); Loading @@ -197,6 +202,8 @@ inline void adreno_perfcounter_save(struct adreno_device *adreno_dev) counter); } } adreno_perfcntr_active_oob_put(adreno_dev); } static int adreno_perfcounter_enable(struct adreno_device *adreno_dev, Loading Loading
drivers/gpu/msm/adreno.c +62 −8 Original line number Diff line number Diff line Loading @@ -554,7 +554,13 @@ static int _soft_reset(struct adreno_device *adreno_dev) return 0; } /** * adreno_irqctrl() - Enables/disables the RBBM interrupt mask * @adreno_dev: Pointer to an adreno_device * @state: 1 for masked or 0 for unmasked * Power: The caller of this function must make sure to use OOBs * so that we know that the GPU is powered on */ void adreno_irqctrl(struct adreno_device *adreno_dev, int state) { struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); Loading Loading @@ -599,7 +605,7 @@ static irqreturn_t adreno_irq_handler(struct kgsl_device *device) struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); struct adreno_irq *irq_params = gpudev->irq; irqreturn_t ret = IRQ_NONE; unsigned int status = 0, tmp, int_bit; unsigned int status = 0, fence = 0, tmp, int_bit; int i; atomic_inc(&adreno_dev->pending_irq_refcnt); Loading @@ -614,6 +620,17 @@ static irqreturn_t adreno_irq_handler(struct kgsl_device *device) if (gpudev->gpu_keepalive) gpudev->gpu_keepalive(adreno_dev, true); /* * If the AHB fence is not in ALLOW mode when we receive an RBBM * interrupt, something went wrong. Set a fault and change the * fence to ALLOW so we can clear the interrupt. */ adreno_readreg(adreno_dev, ADRENO_REG_GMU_AO_AHB_FENCE_CTRL, &fence); if (fence != 0) { KGSL_DRV_CRIT_RATELIMIT(device, "AHB fence is stuck in ISR\n"); return ret; } adreno_readreg(adreno_dev, ADRENO_REG_RBBM_INT_0_STATUS, &status); /* Loading Loading @@ -1498,9 +1515,9 @@ static int _adreno_start(struct adreno_device *adreno_dev) /* Send OOB request to turn on the GX */ if (gpudev->oob_set) { status = gpudev->oob_set(adreno_dev, OOB_GPUSTART_SET_MASK, OOB_GPUSTART_CHECK_MASK, OOB_GPUSTART_CLEAR_MASK); status = gpudev->oob_set(adreno_dev, OOB_GPU_SET_MASK, OOB_GPU_CHECK_MASK, OOB_GPU_CLEAR_MASK); if (status) goto error_mmu_off; } Loading Loading @@ -1599,17 +1616,28 @@ static int _adreno_start(struct adreno_device *adreno_dev) pmqos_active_vote); /* Send OOB request to allow IFPC */ if (gpudev->oob_clear) gpudev->oob_clear(adreno_dev, OOB_GPUSTART_CLEAR_MASK); if (gpudev->oob_clear) { gpudev->oob_clear(adreno_dev, OOB_GPU_CLEAR_MASK); /* If we made it this far, the BOOT OOB was sent to the GMU */ if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG)) gpudev->oob_clear(adreno_dev, OOB_BOOT_SLUMBER_CLEAR_MASK); } return 0; error_oob_clear: if (gpudev->oob_clear) gpudev->oob_clear(adreno_dev, OOB_GPUSTART_CLEAR_MASK); gpudev->oob_clear(adreno_dev, OOB_GPU_CLEAR_MASK); error_mmu_off: kgsl_mmu_stop(&device->mmu); if (gpudev->oob_clear && ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG)) { gpudev->oob_clear(adreno_dev, OOB_BOOT_SLUMBER_CLEAR_MASK); } error_pwr_off: /* set the state back to original state */ Loading Loading @@ -1667,10 +1695,23 @@ static void adreno_set_active_ctxs_null(struct adreno_device *adreno_dev) static int adreno_stop(struct kgsl_device *device) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); int error = 0; if (!test_bit(ADRENO_DEVICE_STARTED, &adreno_dev->priv)) return 0; /* Turn the power on one last time before stopping */ if (gpudev->oob_set) { error = gpudev->oob_set(adreno_dev, OOB_GPU_SET_MASK, OOB_GPU_CHECK_MASK, OOB_GPU_CLEAR_MASK); if (error) { gpudev->oob_clear(adreno_dev, OOB_GPU_CLEAR_MASK); return error; } } adreno_set_active_ctxs_null(adreno_dev); adreno_dispatcher_stop(adreno_dev); Loading @@ -1694,6 +1735,19 @@ static int adreno_stop(struct kgsl_device *device) /* Save physical performance counter values before GPU power down*/ adreno_perfcounter_save(adreno_dev); if (gpudev->oob_clear) gpudev->oob_clear(adreno_dev, OOB_GPU_CLEAR_MASK); /* * Saving perfcounters will use an OOB to put the GMU into * active state. Before continuing, we should wait for the * GMU to return to the lowest idle level. This is * because some idle level transitions require VBIF and MMU. */ if (gpudev->wait_for_lowest_idle && gpudev->wait_for_lowest_idle(adreno_dev)) return -EINVAL; adreno_vbif_clear_pending_transactions(device); kgsl_mmu_stop(&device->mmu); Loading
drivers/gpu/msm/adreno.h +2 −0 Original line number Diff line number Diff line Loading @@ -638,6 +638,7 @@ enum adreno_regs { ADRENO_REG_VBIF_VERSION, ADRENO_REG_GBIF_HALT, ADRENO_REG_GBIF_HALT_ACK, ADRENO_REG_GMU_AO_AHB_FENCE_CTRL, ADRENO_REG_GMU_AO_INTERRUPT_EN, ADRENO_REG_GMU_AO_HOST_INTERRUPT_CLR, ADRENO_REG_GMU_AO_HOST_INTERRUPT_STATUS, Loading Loading @@ -886,6 +887,7 @@ struct adreno_gpudev { int (*rpmh_gpu_pwrctrl)(struct adreno_device *, unsigned int ops, unsigned int arg1, unsigned int arg2); bool (*hw_isidle)(struct adreno_device *); int (*wait_for_lowest_idle)(struct adreno_device *); int (*wait_for_gmu_idle)(struct adreno_device *); const char *(*iommu_fault_block)(struct adreno_device *adreno_dev, unsigned int fsynr1); Loading
drivers/gpu/msm/adreno_a6xx.c +69 −15 Original line number Diff line number Diff line Loading @@ -1025,6 +1025,15 @@ static int timed_poll_check(struct kgsl_device *device, return -EINVAL; } /* * The lowest 16 bits of this value are the number of XO clock cycles * for main hysteresis. This is the first hysteresis. Here we set it * to 0x5DC cycles, or 78.1 us. The highest 16 bits of this value are * the number of XO clock cycles for short hysteresis. This happens * after main hysteresis. Here we set it to 0xA cycles, or 0.5 us. */ #define GMU_PWR_COL_HYST 0x000A05DC /* * a6xx_gmu_power_config() - Configure and enable GMU's low power mode * setting based on ADRENO feature flags. Loading Loading @@ -1056,13 +1065,13 @@ static void a6xx_gmu_power_config(struct kgsl_device *device) /* fall through */ case GPU_HW_IFPC: kgsl_gmu_regwrite(device, A6XX_GMU_PWR_COL_INTER_FRAME_HYST, 0x000A0080); GMU_PWR_COL_HYST); kgsl_gmu_regrmw(device, A6XX_GMU_PWR_COL_INTER_FRAME_CTRL, 0, IFPC_ENABLE_MASK); /* fall through */ case GPU_HW_SPTP_PC: kgsl_gmu_regwrite(device, A6XX_GMU_PWR_COL_SPTPRAC_HYST, 0x000A0080); GMU_PWR_COL_HYST); kgsl_gmu_regrmw(device, A6XX_GMU_PWR_COL_INTER_FRAME_CTRL, 0, SPTP_ENABLE_MASK); /* fall through */ Loading Loading @@ -1281,21 +1290,12 @@ static bool a6xx_gx_is_on(struct adreno_device *adreno_dev) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); unsigned int val; bool state; if (!kgsl_gmu_isenabled(device)) return true; kgsl_gmu_regread(device, A6XX_GMU_SPTPRAC_PWR_CLK_STATUS, &val); state = !(val & (GX_GDSC_POWER_OFF | GX_CLK_OFF)); /* If GMU is holding on to the fence then we cannot dump any GX stuff */ kgsl_gmu_regread(device, A6XX_GMU_AO_AHB_FENCE_CTRL, &val); if (val) return false; return state; return !(val & (GX_GDSC_POWER_OFF | GX_CLK_OFF)); } /* Loading Loading @@ -1366,12 +1366,13 @@ static int a6xx_notify_slumber(struct kgsl_device *device) /* Disable the power counter so that the GMU is not busy */ kgsl_gmu_regwrite(device, A6XX_GMU_CX_GMU_POWER_COUNTER_ENABLE, 0); /* Turn off SPTPRAC before GMU turns off GX */ /* Turn off SPTPRAC if we own it */ if (gmu->idle_level < GPU_HW_SPTP_PC) a6xx_sptprac_disable(adreno_dev); if (!ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG)) { ret = hfi_notify_slumber(gmu, perf_idx, bus_level); return ret; goto out; } kgsl_gmu_regwrite(device, A6XX_GMU_BOOT_SLUMBER_OPTION, Loading @@ -1397,6 +1398,9 @@ static int a6xx_notify_slumber(struct kgsl_device *device) } } out: /* Make sure the fence is in ALLOW mode */ kgsl_gmu_regwrite(device, A6XX_GMU_AO_AHB_FENCE_CTRL, 0); return ret; } Loading Loading @@ -1744,6 +1748,53 @@ static bool a6xx_hw_isidle(struct adreno_device *adreno_dev) return true; } static int a6xx_wait_for_lowest_idle(struct adreno_device *adreno_dev) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct gmu_device *gmu = &device->gmu; struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); unsigned int reg; unsigned long t; if (!kgsl_gmu_isenabled(device)) return 0; t = jiffies + msecs_to_jiffies(GMU_IDLE_TIMEOUT); while (!time_after(jiffies, t)) { adreno_read_gmureg(ADRENO_DEVICE(device), ADRENO_REG_GMU_RPMH_POWER_STATE, ®); /* SPTPRAC PC has the same idle level as IFPC */ if ((reg == gmu->idle_level) || (gmu->idle_level == GPU_HW_SPTP_PC && reg == GPU_HW_IFPC)) { /* IFPC is not complete until GX is off */ if (gmu->idle_level != GPU_HW_IFPC || !gpudev->gx_is_on(adreno_dev)) return 0; } /* Wait 100us to reduce unnecessary AHB bus traffic */ udelay(100); cond_resched(); } /* Check one last time */ adreno_read_gmureg(ADRENO_DEVICE(device), ADRENO_REG_GMU_RPMH_POWER_STATE, ®); if ((reg == gmu->idle_level) || (gmu->idle_level == GPU_HW_SPTP_PC && reg == GPU_HW_IFPC)) { if (gmu->idle_level != GPU_HW_IFPC || !gpudev->gx_is_on(adreno_dev)) return 0; } dev_err(&gmu->pdev->dev, "Timeout waiting for lowest idle level: %d\n", reg); return -ETIMEDOUT; } static int a6xx_wait_for_gmu_idle(struct adreno_device *adreno_dev) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); Loading Loading @@ -2939,6 +2990,8 @@ static unsigned int a6xx_register_offsets[ADRENO_REG_REGISTER_MAX] = { A6XX_GMU_ALWAYS_ON_COUNTER_L), ADRENO_REG_DEFINE(ADRENO_REG_RBBM_ALWAYSON_COUNTER_HI, A6XX_GMU_ALWAYS_ON_COUNTER_H), ADRENO_REG_DEFINE(ADRENO_REG_GMU_AO_AHB_FENCE_CTRL, A6XX_GMU_AO_AHB_FENCE_CTRL), ADRENO_REG_DEFINE(ADRENO_REG_GMU_AO_INTERRUPT_EN, A6XX_GMU_AO_INTERRUPT_EN), ADRENO_REG_DEFINE(ADRENO_REG_GMU_AO_HOST_INTERRUPT_CLR, Loading Loading @@ -3019,6 +3072,7 @@ struct adreno_gpudev adreno_a6xx_gpudev = { .gpu_keepalive = a6xx_gpu_keepalive, .rpmh_gpu_pwrctrl = a6xx_rpmh_gpu_pwrctrl, .hw_isidle = a6xx_hw_isidle, /* Replaced by NULL if GMU is disabled */ .wait_for_lowest_idle = a6xx_wait_for_lowest_idle, .wait_for_gmu_idle = a6xx_wait_for_gmu_idle, .iommu_fault_block = a6xx_iommu_fault_block, .reset = a6xx_reset, Loading
drivers/gpu/msm/adreno_a6xx_snapshot.c +6 −0 Original line number Diff line number Diff line Loading @@ -1577,6 +1577,12 @@ void a6xx_snapshot(struct adreno_device *adreno_dev, bool sptprac_on; unsigned int i; /* Make sure the fence is in ALLOW mode so registers can be read */ kgsl_regwrite(device, A6XX_GMU_AO_AHB_FENCE_CTRL, 0); /* GMU TCM data dumped through AHB */ a6xx_snapshot_gmu(adreno_dev, snapshot); sptprac_on = gpudev->sptprac_is_on(adreno_dev); /* Return if the GX is off */ Loading
drivers/gpu/msm/adreno_perfcounter.c +7 −0 Original line number Diff line number Diff line Loading @@ -174,10 +174,15 @@ inline void adreno_perfcounter_save(struct adreno_device *adreno_dev) struct adreno_perfcounters *counters = ADRENO_PERFCOUNTERS(adreno_dev); struct adreno_perfcount_group *group; unsigned int counter, groupid; int ret; if (counters == NULL) return; ret = adreno_perfcntr_active_oob_get(adreno_dev); if (ret) return; for (groupid = 0; groupid < counters->group_count; groupid++) { group = &(counters->groups[groupid]); Loading @@ -197,6 +202,8 @@ inline void adreno_perfcounter_save(struct adreno_device *adreno_dev) counter); } } adreno_perfcntr_active_oob_put(adreno_dev); } static int adreno_perfcounter_enable(struct adreno_device *adreno_dev, Loading