Loading Documentation/devicetree/bindings/gpu/adreno.txt +11 −0 Original line number Diff line number Diff line Loading @@ -110,6 +110,17 @@ Optional Properties: - qcom,l2pc-cpu-mask-latency: The CPU mask latency in microseconds to avoid L2PC on masked CPUs. - qcom,gpu-cx-ipeak: To handle Cx peak current limit. <phandle bit> phandle - phandle of cx ipeak device node bit - bit number of client in relevant register - qcom,gpu-cx-ipeak-clk: GPU clock threshold for Cx Ipeak voting. KGSL 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/kgsl_pwrctrl.c +69 −0 Original line number Diff line number Diff line Loading @@ -361,6 +361,26 @@ void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device, if (new_level == old_level) 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; /* * Set Cx ipeak vote for GPU if it tries to cross * threshold frequency. */ if (old_freq < pwr->gpu_cx_ipeak_clk && new_freq >= pwr->gpu_cx_ipeak_clk) { int ret = cx_ipeak_update(pwr->gpu_cx_ipeak, true); if (ret) { KGSL_PWR_ERR(device, "cx_ipeak_update failed %d\n", ret); return; } } } kgsl_pwrscale_update_stats(device); /* Loading Loading @@ -422,6 +442,24 @@ 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; /* * Reset Cx ipeak vote for GPU if it goes below * threshold frequency. */ if (old_freq >= pwr->gpu_cx_ipeak_clk && new_freq < pwr->gpu_cx_ipeak_clk) { int ret = cx_ipeak_update(pwr->gpu_cx_ipeak, false); if (ret) KGSL_PWR_ERR(device, "cx_ipeak_update failed %d\n", ret); } } } EXPORT_SYMBOL(kgsl_pwrctrl_pwrlevel_change); Loading Loading @@ -2217,8 +2255,37 @@ int kgsl_pwrctrl_init(struct kgsl_device *device) of_property_read_string(pdev->dev.of_node, "qcom,tsens-name", &pwr->tsens_name); /* Cx ipeak client support */ 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-clk", &pwr->gpu_cx_ipeak_clk)) { pwr->gpu_cx_ipeak = cx_ipeak_register(pdev->dev.of_node, "qcom,gpu-cx-ipeak"); } else { KGSL_PWR_ERR(device, "failed to get gpu cxip clk\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 Cx ipeak client %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 @@ -2238,6 +2305,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 +6 −1 Original line number Diff line number Diff line /* Copyright (c) 2010-2016, The Linux Foundation. All rights reserved. /* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading @@ -14,6 +14,7 @@ #define __KGSL_PWRCTRL_H #include <linux/pm_qos.h> #include <soc/qcom/cx_ipeak.h> /***************************************************************************** ** power flags Loading Loading @@ -153,6 +154,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. * tsens_name - pointer to temperature sensor name of GPU temperature sensor * gpu_cx_ipeak - pointer to cx ipeak client used by GPU * gpu_cx_ipeak_clk - GPU threshold frequency to call cx ipeak driver API */ struct kgsl_pwrctrl { Loading Loading @@ -206,6 +209,8 @@ struct kgsl_pwrctrl { unsigned int gpu_bimc_int_clk_freq; bool gpu_bimc_interface_enabled; const char *tsens_name; struct cx_ipeak_client *gpu_cx_ipeak; unsigned int gpu_cx_ipeak_clk; }; int kgsl_pwrctrl_init(struct kgsl_device *device); Loading Loading
Documentation/devicetree/bindings/gpu/adreno.txt +11 −0 Original line number Diff line number Diff line Loading @@ -110,6 +110,17 @@ Optional Properties: - qcom,l2pc-cpu-mask-latency: The CPU mask latency in microseconds to avoid L2PC on masked CPUs. - qcom,gpu-cx-ipeak: To handle Cx peak current limit. <phandle bit> phandle - phandle of cx ipeak device node bit - bit number of client in relevant register - qcom,gpu-cx-ipeak-clk: GPU clock threshold for Cx Ipeak voting. KGSL 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/kgsl_pwrctrl.c +69 −0 Original line number Diff line number Diff line Loading @@ -361,6 +361,26 @@ void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device, if (new_level == old_level) 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; /* * Set Cx ipeak vote for GPU if it tries to cross * threshold frequency. */ if (old_freq < pwr->gpu_cx_ipeak_clk && new_freq >= pwr->gpu_cx_ipeak_clk) { int ret = cx_ipeak_update(pwr->gpu_cx_ipeak, true); if (ret) { KGSL_PWR_ERR(device, "cx_ipeak_update failed %d\n", ret); return; } } } kgsl_pwrscale_update_stats(device); /* Loading Loading @@ -422,6 +442,24 @@ 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; /* * Reset Cx ipeak vote for GPU if it goes below * threshold frequency. */ if (old_freq >= pwr->gpu_cx_ipeak_clk && new_freq < pwr->gpu_cx_ipeak_clk) { int ret = cx_ipeak_update(pwr->gpu_cx_ipeak, false); if (ret) KGSL_PWR_ERR(device, "cx_ipeak_update failed %d\n", ret); } } } EXPORT_SYMBOL(kgsl_pwrctrl_pwrlevel_change); Loading Loading @@ -2217,8 +2255,37 @@ int kgsl_pwrctrl_init(struct kgsl_device *device) of_property_read_string(pdev->dev.of_node, "qcom,tsens-name", &pwr->tsens_name); /* Cx ipeak client support */ 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-clk", &pwr->gpu_cx_ipeak_clk)) { pwr->gpu_cx_ipeak = cx_ipeak_register(pdev->dev.of_node, "qcom,gpu-cx-ipeak"); } else { KGSL_PWR_ERR(device, "failed to get gpu cxip clk\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 Cx ipeak client %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 @@ -2238,6 +2305,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 +6 −1 Original line number Diff line number Diff line /* Copyright (c) 2010-2016, The Linux Foundation. All rights reserved. /* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading @@ -14,6 +14,7 @@ #define __KGSL_PWRCTRL_H #include <linux/pm_qos.h> #include <soc/qcom/cx_ipeak.h> /***************************************************************************** ** power flags Loading Loading @@ -153,6 +154,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. * tsens_name - pointer to temperature sensor name of GPU temperature sensor * gpu_cx_ipeak - pointer to cx ipeak client used by GPU * gpu_cx_ipeak_clk - GPU threshold frequency to call cx ipeak driver API */ struct kgsl_pwrctrl { Loading Loading @@ -206,6 +209,8 @@ struct kgsl_pwrctrl { unsigned int gpu_bimc_int_clk_freq; bool gpu_bimc_interface_enabled; const char *tsens_name; struct cx_ipeak_client *gpu_cx_ipeak; unsigned int gpu_cx_ipeak_clk; }; int kgsl_pwrctrl_init(struct kgsl_device *device); Loading