Loading Documentation/devicetree/bindings/gpu/adreno.txt +14 −0 Original line number Diff line number Diff line Loading @@ -113,6 +113,20 @@ Optional Properties: - qcom,l2pc-cpu-mask-latency: The CPU mask latency in microseconds to avoid L2PC on masked CPUs. - qcom,gpu-cx-ipeak: CX Ipeak is a mitigation scheme which throttles cDSP frequency if all the clients are running at their respective threshold frequencies to limit CX peak current. <phandle bit> phandle - phandle of CX Ipeak device node bit - Every bit corresponds to a client of CX Ipeak driver in the relevant register. - qcom, gpu-cx-ipeak-freq: GPU frequency threshold for CX Ipeak voting. GPU votes to CX Ipeak driver when GPU clock crosses this threshold. CX Ipeak can limit peak current based on voting from other clients. - qcom,force-32bit: Force the GPU to use 32 bit data sizes even if it is capable of doing 64 bit. Loading drivers/gpu/msm/adreno.c +4 −0 Original line number Diff line number Diff line Loading @@ -1338,6 +1338,10 @@ static int adreno_probe(struct platform_device *pdev) device->mmu.va_padding = adreno_dev->gpucore->va_padding; } if (adreno_dev->gpucore->cx_ipeak_gpu_freq) device->pwrctrl.cx_ipeak_gpu_freq = adreno_dev->gpucore->cx_ipeak_gpu_freq; status = kgsl_device_platform_probe(device); if (status) { device->pdev = NULL; Loading drivers/gpu/msm/adreno.h +2 −0 Original line number Diff line number Diff line Loading @@ -390,6 +390,7 @@ struct adreno_device_private { * @gpmu_tsens: ID for the temporature sensor used by the GPMU * @max_power: Max possible power draw of a core, units elephant tail hairs * @va_padding: Size to pad allocations to, zero if not required * @cx_ipeak_gpu_freq : Default Cx Ipeak GPU frequency */ struct adreno_gpu_core { enum adreno_gpurev gpurev; Loading Loading @@ -421,6 +422,7 @@ struct adreno_gpu_core { unsigned int gpmu_tsens; unsigned int max_power; uint64_t va_padding; unsigned int cx_ipeak_gpu_freq; }; Loading drivers/gpu/msm/kgsl_pwrctrl.c +78 −0 Original line number Diff line number Diff line Loading @@ -428,6 +428,28 @@ void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device, !test_bit(GMU_DCVS_REPLAY, &device->gmu_core.flags)) return; if (pwr->gpu_cx_ipeak) { unsigned int old_freq = pwr->pwrlevels[old_level].gpu_freq; unsigned int new_freq = pwr->pwrlevels[new_level].gpu_freq; unsigned int ipeak_freq = pwr->cx_ipeak_gpu_freq; /* * Set CX Ipeak vote for GPU if it tries to cross * threshold frequency. */ if (old_freq < ipeak_freq && new_freq >= ipeak_freq) { int ret = cx_ipeak_update(pwr->gpu_cx_ipeak, true); /* * Hardware damage is possible at peak current * if mitigation not done to limit peak power. */ if (ret) { KGSL_PWR_ERR(device, "ipeak voting failed due to timeout %d\n", ret); return; } } } kgsl_pwrscale_update_stats(device); /* Loading Loading @@ -492,6 +514,25 @@ void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device, /* Timestamp the frequency change */ device->pwrscale.freq_change_time = ktime_to_ms(ktime_get()); if (pwr->gpu_cx_ipeak) { unsigned int old_freq = pwr->pwrlevels[old_level].gpu_freq; unsigned int new_freq = pwr->pwrlevels[new_level].gpu_freq; unsigned int ipeak_freq = pwr->cx_ipeak_gpu_freq; /* * Reset CX Ipeak vote for GPU if it goes below * threshold frequency. */ if (old_freq >= ipeak_freq && new_freq < ipeak_freq) { int ret = cx_ipeak_update(pwr->gpu_cx_ipeak, false); /* Failed to withdraw the voting from ipeak driver */ if (ret) KGSL_PWR_ERR(device, "Failed to withdraw votes from ipeak %d\n", ret); } } } EXPORT_SYMBOL(kgsl_pwrctrl_pwrlevel_change); Loading Loading @@ -2414,8 +2455,43 @@ int kgsl_pwrctrl_init(struct kgsl_device *device) of_property_read_string(pdev->dev.of_node, "qcom,tzone-name", &pwr->tzone_name); /* * Cx ipeak client support, default value of Cx Ipeak GPU freq * is used if defined in GPU list and it is overridden by * new frequency value if defined in dt. */ if (of_find_property(pdev->dev.of_node, "qcom,gpu-cx-ipeak", NULL)) { if (!of_property_read_u32(pdev->dev.of_node, "qcom,gpu-cx-ipeak-freq", &pwr->cx_ipeak_gpu_freq) || pwr->cx_ipeak_gpu_freq) { pwr->gpu_cx_ipeak = cx_ipeak_register(pdev->dev.of_node, "qcom,gpu-cx-ipeak"); } else { KGSL_PWR_ERR(device, "failed to get GPU-CX-Ipeak Frequency\n"); result = -EINVAL; goto error_cleanup_pwr_limit; } if (IS_ERR(pwr->gpu_cx_ipeak)) { result = PTR_ERR(pwr->gpu_cx_ipeak); KGSL_PWR_ERR(device, "Failed to register client with CX Ipeak %d\n", result); goto error_cleanup_pwr_limit; } } return result; error_cleanup_pwr_limit: pwr->power_flags = 0; if (!IS_ERR_OR_NULL(pwr->sysfs_pwr_limit)) { list_del(&pwr->sysfs_pwr_limit->node); kfree(pwr->sysfs_pwr_limit); pwr->sysfs_pwr_limit = NULL; } kfree(pwr->bus_ib); error_cleanup_pcl: _close_pcl(pwr); error_cleanup_ocmem_pcl: Loading @@ -2435,6 +2511,8 @@ void kgsl_pwrctrl_close(struct kgsl_device *device) KGSL_PWR_INFO(device, "close device %d\n", device->id); cx_ipeak_unregister(pwr->gpu_cx_ipeak); pwr->power_flags = 0; if (!IS_ERR_OR_NULL(pwr->sysfs_pwr_limit)) { Loading drivers/gpu/msm/kgsl_pwrctrl.h +5 −0 Original line number Diff line number Diff line Loading @@ -14,6 +14,7 @@ #define __KGSL_PWRCTRL_H #include <linux/pm_qos.h> #include <soc/qcom/cx_ipeak.h> /***************************************************************************** * power flags Loading Loading @@ -172,6 +173,8 @@ struct kgsl_regulator { * isense_clk_indx - index of isense clock, 0 if no isense * isense_clk_on_level - isense clock rate is XO rate below this level. * tzone_name - pointer to thermal zone name of GPU temperature sensor * gpu_cx_ipeak - pointer to CX Ipeak client used by GPU * cx_ipeak_gpu_freq - Value of GPU CX Ipeak frequency */ struct kgsl_pwrctrl { Loading Loading @@ -229,6 +232,8 @@ struct kgsl_pwrctrl { unsigned int gpu_bimc_int_clk_freq; bool gpu_bimc_interface_enabled; const char *tzone_name; struct cx_ipeak_client *gpu_cx_ipeak; unsigned int cx_ipeak_gpu_freq; }; int kgsl_pwrctrl_init(struct kgsl_device *device); Loading Loading
Documentation/devicetree/bindings/gpu/adreno.txt +14 −0 Original line number Diff line number Diff line Loading @@ -113,6 +113,20 @@ Optional Properties: - qcom,l2pc-cpu-mask-latency: The CPU mask latency in microseconds to avoid L2PC on masked CPUs. - qcom,gpu-cx-ipeak: CX Ipeak is a mitigation scheme which throttles cDSP frequency if all the clients are running at their respective threshold frequencies to limit CX peak current. <phandle bit> phandle - phandle of CX Ipeak device node bit - Every bit corresponds to a client of CX Ipeak driver in the relevant register. - qcom, gpu-cx-ipeak-freq: GPU frequency threshold for CX Ipeak voting. GPU votes to CX Ipeak driver when GPU clock crosses this threshold. CX Ipeak can limit peak current based on voting from other clients. - qcom,force-32bit: Force the GPU to use 32 bit data sizes even if it is capable of doing 64 bit. Loading
drivers/gpu/msm/adreno.c +4 −0 Original line number Diff line number Diff line Loading @@ -1338,6 +1338,10 @@ static int adreno_probe(struct platform_device *pdev) device->mmu.va_padding = adreno_dev->gpucore->va_padding; } if (adreno_dev->gpucore->cx_ipeak_gpu_freq) device->pwrctrl.cx_ipeak_gpu_freq = adreno_dev->gpucore->cx_ipeak_gpu_freq; status = kgsl_device_platform_probe(device); if (status) { device->pdev = NULL; Loading
drivers/gpu/msm/adreno.h +2 −0 Original line number Diff line number Diff line Loading @@ -390,6 +390,7 @@ struct adreno_device_private { * @gpmu_tsens: ID for the temporature sensor used by the GPMU * @max_power: Max possible power draw of a core, units elephant tail hairs * @va_padding: Size to pad allocations to, zero if not required * @cx_ipeak_gpu_freq : Default Cx Ipeak GPU frequency */ struct adreno_gpu_core { enum adreno_gpurev gpurev; Loading Loading @@ -421,6 +422,7 @@ struct adreno_gpu_core { unsigned int gpmu_tsens; unsigned int max_power; uint64_t va_padding; unsigned int cx_ipeak_gpu_freq; }; Loading
drivers/gpu/msm/kgsl_pwrctrl.c +78 −0 Original line number Diff line number Diff line Loading @@ -428,6 +428,28 @@ void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device, !test_bit(GMU_DCVS_REPLAY, &device->gmu_core.flags)) return; if (pwr->gpu_cx_ipeak) { unsigned int old_freq = pwr->pwrlevels[old_level].gpu_freq; unsigned int new_freq = pwr->pwrlevels[new_level].gpu_freq; unsigned int ipeak_freq = pwr->cx_ipeak_gpu_freq; /* * Set CX Ipeak vote for GPU if it tries to cross * threshold frequency. */ if (old_freq < ipeak_freq && new_freq >= ipeak_freq) { int ret = cx_ipeak_update(pwr->gpu_cx_ipeak, true); /* * Hardware damage is possible at peak current * if mitigation not done to limit peak power. */ if (ret) { KGSL_PWR_ERR(device, "ipeak voting failed due to timeout %d\n", ret); return; } } } kgsl_pwrscale_update_stats(device); /* Loading Loading @@ -492,6 +514,25 @@ void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device, /* Timestamp the frequency change */ device->pwrscale.freq_change_time = ktime_to_ms(ktime_get()); if (pwr->gpu_cx_ipeak) { unsigned int old_freq = pwr->pwrlevels[old_level].gpu_freq; unsigned int new_freq = pwr->pwrlevels[new_level].gpu_freq; unsigned int ipeak_freq = pwr->cx_ipeak_gpu_freq; /* * Reset CX Ipeak vote for GPU if it goes below * threshold frequency. */ if (old_freq >= ipeak_freq && new_freq < ipeak_freq) { int ret = cx_ipeak_update(pwr->gpu_cx_ipeak, false); /* Failed to withdraw the voting from ipeak driver */ if (ret) KGSL_PWR_ERR(device, "Failed to withdraw votes from ipeak %d\n", ret); } } } EXPORT_SYMBOL(kgsl_pwrctrl_pwrlevel_change); Loading Loading @@ -2414,8 +2455,43 @@ int kgsl_pwrctrl_init(struct kgsl_device *device) of_property_read_string(pdev->dev.of_node, "qcom,tzone-name", &pwr->tzone_name); /* * Cx ipeak client support, default value of Cx Ipeak GPU freq * is used if defined in GPU list and it is overridden by * new frequency value if defined in dt. */ if (of_find_property(pdev->dev.of_node, "qcom,gpu-cx-ipeak", NULL)) { if (!of_property_read_u32(pdev->dev.of_node, "qcom,gpu-cx-ipeak-freq", &pwr->cx_ipeak_gpu_freq) || pwr->cx_ipeak_gpu_freq) { pwr->gpu_cx_ipeak = cx_ipeak_register(pdev->dev.of_node, "qcom,gpu-cx-ipeak"); } else { KGSL_PWR_ERR(device, "failed to get GPU-CX-Ipeak Frequency\n"); result = -EINVAL; goto error_cleanup_pwr_limit; } if (IS_ERR(pwr->gpu_cx_ipeak)) { result = PTR_ERR(pwr->gpu_cx_ipeak); KGSL_PWR_ERR(device, "Failed to register client with CX Ipeak %d\n", result); goto error_cleanup_pwr_limit; } } return result; error_cleanup_pwr_limit: pwr->power_flags = 0; if (!IS_ERR_OR_NULL(pwr->sysfs_pwr_limit)) { list_del(&pwr->sysfs_pwr_limit->node); kfree(pwr->sysfs_pwr_limit); pwr->sysfs_pwr_limit = NULL; } kfree(pwr->bus_ib); error_cleanup_pcl: _close_pcl(pwr); error_cleanup_ocmem_pcl: Loading @@ -2435,6 +2511,8 @@ void kgsl_pwrctrl_close(struct kgsl_device *device) KGSL_PWR_INFO(device, "close device %d\n", device->id); cx_ipeak_unregister(pwr->gpu_cx_ipeak); pwr->power_flags = 0; if (!IS_ERR_OR_NULL(pwr->sysfs_pwr_limit)) { Loading
drivers/gpu/msm/kgsl_pwrctrl.h +5 −0 Original line number Diff line number Diff line Loading @@ -14,6 +14,7 @@ #define __KGSL_PWRCTRL_H #include <linux/pm_qos.h> #include <soc/qcom/cx_ipeak.h> /***************************************************************************** * power flags Loading Loading @@ -172,6 +173,8 @@ struct kgsl_regulator { * isense_clk_indx - index of isense clock, 0 if no isense * isense_clk_on_level - isense clock rate is XO rate below this level. * tzone_name - pointer to thermal zone name of GPU temperature sensor * gpu_cx_ipeak - pointer to CX Ipeak client used by GPU * cx_ipeak_gpu_freq - Value of GPU CX Ipeak frequency */ struct kgsl_pwrctrl { Loading Loading @@ -229,6 +232,8 @@ struct kgsl_pwrctrl { unsigned int gpu_bimc_int_clk_freq; bool gpu_bimc_interface_enabled; const char *tzone_name; struct cx_ipeak_client *gpu_cx_ipeak; unsigned int cx_ipeak_gpu_freq; }; int kgsl_pwrctrl_init(struct kgsl_device *device); Loading