mirror of
https://github.com/u-boot/u-boot.git
synced 2025-04-22 20:58:22 +00:00
Merge patch series "PLL Sequencing update"
Manorit Chawdhry <m-chawdhry@ti.com> says: It has done a re-write of the full driver and the commits aren't split to keep the bisectability intact. Boot Logs: https://gist.github.com/manorit2001/1eaba109d722715a233244da693133d3 Link: https://lore.kernel.org/r/20241121-b4-upstream-pll-fix-v1-0-904f618897a7@ti.com
This commit is contained in:
commit
a03f0f9e6f
13 changed files with 341 additions and 112 deletions
|
@ -5,13 +5,3 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "k3-am62-lp-sk-binman.dtsi"
|
#include "k3-am62-lp-sk-binman.dtsi"
|
||||||
|
|
||||||
/ {
|
|
||||||
chosen {
|
|
||||||
tick-timer = &main_timer0;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
&main_timer0 {
|
|
||||||
clock-frequency = <25000000>;
|
|
||||||
};
|
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
/ {
|
/ {
|
||||||
aliases {
|
aliases {
|
||||||
|
tick-timer = &main_timer0;
|
||||||
remoteproc0 = &sysctrler;
|
remoteproc0 = &sysctrler;
|
||||||
remoteproc1 = &a53_0;
|
remoteproc1 = &a53_0;
|
||||||
serial0 = &wkup_uart0;
|
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 is used for DM firmware logs */
|
||||||
&wkup_uart0 {
|
&wkup_uart0 {
|
||||||
status = "okay";
|
status = "okay";
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
/ {
|
/ {
|
||||||
aliases {
|
aliases {
|
||||||
|
tick-timer = &main_timer0;
|
||||||
remoteproc0 = &sysctrler;
|
remoteproc0 = &sysctrler;
|
||||||
remoteproc1 = &a53_0;
|
remoteproc1 = &a53_0;
|
||||||
serial0 = &wkup_uart0;
|
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 is used for DM firmware logs */
|
||||||
&wkup_uart0 {
|
&wkup_uart0 {
|
||||||
status = "okay";
|
status = "okay";
|
||||||
|
|
|
@ -6,16 +6,6 @@
|
||||||
|
|
||||||
#include "k3-am625-sk-binman.dtsi"
|
#include "k3-am625-sk-binman.dtsi"
|
||||||
|
|
||||||
/ {
|
|
||||||
chosen {
|
|
||||||
tick-timer = &main_timer0;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
&main_timer0 {
|
|
||||||
clock-frequency = <25000000>;
|
|
||||||
};
|
|
||||||
|
|
||||||
&main_bcdma {
|
&main_bcdma {
|
||||||
reg = <0x00 0x485c0100 0x00 0x100>,
|
reg = <0x00 0x485c0100 0x00 0x100>,
|
||||||
<0x00 0x4c000000 0x00 0x20000>,
|
<0x00 0x4c000000 0x00 0x20000>,
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
/ {
|
/ {
|
||||||
aliases {
|
aliases {
|
||||||
|
tick-timer = &main_timer0;
|
||||||
remoteproc0 = &sysctrler;
|
remoteproc0 = &sysctrler;
|
||||||
remoteproc1 = &a53_0;
|
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 {
|
&wkup_uart0_pins_default {
|
||||||
bootph-pre-ram;
|
bootph-pre-ram;
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
/ {
|
/ {
|
||||||
chosen {
|
chosen {
|
||||||
stdout-path = "serial2:115200n8";
|
stdout-path = "serial2:115200n8";
|
||||||
tick-timer = &main_timer0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
memory@80000000 {
|
memory@80000000 {
|
||||||
|
@ -17,10 +16,6 @@
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
&main_timer0 {
|
|
||||||
bootph-all;
|
|
||||||
};
|
|
||||||
|
|
||||||
&cbass_main {
|
&cbass_main {
|
||||||
bootph-all;
|
bootph-all;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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 is used for DM firmware logs */
|
||||||
&wkup_uart0 {
|
&wkup_uart0 {
|
||||||
status = "okay";
|
status = "okay";
|
||||||
|
|
|
@ -54,6 +54,10 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
&mcu_timer0 {
|
&mcu_timer0 {
|
||||||
|
/delete-property/ clocks;
|
||||||
|
/delete-property/ clocks-names;
|
||||||
|
/delete-property/ assigned-clocks;
|
||||||
|
/delete-property/ assigned-clock-parents;
|
||||||
clock-frequency = <250000000>;
|
clock-frequency = <250000000>;
|
||||||
bootph-pre-ram;
|
bootph-pre-ram;
|
||||||
};
|
};
|
||||||
|
|
|
@ -42,7 +42,11 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
&mcu_timer0 {
|
&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;
|
bootph-pre-ram;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,10 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
&mcu_timer0 {
|
&mcu_timer0 {
|
||||||
|
/delete-property/ clocks;
|
||||||
|
/delete-property/ clocks-names;
|
||||||
|
/delete-property/ assigned-clocks;
|
||||||
|
/delete-property/ assigned-clock-parents;
|
||||||
clock-frequency = <250000000>;
|
clock-frequency = <250000000>;
|
||||||
bootph-pre-ram;
|
bootph-pre-ram;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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 is used for DM firmware logs */
|
||||||
&wkup_uart0 {
|
&wkup_uart0 {
|
||||||
status = "okay";
|
status = "okay";
|
||||||
|
|
|
@ -41,7 +41,10 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
&mcu_timer0 {
|
&mcu_timer0 {
|
||||||
status = "okay";
|
/delete-property/ clocks;
|
||||||
|
/delete-property/ clocks-names;
|
||||||
|
/delete-property/ assigned-clocks;
|
||||||
|
/delete-property/ assigned-clock-parents;
|
||||||
clock-frequency = <250000000>;
|
clock-frequency = <250000000>;
|
||||||
bootph-pre-ram;
|
bootph-pre-ram;
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <linux/clk-provider.h>
|
#include <linux/clk-provider.h>
|
||||||
#include "k3-clk.h"
|
#include "k3-clk.h"
|
||||||
#include <linux/rational.h>
|
#include <linux/rational.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
|
||||||
/* 16FFT register offsets */
|
/* 16FFT register offsets */
|
||||||
#define PLL_16FFT_CFG 0x08
|
#define PLL_16FFT_CFG 0x08
|
||||||
|
@ -29,10 +30,12 @@
|
||||||
|
|
||||||
/* CAL STAT register bits */
|
/* CAL STAT register bits */
|
||||||
#define PLL_16FFT_CAL_STAT_CAL_LOCK BIT(31)
|
#define PLL_16FFT_CAL_STAT_CAL_LOCK BIT(31)
|
||||||
|
#define PLL_16FFT_CAL_STAT_CAL_LOCK_TIMEOUT (4350U * 100U)
|
||||||
|
|
||||||
/* CFG register bits */
|
/* CFG register bits */
|
||||||
#define PLL_16FFT_CFG_PLL_TYPE_SHIFT (0)
|
#define PLL_16FFT_CFG_PLL_TYPE_SHIFT (0)
|
||||||
#define PLL_16FFT_CFG_PLL_TYPE_MASK (0x3 << 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
|
#define PLL_16FFT_CFG_PLL_TYPE_FRACF 1
|
||||||
|
|
||||||
/* CAL CTRL register bits */
|
/* CAL CTRL register bits */
|
||||||
|
@ -41,14 +44,21 @@
|
||||||
#define PLL_16FFT_CAL_CTRL_CAL_BYP BIT(15)
|
#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_SHIFT 16
|
||||||
#define PLL_16FFT_CAL_CTRL_CAL_CNT_MASK (0x7 << 16)
|
#define PLL_16FFT_CAL_CTRL_CAL_CNT_MASK (0x7 << 16)
|
||||||
|
#define PLL_16FFT_CAL_CTRL_CAL_IN_MASK (0xFFFU)
|
||||||
|
|
||||||
/* CTRL register bits */
|
/* CTRL register bits */
|
||||||
#define PLL_16FFT_CTRL_BYPASS_EN BIT(31)
|
#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_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_DSM_EN BIT(1)
|
||||||
|
#define PLL_16FFT_CTRL_DAC_EN BIT(0)
|
||||||
|
|
||||||
/* STAT register bits */
|
/* STAT register bits */
|
||||||
#define PLL_16FFT_STAT_LOCK BIT(0)
|
#define PLL_16FFT_STAT_LOCK BIT(0)
|
||||||
|
#define PLL_16FFT_STAT_LOCK_TIMEOUT (150U * 100U)
|
||||||
|
|
||||||
/* FREQ_CTRL0 bits */
|
/* FREQ_CTRL0 bits */
|
||||||
#define PLL_16FFT_FREQ_CTRL0_FB_DIV_INT_MASK 0xfff
|
#define PLL_16FFT_FREQ_CTRL0_FB_DIV_INT_MASK 0xfff
|
||||||
|
@ -62,7 +72,6 @@
|
||||||
/* FREQ_CTRL1 bits */
|
/* FREQ_CTRL1 bits */
|
||||||
#define PLL_16FFT_FREQ_CTRL1_FB_DIV_FRAC_BITS 24
|
#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_MASK 0xffffff
|
||||||
#define PLL_16FFT_FREQ_CTRL1_FB_DIV_FRAC_SHIFT 0
|
|
||||||
|
|
||||||
/* KICK register magic values */
|
/* KICK register magic values */
|
||||||
#define PLL_KICK0_VALUE 0x68ef3490
|
#define PLL_KICK0_VALUE 0x68ef3490
|
||||||
|
@ -75,68 +84,199 @@
|
||||||
*/
|
*/
|
||||||
struct ti_pll_clk {
|
struct ti_pll_clk {
|
||||||
struct clk clk;
|
struct clk clk;
|
||||||
void __iomem *reg;
|
void __iomem *base;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define to_clk_pll(_clk) container_of(_clk, struct ti_pll_clk, clk)
|
#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)
|
static int ti_pll_wait_for_lock(struct clk *clk)
|
||||||
{
|
{
|
||||||
struct ti_pll_clk *pll = to_clk_pll(clk);
|
struct ti_pll_clk *pll = to_clk_pll(clk);
|
||||||
u32 stat;
|
|
||||||
u32 cfg;
|
u32 cfg;
|
||||||
u32 cal;
|
u32 cal;
|
||||||
u32 freq_ctrl1;
|
u32 freq_ctrl1;
|
||||||
int i;
|
unsigned int i;
|
||||||
u32 pllfm;
|
u32 pllfm;
|
||||||
u32 pll_type;
|
u32 pll_type;
|
||||||
int success;
|
u32 cal_en = 0;
|
||||||
|
bool success;
|
||||||
|
|
||||||
for (i = 0; i < 100000; i++) {
|
/*
|
||||||
stat = readl(pll->reg + PLL_16FFT_STAT);
|
* Minimum VCO input freq is 5MHz, and the longest a lock should
|
||||||
if (stat & PLL_16FFT_STAT_LOCK) {
|
* be consider to be timed out after 750 cycles. Be conservative
|
||||||
success = 1;
|
* 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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Enable calibration if not in fractional mode of the FRACF PLL */
|
/* Disable calibration in the fractional mode of the FRACF PLL based on data
|
||||||
freq_ctrl1 = readl(pll->reg + PLL_16FFT_FREQ_CTRL1);
|
* 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 = 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;
|
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) {
|
if (success && pll_type == PLL_16FFT_CFG_PLL_TYPE_FRACF) {
|
||||||
cal = readl(pll->reg + PLL_16FFT_CAL_CTRL);
|
cal = readl(pll->base + PLL_16FFT_CAL_CTRL);
|
||||||
|
cal_en = (cal & PLL_16FFT_CAL_CTRL_CAL_EN);
|
||||||
|
}
|
||||||
|
|
||||||
/* Enable calibration for FRACF */
|
if (success && pll_type == PLL_16FFT_CFG_PLL_TYPE_FRACF &&
|
||||||
cal |= PLL_16FFT_CAL_CTRL_CAL_EN;
|
pllfm == 0 && cal_en == 1) {
|
||||||
|
/*
|
||||||
/* Enable fast cal mode */
|
* Wait for calibration lock.
|
||||||
cal |= PLL_16FFT_CAL_CTRL_FAST_CAL;
|
*
|
||||||
|
* Lock should occur within:
|
||||||
/* Disable calibration bypass */
|
*
|
||||||
cal &= ~PLL_16FFT_CAL_CTRL_CAL_BYP;
|
* 170 * 2^(5+CALCNT) / PFD
|
||||||
|
* 21760 / PFD
|
||||||
/* Set CALCNT to 2 */
|
*
|
||||||
cal &= ~PLL_16FFT_CAL_CTRL_CAL_CNT_MASK;
|
* CALCNT = 2, PFD = 5-50MHz. This gives a range of 0.435mS to
|
||||||
cal |= 2 << PLL_16FFT_CAL_CTRL_CAL_CNT_SHIFT;
|
* 4.35mS depending on PFD frequency.
|
||||||
|
*
|
||||||
/* Note this register does not readback the written value. */
|
* Be conservative and assume each loop takes 10 cycles and we run at a
|
||||||
writel(cal, pll->reg + PLL_16FFT_CAL_CTRL);
|
* max of 1GHz. That gives 435000 loop cycles. We may end up waiting
|
||||||
|
* longer than necessary for timeout, but that should be ok.
|
||||||
success = 0;
|
*
|
||||||
for (i = 0; i < 100000; i++) {
|
* The recommend timeout for CALLOCK to go high is 4.35 ms
|
||||||
stat = readl(pll->reg + PLL_16FFT_CAL_STAT);
|
*/
|
||||||
if (stat & PLL_16FFT_CAL_STAT_CAL_LOCK) {
|
success = false;
|
||||||
success = 1;
|
for (i = 0; i < PLL_16FFT_CAL_STAT_CAL_LOCK_TIMEOUT; i++) {
|
||||||
|
if (clk_pll_16fft_check_cal_lock(pll)) {
|
||||||
|
success = true;
|
||||||
break;
|
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__,
|
printf("%s: pll (%s) failed to lock\n", __func__,
|
||||||
clk->dev->name);
|
clk->dev->name);
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
@ -156,14 +296,14 @@ static ulong ti_pll_clk_get_rate(struct clk *clk)
|
||||||
u32 ctrl;
|
u32 ctrl;
|
||||||
|
|
||||||
/* Check if we are in bypass */
|
/* 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)
|
if (ctrl & PLL_16FFT_CTRL_BYPASS_EN)
|
||||||
return parent_freq;
|
return parent_freq;
|
||||||
|
|
||||||
pllm = readl(pll->reg + PLL_16FFT_FREQ_CTRL0);
|
pllm = readl(pll->base + PLL_16FFT_FREQ_CTRL0);
|
||||||
pllfm = readl(pll->reg + PLL_16FFT_FREQ_CTRL1);
|
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;
|
PLL_16FFT_DIV_CTRL_REF_DIV_MASK;
|
||||||
|
|
||||||
current_freq = parent_freq * pllm / plld;
|
current_freq = parent_freq * pllm / plld;
|
||||||
|
@ -180,6 +320,30 @@ static ulong ti_pll_clk_get_rate(struct clk *clk)
|
||||||
return current_freq;
|
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)
|
static ulong ti_pll_clk_set_rate(struct clk *clk, ulong rate)
|
||||||
{
|
{
|
||||||
struct ti_pll_clk *pll = to_clk_pll(clk);
|
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);
|
u64 parent_freq = clk_get_parent_rate(clk);
|
||||||
int ret;
|
int ret;
|
||||||
u32 ctrl;
|
u32 ctrl;
|
||||||
|
u32 cfg;
|
||||||
|
u32 pll_type;
|
||||||
unsigned long pllm;
|
unsigned long pllm;
|
||||||
u32 pllfm = 0;
|
u32 pllfm = 0;
|
||||||
unsigned long plld;
|
unsigned long plld;
|
||||||
|
u32 freq_ctrl0;
|
||||||
|
u32 freq_ctrl1;
|
||||||
u32 div_ctrl;
|
u32 div_ctrl;
|
||||||
u32 rem;
|
u32 rem;
|
||||||
int shift;
|
int shift;
|
||||||
|
@ -212,16 +380,22 @@ static ulong ti_pll_clk_set_rate(struct clk *clk, ulong rate)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Put PLL to bypass mode */
|
if (!ti_pll_clk_is_bypass(pll)) {
|
||||||
ctrl = readl(pll->reg + PLL_16FFT_CTRL);
|
/* Put the PLL into bypass */
|
||||||
ctrl |= PLL_16FFT_CTRL_BYPASS_EN;
|
ti_pll_clk_bypass(pll, true);
|
||||||
writel(ctrl, pll->reg + PLL_16FFT_CTRL);
|
}
|
||||||
|
|
||||||
|
/* Disable the PLL */
|
||||||
|
ti_pll_clk_disable(clk);
|
||||||
|
|
||||||
if (rate == parent_freq) {
|
if (rate == parent_freq) {
|
||||||
debug("%s: put %s to bypass\n", __func__, clk->dev->name);
|
debug("%s: put %s to bypass\n", __func__, clk->dev->name);
|
||||||
return rate;
|
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",
|
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);
|
__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;
|
plld = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pllfm)
|
/* Program the new rate */
|
||||||
ctrl |= PLL_16FFT_CTRL_DSM_EN;
|
freq_ctrl0 = readl(pll->base + PLL_16FFT_FREQ_CTRL0);
|
||||||
else
|
freq_ctrl1 = readl(pll->base + PLL_16FFT_FREQ_CTRL1);
|
||||||
ctrl &= ~PLL_16FFT_CTRL_DSM_EN;
|
div_ctrl = readl(pll->base + PLL_16FFT_DIV_CTRL);
|
||||||
|
|
||||||
writel(pllm, pll->reg + PLL_16FFT_FREQ_CTRL0);
|
freq_ctrl0 &= ~PLL_16FFT_FREQ_CTRL0_FB_DIV_INT_MASK;
|
||||||
writel(pllfm, pll->reg + PLL_16FFT_FREQ_CTRL1);
|
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
|
* div_ctrl register contains other divider values, so rmw
|
||||||
* only plld and leave existing values alone
|
* 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 &= ~PLL_16FFT_DIV_CTRL_REF_DIV_MASK;
|
||||||
div_ctrl |= plld;
|
div_ctrl |= plld;
|
||||||
writel(div_ctrl, pll->reg + PLL_16FFT_DIV_CTRL);
|
|
||||||
|
|
||||||
ctrl &= ~PLL_16FFT_CTRL_BYPASS_EN;
|
/* Make sure we have fractional support if required */
|
||||||
ctrl |= PLL_16FFT_CTRL_PLL_EN;
|
ctrl = readl(pll->base + PLL_16FFT_CTRL);
|
||||||
writel(ctrl, pll->reg + 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);
|
ret = ti_pll_wait_for_lock(clk);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
ti_pll_clk_bypass(pll, false);
|
||||||
|
|
||||||
debug("%s: pllm=%u, plld=%u, pllfm=%u, parent_freq=%u\n",
|
debug("%s: pllm=%u, plld=%u, pllfm=%u, parent_freq=%u\n",
|
||||||
__func__, (u32)pllm, (u32)plld, (u32)pllfm, (u32)parent_freq);
|
__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;
|
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 = {
|
static const struct clk_ops ti_pll_clk_ops = {
|
||||||
.get_rate = ti_pll_clk_get_rate,
|
.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)
|
if (!pll)
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
pll->reg = reg;
|
pll->base = reg;
|
||||||
|
|
||||||
ret = clk_register(&pll->clk, "ti-pll-clk", name, parent_name);
|
ret = clk_register(&pll->clk, "ti-pll-clk", name, parent_name);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
@ -333,19 +528,19 @@ struct clk *clk_register_ti_pll(const char *name, const char *parent_name,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Unlock the PLL registers */
|
/* Unlock the PLL registers */
|
||||||
writel(PLL_KICK0_VALUE, pll->reg + PLL_KICK0);
|
writel(PLL_KICK0_VALUE, pll->base + PLL_KICK0);
|
||||||
writel(PLL_KICK1_VALUE, pll->reg + PLL_KICK1);
|
writel(PLL_KICK1_VALUE, pll->base + PLL_KICK1);
|
||||||
|
|
||||||
/* Enable all HSDIV outputs */
|
/* Enable all HSDIV outputs */
|
||||||
cfg = readl(pll->reg + PLL_16FFT_CFG);
|
cfg = readl(pll->base + PLL_16FFT_CFG);
|
||||||
for (i = 0; i < 16; i++) {
|
for (i = 0; i < 16; i++) {
|
||||||
hsdiv_presence_bit = BIT(16 + i);
|
hsdiv_presence_bit = BIT(16 + i);
|
||||||
hsdiv_ctrl_offs = 0x80 + (i * 4);
|
hsdiv_ctrl_offs = 0x80 + (i * 4);
|
||||||
/* Enable HSDIV output if present */
|
/* Enable HSDIV output if present */
|
||||||
if ((hsdiv_presence_bit & cfg) != 0UL) {
|
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;
|
ctrl |= PLL_16FFT_HSDIV_CTRL_CLKOUT_EN;
|
||||||
writel(ctrl, pll->reg + hsdiv_ctrl_offs);
|
writel(ctrl, pll->base + hsdiv_ctrl_offs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue