Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
OS
U-Boot.Mirror
提交
b242d1b1
U
U-Boot.Mirror
项目概览
OS
/
U-Boot.Mirror
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
U
U-Boot.Mirror
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
b242d1b1
编写于
8月 23, 2019
作者:
T
Tom Rini
浏览文件
操作
浏览文件
下载
差异文件
Merge
https://gitlab.denx.de/u-boot/custodians/u-boot-clk
上级
c399dca8
f62ec5c4
变更
15
隐藏空白更改
内联
并排
Showing
15 changed file
with
1178 addition
and
38 deletion
+1178
-38
cmd/clk.c
cmd/clk.c
+49
-30
drivers/clk/Kconfig
drivers/clk/Kconfig
+0
-2
drivers/clk/clk-uclass.c
drivers/clk/clk-uclass.c
+71
-6
drivers/clk/clk.c
drivers/clk/clk.c
+1
-0
drivers/clk/clk_fixed_rate.c
drivers/clk/clk_fixed_rate.c
+1
-0
drivers/clk/clk_sandbox_ccf.c
drivers/clk/clk_sandbox_ccf.c
+15
-0
drivers/clk/imx/Kconfig
drivers/clk/imx/Kconfig
+16
-0
drivers/clk/imx/Makefile
drivers/clk/imx/Makefile
+2
-0
drivers/clk/imx/clk-composite-8m.c
drivers/clk/imx/clk-composite-8m.c
+170
-0
drivers/clk/imx/clk-imx8mm.c
drivers/clk/imx/clk-imx8mm.c
+415
-0
drivers/clk/imx/clk-pll14xx.c
drivers/clk/imx/clk-pll14xx.c
+381
-0
drivers/clk/imx/clk.h
drivers/clk/imx/clk.h
+25
-0
include/clk.h
include/clk.h
+1
-0
include/sandbox-clk.h
include/sandbox-clk.h
+3
-0
test/dm/clk_ccf.c
test/dm/clk_ccf.c
+28
-0
未找到文件。
cmd/clk.c
浏览文件 @
b242d1b1
...
...
@@ -7,51 +7,70 @@
#include <clk.h>
#if defined(CONFIG_DM) && defined(CONFIG_CLK)
#include <dm.h>
#include <dm/device.h>
#include <dm/root.h>
#include <dm/device-internal.h>
#include <linux/clk-provider.h>
#endif
int
__weak
soc_clk_dump
(
void
)
{
#if defined(CONFIG_DM) && defined(CONFIG_CLK)
struct
udevice
*
dev
;
struct
uclass
*
uc
;
struct
clk
clk
;
int
ret
;
ulong
rate
;
/* Device addresses start at 1 */
ret
=
uclass_get
(
UCLASS_CLK
,
&
uc
);
if
(
ret
)
return
ret
;
uclass_foreach_dev
(
dev
,
uc
)
{
memset
(
&
clk
,
0
,
sizeof
(
clk
));
ret
=
device_probe
(
dev
);
if
(
ret
)
goto
noclk
;
static
void
show_clks
(
struct
udevice
*
dev
,
int
depth
,
int
last_flag
)
{
int
i
,
is_last
;
struct
udevice
*
child
;
struct
clk
*
clkp
;
u32
rate
;
clkp
=
dev_get_clk_ptr
(
dev
);
if
(
device_get_uclass_id
(
dev
)
==
UCLASS_CLK
&&
clkp
)
{
rate
=
clk_get_rate
(
clkp
);
printf
(
" %-12u %8d "
,
rate
,
clkp
->
enable_count
);
for
(
i
=
depth
;
i
>=
0
;
i
--
)
{
is_last
=
(
last_flag
>>
i
)
&
1
;
if
(
i
)
{
if
(
is_last
)
printf
(
" "
);
else
printf
(
"| "
);
}
else
{
if
(
is_last
)
printf
(
"`-- "
);
else
printf
(
"|-- "
);
}
}
ret
=
clk_request
(
dev
,
&
clk
);
if
(
ret
)
goto
noclk
;
printf
(
"%s
\n
"
,
dev
->
name
);
}
rate
=
clk_get_rate
(
&
clk
);
clk_free
(
&
clk
);
list_for_each_entry
(
child
,
&
dev
->
child_head
,
sibling_node
)
{
is_last
=
list_is_last
(
&
child
->
sibling_node
,
&
dev
->
child_head
);
show_clks
(
child
,
depth
+
1
,
(
last_flag
<<
1
)
|
is_last
);
}
}
if
(
rate
==
-
ENODEV
)
goto
noclk
;
int
__weak
soc_clk_dump
(
void
)
{
struct
udevice
*
root
;
printf
(
"%-30.30s : %lu Hz
\n
"
,
dev
->
name
,
rate
);
continue
;
noclk:
printf
(
"%-30.30s : ? Hz
\n
"
,
dev
->
name
);
root
=
dm_root
();
if
(
root
)
{
printf
(
" Rate Usecnt Name
\n
"
);
printf
(
"------------------------------------------
\n
"
);
show_clks
(
root
,
-
1
,
0
);
}
return
0
;
}
#else
int
__weak
soc_clk_dump
(
void
)
{
puts
(
"Not implemented
\n
"
);
return
1
;
#endif
}
#endif
static
int
do_clk_dump
(
cmd_tbl_t
*
cmdtp
,
int
flag
,
int
argc
,
char
*
const
argv
[])
...
...
drivers/clk/Kconfig
浏览文件 @
b242d1b1
...
...
@@ -48,7 +48,6 @@ config CLK_BOSTON
config SPL_CLK_CCF
bool "SPL Common Clock Framework [CCF] support "
depends on SPL_CLK_IMX6Q
help
Enable this option if you want to (re-)use the Linux kernel's Common
Clock Framework [CCF] code in U-Boot's SPL.
...
...
@@ -62,7 +61,6 @@ config SPL_CLK_COMPOSITE_CCF
config CLK_CCF
bool "Common Clock Framework [CCF] support "
depends on CLK_IMX6Q || SANDBOX_CLK_CCF
help
Enable this option if you want to (re-)use the Linux kernel's Common
Clock Framework [CCF] code in U-Boot's clock driver.
...
...
drivers/clk/clk-uclass.c
浏览文件 @
b242d1b1
...
...
@@ -449,13 +449,45 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
int
clk_enable
(
struct
clk
*
clk
)
{
const
struct
clk_ops
*
ops
=
clk_dev_ops
(
clk
->
dev
);
struct
clk
*
clkp
=
NULL
;
int
ret
;
debug
(
"%s(clk=%p)
\n
"
,
__func__
,
clk
);
if
(
!
ops
->
enable
)
return
-
ENOSYS
;
if
(
CONFIG_IS_ENABLED
(
CLK_CCF
))
{
/* Take id 0 as a non-valid clk, such as dummy */
if
(
clk
->
id
&&
!
clk_get_by_id
(
clk
->
id
,
&
clkp
))
{
if
(
clkp
->
enable_count
)
{
clkp
->
enable_count
++
;
return
0
;
}
if
(
clkp
->
dev
->
parent
&&
device_get_uclass_id
(
clkp
->
dev
)
==
UCLASS_CLK
)
{
ret
=
clk_enable
(
dev_get_clk_ptr
(
clkp
->
dev
->
parent
));
if
(
ret
)
{
printf
(
"Enable %s failed
\n
"
,
clkp
->
dev
->
parent
->
name
);
return
ret
;
}
}
}
return
ops
->
enable
(
clk
);
if
(
ops
->
enable
)
{
ret
=
ops
->
enable
(
clk
);
if
(
ret
)
{
printf
(
"Enable %s failed
\n
"
,
clk
->
dev
->
name
);
return
ret
;
}
}
if
(
clkp
)
clkp
->
enable_count
++
;
}
else
{
if
(
!
ops
->
enable
)
return
-
ENOSYS
;
return
ops
->
enable
(
clk
);
}
return
0
;
}
int
clk_enable_bulk
(
struct
clk_bulk
*
bulk
)
...
...
@@ -474,13 +506,46 @@ int clk_enable_bulk(struct clk_bulk *bulk)
int
clk_disable
(
struct
clk
*
clk
)
{
const
struct
clk_ops
*
ops
=
clk_dev_ops
(
clk
->
dev
);
struct
clk
*
clkp
=
NULL
;
int
ret
;
debug
(
"%s(clk=%p)
\n
"
,
__func__
,
clk
);
if
(
!
ops
->
disable
)
return
-
ENOSYS
;
if
(
CONFIG_IS_ENABLED
(
CLK_CCF
))
{
if
(
clk
->
id
&&
!
clk_get_by_id
(
clk
->
id
,
&
clkp
))
{
if
(
clkp
->
enable_count
==
0
)
{
printf
(
"clk %s already disabled
\n
"
,
clkp
->
dev
->
name
);
return
0
;
}
return
ops
->
disable
(
clk
);
if
(
--
clkp
->
enable_count
>
0
)
return
0
;
}
if
(
ops
->
disable
)
{
ret
=
ops
->
disable
(
clk
);
if
(
ret
)
return
ret
;
}
if
(
clkp
&&
clkp
->
dev
->
parent
&&
device_get_uclass_id
(
clkp
->
dev
)
==
UCLASS_CLK
)
{
ret
=
clk_disable
(
dev_get_clk_ptr
(
clkp
->
dev
->
parent
));
if
(
ret
)
{
printf
(
"Disable %s failed
\n
"
,
clkp
->
dev
->
parent
->
name
);
return
ret
;
}
}
}
else
{
if
(
!
ops
->
disable
)
return
-
ENOSYS
;
return
ops
->
disable
(
clk
);
}
return
0
;
}
int
clk_disable_bulk
(
struct
clk_bulk
*
bulk
)
...
...
drivers/clk/clk.c
浏览文件 @
b242d1b1
...
...
@@ -40,6 +40,7 @@ int clk_register(struct clk *clk, const char *drv_name,
return
ret
;
}
clk
->
enable_count
=
0
;
/* Store back pointer to clk from udevice */
clk
->
dev
->
uclass_priv
=
clk
;
...
...
drivers/clk/clk_fixed_rate.c
浏览文件 @
b242d1b1
...
...
@@ -27,6 +27,7 @@ static int clk_fixed_rate_ofdata_to_platdata(struct udevice *dev)
/* Make fixed rate clock accessible from higher level struct clk */
dev
->
uclass_priv
=
clk
;
clk
->
dev
=
dev
;
clk
->
enable_count
=
0
;
return
0
;
}
...
...
drivers/clk/clk_sandbox_ccf.c
浏览文件 @
b242d1b1
...
...
@@ -25,6 +25,18 @@ struct clk_pllv3 {
u32
div_shift
;
};
int
sandbox_clk_enable_count
(
struct
clk
*
clk
)
{
struct
clk
*
clkp
=
NULL
;
int
ret
;
ret
=
clk_get_by_id
(
clk
->
id
,
&
clkp
);
if
(
ret
)
return
0
;
return
clkp
->
enable_count
;
}
static
ulong
clk_pllv3_get_rate
(
struct
clk
*
clk
)
{
unsigned
long
parent_rate
=
clk_get_parent_rate
(
clk
);
...
...
@@ -254,6 +266,9 @@ static int sandbox_clk_ccf_probe(struct udevice *dev)
sandbox_clk_composite
(
"i2c"
,
i2c_sels
,
ARRAY_SIZE
(
i2c_sels
),
&
reg
,
0
));
clk_dm
(
SANDBOX_CLK_I2C_ROOT
,
sandbox_clk_gate2
(
"i2c_root"
,
"i2c"
,
base
+
0x7c
,
0
));
return
0
;
}
...
...
drivers/clk/imx/Kconfig
浏览文件 @
b242d1b1
...
...
@@ -20,3 +20,19 @@ config CLK_IMX8
select CLK
help
This enables support clock driver for i.MX8 platforms.
config SPL_CLK_IMX8MM
bool "SPL clock support for i.MX8MM"
depends on ARCH_IMX8M && SPL
select SPL_CLK
select SPL_CLK_CCF
help
This enables SPL DM/DTS support for clock driver in i.MX8MM
config CLK_IMX8MM
bool "Clock support for i.MX8MM"
depends on ARCH_IMX8M
select CLK
select CLK_CCF
help
This enables support clock driver for i.MX8MM platforms.
drivers/clk/imx/Makefile
浏览文件 @
b242d1b1
...
...
@@ -10,3 +10,5 @@ ifdef CONFIG_CLK_IMX8
obj-$(CONFIG_IMX8QXP)
+=
clk-imx8qxp.o
obj-$(CONFIG_IMX8QM)
+=
clk-imx8qm.o
endif
obj-$(CONFIG_$(SPL_TPL_)CLK_IMX8MM)
+=
clk-imx8mm.o clk-pll14xx.o
\
clk-composite-8m.o
drivers/clk/imx/clk-composite-8m.c
0 → 100644
浏览文件 @
b242d1b1
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright 2019 NXP
*/
#include <common.h>
#include <asm/io.h>
#include <malloc.h>
#include <clk-uclass.h>
#include <dm/device.h>
#include <linux/clk-provider.h>
#include <clk.h>
#include "clk.h"
#define UBOOT_DM_CLK_IMX_COMPOSITE "imx_clk_composite"
#define PCG_PREDIV_SHIFT 16
#define PCG_PREDIV_WIDTH 3
#define PCG_PREDIV_MAX 8
#define PCG_DIV_SHIFT 0
#define PCG_DIV_WIDTH 6
#define PCG_DIV_MAX 64
#define PCG_PCS_SHIFT 24
#define PCG_PCS_MASK 0x7
#define PCG_CGC_SHIFT 28
static
unsigned
long
imx8m_clk_composite_divider_recalc_rate
(
struct
clk
*
clk
)
{
struct
clk_divider
*
divider
=
(
struct
clk_divider
*
)
to_clk_divider
(
clk
);
struct
clk_composite
*
composite
=
(
struct
clk_composite
*
)
clk
->
data
;
ulong
parent_rate
=
clk_get_parent_rate
(
&
composite
->
clk
);
unsigned
long
prediv_rate
;
unsigned
int
prediv_value
;
unsigned
int
div_value
;
debug
(
"%s: name %s prate: %lu reg: %p
\n
"
,
__func__
,
(
&
composite
->
clk
)
->
dev
->
name
,
parent_rate
,
divider
->
reg
);
prediv_value
=
readl
(
divider
->
reg
)
>>
divider
->
shift
;
prediv_value
&=
clk_div_mask
(
divider
->
width
);
prediv_rate
=
divider_recalc_rate
(
clk
,
parent_rate
,
prediv_value
,
NULL
,
divider
->
flags
,
divider
->
width
);
div_value
=
readl
(
divider
->
reg
)
>>
PCG_DIV_SHIFT
;
div_value
&=
clk_div_mask
(
PCG_DIV_WIDTH
);
return
divider_recalc_rate
(
clk
,
prediv_rate
,
div_value
,
NULL
,
divider
->
flags
,
PCG_DIV_WIDTH
);
}
static
int
imx8m_clk_composite_compute_dividers
(
unsigned
long
rate
,
unsigned
long
parent_rate
,
int
*
prediv
,
int
*
postdiv
)
{
int
div1
,
div2
;
int
error
=
INT_MAX
;
int
ret
=
-
EINVAL
;
*
prediv
=
1
;
*
postdiv
=
1
;
for
(
div1
=
1
;
div1
<=
PCG_PREDIV_MAX
;
div1
++
)
{
for
(
div2
=
1
;
div2
<=
PCG_DIV_MAX
;
div2
++
)
{
int
new_error
=
((
parent_rate
/
div1
)
/
div2
)
-
rate
;
if
(
abs
(
new_error
)
<
abs
(
error
))
{
*
prediv
=
div1
;
*
postdiv
=
div2
;
error
=
new_error
;
ret
=
0
;
}
}
}
return
ret
;
}
/*
* The clk are bound to a dev, because it is part of composite clk
* use composite clk to get dev
*/
static
ulong
imx8m_clk_composite_divider_set_rate
(
struct
clk
*
clk
,
unsigned
long
rate
)
{
struct
clk_divider
*
divider
=
(
struct
clk_divider
*
)
to_clk_divider
(
clk
);
struct
clk_composite
*
composite
=
(
struct
clk_composite
*
)
clk
->
data
;
ulong
parent_rate
=
clk_get_parent_rate
(
&
composite
->
clk
);
int
prediv_value
;
int
div_value
;
int
ret
;
u32
val
;
ret
=
imx8m_clk_composite_compute_dividers
(
rate
,
parent_rate
,
&
prediv_value
,
&
div_value
);
if
(
ret
)
return
ret
;
val
=
readl
(
divider
->
reg
);
val
&=
~
((
clk_div_mask
(
divider
->
width
)
<<
divider
->
shift
)
|
(
clk_div_mask
(
PCG_DIV_WIDTH
)
<<
PCG_DIV_SHIFT
));
val
|=
(
u32
)(
prediv_value
-
1
)
<<
divider
->
shift
;
val
|=
(
u32
)(
div_value
-
1
)
<<
PCG_DIV_SHIFT
;
writel
(
val
,
divider
->
reg
);
return
clk_get_rate
(
&
composite
->
clk
);
}
static
const
struct
clk_ops
imx8m_clk_composite_divider_ops
=
{
.
get_rate
=
imx8m_clk_composite_divider_recalc_rate
,
.
set_rate
=
imx8m_clk_composite_divider_set_rate
,
};
struct
clk
*
imx8m_clk_composite_flags
(
const
char
*
name
,
const
char
*
const
*
parent_names
,
int
num_parents
,
void
__iomem
*
reg
,
unsigned
long
flags
)
{
struct
clk
*
clk
=
ERR_PTR
(
-
ENOMEM
);
struct
clk_divider
*
div
=
NULL
;
struct
clk_gate
*
gate
=
NULL
;
struct
clk_mux
*
mux
=
NULL
;
mux
=
kzalloc
(
sizeof
(
*
mux
),
GFP_KERNEL
);
if
(
!
mux
)
goto
fail
;
mux
->
reg
=
reg
;
mux
->
shift
=
PCG_PCS_SHIFT
;
mux
->
mask
=
PCG_PCS_MASK
;
mux
->
num_parents
=
num_parents
;
mux
->
flags
=
flags
;
mux
->
parent_names
=
parent_names
;
div
=
kzalloc
(
sizeof
(
*
div
),
GFP_KERNEL
);
if
(
!
div
)
goto
fail
;
div
->
reg
=
reg
;
div
->
shift
=
PCG_PREDIV_SHIFT
;
div
->
width
=
PCG_PREDIV_WIDTH
;
div
->
flags
=
CLK_DIVIDER_ROUND_CLOSEST
|
flags
;
gate
=
kzalloc
(
sizeof
(
*
gate
),
GFP_KERNEL
);
if
(
!
gate
)
goto
fail
;
gate
->
reg
=
reg
;
gate
->
bit_idx
=
PCG_CGC_SHIFT
;
gate
->
flags
=
flags
;
clk
=
clk_register_composite
(
NULL
,
name
,
parent_names
,
num_parents
,
&
mux
->
clk
,
&
clk_mux_ops
,
&
div
->
clk
,
&
imx8m_clk_composite_divider_ops
,
&
gate
->
clk
,
&
clk_gate_ops
,
flags
);
if
(
IS_ERR
(
clk
))
goto
fail
;
return
clk
;
fail:
kfree
(
gate
);
kfree
(
div
);
kfree
(
mux
);
return
ERR_CAST
(
clk
);
}
drivers/clk/imx/clk-imx8mm.c
0 → 100644
浏览文件 @
b242d1b1
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright 2019 NXP
* Peng Fan <peng.fan@nxp.com>
*/
#include <common.h>
#include <clk.h>
#include <clk-uclass.h>
#include <dm.h>
#include <asm/arch/clock.h>
#include <asm/arch/imx-regs.h>
#include <dt-bindings/clock/imx8mm-clock.h>
#include "clk.h"
#define PLL_1416X_RATE(_rate, _m, _p, _s) \
{ \
.rate = (_rate), \
.mdiv = (_m), \
.pdiv = (_p), \
.sdiv = (_s), \
}
#define PLL_1443X_RATE(_rate, _m, _p, _s, _k) \
{ \
.rate = (_rate), \
.mdiv = (_m), \
.pdiv = (_p), \
.sdiv = (_s), \
.kdiv = (_k), \
}
static
const
struct
imx_pll14xx_rate_table
imx8mm_pll1416x_tbl
[]
=
{
PLL_1416X_RATE
(
1800000000U
,
225
,
3
,
0
),
PLL_1416X_RATE
(
1600000000U
,
200
,
3
,
0
),
PLL_1416X_RATE
(
1200000000U
,
300
,
3
,
1
),
PLL_1416X_RATE
(
1000000000U
,
250
,
3
,
1
),
PLL_1416X_RATE
(
800000000U
,
200
,
3
,
1
),
PLL_1416X_RATE
(
750000000U
,
250
,
2
,
2
),
PLL_1416X_RATE
(
700000000U
,
350
,
3
,
2
),
PLL_1416X_RATE
(
600000000U
,
300
,
3
,
2
),
};
static
const
struct
imx_pll14xx_rate_table
imx8mm_drampll_tbl
[]
=
{
PLL_1443X_RATE
(
650000000U
,
325
,
3
,
2
,
0
),
};
static
struct
imx_pll14xx_clk
imx8mm_dram_pll
__initdata
=
{
.
type
=
PLL_1443X
,
.
rate_table
=
imx8mm_drampll_tbl
,
.
rate_count
=
ARRAY_SIZE
(
imx8mm_drampll_tbl
),
};
static
struct
imx_pll14xx_clk
imx8mm_arm_pll
__initdata
=
{
.
type
=
PLL_1416X
,
.
rate_table
=
imx8mm_pll1416x_tbl
,
.
rate_count
=
ARRAY_SIZE
(
imx8mm_pll1416x_tbl
),
};
static
struct
imx_pll14xx_clk
imx8mm_sys_pll
__initdata
=
{
.
type
=
PLL_1416X
,
.
rate_table
=
imx8mm_pll1416x_tbl
,
.
rate_count
=
ARRAY_SIZE
(
imx8mm_pll1416x_tbl
),
};
static
const
char
*
pll_ref_sels
[]
=
{
"clock-osc-24m"
,
"dummy"
,
"dummy"
,
"dummy"
,
};
static
const
char
*
dram_pll_bypass_sels
[]
=
{
"dram_pll"
,
"dram_pll_ref_sel"
,
};
static
const
char
*
arm_pll_bypass_sels
[]
=
{
"arm_pll"
,
"arm_pll_ref_sel"
,
};
static
const
char
*
sys_pll1_bypass_sels
[]
=
{
"sys_pll1"
,
"sys_pll1_ref_sel"
,
};
static
const
char
*
sys_pll2_bypass_sels
[]
=
{
"sys_pll2"
,
"sys_pll2_ref_sel"
,
};
static
const
char
*
sys_pll3_bypass_sels
[]
=
{
"sys_pll3"
,
"sys_pll3_ref_sel"
,
};
static
const
char
*
imx8mm_a53_sels
[]
=
{
"clock-osc-24m"
,
"arm_pll_out"
,
"sys_pll2_500m"
,
"sys_pll2_1000m"
,
"sys_pll1_800m"
,
"sys_pll1_400m"
,
"audio_pll1_out"
,
"sys_pll3_out"
,
};
static
const
char
*
imx8mm_ahb_sels
[]
=
{
"osc_24m"
,
"sys_pll1_133m"
,
"sys_pll1_800m"
,
"sys_pll1_400m"
,
"sys_pll2_125m"
,
"sys_pll3_out"
,
"audio_pll1_out"
,
"video_pll1_out"
,
};
static
const
char
*
imx8mm_enet_axi_sels
[]
=
{
"clock-osc-24m"
,
"sys_pll1_266m"
,
"sys_pll1_800m"
,
"sys_pll2_250m"
,
"sys_pll2_200m"
,
"audio_pll1_out"
,
"video_pll1_out"
,
"sys_pll3_out"
,
};
static
const
char
*
imx8mm_nand_usdhc_sels
[]
=
{
"clock-osc-24m"
,
"sys_pll1_266m"
,
"sys_pll1_800m"
,
"sys_pll2_200m"
,
"sys_pll1_133m"
,
"sys_pll3_out"
,
"sys_pll2_250m"
,
"audio_pll1_out"
,
};
static
const
char
*
imx8mm_usdhc1_sels
[]
=
{
"clock-osc-24m"
,
"sys_pll1_400m"
,
"sys_pll1_800m"
,
"sys_pll2_500m"
,
"sys_pll3_out"
,
"sys_pll1_266m"
,
"audio_pll2_out"
,
"sys_pll1_100m"
,
};
static
const
char
*
imx8mm_usdhc2_sels
[]
=
{
"clock-osc-24m"
,
"sys_pll1_400m"
,
"sys_pll1_800m"
,
"sys_pll2_500m"
,
"sys_pll3_out"
,
"sys_pll1_266m"
,
"audio_pll2_out"
,
"sys_pll1_100m"
,
};
static
const
char
*
imx8mm_i2c1_sels
[]
=
{
"clock-osc-24m"
,
"sys_pll1_160m"
,
"sys_pll2_50m"
,
"sys_pll3_out"
,
"audio_pll1_out"
,
"video_pll1_out"
,
"audio_pll2_out"
,
"sys_pll1_133m"
,
};
static
const
char
*
imx8mm_i2c2_sels
[]
=
{
"clock-osc-24m"
,
"sys_pll1_160m"
,
"sys_pll2_50m"
,
"sys_pll3_out"
,
"audio_pll1_out"
,
"video_pll1_out"
,
"audio_pll2_out"
,
"sys_pll1_133m"
,
};
static
const
char
*
imx8mm_i2c3_sels
[]
=
{
"clock-osc-24m"
,
"sys_pll1_160m"
,
"sys_pll2_50m"
,
"sys_pll3_out"
,
"audio_pll1_out"
,
"video_pll1_out"
,
"audio_pll2_out"
,
"sys_pll1_133m"
,
};
static
const
char
*
imx8mm_i2c4_sels
[]
=
{
"clock-osc-24m"
,
"sys_pll1_160m"
,
"sys_pll2_50m"
,
"sys_pll3_out"
,
"audio_pll1_out"
,
"video_pll1_out"
,
"audio_pll2_out"
,
"sys_pll1_133m"
,
};
static
const
char
*
imx8mm_wdog_sels
[]
=
{
"clock-osc-24m"
,
"sys_pll1_133m"
,
"sys_pll1_160m"
,
"vpu_pll_out"
,
"sys_pll2_125m"
,
"sys_pll3_out"
,
"sys_pll1_80m"
,
"sys_pll2_166m"
,
};
static
const
char
*
imx8mm_usdhc3_sels
[]
=
{
"clock-osc-24m"
,
"sys_pll1_400m"
,
"sys_pll1_800m"
,
"sys_pll2_500m"
,
"sys_pll3_out"
,
"sys_pll1_266m"
,
"audio_pll2_clk"
,
"sys_pll1_100m"
,
};
static
ulong
imx8mm_clk_get_rate
(
struct
clk
*
clk
)
{
struct
clk
*
c
;
int
ret
;
debug
(
"%s(#%lu)
\n
"
,
__func__
,
clk
->
id
);
ret
=
clk_get_by_id
(
clk
->
id
,
&
c
);
if
(
ret
)
return
ret
;
return
clk_get_rate
(
c
);
}
static
ulong
imx8mm_clk_set_rate
(
struct
clk
*
clk
,
unsigned
long
rate
)
{
struct
clk
*
c
;
int
ret
;
debug
(
"%s(#%lu), rate: %lu
\n
"
,
__func__
,
clk
->
id
,
rate
);
ret
=
clk_get_by_id
(
clk
->
id
,
&
c
);
if
(
ret
)
return
ret
;
return
clk_set_rate
(
c
,
rate
);
}
static
int
__imx8mm_clk_enable
(
struct
clk
*
clk
,
bool
enable
)
{
struct
clk
*
c
;
int
ret
;
debug
(
"%s(#%lu) en: %d
\n
"
,
__func__
,
clk
->
id
,
enable
);
ret
=
clk_get_by_id
(
clk
->
id
,
&
c
);
if
(
ret
)
return
ret
;
if
(
enable
)
ret
=
clk_enable
(
c
);
else
ret
=
clk_disable
(
c
);
return
ret
;
}
static
int
imx8mm_clk_disable
(
struct
clk
*
clk
)
{
return
__imx8mm_clk_enable
(
clk
,
0
);
}
static
int
imx8mm_clk_enable
(
struct
clk
*
clk
)
{
return
__imx8mm_clk_enable
(
clk
,
1
);
}
static
struct
clk_ops
imx8mm_clk_ops
=
{
.
set_rate
=
imx8mm_clk_set_rate
,
.
get_rate
=
imx8mm_clk_get_rate
,
.
enable
=
imx8mm_clk_enable
,
.
disable
=
imx8mm_clk_disable
,
};
static
int
imx8mm_clk_probe
(
struct
udevice
*
dev
)
{
void
__iomem
*
base
;
base
=
(
void
*
)
ANATOP_BASE_ADDR
;
clk_dm
(
IMX8MM_DRAM_PLL_REF_SEL
,
imx_clk_mux
(
"dram_pll_ref_sel"
,
base
+
0x50
,
0
,
2
,
pll_ref_sels
,
ARRAY_SIZE
(
pll_ref_sels
)));
clk_dm
(
IMX8MM_ARM_PLL_REF_SEL
,
imx_clk_mux
(
"arm_pll_ref_sel"
,
base
+
0x84
,
0
,
2
,
pll_ref_sels
,
ARRAY_SIZE
(
pll_ref_sels
)));
clk_dm
(
IMX8MM_SYS_PLL1_REF_SEL
,
imx_clk_mux
(
"sys_pll1_ref_sel"
,
base
+
0x94
,
0
,
2
,
pll_ref_sels
,
ARRAY_SIZE
(
pll_ref_sels
)));
clk_dm
(
IMX8MM_SYS_PLL2_REF_SEL
,
imx_clk_mux
(
"sys_pll2_ref_sel"
,
base
+
0x104
,
0
,
2
,
pll_ref_sels
,
ARRAY_SIZE
(
pll_ref_sels
)));
clk_dm
(
IMX8MM_SYS_PLL3_REF_SEL
,
imx_clk_mux
(
"sys_pll3_ref_sel"
,
base
+
0x114
,
0
,
2
,
pll_ref_sels
,
ARRAY_SIZE
(
pll_ref_sels
)));
clk_dm
(
IMX8MM_DRAM_PLL
,
imx_clk_pll14xx
(
"dram_pll"
,
"dram_pll_ref_sel"
,
base
+
0x50
,
&
imx8mm_dram_pll
));
clk_dm
(
IMX8MM_ARM_PLL
,
imx_clk_pll14xx
(
"arm_pll"
,
"arm_pll_ref_sel"
,
base
+
0x84
,
&
imx8mm_arm_pll
));
clk_dm
(
IMX8MM_SYS_PLL1
,
imx_clk_pll14xx
(
"sys_pll1"
,
"sys_pll1_ref_sel"
,
base
+
0x94
,
&
imx8mm_sys_pll
));
clk_dm
(
IMX8MM_SYS_PLL2
,
imx_clk_pll14xx
(
"sys_pll2"
,
"sys_pll2_ref_sel"
,
base
+
0x104
,
&
imx8mm_sys_pll
));
clk_dm
(
IMX8MM_SYS_PLL3
,
imx_clk_pll14xx
(
"sys_pll3"
,
"sys_pll3_ref_sel"
,
base
+
0x114
,
&
imx8mm_sys_pll
));
/* PLL bypass out */
clk_dm
(
IMX8MM_DRAM_PLL_BYPASS
,
imx_clk_mux_flags
(
"dram_pll_bypass"
,
base
+
0x50
,
4
,
1
,
dram_pll_bypass_sels
,
ARRAY_SIZE
(
dram_pll_bypass_sels
),
CLK_SET_RATE_PARENT
));
clk_dm
(
IMX8MM_ARM_PLL_BYPASS
,
imx_clk_mux_flags
(
"arm_pll_bypass"
,
base
+
0x84
,
4
,
1
,
arm_pll_bypass_sels
,
ARRAY_SIZE
(
arm_pll_bypass_sels
),
CLK_SET_RATE_PARENT
));
clk_dm
(
IMX8MM_SYS_PLL1_BYPASS
,
imx_clk_mux_flags
(
"sys_pll1_bypass"
,
base
+
0x94
,
4
,
1
,
sys_pll1_bypass_sels
,
ARRAY_SIZE
(
sys_pll1_bypass_sels
),
CLK_SET_RATE_PARENT
));
clk_dm
(
IMX8MM_SYS_PLL2_BYPASS
,
imx_clk_mux_flags
(
"sys_pll2_bypass"
,
base
+
0x104
,
4
,
1
,
sys_pll2_bypass_sels
,
ARRAY_SIZE
(
sys_pll2_bypass_sels
),
CLK_SET_RATE_PARENT
));
clk_dm
(
IMX8MM_SYS_PLL3_BYPASS
,
imx_clk_mux_flags
(
"sys_pll3_bypass"
,
base
+
0x114
,
4
,
1
,
sys_pll3_bypass_sels
,
ARRAY_SIZE
(
sys_pll3_bypass_sels
),
CLK_SET_RATE_PARENT
));
/* PLL out gate */
clk_dm
(
IMX8MM_DRAM_PLL_OUT
,
imx_clk_gate
(
"dram_pll_out"
,
"dram_pll_bypass"
,
base
+
0x50
,
13
));
clk_dm
(
IMX8MM_ARM_PLL_OUT
,
imx_clk_gate
(
"arm_pll_out"
,
"arm_pll_bypass"
,
base
+
0x84
,
11
));
clk_dm
(
IMX8MM_SYS_PLL1_OUT
,
imx_clk_gate
(
"sys_pll1_out"
,
"sys_pll1_bypass"
,
base
+
0x94
,
11
));
clk_dm
(
IMX8MM_SYS_PLL2_OUT
,
imx_clk_gate
(
"sys_pll2_out"
,
"sys_pll2_bypass"
,
base
+
0x104
,
11
));
clk_dm
(
IMX8MM_SYS_PLL3_OUT
,
imx_clk_gate
(
"sys_pll3_out"
,
"sys_pll3_bypass"
,
base
+
0x114
,
11
));
/* SYS PLL fixed output */
clk_dm
(
IMX8MM_SYS_PLL1_40M
,
imx_clk_fixed_factor
(
"sys_pll1_40m"
,
"sys_pll1_out"
,
1
,
20
));
clk_dm
(
IMX8MM_SYS_PLL1_80M
,
imx_clk_fixed_factor
(
"sys_pll1_80m"
,
"sys_pll1_out"
,
1
,
10
));
clk_dm
(
IMX8MM_SYS_PLL1_100M
,
imx_clk_fixed_factor
(
"sys_pll1_100m"
,
"sys_pll1_out"
,
1
,
8
));
clk_dm
(
IMX8MM_SYS_PLL1_133M
,
imx_clk_fixed_factor
(
"sys_pll1_133m"
,
"sys_pll1_out"
,
1
,
6
));
clk_dm
(
IMX8MM_SYS_PLL1_160M
,
imx_clk_fixed_factor
(
"sys_pll1_160m"
,
"sys_pll1_out"
,
1
,
5
));
clk_dm
(
IMX8MM_SYS_PLL1_200M
,
imx_clk_fixed_factor
(
"sys_pll1_200m"
,
"sys_pll1_out"
,
1
,
4
));
clk_dm
(
IMX8MM_SYS_PLL1_266M
,
imx_clk_fixed_factor
(
"sys_pll1_266m"
,
"sys_pll1_out"
,
1
,
3
));
clk_dm
(
IMX8MM_SYS_PLL1_400M
,
imx_clk_fixed_factor
(
"sys_pll1_400m"
,
"sys_pll1_out"
,
1
,
2
));
clk_dm
(
IMX8MM_SYS_PLL1_800M
,
imx_clk_fixed_factor
(
"sys_pll1_800m"
,
"sys_pll1_out"
,
1
,
1
));
clk_dm
(
IMX8MM_SYS_PLL2_50M
,
imx_clk_fixed_factor
(
"sys_pll2_50m"
,
"sys_pll2_out"
,
1
,
20
));
clk_dm
(
IMX8MM_SYS_PLL2_100M
,
imx_clk_fixed_factor
(
"sys_pll2_100m"
,
"sys_pll2_out"
,
1
,
10
));
clk_dm
(
IMX8MM_SYS_PLL2_125M
,
imx_clk_fixed_factor
(
"sys_pll2_125m"
,
"sys_pll2_out"
,
1
,
8
));
clk_dm
(
IMX8MM_SYS_PLL2_166M
,
imx_clk_fixed_factor
(
"sys_pll2_166m"
,
"sys_pll2_out"
,
1
,
6
));
clk_dm
(
IMX8MM_SYS_PLL2_200M
,
imx_clk_fixed_factor
(
"sys_pll2_200m"
,
"sys_pll2_out"
,
1
,
5
));
clk_dm
(
IMX8MM_SYS_PLL2_250M
,
imx_clk_fixed_factor
(
"sys_pll2_250m"
,
"sys_pll2_out"
,
1
,
4
));
clk_dm
(
IMX8MM_SYS_PLL2_333M
,
imx_clk_fixed_factor
(
"sys_pll2_333m"
,
"sys_pll2_out"
,
1
,
3
));
clk_dm
(
IMX8MM_SYS_PLL2_500M
,
imx_clk_fixed_factor
(
"sys_pll2_500m"
,
"sys_pll2_out"
,
1
,
2
));
clk_dm
(
IMX8MM_SYS_PLL2_1000M
,
imx_clk_fixed_factor
(
"sys_pll2_1000m"
,
"sys_pll2_out"
,
1
,
1
));
base
=
dev_read_addr_ptr
(
dev
);
if
(
base
==
(
void
*
)
FDT_ADDR_T_NONE
)
return
-
EINVAL
;
clk_dm
(
IMX8MM_CLK_A53_SRC
,
imx_clk_mux2
(
"arm_a53_src"
,
base
+
0x8000
,
24
,
3
,
imx8mm_a53_sels
,
ARRAY_SIZE
(
imx8mm_a53_sels
)));
clk_dm
(
IMX8MM_CLK_A53_CG
,
imx_clk_gate3
(
"arm_a53_cg"
,
"arm_a53_src"
,
base
+
0x8000
,
28
));
clk_dm
(
IMX8MM_CLK_A53_DIV
,
imx_clk_divider2
(
"arm_a53_div"
,
"arm_a53_cg"
,
base
+
0x8000
,
0
,
3
));
clk_dm
(
IMX8MM_CLK_AHB
,
imx8m_clk_composite_critical
(
"ahb"
,
imx8mm_ahb_sels
,
base
+
0x9000
));
clk_dm
(
IMX8MM_CLK_IPG_ROOT
,
imx_clk_divider2
(
"ipg_root"
,
"ahb"
,
base
+
0x9080
,
0
,
1
));
clk_dm
(
IMX8MM_CLK_ENET_AXI
,
imx8m_clk_composite
(
"enet_axi"
,
imx8mm_enet_axi_sels
,
base
+
0x8880
));
clk_dm
(
IMX8MM_CLK_NAND_USDHC_BUS
,
imx8m_clk_composite_critical
(
"nand_usdhc_bus"
,
imx8mm_nand_usdhc_sels
,
base
+
0x8900
));
/* IP */
clk_dm
(
IMX8MM_CLK_USDHC1
,
imx8m_clk_composite
(
"usdhc1"
,
imx8mm_usdhc1_sels
,
base
+
0xac00
));
clk_dm
(
IMX8MM_CLK_USDHC2
,
imx8m_clk_composite
(
"usdhc2"
,
imx8mm_usdhc2_sels
,
base
+
0xac80
));
clk_dm
(
IMX8MM_CLK_I2C1
,
imx8m_clk_composite
(
"i2c1"
,
imx8mm_i2c1_sels
,
base
+
0xad00
));
clk_dm
(
IMX8MM_CLK_I2C2
,
imx8m_clk_composite
(
"i2c2"
,
imx8mm_i2c2_sels
,
base
+
0xad80
));
clk_dm
(
IMX8MM_CLK_I2C3
,
imx8m_clk_composite
(
"i2c3"
,
imx8mm_i2c3_sels
,
base
+
0xae00
));
clk_dm
(
IMX8MM_CLK_I2C4
,
imx8m_clk_composite
(
"i2c4"
,
imx8mm_i2c4_sels
,
base
+
0xae80
));
clk_dm
(
IMX8MM_CLK_WDOG
,
imx8m_clk_composite
(
"wdog"
,
imx8mm_wdog_sels
,
base
+
0xb900
));
clk_dm
(
IMX8MM_CLK_USDHC3
,
imx8m_clk_composite
(
"usdhc3"
,
imx8mm_usdhc3_sels
,
base
+
0xbc80
));
clk_dm
(
IMX8MM_CLK_I2C1_ROOT
,
imx_clk_gate4
(
"i2c1_root_clk"
,
"i2c1"
,
base
+
0x4170
,
0
));
clk_dm
(
IMX8MM_CLK_I2C2_ROOT
,
imx_clk_gate4
(
"i2c2_root_clk"
,
"i2c2"
,
base
+
0x4180
,
0
));
clk_dm
(
IMX8MM_CLK_I2C3_ROOT
,
imx_clk_gate4
(
"i2c3_root_clk"
,
"i2c3"
,
base
+
0x4190
,
0
));
clk_dm
(
IMX8MM_CLK_I2C4_ROOT
,
imx_clk_gate4
(
"i2c4_root_clk"
,
"i2c4"
,
base
+
0x41a0
,
0
));
clk_dm
(
IMX8MM_CLK_OCOTP_ROOT
,
imx_clk_gate4
(
"ocotp_root_clk"
,
"ipg_root"
,
base
+
0x4220
,
0
));
clk_dm
(
IMX8MM_CLK_USDHC1_ROOT
,
imx_clk_gate4
(
"usdhc1_root_clk"
,
"usdhc1"
,
base
+
0x4510
,
0
));
clk_dm
(
IMX8MM_CLK_USDHC2_ROOT
,
imx_clk_gate4
(
"usdhc2_root_clk"
,
"usdhc2"
,
base
+
0x4520
,
0
));
clk_dm
(
IMX8MM_CLK_WDOG1_ROOT
,
imx_clk_gate4
(
"wdog1_root_clk"
,
"wdog"
,
base
+
0x4530
,
0
));
clk_dm
(
IMX8MM_CLK_WDOG2_ROOT
,
imx_clk_gate4
(
"wdog2_root_clk"
,
"wdog"
,
base
+
0x4540
,
0
));
clk_dm
(
IMX8MM_CLK_WDOG3_ROOT
,
imx_clk_gate4
(
"wdog3_root_clk"
,
"wdog"
,
base
+
0x4550
,
0
));
clk_dm
(
IMX8MM_CLK_USDHC3_ROOT
,
imx_clk_gate4
(
"usdhc3_root_clk"
,
"usdhc3"
,
base
+
0x45e0
,
0
));
#ifdef CONFIG_SPL_BUILD
struct
clk
*
clkp
,
*
clkp1
;
clk_get_by_id
(
IMX8MM_CLK_WDOG1_ROOT
,
&
clkp
);
clk_enable
(
clkp
);
clk_get_by_id
(
IMX8MM_CLK_WDOG2_ROOT
,
&
clkp
);
clk_enable
(
clkp
);
clk_get_by_id
(
IMX8MM_CLK_WDOG3_ROOT
,
&
clkp
);
clk_enable
(
clkp
);
/* Configure SYS_PLL3 to 750MHz */
clk_get_by_id
(
IMX8MM_SYS_PLL3
,
&
clkp
);
clk_set_rate
(
clkp
,
750000000UL
);
clk_enable
(
clkp
);
/* Configure ARM to sys_pll2_500m */
clk_get_by_id
(
IMX8MM_CLK_A53_SRC
,
&
clkp
);
clk_get_by_id
(
IMX8MM_SYS_PLL2_OUT
,
&
clkp1
);
clk_enable
(
clkp1
);
clk_get_by_id
(
IMX8MM_SYS_PLL2_500M
,
&
clkp1
);
clk_set_parent
(
clkp
,
clkp1
);
/* Configure ARM PLL to 1.2GHz */
clk_get_by_id
(
IMX8MM_ARM_PLL
,
&
clkp1
);
clk_set_rate
(
clkp1
,
1200000000UL
);
clk_get_by_id
(
IMX8MM_ARM_PLL_OUT
,
&
clkp1
);
clk_enable
(
clkp1
);
clk_set_parent
(
clkp
,
clkp1
);
/* Configure DIV to 1.2GHz */
clk_get_by_id
(
IMX8MM_CLK_A53_DIV
,
&
clkp1
);
clk_set_rate
(
clkp1
,
1200000000UL
);
#endif
return
0
;
}
static
const
struct
udevice_id
imx8mm_clk_ids
[]
=
{
{
.
compatible
=
"fsl,imx8mm-ccm"
},
{
},
};
U_BOOT_DRIVER
(
imx8mm_clk
)
=
{
.
name
=
"clk_imx8mm"
,
.
id
=
UCLASS_CLK
,
.
of_match
=
imx8mm_clk_ids
,
.
ops
=
&
imx8mm_clk_ops
,
.
probe
=
imx8mm_clk_probe
,
.
flags
=
DM_FLAG_PRE_RELOC
,
};
drivers/clk/imx/clk-pll14xx.c
0 → 100644
浏览文件 @
b242d1b1
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright 2017-2019 NXP.
*
* Peng Fan <peng.fan@nxp.com>
*/
#include <common.h>
#include <asm/io.h>
#include <malloc.h>
#include <clk-uclass.h>
#include <dm/device.h>
#include <linux/clk-provider.h>
#include <linux/iopoll.h>
#include <clk.h>
#include <div64.h>
#include "clk.h"
#define UBOOT_DM_CLK_IMX_PLL1443X "imx_clk_pll1443x"
#define UBOOT_DM_CLK_IMX_PLL1416X "imx_clk_pll1416x"
#define GNRL_CTL 0x0
#define DIV_CTL 0x4
#define LOCK_STATUS BIT(31)
#define LOCK_SEL_MASK BIT(29)
#define CLKE_MASK BIT(11)
#define RST_MASK BIT(9)
#define BYPASS_MASK BIT(4)
#define MDIV_SHIFT 12
#define MDIV_MASK GENMASK(21, 12)
#define PDIV_SHIFT 4
#define PDIV_MASK GENMASK(9, 4)
#define SDIV_SHIFT 0
#define SDIV_MASK GENMASK(2, 0)
#define KDIV_SHIFT 0
#define KDIV_MASK GENMASK(15, 0)
#define LOCK_TIMEOUT_US 10000
struct
clk_pll14xx
{
struct
clk
clk
;
void
__iomem
*
base
;
enum
imx_pll14xx_type
type
;
const
struct
imx_pll14xx_rate_table
*
rate_table
;
int
rate_count
;
};
#define to_clk_pll14xx(_clk) container_of(_clk, struct clk_pll14xx, clk)
static
const
struct
imx_pll14xx_rate_table
*
imx_get_pll_settings
(
struct
clk_pll14xx
*
pll
,
unsigned
long
rate
)
{
const
struct
imx_pll14xx_rate_table
*
rate_table
=
pll
->
rate_table
;
int
i
;
for
(
i
=
0
;
i
<
pll
->
rate_count
;
i
++
)
if
(
rate
==
rate_table
[
i
].
rate
)
return
&
rate_table
[
i
];
return
NULL
;
}
static
unsigned
long
clk_pll1416x_recalc_rate
(
struct
clk
*
clk
)
{
struct
clk_pll14xx
*
pll
=
to_clk_pll14xx
(
dev_get_clk_ptr
(
clk
->
dev
));
u64
fvco
=
clk_get_parent_rate
(
clk
);
u32
mdiv
,
pdiv
,
sdiv
,
pll_div
;
pll_div
=
readl
(
pll
->
base
+
4
);
mdiv
=
(
pll_div
&
MDIV_MASK
)
>>
MDIV_SHIFT
;
pdiv
=
(
pll_div
&
PDIV_MASK
)
>>
PDIV_SHIFT
;
sdiv
=
(
pll_div
&
SDIV_MASK
)
>>
SDIV_SHIFT
;
fvco
*=
mdiv
;
do_div
(
fvco
,
pdiv
<<
sdiv
);
return
fvco
;
}
static
unsigned
long
clk_pll1443x_recalc_rate
(
struct
clk
*
clk
)
{
struct
clk_pll14xx
*
pll
=
to_clk_pll14xx
(
dev_get_clk_ptr
(
clk
->
dev
));
u64
fvco
=
clk_get_parent_rate
(
clk
);
u32
mdiv
,
pdiv
,
sdiv
,
pll_div_ctl0
,
pll_div_ctl1
;
short
int
kdiv
;
pll_div_ctl0
=
readl
(
pll
->
base
+
4
);
pll_div_ctl1
=
readl
(
pll
->
base
+
8
);
mdiv
=
(
pll_div_ctl0
&
MDIV_MASK
)
>>
MDIV_SHIFT
;
pdiv
=
(
pll_div_ctl0
&
PDIV_MASK
)
>>
PDIV_SHIFT
;
sdiv
=
(
pll_div_ctl0
&
SDIV_MASK
)
>>
SDIV_SHIFT
;
kdiv
=
pll_div_ctl1
&
KDIV_MASK
;
/* fvco = (m * 65536 + k) * Fin / (p * 65536) */
fvco
*=
(
mdiv
*
65536
+
kdiv
);
pdiv
*=
65536
;
do_div
(
fvco
,
pdiv
<<
sdiv
);
return
fvco
;
}
static
inline
bool
clk_pll1416x_mp_change
(
const
struct
imx_pll14xx_rate_table
*
rate
,
u32
pll_div
)
{
u32
old_mdiv
,
old_pdiv
;
old_mdiv
=
(
pll_div
&
MDIV_MASK
)
>>
MDIV_SHIFT
;
old_pdiv
=
(
pll_div
&
PDIV_MASK
)
>>
PDIV_SHIFT
;
return
rate
->
mdiv
!=
old_mdiv
||
rate
->
pdiv
!=
old_pdiv
;
}
static
inline
bool
clk_pll1443x_mpk_change
(
const
struct
imx_pll14xx_rate_table
*
rate
,
u32
pll_div_ctl0
,
u32
pll_div_ctl1
)
{
u32
old_mdiv
,
old_pdiv
,
old_kdiv
;
old_mdiv
=
(
pll_div_ctl0
&
MDIV_MASK
)
>>
MDIV_SHIFT
;
old_pdiv
=
(
pll_div_ctl0
&
PDIV_MASK
)
>>
PDIV_SHIFT
;
old_kdiv
=
(
pll_div_ctl1
&
KDIV_MASK
)
>>
KDIV_SHIFT
;
return
rate
->
mdiv
!=
old_mdiv
||
rate
->
pdiv
!=
old_pdiv
||
rate
->
kdiv
!=
old_kdiv
;
}
static
inline
bool
clk_pll1443x_mp_change
(
const
struct
imx_pll14xx_rate_table
*
rate
,
u32
pll_div_ctl0
,
u32
pll_div_ctl1
)
{
u32
old_mdiv
,
old_pdiv
,
old_kdiv
;
old_mdiv
=
(
pll_div_ctl0
&
MDIV_MASK
)
>>
MDIV_SHIFT
;
old_pdiv
=
(
pll_div_ctl0
&
PDIV_MASK
)
>>
PDIV_SHIFT
;
old_kdiv
=
(
pll_div_ctl1
&
KDIV_MASK
)
>>
KDIV_SHIFT
;
return
rate
->
mdiv
!=
old_mdiv
||
rate
->
pdiv
!=
old_pdiv
||
rate
->
kdiv
!=
old_kdiv
;
}
static
int
clk_pll14xx_wait_lock
(
struct
clk_pll14xx
*
pll
)
{
u32
val
;
return
readl_poll_timeout
(
pll
->
base
,
val
,
val
&
LOCK_TIMEOUT_US
,
LOCK_TIMEOUT_US
);
}
static
ulong
clk_pll1416x_set_rate
(
struct
clk
*
clk
,
unsigned
long
drate
)
{
struct
clk_pll14xx
*
pll
=
to_clk_pll14xx
(
dev_get_clk_ptr
(
clk
->
dev
));
const
struct
imx_pll14xx_rate_table
*
rate
;
u32
tmp
,
div_val
;
int
ret
;
rate
=
imx_get_pll_settings
(
pll
,
drate
);
if
(
!
rate
)
{
pr_err
(
"%s: Invalid rate : %lu for pll clk %s
\n
"
,
__func__
,
drate
,
"xxxx"
);
return
-
EINVAL
;
}
tmp
=
readl
(
pll
->
base
+
4
);
if
(
!
clk_pll1416x_mp_change
(
rate
,
tmp
))
{
tmp
&=
~
(
SDIV_MASK
)
<<
SDIV_SHIFT
;
tmp
|=
rate
->
sdiv
<<
SDIV_SHIFT
;
writel
(
tmp
,
pll
->
base
+
4
);
return
clk_pll1416x_recalc_rate
(
clk
);
}
/* Bypass clock and set lock to pll output lock */
tmp
=
readl
(
pll
->
base
);
tmp
|=
LOCK_SEL_MASK
;
writel
(
tmp
,
pll
->
base
);
/* Enable RST */
tmp
&=
~
RST_MASK
;
writel
(
tmp
,
pll
->
base
);
/* Enable BYPASS */
tmp
|=
BYPASS_MASK
;
writel
(
tmp
,
pll
->
base
);
div_val
=
(
rate
->
mdiv
<<
MDIV_SHIFT
)
|
(
rate
->
pdiv
<<
PDIV_SHIFT
)
|
(
rate
->
sdiv
<<
SDIV_SHIFT
);
writel
(
div_val
,
pll
->
base
+
0x4
);
/*
* According to SPEC, t3 - t2 need to be greater than
* 1us and 1/FREF, respectively.
* FREF is FIN / Prediv, the prediv is [1, 63], so choose
* 3us.
*/
udelay
(
3
);
/* Disable RST */
tmp
|=
RST_MASK
;
writel
(
tmp
,
pll
->
base
);
/* Wait Lock */
ret
=
clk_pll14xx_wait_lock
(
pll
);
if
(
ret
)
return
ret
;
/* Bypass */
tmp
&=
~
BYPASS_MASK
;
writel
(
tmp
,
pll
->
base
);
return
clk_pll1416x_recalc_rate
(
clk
);
}
static
ulong
clk_pll1443x_set_rate
(
struct
clk
*
clk
,
unsigned
long
drate
)
{
struct
clk_pll14xx
*
pll
=
to_clk_pll14xx
(
dev_get_clk_ptr
(
clk
->
dev
));
const
struct
imx_pll14xx_rate_table
*
rate
;
u32
tmp
,
div_val
;
int
ret
;
rate
=
imx_get_pll_settings
(
pll
,
drate
);
if
(
!
rate
)
{
pr_err
(
"%s: Invalid rate : %lu for pll clk %s
\n
"
,
__func__
,
drate
,
"==="
);
return
-
EINVAL
;
}
tmp
=
readl
(
pll
->
base
+
4
);
div_val
=
readl
(
pll
->
base
+
8
);
if
(
!
clk_pll1443x_mpk_change
(
rate
,
tmp
,
div_val
))
{
tmp
&=
~
(
SDIV_MASK
)
<<
SDIV_SHIFT
;
tmp
|=
rate
->
sdiv
<<
SDIV_SHIFT
;
writel
(
tmp
,
pll
->
base
+
4
);
return
clk_pll1443x_recalc_rate
(
clk
);
}
tmp
=
readl
(
pll
->
base
);
/* Enable RST */
tmp
&=
~
RST_MASK
;
writel
(
tmp
,
pll
->
base
);
/* Enable BYPASS */
tmp
|=
BYPASS_MASK
;
writel
(
tmp
,
pll
->
base
);
div_val
=
(
rate
->
mdiv
<<
MDIV_SHIFT
)
|
(
rate
->
pdiv
<<
PDIV_SHIFT
)
|
(
rate
->
sdiv
<<
SDIV_SHIFT
);
writel
(
div_val
,
pll
->
base
+
0x4
);
writel
(
rate
->
kdiv
<<
KDIV_SHIFT
,
pll
->
base
+
0x8
);
/*
* According to SPEC, t3 - t2 need to be greater than
* 1us and 1/FREF, respectively.
* FREF is FIN / Prediv, the prediv is [1, 63], so choose
* 3us.
*/
udelay
(
3
);
/* Disable RST */
tmp
|=
RST_MASK
;
writel
(
tmp
,
pll
->
base
);
/* Wait Lock*/
ret
=
clk_pll14xx_wait_lock
(
pll
);
if
(
ret
)
return
ret
;
/* Bypass */
tmp
&=
~
BYPASS_MASK
;
writel
(
tmp
,
pll
->
base
);
return
clk_pll1443x_recalc_rate
(
clk
);
}
static
int
clk_pll14xx_prepare
(
struct
clk
*
clk
)
{
struct
clk_pll14xx
*
pll
=
to_clk_pll14xx
(
dev_get_clk_ptr
(
clk
->
dev
));
u32
val
;
/*
* RESETB = 1 from 0, PLL starts its normal
* operation after lock time
*/
val
=
readl
(
pll
->
base
+
GNRL_CTL
);
val
|=
RST_MASK
;
writel
(
val
,
pll
->
base
+
GNRL_CTL
);
return
clk_pll14xx_wait_lock
(
pll
);
}
static
int
clk_pll14xx_unprepare
(
struct
clk
*
clk
)
{
struct
clk_pll14xx
*
pll
=
to_clk_pll14xx
(
dev_get_clk_ptr
(
clk
->
dev
));
u32
val
;
/*
* Set RST to 0, power down mode is enabled and
* every digital block is reset
*/
val
=
readl
(
pll
->
base
+
GNRL_CTL
);
val
&=
~
RST_MASK
;
writel
(
val
,
pll
->
base
+
GNRL_CTL
);
return
0
;
}
static
const
struct
clk_ops
clk_pll1416x_ops
=
{
.
enable
=
clk_pll14xx_prepare
,
.
disable
=
clk_pll14xx_unprepare
,
.
set_rate
=
clk_pll1416x_set_rate
,
.
get_rate
=
clk_pll1416x_recalc_rate
,
};
static
const
struct
clk_ops
clk_pll1443x_ops
=
{
.
enable
=
clk_pll14xx_prepare
,
.
disable
=
clk_pll14xx_unprepare
,
.
set_rate
=
clk_pll1443x_set_rate
,
.
get_rate
=
clk_pll1443x_recalc_rate
,
};
struct
clk
*
imx_clk_pll14xx
(
const
char
*
name
,
const
char
*
parent_name
,
void
__iomem
*
base
,
const
struct
imx_pll14xx_clk
*
pll_clk
)
{
struct
clk_pll14xx
*
pll
;
struct
clk
*
clk
;
char
*
type_name
;
int
ret
;
pll
=
kzalloc
(
sizeof
(
*
pll
),
GFP_KERNEL
);
if
(
!
pll
)
return
ERR_PTR
(
-
ENOMEM
);
switch
(
pll_clk
->
type
)
{
case
PLL_1416X
:
type_name
=
UBOOT_DM_CLK_IMX_PLL1416X
;
break
;
case
PLL_1443X
:
type_name
=
UBOOT_DM_CLK_IMX_PLL1443X
;
break
;
default:
pr_err
(
"%s: Unknown pll type for pll clk %s
\n
"
,
__func__
,
name
);
return
ERR_PTR
(
-
EINVAL
);
};
pll
->
base
=
base
;
pll
->
type
=
pll_clk
->
type
;
pll
->
rate_table
=
pll_clk
->
rate_table
;
pll
->
rate_count
=
pll_clk
->
rate_count
;
clk
=
&
pll
->
clk
;
ret
=
clk_register
(
clk
,
type_name
,
name
,
parent_name
);
if
(
ret
)
{
pr_err
(
"%s: failed to register pll %s %d
\n
"
,
__func__
,
name
,
ret
);
kfree
(
pll
);
return
ERR_PTR
(
ret
);
}
return
clk
;
}
U_BOOT_DRIVER
(
clk_pll1443x
)
=
{
.
name
=
UBOOT_DM_CLK_IMX_PLL1443X
,
.
id
=
UCLASS_CLK
,
.
ops
=
&
clk_pll1443x_ops
,
.
flags
=
DM_FLAG_PRE_RELOC
,
};
U_BOOT_DRIVER
(
clk_pll1416x
)
=
{
.
name
=
UBOOT_DM_CLK_IMX_PLL1416X
,
.
id
=
UCLASS_CLK
,
.
ops
=
&
clk_pll1416x_ops
,
.
flags
=
DM_FLAG_PRE_RELOC
,
};
drivers/clk/imx/clk.h
浏览文件 @
b242d1b1
...
...
@@ -20,6 +20,31 @@ enum imx_pllv3_type {
IMX_PLLV3_DDR_IMX7
,
};
enum
imx_pll14xx_type
{
PLL_1416X
,
PLL_1443X
,
};
/* NOTE: Rate table should be kept sorted in descending order. */
struct
imx_pll14xx_rate_table
{
unsigned
int
rate
;
unsigned
int
pdiv
;
unsigned
int
mdiv
;
unsigned
int
sdiv
;
unsigned
int
kdiv
;
};
struct
imx_pll14xx_clk
{
enum
imx_pll14xx_type
type
;
const
struct
imx_pll14xx_rate_table
*
rate_table
;
int
rate_count
;
int
flags
;
};
struct
clk
*
imx_clk_pll14xx
(
const
char
*
name
,
const
char
*
parent_name
,
void
__iomem
*
base
,
const
struct
imx_pll14xx_clk
*
pll_clk
);
struct
clk
*
clk_register_gate2
(
struct
device
*
dev
,
const
char
*
name
,
const
char
*
parent_name
,
unsigned
long
flags
,
void
__iomem
*
reg
,
u8
bit_idx
,
u8
cgr_val
,
...
...
include/clk.h
浏览文件 @
b242d1b1
...
...
@@ -61,6 +61,7 @@ struct clk {
struct
udevice
*
dev
;
long
long
rate
;
/* in HZ */
u32
flags
;
int
enable_count
;
/*
* Written by of_xlate. In the future, we might add more fields here.
*/
...
...
include/sandbox-clk.h
浏览文件 @
b242d1b1
...
...
@@ -20,6 +20,7 @@ enum {
SANDBOX_CLK_USDHC1_SEL
,
SANDBOX_CLK_USDHC2_SEL
,
SANDBOX_CLK_I2C
,
SANDBOX_CLK_I2C_ROOT
,
};
enum
sandbox_pllv3_type
{
...
...
@@ -74,4 +75,6 @@ static inline struct clk *sandbox_clk_mux(const char *name, void __iomem *reg,
width
,
0
);
}
int
sandbox_clk_enable_count
(
struct
clk
*
clk
);
#endif
/* __SANDBOX_CLK_H__ */
test/dm/clk_ccf.c
浏览文件 @
b242d1b1
...
...
@@ -64,6 +64,34 @@ static int dm_test_clk_ccf(struct unit_test_state *uts)
rate
=
clk_get_rate
(
clk
);
ut_asserteq
(
rate
,
60000000
);
#if CONFIG_IS_ENABLED(CLK_CCF)
/* Test clk tree enable/disable */
ret
=
clk_get_by_id
(
SANDBOX_CLK_I2C_ROOT
,
&
clk
);
ut_assertok
(
ret
);
ut_asserteq_str
(
"i2c_root"
,
clk
->
dev
->
name
);
ret
=
clk_enable
(
clk
);
ut_assertok
(
ret
);
ret
=
sandbox_clk_enable_count
(
clk
);
ut_asserteq
(
ret
,
1
);
ret
=
clk_get_by_id
(
SANDBOX_CLK_I2C
,
&
pclk
);
ut_assertok
(
ret
);
ret
=
sandbox_clk_enable_count
(
pclk
);
ut_asserteq
(
ret
,
1
);
ret
=
clk_disable
(
clk
);
ut_assertok
(
ret
);
ret
=
sandbox_clk_enable_count
(
clk
);
ut_asserteq
(
ret
,
0
);
ret
=
sandbox_clk_enable_count
(
pclk
);
ut_asserteq
(
ret
,
0
);
#endif
return
1
;
}
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录