Files
BPI-M2C/source_sync_rls_25c/source/bsp/chipram/include/clk.h
T
2026-09-22 09:38:26 +08:00

192 lines
4.1 KiB
C
Executable File

// SPDX-License-Identifier: GPL-2.0
//
// Spreadtrum pll clock driver
//
// Copyright (C) 2015~2017 Spreadtrum, Inc.
// Author: Chunyan Zhang <chunyan.zhang@spreadtrum.com>
#ifndef _SPRD_PLL_H_
#define _SPRD_PLL_H_
#include <common.h>
#include <asm/io.h>
#include <timer.h>
#include <asm/sizes.h>
#include <asm/arch/sprd_reg.h>
#include <config.h>
#include <malloc.h>
#define INVALID_MAX_IBIAS 0xFF
#define INVALID_MAX_FREQ 0xFFFFFFFF
#define INVALID_MAX_VCO_SEL 0xFF
/*
* Divide positive or negative dividend by positive or negative divisor
* and round to closest integer. Result is undefined for negative
* divisors if the dividend variable type is unsigned and for negative
* dividends if the divisor variable type is unsigned.
*/
/*
* Same as above but for u64 dividends. divisor must be a 32-bit
* number.
*/
#define DIV_ROUND_CLOSEST_ULL(x, divisor)( \
{ \
typeof(divisor) __d = divisor; \
unsigned long long _tmp = (x) + (__d) / 2; \
do_div(_tmp, __d); \
_tmp; \
} \
)
#define GENMASK(h, l) \
(((~0U) << (l)) & (~0U >> (BITS_PER_LONG - 1 - (h))))
/*
* ffs: find first bit set. This is defined the same way as
* the libc and compiler builtin ffs routines, therefore
* differs in spirit from the above ffz (man ffs).
*/
static inline int generic_ffs(int x)
{
int r = 1;
if (!x)
return 0;
if (!(x & 0xffff)) {
x >>= 16;
r += 16;
}
if (!(x & 0xff)) {
x >>= 8;
r += 8;
}
if (!(x & 0xf)) {
x >>= 4;
r += 4;
}
if (!(x & 3)) {
x >>= 2;
r += 2;
}
if (!(x & 1)) {
x >>= 1;
r += 1;
}
return r;
}
#define __ffs(x) generic_ffs(x)
struct reg_cfg {
u32 val; /* reg value */
u32 msk; /* mask */
};
struct clk_bit_field {
u8 shift; /* shift */
u8 width; /* width */
};
struct freq_table {
u32 ibias;
u64 max_freq; /* max frequecy*/
u32 vco_sel;
};
enum {
PLL_LOCK_DONE, /* 0 */
PLL_DIV_S, /* 1 */
PLL_MOD_EN,
PLL_SDM_EN,
PLL_REFIN, /* 4 */
PLL_IBIAS,
PLL_N,
PLL_NINT,
PLL_KINT, /* 8 */
PLL_PREDIV,
PLL_POSTDIV, /* 10 */
PLL_REFDIV,
PLL_VCOSEL,
PLL_FACT_MAX
};
struct sprd_clk_common {
u32 reg_base;
union {
u32 reg;
u32 id;
};
const char *name;
const char *parent_name;
};
/*
* struct sprd_pll - definition of adjustable pll clock
*
* @reg: it is registers used to set the configuration of pll clock,
* and reg[0] shows how many registers this pll clock uses.
* @ftable: it is pll freq table
* @udelay it is delay time after setting rate
* @factors it is used to calculate the pll clock rate
* @fvco: it is the fvco threshold rate
* @fflag: it is the fvco flag
*/
struct sprd_pll {
u32 regs_num;
const struct freq_table *ftable;
const struct clk_bit_field *factors;
u16 udelay;
u16 k1;
u16 k2;
u16 fflag;
u64 fvco;
struct sprd_clk_common common;
};
#define SPRD_PLL_WITH_ITABLE_K_FVCO(_struct, _name, _parent, _reg_base, \
_reg, _regs_num, _ftable, _factors, \
_udelay, _k_1, _k_2, _fflag, _fvco) \
struct sprd_pll _struct = { \
.regs_num = _regs_num, \
.ftable = _ftable, \
.factors = _factors, \
.udelay = _udelay, \
.k1 = _k_1, \
.k2 = _k_2, \
.fflag = _fflag, \
.fvco = _fvco, \
.common = { \
.reg_base = _reg_base, \
.reg = _reg, \
.name = _name, \
.parent_name = _parent, \
}, \
}
#define SPRD_PLL_WITH_ITABLE_K(_struct, _name, _parent, _reg_base, \
_reg, _regs_num, _ftable, _factors, \
_udelay, _k_1, _k_2) \
SPRD_PLL_WITH_ITABLE_K_FVCO(_struct, _name, _parent, _reg_base, \
_reg, _regs_num, _ftable, _factors,\
_udelay, _k_1, _k_2, 0, 0)
#define SPRD_PLL_WITH_ITABLE_1K(_struct, _name, _parent, _reg_base, \
_reg, _regs_num, _ftable, _factors, _udelay) \
SPRD_PLL_WITH_ITABLE_K_FVCO(_struct, _name, _parent, _reg_base, \
_reg, _regs_num, _ftable, _factors, \
_udelay, 1000, 1000, 0, 0)
unsigned long sprd_pll_recalc_rate(const struct sprd_pll *pll,
unsigned long parent_rate);
int sprd_pll_set_rate(const struct sprd_pll *pll,
unsigned long rate,
unsigned long parent_rate);
#endif /* _SPRD_PLL_H_ */