From da39577432c482830ffebf9318ae968a570391e8 Mon Sep 17 00:00:00 2001 From: Anders Kugler Date: Tue, 3 Feb 2015 18:58:19 -0800 Subject: gpu: nvgpu: tegra gpu to emc frequency mapping o emc clock scaling Only take the gpu load into account for gpu frequencies below fmax @ Vmin. The granularity of frequency steps is much larger in the gpu frequency range below fmax @ Vmin than in the upper frequency range. Above fmax @ Vmin, keep the gpu unblocked and disregard the gpu load when evaluating the emc target. o tegra_postscale() Round the new emc target to nearest discrete frequency. Set the emc frequency only if the new emc target is different from the previously requested emc frequency to avoid the penalty of the locks inside clk_set_rate(). Bug 1591643 Change-Id: I1a1a8734a74569c4d57b6e2bda4c11b2bda3f5f3 Signed-off-by: Anders Kugler Reviewed-on: http://git-master/r/680937 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Ilan Aelion Reviewed-by: Terje Bergstrom --- drivers/gpu/nvgpu/gk20a/platform_gk20a_tegra.c | 74 ++++++++++++++++++++++---- 1 file changed, 63 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/nvgpu/gk20a/platform_gk20a_tegra.c b/drivers/gpu/nvgpu/gk20a/platform_gk20a_tegra.c index 8609e3ae..fea2c774 100644 --- a/drivers/gpu/nvgpu/gk20a/platform_gk20a_tegra.c +++ b/drivers/gpu/nvgpu/gk20a/platform_gk20a_tegra.c @@ -25,6 +25,10 @@ #include #include #include +#include +#include +#include +#include #include "gk20a.h" #include "hal_gk20a.h" @@ -41,6 +45,7 @@ static struct gk20a_platform t132_gk20a_tegra_platform; struct gk20a_emc_params { long bw_ratio; + long freq_last_set; }; #define MHZ_TO_HZ(x) ((x) * 1000000) @@ -150,19 +155,26 @@ fail: * This function returns the minimum emc clock based on gpu frequency */ -static long gk20a_tegra_get_emc_rate(struct gk20a *g, - struct gk20a_emc_params *emc_params, long freq) +static unsigned long gk20a_tegra_get_emc_rate(struct gk20a *g, + struct gk20a_emc_params *emc_params) { - long hz; + unsigned long gpu_freq, gpu_fmax_at_vmin; + unsigned long emc_rate, emc_scale; - freq = HZ_TO_MHZ(freq); + gpu_freq = clk_get_rate(g->clk.tegra_clk); + gpu_fmax_at_vmin = tegra_dvfs_get_fmax_at_vmin_safe_t( + clk_get_parent(g->clk.tegra_clk)); - hz = (freq * emc_params->bw_ratio); - hz = (hz * min(g->pmu.load_avg, g->emc3d_ratio)) / 1000; + /* When scaling emc, only account for the gpu load below fmax@vmin */ + if (gpu_freq < gpu_fmax_at_vmin) + emc_scale = min(g->pmu.load_avg, g->emc3d_ratio); + else + emc_scale = g->emc3d_ratio; - hz = MHZ_TO_HZ(hz); + emc_rate = + (HZ_TO_MHZ(gpu_freq) * emc_params->bw_ratio * emc_scale) / 1000; - return hz; + return MHZ_TO_HZ(emc_rate); } /* @@ -178,11 +190,50 @@ static void gk20a_tegra_postscale(struct platform_device *pdev, struct gk20a_scale_profile *profile = platform->g->scale_profile; struct gk20a_emc_params *emc_params = profile->private_data; struct gk20a *g = get_gk20a(pdev); + struct clk *emc_clk = platform->clk[2]; + enum tegra_chipid chip_id = tegra_get_chip_id(); + unsigned long emc_target; + long emc_freq_lower, emc_freq_upper, emc_freq_rounded; - long after = clk_get_rate(g->clk.tegra_clk); - long emc_target = gk20a_tegra_get_emc_rate(g, emc_params, after); + emc_target = gk20a_tegra_get_emc_rate(g, emc_params); - clk_set_rate(platform->clk[2], emc_target); + switch (chip_id) { + case TEGRA_CHIPID_TEGRA12: + case TEGRA_CHIPID_TEGRA13: + /* T124 and T132 don't apply any rounding. The resulting + * emc frequency gets implicitly rounded up after issuing + * the clock_set_request. + * So explicitly round up the emc target here to achieve + * the same outcome. */ + emc_freq_rounded = + tegra_emc_round_rate_updown(emc_target, true); + break; + + case TEGRA_CHIPID_TEGRA21: + emc_freq_lower = tegra_emc_round_rate_updown(emc_target, false); + emc_freq_upper = tegra_emc_round_rate_updown(emc_target, true); + + /* round to the nearest frequency step */ + if (emc_target < (emc_freq_lower + emc_freq_upper) / 2) + emc_freq_rounded = emc_freq_lower; + else + emc_freq_rounded = emc_freq_upper; + break; + + case TEGRA_CHIPID_UNKNOWN: + default: + /* a proper rounding function needs to be implemented + * for emc in t18x */ + emc_freq_rounded = clk_round_rate(emc_clk, emc_target); + break; + } + + /* only change the emc clock if new rounded frequency is different + * from previously set emc rate */ + if (emc_freq_rounded != emc_params->freq_last_set) { + clk_set_rate(emc_clk, emc_freq_rounded); + emc_params->freq_last_set = emc_freq_rounded; + } } /* @@ -384,6 +435,7 @@ static void gk20a_tegra_scale_init(struct platform_device *pdev) if (!emc_params) return; + emc_params->freq_last_set = -1; gk20a_tegra_calibrate_emc(pdev, emc_params); profile->private_data = emc_params; -- cgit v1.2.2