u32 mfd;
};
-const struct fixed_pll_mfd fixed_mfd[] = {
+static const struct fixed_pll_mfd fixed_mfd[] = {
{MXC_HCLK, 24 * 16},
};
#define PLL_FREQ_MAX(ref_clk) (4 * (ref_clk) * PLL_MFI_MAX)
#define PLL_FREQ_MIN(ref_clk) \
- ((2 * (ref_clk) * (PLL_MFI_MIN - 1)) / PLL_PD_MAX)
+ ((4 * (ref_clk) * PLL_MFI_MIN) / PLL_PD_MAX)
#define MAX_DDR_CLK 420000000
#define NFC_CLK_MAX 34000000
*/
static uint32_t decode_pll(struct mxc_pll_reg *pll, uint32_t infreq)
{
- uint32_t ctrl, op, mfd, mfn, mfi, pdf, ret;
+ uint32_t ctrl, op;
+ int mfd, mfn, mfi, pdf, ret;
uint64_t refclk, temp;
- int32_t mfn_abs;
+ uint32_t mfn_abs;
ctrl = readl(&pll->ctrl);
if (mfn >= 0x04000000) {
mfn |= 0xfc000000;
mfn_abs = -mfn;
- } else
+ } else {
mfn_abs = mfn;
-
+ }
refclk = infreq * 2;
if (ctrl & MXC_DPLLC_CTL_DPDCK0_2_EN)
refclk *= 2;
- do_div(refclk, pdf + 1);
temp = refclk * mfn_abs;
do_div(temp, mfd + 1);
ret = refclk * mfi;
- if ((int)mfn < 0)
+ if (mfn < 0)
ret -= temp;
else
ret += temp;
+ ret /= pdf + 1;
return ret;
}
*/
static int calc_pll_params(u32 ref, u32 target, struct pll_param *pll)
{
- u64 pd, mfi = 1, mfn, mfd, t1;
- u32 n_target = target;
- u32 n_ref = ref, i;
+ int pd, mfi = 1, mfn, mfd;
+ u64 t1;
+ size_t i;
/*
* Make sure targeted freq is in the valid range.
* Otherwise the following calculation might be wrong!!!
*/
- if (n_target < PLL_FREQ_MIN(ref) ||
- n_target > PLL_FREQ_MAX(ref)) {
- printf("Targeted peripheral clock should be within [%d - %d]\n",
+ if (target < PLL_FREQ_MIN(ref) ||
+ target > PLL_FREQ_MAX(ref)) {
+ printf("Targeted pll clock should be within [%d - %d]\n",
PLL_FREQ_MIN(ref) / SZ_DEC_1M,
PLL_FREQ_MAX(ref) / SZ_DEC_1M);
return -EINVAL;
if (i == ARRAY_SIZE(fixed_mfd))
return -EINVAL;
- /* Use n_target and n_ref to avoid overflow */
for (pd = 1; pd <= PLL_PD_MAX; pd++) {
- t1 = n_target * pd;
- do_div(t1, (4 * n_ref));
+ t1 = (u64)target * pd;
+ do_div(t1, (4 * ref));
mfi = t1;
if (mfi > PLL_MFI_MAX)
return -EINVAL;
/*
* Now got pd and mfi already
*
- * mfn = (((n_target * pd) / 4 - n_ref * mfi) * mfd) / n_ref;
+ * mfn = (((target * pd) / 4 - ref * mfi) * mfd) / ref;
*/
- t1 = n_target * pd;
+ t1 = (u64)target * pd;
do_div(t1, 4);
- t1 -= n_ref * mfi;
- t1 *= mfd;
- do_div(t1, n_ref);
+ t1 = (t1 - ref * mfi) * mfd;
+ do_div(t1, ref);
mfn = t1;
- debug("ref=%d, target=%d, pd=%d," "mfi=%d,mfn=%d, mfd=%d\n",
- ref, n_target, (u32)pd, (u32)mfi, (u32)mfn, (u32)mfd);
- i = 1;
- if (mfn != 0)
+ if (mfn != 0) {
i = gcd(mfd, mfn);
- pll->pd = (u32)pd;
- pll->mfi = (u32)mfi;
- do_div(mfn, i);
- pll->mfn = (u32)mfn;
- do_div(mfd, i);
- pll->mfd = (u32)mfd;
+ mfn /= i;
+ mfd /= i;
+ } else {
+ mfd = 1;
+ }
+ debug("ref=%d, target=%d, pd=%d, mfi=%d, mfn=%d, mfd=%d\n",
+ ref, target, pd, mfi, mfn, mfd);
+ pll->pd = pd;
+ pll->mfi = mfi;
+ pll->mfn = mfn;
+ pll->mfd = mfd;
return 0;
}
return 0;
}
+static int __adjust_core_voltage_stub(u32 freq)
+{
+ return 0;
+}
+int adjust_core_voltage(u32 freq)
+ __attribute__((weak, alias("__adjust_core_voltage_stub")));
+
/* Config CPU clock */
static int config_core_clk(u32 ref, u32 freq)
{
int ret = 0;
struct pll_param pll_param;
+ u32 cur_freq = decode_pll(mxc_plls[PLL1_CLOCK], MXC_HCLK);
+
+ if (freq == cur_freq)
+ return 0;
memset(&pll_param, 0, sizeof(struct pll_param));
ref / 1000000, ref / 1000 % 1000);
return ret;
}
-
- return config_pll_clk(PLL1_CLOCK, &pll_param);
+ if (freq > cur_freq) {
+ ret = adjust_core_voltage(freq);
+ if (ret < 0) {
+ printf("Failed to adjust core voltage for changing ARM clk from %u.%03uMHz to %u.%03uMHz\n",
+ cur_freq / 1000000, cur_freq / 1000 % 1000,
+ freq / 1000000, freq / 1000 % 1000);
+ return ret;
+ }
+ ret = config_pll_clk(PLL1_CLOCK, &pll_param);
+ if (ret) {
+ adjust_core_voltage(cur_freq);
+ }
+ } else {
+ ret = config_pll_clk(PLL1_CLOCK, &pll_param);
+ if (ret) {
+ return ret;
+ }
+ ret = adjust_core_voltage(freq);
+ if (ret < 0) {
+ printf("Failed to adjust core voltage for changing ARM clk from %u.%03uMHz to %u.%03uMHz\n",
+ cur_freq / 1000000, cur_freq / 1000 % 1000,
+ freq / 1000000, freq / 1000 % 1000);
+ calc_pll_params(ref, cur_freq, &pll_param);
+ config_pll_clk(PLL1_CLOCK, &pll_param);
+ }
+ }
+ return ret;
}
static int config_nfc_clk(u32 nfc_clk)