static int nvhost_scale_make_freq_table(struct nvhost_device_profile *profile) { unsigned long *freqs; int num_freqs, err; unsigned long max_freq = clk_round_rate(profile->clk, UINT_MAX); unsigned long min_freq = clk_round_rate(profile->clk, 0); err = tegra_dvfs_get_freqs(clk_get_parent(profile->clk), &freqs, &num_freqs); if (err) return -ENOSYS; /* check for duplicate frequencies at higher end */ while ((num_freqs >= 2 && freqs[num_freqs - 2] == freqs[num_freqs - 1]) || (num_freqs && max_freq < freqs[num_freqs - 1])) num_freqs--; /* check low end */ while ((num_freqs >= 2 && freqs[0] == freqs[1]) || (num_freqs && freqs[0] < min_freq)) { freqs++; num_freqs--; } if (!num_freqs) dev_warn(&profile->pdev->dev, "dvfs table had no applicable frequencies!\n"); profile->devfreq_profile.freq_table = (unsigned long *)freqs; profile->devfreq_profile.max_state = num_freqs; return 0; }
static int gk20a_scale_make_freq_table(struct gk20a_scale_profile *profile) { struct gk20a *g = get_gk20a(profile->pdev); unsigned long *freqs; int num_freqs, err; /* make sure the clock is available */ if (!gk20a_clk_get(g)) return -ENOSYS; /* get gpu dvfs table */ err = tegra_dvfs_get_freqs(clk_get_parent(g->clk.tegra_clk), &freqs, &num_freqs); if (err) return -ENOSYS; profile->devfreq_profile.freq_table = (unsigned long *)freqs; profile->devfreq_profile.max_state = num_freqs; return 0; }
static int gk20a_init_clk_setup_sw(struct gk20a *g) { struct clk_gk20a *clk = &g->clk; static int initialized; unsigned long *freqs; int err, num_freqs; struct clk *ref; unsigned long ref_rate; nvhost_dbg_fn(""); if (clk->sw_ready) { nvhost_dbg_fn("skip init"); return 0; } if (!gk20a_clk_get(g)) return -EINVAL; ref = clk_get_parent(clk_get_parent(clk->tegra_clk)); if (IS_ERR(ref)) { nvhost_err(dev_from_gk20a(g), "failed to get GPCPLL reference clock"); return -EINVAL; } ref_rate = clk_get_rate(ref); clk->pll_delay = 300; /* usec */ clk->gpc_pll.id = GK20A_GPC_PLL; clk->gpc_pll.clk_in = ref_rate / 1000000; /* MHz */ /* Decide initial frequency */ if (!initialized) { initialized = 1; clk->gpc_pll.M = 1; clk->gpc_pll.N = DIV_ROUND_UP(gpc_pll_params.min_vco, clk->gpc_pll.clk_in); clk->gpc_pll.PL = 1; clk->gpc_pll.freq = clk->gpc_pll.clk_in * clk->gpc_pll.N; clk->gpc_pll.freq /= pl_to_div[clk->gpc_pll.PL]; } err = tegra_dvfs_get_freqs(clk_get_parent(clk->tegra_clk), &freqs, &num_freqs); if (!err) { int i, j; /* init j for inverse traversal of frequencies */ j = num_freqs - 1; gpu_cooling_freq = kzalloc( (1 + num_freqs) * sizeof(*gpu_cooling_freq), GFP_KERNEL); /* store frequencies in inverse order */ for (i = 0; i < num_freqs; ++i, --j) { gpu_cooling_freq[i].index = i; gpu_cooling_freq[i].frequency = freqs[j]; } /* add 'end of table' marker */ gpu_cooling_freq[i].index = i; gpu_cooling_freq[i].frequency = GPUFREQ_TABLE_END; /* store number of frequencies */ num_gpu_cooling_freq = num_freqs + 1; } mutex_init(&clk->clk_mutex); clk->sw_ready = true; nvhost_dbg_fn("done"); return 0; }