blob: b775bd55faab98db3c1a7b6093b5e9ff402a5050 [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0+
/*
* Texas Instruments K3 SoC PLL clock driver
*
* Copyright (C) 2020-2021 Texas Instruments Incorporated - https://www.ti.com/
* Tero Kristo <t-kristo@ti.com>
*/
#include <asm/io.h>
#include <dm.h>
#include <div64.h>
#include <errno.h>
#include <clk-uclass.h>
#include <linux/clk-provider.h>
#include "k3-clk.h"
#include <linux/rational.h>
#include <linux/delay.h>
/* 16FFT register offsets */
#define PLL_16FFT_CFG 0x08
#define PLL_KICK0 0x10
#define PLL_KICK1 0x14
#define PLL_16FFT_CTRL 0x20
#define PLL_16FFT_STAT 0x24
#define PLL_16FFT_FREQ_CTRL0 0x30
#define PLL_16FFT_FREQ_CTRL1 0x34
#define PLL_16FFT_DIV_CTRL 0x38
#define PLL_16FFT_CAL_CTRL 0x60
#define PLL_16FFT_CAL_STAT 0x64
/* 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 */
#define PLL_16FFT_CAL_CTRL_CAL_EN BIT(31)
#define PLL_16FFT_CAL_CTRL_FAST_CAL BIT(20)
#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
/* DIV CTRL register bits */
#define PLL_16FFT_DIV_CTRL_REF_DIV_MASK 0x3f
/* HSDIV register bits*/
#define PLL_16FFT_HSDIV_CTRL_CLKOUT_EN BIT(15)
/* FREQ_CTRL1 bits */
#define PLL_16FFT_FREQ_CTRL1_FB_DIV_FRAC_BITS 24
#define PLL_16FFT_FREQ_CTRL1_FB_DIV_FRAC_MASK 0xffffff
/* KICK register magic values */
#define PLL_KICK0_VALUE 0x68ef3490
#define PLL_KICK1_VALUE 0xd172bc5a
/**
* struct ti_pll_clk - TI PLL clock data info structure
* @clk: core clock structure
* @reg: memory address of the PLL controller
*/
struct ti_pll_clk {
struct clk clk;
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 cfg;
u32 cal;
u32 freq_ctrl1;
unsigned int i;
u32 pllfm;
u32 pll_type;
u32 cal_en = 0;
bool success;
/*
* 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;
}
}
/* 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;
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) {
cal = readl(pll->base + PLL_16FFT_CAL_CTRL);
cal_en = (cal & PLL_16FFT_CAL_CTRL_CAL_EN);
}
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) {
printf("%s: pll (%s) failed to lock\n", __func__,
clk->dev->name);
return -EBUSY;
} else {
return 0;
}
}
static ulong ti_pll_clk_get_rate(struct clk *clk)
{
struct ti_pll_clk *pll = to_clk_pll(clk);
u64 current_freq;
u64 parent_freq = clk_get_parent_rate(clk);
u32 pllm;
u32 plld;
u32 pllfm;
u32 ctrl;
/* Check if we are in bypass */
ctrl = readl(pll->base + PLL_16FFT_CTRL);
if (ctrl & PLL_16FFT_CTRL_BYPASS_EN)
return parent_freq;
pllm = readl(pll->base + PLL_16FFT_FREQ_CTRL0);
pllfm = readl(pll->base + PLL_16FFT_FREQ_CTRL1);
plld = readl(pll->base + PLL_16FFT_DIV_CTRL) &
PLL_16FFT_DIV_CTRL_REF_DIV_MASK;
current_freq = parent_freq * pllm / plld;
if (pllfm) {
u64 tmp;
tmp = parent_freq * pllfm;
do_div(tmp, plld);
tmp >>= PLL_16FFT_FREQ_CTRL1_FB_DIV_FRAC_BITS;
current_freq += tmp;
}
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);
u64 current_freq;
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;
debug("%s(clk=%p, rate=%u)\n", __func__, clk, (u32)rate);
if (ti_pll_clk_get_rate(clk) == rate)
return rate;
if (rate != parent_freq)
/*
* Attempt with higher max multiplier value first to give
* some space for fractional divider to kick in.
*/
for (shift = 8; shift >= 0; shift -= 8) {
rational_best_approximation(rate, parent_freq,
((PLL_16FFT_FREQ_CTRL0_FB_DIV_INT_MASK + 1) << shift) - 1,
PLL_16FFT_DIV_CTRL_REF_DIV_MASK, &pllm, &plld);
if (pllm / plld <= PLL_16FFT_FREQ_CTRL0_FB_DIV_INT_MASK)
break;
}
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);
/* Check if we need fractional config */
if (plld > 1) {
pllfm = pllm % plld;
pllfm <<= PLL_16FFT_FREQ_CTRL1_FB_DIV_FRAC_BITS;
rem = pllfm % plld;
pllfm /= plld;
if (rem)
pllfm++;
pllm /= plld;
plld = 1;
}
/* 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);
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 &= ~PLL_16FFT_DIV_CTRL_REF_DIV_MASK;
div_ctrl |= plld;
/* 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);
current_freq = parent_freq * pllm / plld;
if (pllfm) {
u64 tmp;
tmp = parent_freq * pllfm;
do_div(tmp, plld);
tmp >>= PLL_16FFT_FREQ_CTRL1_FB_DIV_FRAC_BITS;
current_freq += tmp;
}
return current_freq;
}
static const struct clk_ops ti_pll_clk_ops = {
.get_rate = ti_pll_clk_get_rate,
.set_rate = ti_pll_clk_set_rate,
.enable = ti_pll_clk_enable,
.disable = ti_pll_clk_disable,
};
struct clk *clk_register_ti_pll(const char *name, const char *parent_name,
void __iomem *reg)
{
struct ti_pll_clk *pll;
int ret;
int i;
u32 cfg, ctrl, hsdiv_presence_bit, hsdiv_ctrl_offs;
pll = kzalloc(sizeof(*pll), GFP_KERNEL);
if (!pll)
return ERR_PTR(-ENOMEM);
pll->base = reg;
ret = clk_register(&pll->clk, "ti-pll-clk", name, parent_name);
if (ret) {
printf("%s: failed to register: %d\n", __func__, ret);
kfree(pll);
return ERR_PTR(ret);
}
/* Unlock the PLL registers */
writel(PLL_KICK0_VALUE, pll->base + PLL_KICK0);
writel(PLL_KICK1_VALUE, pll->base + PLL_KICK1);
/* Enable all HSDIV outputs */
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->base + hsdiv_ctrl_offs);
ctrl |= PLL_16FFT_HSDIV_CTRL_CLKOUT_EN;
writel(ctrl, pll->base + hsdiv_ctrl_offs);
}
}
return &pll->clk;
}
U_BOOT_DRIVER(ti_pll_clk) = {
.name = "ti-pll-clk",
.id = UCLASS_CLK,
.ops = &ti_pll_clk_ops,
.flags = DM_FLAG_PRE_RELOC,
};