static int nvhost_scale3d_target(struct device *d, unsigned long *freq, u32 flags) { long hz; long after; /* Inform that the clock is disabled */ if (!tegra_is_clk_enabled(power_profile.clk_3d)) { *freq = 0; return 0; } /* Limit the frequency */ if (*freq < power_profile.min_rate_3d) *freq = power_profile.min_rate_3d; else if (*freq > power_profile.max_rate_3d) *freq = power_profile.max_rate_3d; /* Check if we're already running at the desired speed */ if (*freq == clk_get_rate(power_profile.clk_3d)) return 0; /* Set GPU clockrate */ if (tegra_get_chipid() == TEGRA_CHIPID_TEGRA3) nvhost_module_set_devfreq_rate(power_profile.dev, clk_to_idx(power_profile.clk_3d2), 0); nvhost_module_set_devfreq_rate(power_profile.dev, clk_to_idx(power_profile.clk_3d), *freq); /* Set EMC clockrate */ after = (long) clk_get_rate(power_profile.clk_3d); after = INT_TO_FX(HZ_TO_MHZ(after)); hz = FXMUL(after, power_profile.emc_slope) + power_profile.emc_offset; hz -= FXMUL(power_profile.emc_dip_slope, FXMUL(after - power_profile.emc_xmid, after - power_profile.emc_xmid)) + power_profile.emc_dip_offset; hz = MHZ_TO_HZ(FX_TO_INT(hz + FX_HALF)); /* round to nearest */ hz = (hz < 0) ? 0 : hz; nvhost_module_set_devfreq_rate(power_profile.dev, clk_to_idx(power_profile.clk_3d_emc), hz); /* Get the new clockrate */ *freq = clk_get_rate(power_profile.clk_3d); return 0; }
void nvhost_scale_emc_calibrate_emc(struct nvhost_emc_params *emc_params, struct clk *clk_3d, struct clk *clk_3d_emc, bool linear_emc) { long correction; unsigned long max_emc; unsigned long min_emc; unsigned long min_rate_3d; unsigned long max_rate_3d; max_emc = clk_round_rate(clk_3d_emc, UINT_MAX); max_emc = INT_TO_FX(HZ_TO_MHZ(max_emc)); min_emc = clk_round_rate(clk_3d_emc, 0); min_emc = INT_TO_FX(HZ_TO_MHZ(min_emc)); max_rate_3d = clk_round_rate(clk_3d, UINT_MAX); max_rate_3d = INT_TO_FX(HZ_TO_MHZ(max_rate_3d)); min_rate_3d = clk_round_rate(clk_3d, 0); min_rate_3d = INT_TO_FX(HZ_TO_MHZ(min_rate_3d)); emc_params->emc_slope = FXDIV((max_emc - min_emc), (max_rate_3d - min_rate_3d)); emc_params->emc_offset = max_emc - FXMUL(emc_params->emc_slope, max_rate_3d); /* Guarantee max 3d rate maps to max emc rate */ emc_params->emc_offset += max_emc - (FXMUL(emc_params->emc_slope, max_rate_3d) + emc_params->emc_offset); emc_params->linear = linear_emc; if (linear_emc) return; emc_params->emc_dip_offset = (max_emc - min_emc) / 4; emc_params->emc_dip_slope = -FXDIV(emc_params->emc_slope, max_rate_3d - min_rate_3d); emc_params->emc_xmid = (max_rate_3d + min_rate_3d) / 2; correction = emc_params->emc_dip_offset + FXMUL(emc_params->emc_dip_slope, FXMUL(max_rate_3d - emc_params->emc_xmid, max_rate_3d - emc_params->emc_xmid)); emc_params->emc_dip_offset -= correction; }
long nvhost_scale_emc_get_emc_rate(struct nvhost_emc_params *emc_params, long freq) { long hz; freq = INT_TO_FX(HZ_TO_MHZ(freq)); hz = FXMUL(freq, emc_params->emc_slope) + emc_params->emc_offset; if (!emc_params->linear) hz -= FXMUL(emc_params->emc_dip_slope, FXMUL(freq - emc_params->emc_xmid, freq - emc_params->emc_xmid)) + emc_params->emc_dip_offset; hz = MHZ_TO_HZ(FX_TO_INT(hz + FX_HALF)); /* round to nearest */ hz = (hz < 0) ? 0 : hz; return hz; }
static void nvhost_scale3d_calibrate_emc(void) { long correction; unsigned long max_emc; unsigned long min_emc; unsigned long min_rate_3d; unsigned long max_rate_3d; max_emc = clk_round_rate(power_profile.clk_3d_emc, UINT_MAX); max_emc = INT_TO_FX(HZ_TO_MHZ(max_emc)); min_emc = clk_round_rate(power_profile.clk_3d_emc, 0); min_emc = INT_TO_FX(HZ_TO_MHZ(min_emc)); max_rate_3d = INT_TO_FX(HZ_TO_MHZ(power_profile.max_rate_3d)); min_rate_3d = INT_TO_FX(HZ_TO_MHZ(power_profile.min_rate_3d)); power_profile.emc_slope = FXDIV((max_emc - min_emc), (max_rate_3d - min_rate_3d)); power_profile.emc_offset = max_emc - FXMUL(power_profile.emc_slope, max_rate_3d); /* Guarantee max 3d rate maps to max emc rate */ power_profile.emc_offset += max_emc - (FXMUL(power_profile.emc_slope, max_rate_3d) + power_profile.emc_offset); power_profile.emc_dip_offset = (max_emc - min_emc) / 4; power_profile.emc_dip_slope = -4 * FXDIV(power_profile.emc_dip_offset, (FXMUL(max_rate_3d - min_rate_3d, max_rate_3d - min_rate_3d))); power_profile.emc_xmid = (max_rate_3d + min_rate_3d) / 2; correction = power_profile.emc_dip_offset + FXMUL(power_profile.emc_dip_slope, FXMUL(max_rate_3d - power_profile.emc_xmid, max_rate_3d - power_profile.emc_xmid)); power_profile.emc_dip_offset -= correction; }