diff --git a/arch/arm/dts/k3-am62-lp-sk-u-boot.dtsi b/arch/arm/dts/k3-am62-lp-sk-u-boot.dtsi index cbcc7f3bb45..848bc350698 100644 --- a/arch/arm/dts/k3-am62-lp-sk-u-boot.dtsi +++ b/arch/arm/dts/k3-am62-lp-sk-u-boot.dtsi @@ -5,13 +5,3 @@ */ #include "k3-am62-lp-sk-binman.dtsi" - -/ { - chosen { - tick-timer = &main_timer0; - }; -}; - -&main_timer0 { - clock-frequency = <25000000>; -}; diff --git a/arch/arm/dts/k3-am62-r5-lp-sk.dts b/arch/arm/dts/k3-am62-r5-lp-sk.dts index b8e5f49a1fc..135e8d49b91 100644 --- a/arch/arm/dts/k3-am62-r5-lp-sk.dts +++ b/arch/arm/dts/k3-am62-r5-lp-sk.dts @@ -12,6 +12,7 @@ / { aliases { + tick-timer = &main_timer0; remoteproc0 = &sysctrler; remoteproc1 = &a53_0; serial0 = &wkup_uart0; @@ -72,6 +73,14 @@ }; }; +&main_timer0 { + /delete-property/ clocks; + /delete-property/ clocks-names; + /delete-property/ assigned-clocks; + /delete-property/ assigned-clock-parents; + clock-frequency = <25000000>; +}; + /* WKUP UART0 is used for DM firmware logs */ &wkup_uart0 { status = "okay"; diff --git a/arch/arm/dts/k3-am625-r5-sk.dts b/arch/arm/dts/k3-am625-r5-sk.dts index d2dd75469c1..34c501dd51b 100644 --- a/arch/arm/dts/k3-am625-r5-sk.dts +++ b/arch/arm/dts/k3-am625-r5-sk.dts @@ -12,6 +12,7 @@ / { aliases { + tick-timer = &main_timer0; remoteproc0 = &sysctrler; remoteproc1 = &a53_0; serial0 = &wkup_uart0; @@ -70,6 +71,14 @@ }; }; +&main_timer0 { + /delete-property/ clocks; + /delete-property/ clocks-names; + /delete-property/ assigned-clocks; + /delete-property/ assigned-clock-parents; + clock-frequency = <25000000>; +}; + /* WKUP UART0 is used for DM firmware logs */ &wkup_uart0 { status = "okay"; diff --git a/arch/arm/dts/k3-am625-sk-u-boot.dtsi b/arch/arm/dts/k3-am625-sk-u-boot.dtsi index 1fc0d407cbf..487ccf04b55 100644 --- a/arch/arm/dts/k3-am625-sk-u-boot.dtsi +++ b/arch/arm/dts/k3-am625-sk-u-boot.dtsi @@ -6,16 +6,6 @@ #include "k3-am625-sk-binman.dtsi" -/ { - chosen { - tick-timer = &main_timer0; - }; -}; - -&main_timer0 { - clock-frequency = <25000000>; -}; - &main_bcdma { reg = <0x00 0x485c0100 0x00 0x100>, <0x00 0x4c000000 0x00 0x20000>, diff --git a/arch/arm/dts/k3-am62a7-r5-sk.dts b/arch/arm/dts/k3-am62a7-r5-sk.dts index 464227b3b25..49e62533a95 100644 --- a/arch/arm/dts/k3-am62a7-r5-sk.dts +++ b/arch/arm/dts/k3-am62a7-r5-sk.dts @@ -12,6 +12,7 @@ / { aliases { + tick-timer = &main_timer0; remoteproc0 = &sysctrler; remoteproc1 = &a53_0; }; @@ -71,6 +72,15 @@ }; }; +&main_timer0 { + /delete-property/ clocks; + /delete-property/ clocks-names; + /delete-property/ assigned-clocks; + /delete-property/ assigned-clock-parents; + clock-frequency = <25000000>; + bootph-pre-ram; +}; + &wkup_uart0_pins_default { bootph-pre-ram; }; diff --git a/arch/arm/dts/k3-am62a7-sk-u-boot.dtsi b/arch/arm/dts/k3-am62a7-sk-u-boot.dtsi index c42dec16194..7dfbeb10c32 100644 --- a/arch/arm/dts/k3-am62a7-sk-u-boot.dtsi +++ b/arch/arm/dts/k3-am62a7-sk-u-boot.dtsi @@ -9,7 +9,6 @@ / { chosen { stdout-path = "serial2:115200n8"; - tick-timer = &main_timer0; }; memory@80000000 { @@ -17,10 +16,6 @@ }; }; -&main_timer0 { - bootph-all; -}; - &cbass_main { bootph-all; }; diff --git a/arch/arm/dts/k3-am62p5-r5-sk.dts b/arch/arm/dts/k3-am62p5-r5-sk.dts index baf1a83dc12..b18b4ce1272 100644 --- a/arch/arm/dts/k3-am62p5-r5-sk.dts +++ b/arch/arm/dts/k3-am62p5-r5-sk.dts @@ -78,6 +78,14 @@ }; }; +&main_timer0 { + /delete-property/ clocks; + /delete-property/ clocks-names; + /delete-property/ assigned-clocks; + /delete-property/ assigned-clock-parents; + clock-frequency = <25000000>; +}; + /* WKUP UART0 is used for DM firmware logs */ &wkup_uart0 { status = "okay"; diff --git a/arch/arm/dts/k3-j7200-r5-common-proc-board.dts b/arch/arm/dts/k3-j7200-r5-common-proc-board.dts index 06fffe2a11b..5fc4a39c8c4 100644 --- a/arch/arm/dts/k3-j7200-r5-common-proc-board.dts +++ b/arch/arm/dts/k3-j7200-r5-common-proc-board.dts @@ -54,6 +54,10 @@ }; &mcu_timer0 { + /delete-property/ clocks; + /delete-property/ clocks-names; + /delete-property/ assigned-clocks; + /delete-property/ assigned-clock-parents; clock-frequency = <250000000>; bootph-pre-ram; }; diff --git a/arch/arm/dts/k3-j721e-r5.dtsi b/arch/arm/dts/k3-j721e-r5.dtsi index 688a6cf4089..786a41c5e90 100644 --- a/arch/arm/dts/k3-j721e-r5.dtsi +++ b/arch/arm/dts/k3-j721e-r5.dtsi @@ -42,7 +42,11 @@ }; &mcu_timer0 { - status = "okay"; + /delete-property/ clocks; + /delete-property/ clocks-names; + /delete-property/ assigned-clocks; + /delete-property/ assigned-clock-parents; + clock-frequency = <166666666>; bootph-pre-ram; }; diff --git a/arch/arm/dts/k3-j721s2-r5.dtsi b/arch/arm/dts/k3-j721s2-r5.dtsi index 634676c8491..a820f516015 100644 --- a/arch/arm/dts/k3-j721s2-r5.dtsi +++ b/arch/arm/dts/k3-j721s2-r5.dtsi @@ -43,6 +43,10 @@ }; &mcu_timer0 { + /delete-property/ clocks; + /delete-property/ clocks-names; + /delete-property/ assigned-clocks; + /delete-property/ assigned-clock-parents; clock-frequency = <250000000>; bootph-pre-ram; }; diff --git a/arch/arm/dts/k3-j722s-r5-evm.dts b/arch/arm/dts/k3-j722s-r5-evm.dts index 5e5c2e3111e..08286ed792d 100644 --- a/arch/arm/dts/k3-j722s-r5-evm.dts +++ b/arch/arm/dts/k3-j722s-r5-evm.dts @@ -77,6 +77,14 @@ }; }; +&main_timer0 { + /delete-property/ clocks; + /delete-property/ clocks-names; + /delete-property/ assigned-clocks; + /delete-property/ assigned-clock-parents; + clock-frequency = <25000000>; +}; + /* WKUP UART0 is used for DM firmware logs */ &wkup_uart0 { status = "okay"; diff --git a/arch/arm/dts/k3-j784s4-r5.dtsi b/arch/arm/dts/k3-j784s4-r5.dtsi index 8bd863e8fcb..a1394115b8b 100644 --- a/arch/arm/dts/k3-j784s4-r5.dtsi +++ b/arch/arm/dts/k3-j784s4-r5.dtsi @@ -41,7 +41,10 @@ }; &mcu_timer0 { - status = "okay"; + /delete-property/ clocks; + /delete-property/ clocks-names; + /delete-property/ assigned-clocks; + /delete-property/ assigned-clock-parents; clock-frequency = <250000000>; bootph-pre-ram; }; diff --git a/drivers/clk/ti/clk-k3-pll.c b/drivers/clk/ti/clk-k3-pll.c index b3a1b4cedb7..b775bd55faa 100644 --- a/drivers/clk/ti/clk-k3-pll.c +++ b/drivers/clk/ti/clk-k3-pll.c @@ -14,6 +14,7 @@ #include #include "k3-clk.h" #include +#include /* 16FFT register offsets */ #define PLL_16FFT_CFG 0x08 @@ -29,10 +30,12 @@ /* CAL STAT register bits */ #define PLL_16FFT_CAL_STAT_CAL_LOCK BIT(31) +#define PLL_16FFT_CAL_STAT_CAL_LOCK_TIMEOUT (4350U * 100U) /* CFG register bits */ #define PLL_16FFT_CFG_PLL_TYPE_SHIFT (0) #define PLL_16FFT_CFG_PLL_TYPE_MASK (0x3 << 0) +#define PLL_16FFT_CFG_PLL_TYPE_FRAC2 0 #define PLL_16FFT_CFG_PLL_TYPE_FRACF 1 /* CAL CTRL register bits */ @@ -41,14 +44,21 @@ #define PLL_16FFT_CAL_CTRL_CAL_BYP BIT(15) #define PLL_16FFT_CAL_CTRL_CAL_CNT_SHIFT 16 #define PLL_16FFT_CAL_CTRL_CAL_CNT_MASK (0x7 << 16) +#define PLL_16FFT_CAL_CTRL_CAL_IN_MASK (0xFFFU) /* CTRL register bits */ #define PLL_16FFT_CTRL_BYPASS_EN BIT(31) +#define PLL_16FFT_CTRL_BYP_ON_LOCKLOSS BIT(16) #define PLL_16FFT_CTRL_PLL_EN BIT(15) +#define PLL_16FFT_CTRL_INTL_BYP_EN BIT(8) +#define PLL_16FFT_CTRL_CLK_4PH_EN BIT(5) +#define PLL_16FFT_CTRL_CLK_POSTDIV_EN BIT(4) #define PLL_16FFT_CTRL_DSM_EN BIT(1) +#define PLL_16FFT_CTRL_DAC_EN BIT(0) /* STAT register bits */ #define PLL_16FFT_STAT_LOCK BIT(0) +#define PLL_16FFT_STAT_LOCK_TIMEOUT (150U * 100U) /* FREQ_CTRL0 bits */ #define PLL_16FFT_FREQ_CTRL0_FB_DIV_INT_MASK 0xfff @@ -62,7 +72,6 @@ /* FREQ_CTRL1 bits */ #define PLL_16FFT_FREQ_CTRL1_FB_DIV_FRAC_BITS 24 #define PLL_16FFT_FREQ_CTRL1_FB_DIV_FRAC_MASK 0xffffff -#define PLL_16FFT_FREQ_CTRL1_FB_DIV_FRAC_SHIFT 0 /* KICK register magic values */ #define PLL_KICK0_VALUE 0x68ef3490 @@ -75,68 +84,199 @@ */ struct ti_pll_clk { struct clk clk; - void __iomem *reg; + void __iomem *base; }; #define to_clk_pll(_clk) container_of(_clk, struct ti_pll_clk, clk) +static int ti_pll_clk_disable(struct clk *clk) +{ + struct ti_pll_clk *pll = to_clk_pll(clk); + u32 ctrl; + + ctrl = readl(pll->base + PLL_16FFT_CTRL); + + if ((ctrl & PLL_16FFT_CTRL_PLL_EN)) { + ctrl &= ~PLL_16FFT_CTRL_PLL_EN; + writel(ctrl, pll->base + PLL_16FFT_CTRL); + + /* wait 1us */ + udelay(1); + } + + return 0; +} + +static int ti_pll_clk_enable(struct clk *clk) +{ + struct ti_pll_clk *pll = to_clk_pll(clk); + u32 ctrl; + + ctrl = readl(pll->base + PLL_16FFT_CTRL); + ctrl |= PLL_16FFT_CTRL_PLL_EN; + writel(ctrl, pll->base + PLL_16FFT_CTRL); + + /* Wait 1us */ + udelay(1); + + return 0; +} + +static bool clk_pll_16fft_check_lock(const struct ti_pll_clk *pll) +{ + u32 stat; + + stat = readl(pll->base + PLL_16FFT_STAT); + return (stat & PLL_16FFT_STAT_LOCK); +} + +static bool clk_pll_16fft_check_cal_lock(const struct ti_pll_clk *pll) +{ + u32 stat; + + stat = readl(pll->base + PLL_16FFT_CAL_STAT); + return (stat & PLL_16FFT_CAL_STAT_CAL_LOCK); +} + +static void clk_pll_16fft_cal_int(const struct ti_pll_clk *pll) +{ + u32 cal; + + cal = readl(pll->base + PLL_16FFT_CAL_CTRL); + + /* Enable fast cal mode */ + cal |= PLL_16FFT_CAL_CTRL_FAST_CAL; + + /* Disable calibration bypass */ + cal &= ~PLL_16FFT_CAL_CTRL_CAL_BYP; + + /* Set CALCNT to 2 */ + cal &= ~PLL_16FFT_CAL_CTRL_CAL_CNT_MASK; + cal |= 2 << PLL_16FFT_CAL_CTRL_CAL_CNT_SHIFT; + + /* Set CAL_IN to 0 */ + cal &= ~PLL_16FFT_CAL_CTRL_CAL_IN_MASK; + + /* Note this register does not readback the written value. */ + writel(cal, pll->base + PLL_16FFT_CAL_CTRL); + + /* Wait 1us before enabling the CAL_EN field */ + udelay(1); + + cal = readl(pll->base + PLL_16FFT_CAL_CTRL); + + /* Enable calibration for FRACF */ + cal |= PLL_16FFT_CAL_CTRL_CAL_EN; + + /* Note this register does not readback the written value. */ + writel(cal, pll->base + PLL_16FFT_CAL_CTRL); +} + +static void clk_pll_16fft_disable_cal(const struct ti_pll_clk *pll) +{ + u32 cal, stat; + + cal = readl(pll->base + PLL_16FFT_CAL_CTRL); + cal &= ~PLL_16FFT_CAL_CTRL_CAL_EN; + /* Note this register does not readback the written value. */ + writel(cal, pll->base + PLL_16FFT_CAL_CTRL); + do { + stat = readl(pll->base + PLL_16FFT_CAL_STAT); + } while (stat & PLL_16FFT_CAL_STAT_CAL_LOCK); +} + static int ti_pll_wait_for_lock(struct clk *clk) { struct ti_pll_clk *pll = to_clk_pll(clk); - u32 stat; u32 cfg; u32 cal; u32 freq_ctrl1; - int i; + unsigned int i; u32 pllfm; u32 pll_type; - int success; + u32 cal_en = 0; + bool success; - for (i = 0; i < 100000; i++) { - stat = readl(pll->reg + PLL_16FFT_STAT); - if (stat & PLL_16FFT_STAT_LOCK) { - success = 1; + /* + * Minimum VCO input freq is 5MHz, and the longest a lock should + * be consider to be timed out after 750 cycles. Be conservative + * and assume each loop takes 10 cycles and we run at a + * max of 1GHz. That gives 15000 loop cycles. We may end up waiting + * longer than necessary for timeout, but that should be ok. + */ + success = false; + for (i = 0; i < PLL_16FFT_STAT_LOCK_TIMEOUT; i++) { + if (clk_pll_16fft_check_lock(pll)) { + success = true; break; } } - /* Enable calibration if not in fractional mode of the FRACF PLL */ - freq_ctrl1 = readl(pll->reg + PLL_16FFT_FREQ_CTRL1); + /* Disable calibration in the fractional mode of the FRACF PLL based on data + * from silicon and simulation data. + */ + freq_ctrl1 = readl(pll->base + PLL_16FFT_FREQ_CTRL1); pllfm = freq_ctrl1 & PLL_16FFT_FREQ_CTRL1_FB_DIV_FRAC_MASK; - pllfm >>= PLL_16FFT_FREQ_CTRL1_FB_DIV_FRAC_SHIFT; - cfg = readl(pll->reg + PLL_16FFT_CFG); + + cfg = readl(pll->base + PLL_16FFT_CFG); pll_type = (cfg & PLL_16FFT_CFG_PLL_TYPE_MASK) >> PLL_16FFT_CFG_PLL_TYPE_SHIFT; - if (success && pll_type == PLL_16FFT_CFG_PLL_TYPE_FRACF && pllfm == 0) { - cal = readl(pll->reg + PLL_16FFT_CAL_CTRL); + if (success && pll_type == PLL_16FFT_CFG_PLL_TYPE_FRACF) { + cal = readl(pll->base + PLL_16FFT_CAL_CTRL); + cal_en = (cal & PLL_16FFT_CAL_CTRL_CAL_EN); + } - /* Enable calibration for FRACF */ - cal |= PLL_16FFT_CAL_CTRL_CAL_EN; - - /* Enable fast cal mode */ - cal |= PLL_16FFT_CAL_CTRL_FAST_CAL; - - /* Disable calibration bypass */ - cal &= ~PLL_16FFT_CAL_CTRL_CAL_BYP; - - /* Set CALCNT to 2 */ - cal &= ~PLL_16FFT_CAL_CTRL_CAL_CNT_MASK; - cal |= 2 << PLL_16FFT_CAL_CTRL_CAL_CNT_SHIFT; - - /* Note this register does not readback the written value. */ - writel(cal, pll->reg + PLL_16FFT_CAL_CTRL); - - success = 0; - for (i = 0; i < 100000; i++) { - stat = readl(pll->reg + PLL_16FFT_CAL_STAT); - if (stat & PLL_16FFT_CAL_STAT_CAL_LOCK) { - success = 1; + if (success && pll_type == PLL_16FFT_CFG_PLL_TYPE_FRACF && + pllfm == 0 && cal_en == 1) { + /* + * Wait for calibration lock. + * + * Lock should occur within: + * + * 170 * 2^(5+CALCNT) / PFD + * 21760 / PFD + * + * CALCNT = 2, PFD = 5-50MHz. This gives a range of 0.435mS to + * 4.35mS depending on PFD frequency. + * + * Be conservative and assume each loop takes 10 cycles and we run at a + * max of 1GHz. That gives 435000 loop cycles. We may end up waiting + * longer than necessary for timeout, but that should be ok. + * + * The recommend timeout for CALLOCK to go high is 4.35 ms + */ + success = false; + for (i = 0; i < PLL_16FFT_CAL_STAT_CAL_LOCK_TIMEOUT; i++) { + if (clk_pll_16fft_check_cal_lock(pll)) { + success = true; break; } } + + /* In case of cal lock failure, operate without calibration */ + if (!success) { + debug("Failure for calibration, falling back without calibration\n"); + + /* Disable PLL */ + ti_pll_clk_disable(clk); + + /* Disable Calibration */ + clk_pll_16fft_disable_cal(pll); + + /* Enable PLL */ + ti_pll_clk_enable(clk); + + /* Wait for PLL Lock */ + for (i = 0; i < PLL_16FFT_STAT_LOCK_TIMEOUT; i++) { + if (clk_pll_16fft_check_lock(pll)) { + success = true; + break; + } + } + } } - if (success == 0) { + if (!success) { printf("%s: pll (%s) failed to lock\n", __func__, clk->dev->name); return -EBUSY; @@ -156,14 +296,14 @@ static ulong ti_pll_clk_get_rate(struct clk *clk) u32 ctrl; /* Check if we are in bypass */ - ctrl = readl(pll->reg + PLL_16FFT_CTRL); + ctrl = readl(pll->base + PLL_16FFT_CTRL); if (ctrl & PLL_16FFT_CTRL_BYPASS_EN) return parent_freq; - pllm = readl(pll->reg + PLL_16FFT_FREQ_CTRL0); - pllfm = readl(pll->reg + PLL_16FFT_FREQ_CTRL1); + pllm = readl(pll->base + PLL_16FFT_FREQ_CTRL0); + pllfm = readl(pll->base + PLL_16FFT_FREQ_CTRL1); - plld = readl(pll->reg + PLL_16FFT_DIV_CTRL) & + plld = readl(pll->base + PLL_16FFT_DIV_CTRL) & PLL_16FFT_DIV_CTRL_REF_DIV_MASK; current_freq = parent_freq * pllm / plld; @@ -180,6 +320,30 @@ static ulong ti_pll_clk_get_rate(struct clk *clk) return current_freq; } +static bool ti_pll_clk_is_bypass(struct ti_pll_clk *pll) +{ + u32 ctrl; + bool ret; + + ctrl = readl(pll->base + PLL_16FFT_CTRL); + ret = (ctrl & PLL_16FFT_CTRL_BYPASS_EN) != 0; + + return ret; +} + +static void ti_pll_clk_bypass(struct ti_pll_clk *pll, bool bypass) +{ + u32 ctrl; + + ctrl = readl(pll->base + PLL_16FFT_CTRL); + if (bypass) + ctrl |= PLL_16FFT_CTRL_BYPASS_EN; + else + ctrl &= ~PLL_16FFT_CTRL_BYPASS_EN; + + writel(ctrl, pll->base + PLL_16FFT_CTRL); +} + static ulong ti_pll_clk_set_rate(struct clk *clk, ulong rate) { struct ti_pll_clk *pll = to_clk_pll(clk); @@ -187,9 +351,13 @@ static ulong ti_pll_clk_set_rate(struct clk *clk, ulong rate) u64 parent_freq = clk_get_parent_rate(clk); int ret; u32 ctrl; + u32 cfg; + u32 pll_type; unsigned long pllm; u32 pllfm = 0; unsigned long plld; + u32 freq_ctrl0; + u32 freq_ctrl1; u32 div_ctrl; u32 rem; int shift; @@ -212,16 +380,22 @@ static ulong ti_pll_clk_set_rate(struct clk *clk, ulong rate) break; } - /* Put PLL to bypass mode */ - ctrl = readl(pll->reg + PLL_16FFT_CTRL); - ctrl |= PLL_16FFT_CTRL_BYPASS_EN; - writel(ctrl, pll->reg + PLL_16FFT_CTRL); + if (!ti_pll_clk_is_bypass(pll)) { + /* Put the PLL into bypass */ + ti_pll_clk_bypass(pll, true); + } + + /* Disable the PLL */ + ti_pll_clk_disable(clk); if (rate == parent_freq) { debug("%s: put %s to bypass\n", __func__, clk->dev->name); return rate; } + cfg = readl(pll->base + PLL_16FFT_CFG); + pll_type = (cfg & PLL_16FFT_CFG_PLL_TYPE_MASK) >> PLL_16FFT_CFG_PLL_TYPE_SHIFT; + debug("%s: pre-frac-calc: rate=%u, parent_freq=%u, plld=%u, pllm=%u\n", __func__, (u32)rate, (u32)parent_freq, (u32)plld, (u32)pllm); @@ -237,31 +411,75 @@ static ulong ti_pll_clk_set_rate(struct clk *clk, ulong rate) plld = 1; } - if (pllfm) - ctrl |= PLL_16FFT_CTRL_DSM_EN; - else - ctrl &= ~PLL_16FFT_CTRL_DSM_EN; + /* Program the new rate */ + freq_ctrl0 = readl(pll->base + PLL_16FFT_FREQ_CTRL0); + freq_ctrl1 = readl(pll->base + PLL_16FFT_FREQ_CTRL1); + div_ctrl = readl(pll->base + PLL_16FFT_DIV_CTRL); - writel(pllm, pll->reg + PLL_16FFT_FREQ_CTRL0); - writel(pllfm, pll->reg + PLL_16FFT_FREQ_CTRL1); + freq_ctrl0 &= ~PLL_16FFT_FREQ_CTRL0_FB_DIV_INT_MASK; + freq_ctrl0 |= pllm; + + freq_ctrl1 &= ~PLL_16FFT_FREQ_CTRL1_FB_DIV_FRAC_MASK; + freq_ctrl1 |= pllfm; /* * div_ctrl register contains other divider values, so rmw * only plld and leave existing values alone */ - div_ctrl = readl(pll->reg + PLL_16FFT_DIV_CTRL); div_ctrl &= ~PLL_16FFT_DIV_CTRL_REF_DIV_MASK; div_ctrl |= plld; - writel(div_ctrl, pll->reg + PLL_16FFT_DIV_CTRL); - ctrl &= ~PLL_16FFT_CTRL_BYPASS_EN; - ctrl |= PLL_16FFT_CTRL_PLL_EN; - writel(ctrl, pll->reg + PLL_16FFT_CTRL); + /* Make sure we have fractional support if required */ + ctrl = readl(pll->base + PLL_16FFT_CTRL); + + /* Don't use internal bypass,it is not glitch free. Always prefer glitchless bypass */ + ctrl &= ~(PLL_16FFT_CTRL_INTL_BYP_EN | PLL_16FFT_CTRL_CLK_4PH_EN); + + /* Always enable output if PLL, Always bypass if we lose lock */ + ctrl |= (PLL_16FFT_CTRL_CLK_POSTDIV_EN | PLL_16FFT_CTRL_BYP_ON_LOCKLOSS); + + /* Enable fractional support if required */ + if (pll_type == PLL_16FFT_CFG_PLL_TYPE_FRACF) { + if (pllfm != 0) + ctrl |= (PLL_16FFT_CTRL_DSM_EN | PLL_16FFT_CTRL_DAC_EN); + else + ctrl &= ~(PLL_16FFT_CTRL_DSM_EN | PLL_16FFT_CTRL_DAC_EN); + } + + /* Enable Fractional by default for PLL_16FFT_CFG_PLL_TYPE_FRAC2 */ + if (pll_type == PLL_16FFT_CFG_PLL_TYPE_FRAC2) + ctrl |= (PLL_16FFT_CTRL_DSM_EN | PLL_16FFT_CTRL_DAC_EN); + + writel(freq_ctrl0, pll->base + PLL_16FFT_FREQ_CTRL0); + writel(freq_ctrl1, pll->base + PLL_16FFT_FREQ_CTRL1); + writel(div_ctrl, pll->base + PLL_16FFT_DIV_CTRL); + writel(ctrl, pll->base + PLL_16FFT_CTRL); + + /* Configure PLL calibration*/ + if (pll_type == PLL_16FFT_CFG_PLL_TYPE_FRACF) { + if (pllfm != 0) { + /* Disable Calibration in Fractional mode */ + clk_pll_16fft_disable_cal(pll); + } else { + /* Enable Calibration in Integer mode */ + clk_pll_16fft_cal_int(pll); + } + } + + /* + * Wait at least 1 ref cycle before enabling PLL. + * Minimum VCO input frequency is 5MHz, therefore maximum + * wait time for 1 ref clock is 0.2us. + */ + udelay(1); + ti_pll_clk_enable(clk); ret = ti_pll_wait_for_lock(clk); if (ret) return ret; + ti_pll_clk_bypass(pll, false); + debug("%s: pllm=%u, plld=%u, pllfm=%u, parent_freq=%u\n", __func__, (u32)pllm, (u32)plld, (u32)pllfm, (u32)parent_freq); @@ -279,30 +497,7 @@ static ulong ti_pll_clk_set_rate(struct clk *clk, ulong rate) return current_freq; } -static int ti_pll_clk_enable(struct clk *clk) -{ - struct ti_pll_clk *pll = to_clk_pll(clk); - u32 ctrl; - ctrl = readl(pll->reg + PLL_16FFT_CTRL); - ctrl &= ~PLL_16FFT_CTRL_BYPASS_EN; - ctrl |= PLL_16FFT_CTRL_PLL_EN; - writel(ctrl, pll->reg + PLL_16FFT_CTRL); - - return ti_pll_wait_for_lock(clk); -} - -static int ti_pll_clk_disable(struct clk *clk) -{ - struct ti_pll_clk *pll = to_clk_pll(clk); - u32 ctrl; - - ctrl = readl(pll->reg + PLL_16FFT_CTRL); - ctrl |= PLL_16FFT_CTRL_BYPASS_EN; - writel(ctrl, pll->reg + PLL_16FFT_CTRL); - - return 0; -} static const struct clk_ops ti_pll_clk_ops = { .get_rate = ti_pll_clk_get_rate, @@ -323,7 +518,7 @@ struct clk *clk_register_ti_pll(const char *name, const char *parent_name, if (!pll) return ERR_PTR(-ENOMEM); - pll->reg = reg; + pll->base = reg; ret = clk_register(&pll->clk, "ti-pll-clk", name, parent_name); if (ret) { @@ -333,19 +528,19 @@ struct clk *clk_register_ti_pll(const char *name, const char *parent_name, } /* Unlock the PLL registers */ - writel(PLL_KICK0_VALUE, pll->reg + PLL_KICK0); - writel(PLL_KICK1_VALUE, pll->reg + PLL_KICK1); + writel(PLL_KICK0_VALUE, pll->base + PLL_KICK0); + writel(PLL_KICK1_VALUE, pll->base + PLL_KICK1); /* Enable all HSDIV outputs */ - cfg = readl(pll->reg + PLL_16FFT_CFG); + cfg = readl(pll->base + PLL_16FFT_CFG); for (i = 0; i < 16; i++) { hsdiv_presence_bit = BIT(16 + i); hsdiv_ctrl_offs = 0x80 + (i * 4); /* Enable HSDIV output if present */ if ((hsdiv_presence_bit & cfg) != 0UL) { - ctrl = readl(pll->reg + hsdiv_ctrl_offs); + ctrl = readl(pll->base + hsdiv_ctrl_offs); ctrl |= PLL_16FFT_HSDIV_CTRL_CLKOUT_EN; - writel(ctrl, pll->reg + hsdiv_ctrl_offs); + writel(ctrl, pll->base + hsdiv_ctrl_offs); } }