Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
OpenHarmony
kernel_linux
提交
f49540d1
K
kernel_linux
项目概览
OpenHarmony
/
kernel_linux
上一次同步 4 年多
通知
15
Star
8
Fork
2
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
K
kernel_linux
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
You need to sign in or sign up before continuing.
提交
f49540d1
编写于
9月 14, 2012
作者:
S
Stephen Warren
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'for-3.7/common-clk' into for-3.7/cleanup2
上级
1f10478c
b4350f40
变更
14
展开全部
隐藏空白更改
内联
并排
Showing
14 changed file
with
5103 addition
and
2297 deletion
+5103
-2297
arch/arm/Kconfig
arch/arm/Kconfig
+1
-0
arch/arm/mach-tegra/Makefile
arch/arm/mach-tegra/Makefile
+3
-1
arch/arm/mach-tegra/board-dt-tegra20.c
arch/arm/mach-tegra/board-dt-tegra20.c
+1
-0
arch/arm/mach-tegra/clock.c
arch/arm/mach-tegra/clock.c
+31
-539
arch/arm/mach-tegra/clock.h
arch/arm/mach-tegra/clock.h
+11
-29
arch/arm/mach-tegra/common.c
arch/arm/mach-tegra/common.c
+0
-1
arch/arm/mach-tegra/cpu-tegra.c
arch/arm/mach-tegra/cpu-tegra.c
+47
-1
arch/arm/mach-tegra/include/mach/clk.h
arch/arm/mach-tegra/include/mach/clk.h
+3
-0
arch/arm/mach-tegra/tegra20_clocks.c
arch/arm/mach-tegra/tegra20_clocks.c
+1555
-0
arch/arm/mach-tegra/tegra20_clocks.h
arch/arm/mach-tegra/tegra20_clocks.h
+42
-0
arch/arm/mach-tegra/tegra20_clocks_data.c
arch/arm/mach-tegra/tegra20_clocks_data.c
+1142
-0
arch/arm/mach-tegra/tegra30_clocks.c
arch/arm/mach-tegra/tegra30_clocks.c
+845
-1726
arch/arm/mach-tegra/tegra30_clocks.h
arch/arm/mach-tegra/tegra30_clocks.h
+53
-0
arch/arm/mach-tegra/tegra30_clocks_data.c
arch/arm/mach-tegra/tegra30_clocks_data.c
+1369
-0
未找到文件。
arch/arm/Kconfig
浏览文件 @
f49540d1
...
...
@@ -686,6 +686,7 @@ config ARCH_TEGRA
select NEED_MACH_IO_H if PCI
select ARCH_HAS_CPUFREQ
select USE_OF
select COMMON_CLK
help
This enables support for NVIDIA Tegra based systems (Tegra APX,
Tegra 6xx and Tegra 2 series).
...
...
arch/arm/mach-tegra/Makefile
浏览文件 @
f49540d1
...
...
@@ -12,9 +12,11 @@ obj-y += powergate.o
obj-y
+=
apbio.o
obj-$(CONFIG_CPU_IDLE)
+=
cpuidle.o
obj-$(CONFIG_CPU_IDLE)
+=
sleep.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC)
+=
tegra2_clocks.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC)
+=
tegra20_clocks.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC)
+=
tegra20_clocks_data.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC)
+=
tegra2_emc.o
obj-$(CONFIG_ARCH_TEGRA_3x_SOC)
+=
tegra30_clocks.o
obj-$(CONFIG_ARCH_TEGRA_3x_SOC)
+=
tegra30_clocks_data.o
obj-$(CONFIG_SMP)
+=
platsmp.o headsmp.o
obj-$(CONFIG_SMP)
+=
reset.o
obj-$(CONFIG_HOTPLUG_CPU)
+=
hotplug.o
...
...
arch/arm/mach-tegra/board-dt-tegra20.c
浏览文件 @
f49540d1
...
...
@@ -70,6 +70,7 @@ struct of_dev_auxdata tegra20_auxdata_lookup[] __initdata = {
static
__initdata
struct
tegra_clk_init_table
tegra_dt_clk_init_table
[]
=
{
/* name parent rate enabled */
{
"uarta"
,
"pll_p"
,
216000000
,
true
},
{
"uartd"
,
"pll_p"
,
216000000
,
true
},
{
"usbd"
,
"clk_m"
,
12000000
,
false
},
{
"usb2"
,
"clk_m"
,
12000000
,
false
},
...
...
arch/arm/mach-tegra/clock.c
浏览文件 @
f49540d1
/*
*
* Copyright (C) 2010 Google, Inc.
* Copyright (c) 2012 NVIDIA CORPORATION. All rights reserved.
*
* Author:
* Colin Cross <ccross@google.com>
...
...
@@ -19,8 +20,6 @@
#include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/module.h>
...
...
@@ -36,321 +35,67 @@
/*
* Locking:
*
* Each struct clk has a spinlock.
*
* To avoid AB-BA locking problems, locks must always be traversed from child
* clock to parent clock. For example, when enabling a clock, the clock's lock
* is taken, and then clk_enable is called on the parent, which take's the
* parent clock's lock. There is one exceptions to this ordering: When dumping
* the clock tree through debugfs. In this case, clk_lock_all is called,
* which attemps to iterate through the entire list of clocks and take every
* clock lock. If any call to spin_trylock fails, all locked clocks are
* unlocked, and the process is retried. When all the locks are held,
* the only clock operation that can be called is clk_get_rate_all_locked.
*
* Within a single clock, no clock operation can call another clock operation
* on itself, except for clk_get_rate_locked and clk_set_rate_locked. Any
* clock operation can call any other clock operation on any of it's possible
* parents.
*
* An additional mutex, clock_list_lock, is used to protect the list of all
* clocks.
*
* The clock operations must lock internally to protect against
* read-modify-write on registers that are shared by multiple clocks
*/
static
DEFINE_MUTEX
(
clock_list_lock
);
static
LIST_HEAD
(
clocks
);
struct
clk
*
tegra_get_clock_by_name
(
const
char
*
name
)
void
tegra_clk_add
(
struct
clk
*
clk
)
{
struct
clk
*
c
;
struct
clk
*
ret
=
NULL
;
mutex_lock
(
&
clock_list_lock
);
list_for_each_entry
(
c
,
&
clocks
,
node
)
{
if
(
strcmp
(
c
->
name
,
name
)
==
0
)
{
ret
=
c
;
break
;
}
}
mutex_unlock
(
&
clock_list_lock
);
return
ret
;
}
/* Must be called with c->spinlock held */
static
unsigned
long
clk_predict_rate_from_parent
(
struct
clk
*
c
,
struct
clk
*
p
)
{
u64
rate
;
rate
=
clk_get_rate
(
p
);
if
(
c
->
mul
!=
0
&&
c
->
div
!=
0
)
{
rate
*=
c
->
mul
;
rate
+=
c
->
div
-
1
;
/* round up */
do_div
(
rate
,
c
->
div
);
}
return
rate
;
}
/* Must be called with c->spinlock held */
unsigned
long
clk_get_rate_locked
(
struct
clk
*
c
)
{
unsigned
long
rate
;
if
(
c
->
parent
)
rate
=
clk_predict_rate_from_parent
(
c
,
c
->
parent
);
else
rate
=
c
->
rate
;
return
rate
;
}
unsigned
long
clk_get_rate
(
struct
clk
*
c
)
{
unsigned
long
flags
;
unsigned
long
rate
;
spin_lock_irqsave
(
&
c
->
spinlock
,
flags
);
rate
=
clk_get_rate_locked
(
c
);
spin_unlock_irqrestore
(
&
c
->
spinlock
,
flags
);
return
rate
;
}
EXPORT_SYMBOL
(
clk_get_rate
);
int
clk_reparent
(
struct
clk
*
c
,
struct
clk
*
parent
)
{
c
->
parent
=
parent
;
return
0
;
}
void
clk_init
(
struct
clk
*
c
)
{
spin_lock_init
(
&
c
->
spinlock
);
if
(
c
->
ops
&&
c
->
ops
->
init
)
c
->
ops
->
init
(
c
);
if
(
!
c
->
ops
||
!
c
->
ops
->
enable
)
{
c
->
refcnt
++
;
c
->
set
=
true
;
if
(
c
->
parent
)
c
->
state
=
c
->
parent
->
state
;
else
c
->
state
=
ON
;
}
struct
clk_tegra
*
c
=
to_clk_tegra
(
__clk_get_hw
(
clk
));
mutex_lock
(
&
clock_list_lock
);
list_add
(
&
c
->
node
,
&
clocks
);
mutex_unlock
(
&
clock_list_lock
);
}
int
clk_enable
(
struct
clk
*
c
)
{
int
ret
=
0
;
unsigned
long
flags
;
spin_lock_irqsave
(
&
c
->
spinlock
,
flags
);
if
(
c
->
refcnt
==
0
)
{
if
(
c
->
parent
)
{
ret
=
clk_enable
(
c
->
parent
);
if
(
ret
)
goto
out
;
}
if
(
c
->
ops
&&
c
->
ops
->
enable
)
{
ret
=
c
->
ops
->
enable
(
c
);
if
(
ret
)
{
if
(
c
->
parent
)
clk_disable
(
c
->
parent
);
goto
out
;
}
c
->
state
=
ON
;
c
->
set
=
true
;
}
}
c
->
refcnt
++
;
out:
spin_unlock_irqrestore
(
&
c
->
spinlock
,
flags
);
return
ret
;
}
EXPORT_SYMBOL
(
clk_enable
);
void
clk_disable
(
struct
clk
*
c
)
{
unsigned
long
flags
;
spin_lock_irqsave
(
&
c
->
spinlock
,
flags
);
if
(
c
->
refcnt
==
0
)
{
WARN
(
1
,
"Attempting to disable clock %s with refcnt 0"
,
c
->
name
);
spin_unlock_irqrestore
(
&
c
->
spinlock
,
flags
);
return
;
}
if
(
c
->
refcnt
==
1
)
{
if
(
c
->
ops
&&
c
->
ops
->
disable
)
c
->
ops
->
disable
(
c
);
if
(
c
->
parent
)
clk_disable
(
c
->
parent
);
c
->
state
=
OFF
;
}
c
->
refcnt
--
;
spin_unlock_irqrestore
(
&
c
->
spinlock
,
flags
);
}
EXPORT_SYMBOL
(
clk_disable
);
int
clk_set_parent
(
struct
clk
*
c
,
struct
clk
*
parent
)
{
int
ret
;
unsigned
long
flags
;
unsigned
long
new_rate
;
unsigned
long
old_rate
;
spin_lock_irqsave
(
&
c
->
spinlock
,
flags
);
if
(
!
c
->
ops
||
!
c
->
ops
->
set_parent
)
{
ret
=
-
ENOSYS
;
goto
out
;
}
new_rate
=
clk_predict_rate_from_parent
(
c
,
parent
);
old_rate
=
clk_get_rate_locked
(
c
);
ret
=
c
->
ops
->
set_parent
(
c
,
parent
);
if
(
ret
)
goto
out
;
out:
spin_unlock_irqrestore
(
&
c
->
spinlock
,
flags
);
return
ret
;
}
EXPORT_SYMBOL
(
clk_set_parent
);
struct
clk
*
clk_get_parent
(
struct
clk
*
c
)
{
return
c
->
parent
;
}
EXPORT_SYMBOL
(
clk_get_parent
);
int
clk_set_rate_locked
(
struct
clk
*
c
,
unsigned
long
rate
)
{
long
new_rate
;
if
(
!
c
->
ops
||
!
c
->
ops
->
set_rate
)
return
-
ENOSYS
;
if
(
rate
>
c
->
max_rate
)
rate
=
c
->
max_rate
;
if
(
c
->
ops
&&
c
->
ops
->
round_rate
)
{
new_rate
=
c
->
ops
->
round_rate
(
c
,
rate
);
if
(
new_rate
<
0
)
return
new_rate
;
rate
=
new_rate
;
}
return
c
->
ops
->
set_rate
(
c
,
rate
);
}
int
clk_set_rate
(
struct
clk
*
c
,
unsigned
long
rate
)
{
int
ret
;
unsigned
long
flags
;
spin_lock_irqsave
(
&
c
->
spinlock
,
flags
);
ret
=
clk_set_rate_locked
(
c
,
rate
);
spin_unlock_irqrestore
(
&
c
->
spinlock
,
flags
);
return
ret
;
}
EXPORT_SYMBOL
(
clk_set_rate
);
/* Must be called with clocks lock and all indvidual clock locks held */
unsigned
long
clk_get_rate_all_locked
(
struct
clk
*
c
)
struct
clk
*
tegra_get_clock_by_name
(
const
char
*
name
)
{
u64
rate
;
int
mul
=
1
;
int
div
=
1
;
struct
clk
*
p
=
c
;
while
(
p
)
{
c
=
p
;
if
(
c
->
mul
!=
0
&&
c
->
div
!=
0
)
{
mul
*=
c
->
mul
;
div
*=
c
->
div
;
struct
clk_tegra
*
c
;
struct
clk
*
ret
=
NULL
;
mutex_lock
(
&
clock_list_lock
);
list_for_each_entry
(
c
,
&
clocks
,
node
)
{
if
(
strcmp
(
__clk_get_name
(
c
->
hw
.
clk
),
name
)
==
0
)
{
ret
=
c
->
hw
.
clk
;
break
;
}
p
=
c
->
parent
;
}
rate
=
c
->
rate
;
rate
*=
mul
;
do_div
(
rate
,
div
);
return
rate
;
}
long
clk_round_rate
(
struct
clk
*
c
,
unsigned
long
rate
)
{
unsigned
long
flags
;
long
ret
;
spin_lock_irqsave
(
&
c
->
spinlock
,
flags
);
if
(
!
c
->
ops
||
!
c
->
ops
->
round_rate
)
{
ret
=
-
ENOSYS
;
goto
out
;
}
if
(
rate
>
c
->
max_rate
)
rate
=
c
->
max_rate
;
ret
=
c
->
ops
->
round_rate
(
c
,
rate
);
out:
spin_unlock_irqrestore
(
&
c
->
spinlock
,
flags
);
mutex_unlock
(
&
clock_list_lock
);
return
ret
;
}
EXPORT_SYMBOL
(
clk_round_rate
);
static
int
tegra_clk_init_one_from_table
(
struct
tegra_clk_init_table
*
table
)
{
struct
clk
*
c
;
struct
clk
*
p
;
struct
clk
*
parent
;
int
ret
=
0
;
c
=
tegra_get_clock_by_name
(
table
->
name
);
if
(
!
c
)
{
pr_warn
ing
(
"Unable to initialize clock %s
\n
"
,
pr_warn
(
"Unable to initialize clock %s
\n
"
,
table
->
name
);
return
-
ENODEV
;
}
parent
=
clk_get_parent
(
c
);
if
(
table
->
parent
)
{
p
=
tegra_get_clock_by_name
(
table
->
parent
);
if
(
!
p
)
{
pr_warn
ing
(
"Unable to find parent %s of clock %s
\n
"
,
pr_warn
(
"Unable to find parent %s of clock %s
\n
"
,
table
->
parent
,
table
->
name
);
return
-
ENODEV
;
}
if
(
c
->
parent
!=
p
)
{
if
(
parent
!=
p
)
{
ret
=
clk_set_parent
(
c
,
p
);
if
(
ret
)
{
pr_warn
ing
(
"Unable to set parent %s of clock %s: %d
\n
"
,
pr_warn
(
"Unable to set parent %s of clock %s: %d
\n
"
,
table
->
parent
,
table
->
name
,
ret
);
return
-
EINVAL
;
}
...
...
@@ -360,16 +105,16 @@ static int tegra_clk_init_one_from_table(struct tegra_clk_init_table *table)
if
(
table
->
rate
&&
table
->
rate
!=
clk_get_rate
(
c
))
{
ret
=
clk_set_rate
(
c
,
table
->
rate
);
if
(
ret
)
{
pr_warn
ing
(
"Unable to set clock %s to rate %lu: %d
\n
"
,
pr_warn
(
"Unable to set clock %s to rate %lu: %d
\n
"
,
table
->
name
,
table
->
rate
,
ret
);
return
-
EINVAL
;
}
}
if
(
table
->
enabled
)
{
ret
=
clk_enable
(
c
);
ret
=
clk_
prepare_
enable
(
c
);
if
(
ret
)
{
pr_warn
ing
(
"Unable to enable clock %s: %d
\n
"
,
pr_warn
(
"Unable to enable clock %s: %d
\n
"
,
table
->
name
,
ret
);
return
-
EINVAL
;
}
...
...
@@ -383,19 +128,20 @@ void tegra_clk_init_from_table(struct tegra_clk_init_table *table)
for
(;
table
->
name
;
table
++
)
tegra_clk_init_one_from_table
(
table
);
}
EXPORT_SYMBOL
(
tegra_clk_init_from_table
);
void
tegra_periph_reset_deassert
(
struct
clk
*
c
)
{
BUG_ON
(
!
c
->
ops
->
reset
);
c
->
ops
->
reset
(
c
,
false
);
struct
clk_tegra
*
clk
=
to_clk_tegra
(
__clk_get_hw
(
c
));
BUG_ON
(
!
clk
->
reset
);
clk
->
reset
(
__clk_get_hw
(
c
),
false
);
}
EXPORT_SYMBOL
(
tegra_periph_reset_deassert
);
void
tegra_periph_reset_assert
(
struct
clk
*
c
)
{
BUG_ON
(
!
c
->
ops
->
reset
);
c
->
ops
->
reset
(
c
,
true
);
struct
clk_tegra
*
clk
=
to_clk_tegra
(
__clk_get_hw
(
c
));
BUG_ON
(
!
clk
->
reset
);
clk
->
reset
(
__clk_get_hw
(
c
),
true
);
}
EXPORT_SYMBOL
(
tegra_periph_reset_assert
);
...
...
@@ -405,268 +151,14 @@ EXPORT_SYMBOL(tegra_periph_reset_assert);
int
tegra_clk_cfg_ex
(
struct
clk
*
c
,
enum
tegra_clk_ex_param
p
,
u32
setting
)
{
int
ret
=
0
;
unsigned
long
flags
;
struct
clk_tegra
*
clk
=
to_clk_tegra
(
__clk_get_hw
(
c
))
;
spin_lock_irqsave
(
&
c
->
spinlock
,
flags
);
if
(
!
c
->
ops
||
!
c
->
ops
->
clk_cfg_ex
)
{
if
(
!
clk
->
clk_cfg_ex
)
{
ret
=
-
ENOSYS
;
goto
out
;
}
ret
=
c
->
ops
->
clk_cfg_ex
(
c
,
p
,
setting
);
ret
=
c
lk
->
clk_cfg_ex
(
__clk_get_hw
(
c
)
,
p
,
setting
);
out:
spin_unlock_irqrestore
(
&
c
->
spinlock
,
flags
);
return
ret
;
}
#ifdef CONFIG_DEBUG_FS
static
int
__clk_lock_all_spinlocks
(
void
)
{
struct
clk
*
c
;
list_for_each_entry
(
c
,
&
clocks
,
node
)
if
(
!
spin_trylock
(
&
c
->
spinlock
))
goto
unlock_spinlocks
;
return
0
;
unlock_spinlocks:
list_for_each_entry_continue_reverse
(
c
,
&
clocks
,
node
)
spin_unlock
(
&
c
->
spinlock
);
return
-
EAGAIN
;
}
static
void
__clk_unlock_all_spinlocks
(
void
)
{
struct
clk
*
c
;
list_for_each_entry_reverse
(
c
,
&
clocks
,
node
)
spin_unlock
(
&
c
->
spinlock
);
}
/*
* This function retries until it can take all locks, and may take
* an arbitrarily long time to complete.
* Must be called with irqs enabled, returns with irqs disabled
* Must be called with clock_list_lock held
*/
static
void
clk_lock_all
(
void
)
{
int
ret
;
retry:
local_irq_disable
();
ret
=
__clk_lock_all_spinlocks
();
if
(
ret
)
goto
failed_spinlocks
;
/* All locks taken successfully, return */
return
;
failed_spinlocks:
local_irq_enable
();
yield
();
goto
retry
;
}
/*
* Unlocks all clocks after a clk_lock_all
* Must be called with irqs disabled, returns with irqs enabled
* Must be called with clock_list_lock held
*/
static
void
clk_unlock_all
(
void
)
{
__clk_unlock_all_spinlocks
();
local_irq_enable
();
}
static
struct
dentry
*
clk_debugfs_root
;
static
void
clock_tree_show_one
(
struct
seq_file
*
s
,
struct
clk
*
c
,
int
level
)
{
struct
clk
*
child
;
const
char
*
state
=
"uninit"
;
char
div
[
8
]
=
{
0
};
if
(
c
->
state
==
ON
)
state
=
"on"
;
else
if
(
c
->
state
==
OFF
)
state
=
"off"
;
if
(
c
->
mul
!=
0
&&
c
->
div
!=
0
)
{
if
(
c
->
mul
>
c
->
div
)
{
int
mul
=
c
->
mul
/
c
->
div
;
int
mul2
=
(
c
->
mul
*
10
/
c
->
div
)
%
10
;
int
mul3
=
(
c
->
mul
*
10
)
%
c
->
div
;
if
(
mul2
==
0
&&
mul3
==
0
)
snprintf
(
div
,
sizeof
(
div
),
"x%d"
,
mul
);
else
if
(
mul3
==
0
)
snprintf
(
div
,
sizeof
(
div
),
"x%d.%d"
,
mul
,
mul2
);
else
snprintf
(
div
,
sizeof
(
div
),
"x%d.%d.."
,
mul
,
mul2
);
}
else
{
snprintf
(
div
,
sizeof
(
div
),
"%d%s"
,
c
->
div
/
c
->
mul
,
(
c
->
div
%
c
->
mul
)
?
".5"
:
""
);
}
}
seq_printf
(
s
,
"%*s%c%c%-*s %-6s %-3d %-8s %-10lu
\n
"
,
level
*
3
+
1
,
""
,
c
->
rate
>
c
->
max_rate
?
'!'
:
' '
,
!
c
->
set
?
'*'
:
' '
,
30
-
level
*
3
,
c
->
name
,
state
,
c
->
refcnt
,
div
,
clk_get_rate_all_locked
(
c
));
list_for_each_entry
(
child
,
&
clocks
,
node
)
{
if
(
child
->
parent
!=
c
)
continue
;
clock_tree_show_one
(
s
,
child
,
level
+
1
);
}
}
static
int
clock_tree_show
(
struct
seq_file
*
s
,
void
*
data
)
{
struct
clk
*
c
;
seq_printf
(
s
,
" clock state ref div rate
\n
"
);
seq_printf
(
s
,
"--------------------------------------------------------------
\n
"
);
mutex_lock
(
&
clock_list_lock
);
clk_lock_all
();
list_for_each_entry
(
c
,
&
clocks
,
node
)
if
(
c
->
parent
==
NULL
)
clock_tree_show_one
(
s
,
c
,
0
);
clk_unlock_all
();
mutex_unlock
(
&
clock_list_lock
);
return
0
;
}
static
int
clock_tree_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
return
single_open
(
file
,
clock_tree_show
,
inode
->
i_private
);
}
static
const
struct
file_operations
clock_tree_fops
=
{
.
open
=
clock_tree_open
,
.
read
=
seq_read
,
.
llseek
=
seq_lseek
,
.
release
=
single_release
,
};
static
int
possible_parents_show
(
struct
seq_file
*
s
,
void
*
data
)
{
struct
clk
*
c
=
s
->
private
;
int
i
;
for
(
i
=
0
;
c
->
inputs
[
i
].
input
;
i
++
)
{
char
*
first
=
(
i
==
0
)
?
""
:
" "
;
seq_printf
(
s
,
"%s%s"
,
first
,
c
->
inputs
[
i
].
input
->
name
);
}
seq_printf
(
s
,
"
\n
"
);
return
0
;
}
static
int
possible_parents_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
return
single_open
(
file
,
possible_parents_show
,
inode
->
i_private
);
}
static
const
struct
file_operations
possible_parents_fops
=
{
.
open
=
possible_parents_open
,
.
read
=
seq_read
,
.
llseek
=
seq_lseek
,
.
release
=
single_release
,
};
static
int
clk_debugfs_register_one
(
struct
clk
*
c
)
{
struct
dentry
*
d
;
d
=
debugfs_create_dir
(
c
->
name
,
clk_debugfs_root
);
if
(
!
d
)
return
-
ENOMEM
;
c
->
dent
=
d
;
d
=
debugfs_create_u8
(
"refcnt"
,
S_IRUGO
,
c
->
dent
,
(
u8
*
)
&
c
->
refcnt
);
if
(
!
d
)
goto
err_out
;
d
=
debugfs_create_u32
(
"rate"
,
S_IRUGO
,
c
->
dent
,
(
u32
*
)
&
c
->
rate
);
if
(
!
d
)
goto
err_out
;
d
=
debugfs_create_x32
(
"flags"
,
S_IRUGO
,
c
->
dent
,
(
u32
*
)
&
c
->
flags
);
if
(
!
d
)
goto
err_out
;
if
(
c
->
inputs
)
{
d
=
debugfs_create_file
(
"possible_parents"
,
S_IRUGO
,
c
->
dent
,
c
,
&
possible_parents_fops
);
if
(
!
d
)
goto
err_out
;
}
return
0
;
err_out:
debugfs_remove_recursive
(
c
->
dent
);
return
-
ENOMEM
;
}
static
int
clk_debugfs_register
(
struct
clk
*
c
)
{
int
err
;
struct
clk
*
pa
=
c
->
parent
;
if
(
pa
&&
!
pa
->
dent
)
{
err
=
clk_debugfs_register
(
pa
);
if
(
err
)
return
err
;
}
if
(
!
c
->
dent
)
{
err
=
clk_debugfs_register_one
(
c
);
if
(
err
)
return
err
;
}
return
0
;
}
int
__init
tegra_clk_debugfs_init
(
void
)
{
struct
clk
*
c
;
struct
dentry
*
d
;
int
err
=
-
ENOMEM
;
d
=
debugfs_create_dir
(
"clock"
,
NULL
);
if
(
!
d
)
return
-
ENOMEM
;
clk_debugfs_root
=
d
;
d
=
debugfs_create_file
(
"clock_tree"
,
S_IRUGO
,
clk_debugfs_root
,
NULL
,
&
clock_tree_fops
);
if
(
!
d
)
goto
err_out
;
list_for_each_entry
(
c
,
&
clocks
,
node
)
{
err
=
clk_debugfs_register
(
c
);
if
(
err
)
goto
err_out
;
}
return
0
;
err_out:
debugfs_remove_recursive
(
clk_debugfs_root
);
return
err
;
}
#endif
arch/arm/mach-tegra/clock.h
浏览文件 @
f49540d1
...
...
@@ -2,6 +2,7 @@
* arch/arm/mach-tegra/include/mach/clock.h
*
* Copyright (C) 2010 Google, Inc.
* Copyright (c) 2012 NVIDIA CORPORATION. All rights reserved.
*
* Author:
* Colin Cross <ccross@google.com>
...
...
@@ -20,9 +21,9 @@
#ifndef __MACH_TEGRA_CLOCK_H
#define __MACH_TEGRA_CLOCK_H
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <mach/clk.h>
...
...
@@ -52,7 +53,8 @@
#define ENABLE_ON_INIT (1 << 28)
#define PERIPH_ON_APB (1 << 29)
struct
clk
;
struct
clk_tegra
;
#define to_clk_tegra(_hw) container_of(_hw, struct clk_tegra, hw)
struct
clk_mux_sel
{
struct
clk
*
input
;
...
...
@@ -68,47 +70,29 @@ struct clk_pll_freq_table {
u8
cpcon
;
};
struct
clk_ops
{
void
(
*
init
)(
struct
clk
*
);
int
(
*
enable
)(
struct
clk
*
);
void
(
*
disable
)(
struct
clk
*
);
int
(
*
set_parent
)(
struct
clk
*
,
struct
clk
*
);
int
(
*
set_rate
)(
struct
clk
*
,
unsigned
long
);
long
(
*
round_rate
)(
struct
clk
*
,
unsigned
long
);
void
(
*
reset
)(
struct
clk
*
,
bool
);
int
(
*
clk_cfg_ex
)(
struct
clk
*
,
enum
tegra_clk_ex_param
,
u32
);
};
enum
clk_state
{
UNINITIALIZED
=
0
,
ON
,
OFF
,
};
struct
clk
{
struct
clk
_tegra
{
/* node for master clocks list */
struct
list_head
node
;
/* node for list of all clocks */
struct
list_head
node
;
/* node for list of all clocks */
struct
clk_lookup
lookup
;
struct
clk_hw
hw
;
#ifdef CONFIG_DEBUG_FS
struct
dentry
*
dent
;
#endif
bool
set
;
struct
clk_ops
*
ops
;
unsigned
long
rate
;
unsigned
long
fixed_rate
;
unsigned
long
max_rate
;
unsigned
long
min_rate
;
u32
flags
;
const
char
*
name
;
u32
refcnt
;
enum
clk_state
state
;
struct
clk
*
parent
;
u32
div
;
u32
mul
;
const
struct
clk_mux_sel
*
inputs
;
u32
reg
;
u32
reg_shift
;
...
...
@@ -144,7 +128,8 @@ struct clk {
}
shared_bus_user
;
}
u
;
spinlock_t
spinlock
;
void
(
*
reset
)(
struct
clk_hw
*
,
bool
);
int
(
*
clk_cfg_ex
)(
struct
clk_hw
*
,
enum
tegra_clk_ex_param
,
u32
);
};
struct
clk_duplicate
{
...
...
@@ -159,13 +144,10 @@ struct tegra_clk_init_table {
bool
enabled
;
};
void
tegra_clk_add
(
struct
clk
*
c
);
void
tegra2_init_clocks
(
void
);
void
tegra30_init_clocks
(
void
);
void
clk_init
(
struct
clk
*
clk
);
struct
clk
*
tegra_get_clock_by_name
(
const
char
*
name
);
int
clk_reparent
(
struct
clk
*
c
,
struct
clk
*
parent
);
void
tegra_clk_init_from_table
(
struct
tegra_clk_init_table
*
table
);
unsigned
long
clk_get_rate_locked
(
struct
clk
*
c
);
int
clk_set_rate_locked
(
struct
clk
*
c
,
unsigned
long
rate
);
#endif
arch/arm/mach-tegra/common.c
浏览文件 @
f49540d1
...
...
@@ -152,6 +152,5 @@ void __init tegra30_init_early(void)
void
__init
tegra_init_late
(
void
)
{
tegra_clk_debugfs_init
();
tegra_powergate_debugfs_init
();
}
arch/arm/mach-tegra/cpu-tegra.c
浏览文件 @
f49540d1
...
...
@@ -49,6 +49,8 @@ static struct cpufreq_frequency_table freq_table[] = {
#define NUM_CPUS 2
static
struct
clk
*
cpu_clk
;
static
struct
clk
*
pll_x_clk
;
static
struct
clk
*
pll_p_clk
;
static
struct
clk
*
emc_clk
;
static
unsigned
long
target_cpu_speed
[
NUM_CPUS
];
...
...
@@ -71,6 +73,42 @@ static unsigned int tegra_getspeed(unsigned int cpu)
return
rate
;
}
static
int
tegra_cpu_clk_set_rate
(
unsigned
long
rate
)
{
int
ret
;
/*
* Take an extra reference to the main pll so it doesn't turn
* off when we move the cpu off of it
*/
clk_prepare_enable
(
pll_x_clk
);
ret
=
clk_set_parent
(
cpu_clk
,
pll_p_clk
);
if
(
ret
)
{
pr_err
(
"Failed to switch cpu to clock pll_p
\n
"
);
goto
out
;
}
if
(
rate
==
clk_get_rate
(
pll_p_clk
))
goto
out
;
ret
=
clk_set_rate
(
pll_x_clk
,
rate
);
if
(
ret
)
{
pr_err
(
"Failed to change pll_x to %lu
\n
"
,
rate
);
goto
out
;
}
ret
=
clk_set_parent
(
cpu_clk
,
pll_x_clk
);
if
(
ret
)
{
pr_err
(
"Failed to switch cpu to clock pll_x
\n
"
);
goto
out
;
}
out:
clk_disable_unprepare
(
pll_x_clk
);
return
ret
;
}
static
int
tegra_update_cpu_speed
(
unsigned
long
rate
)
{
int
ret
=
0
;
...
...
@@ -101,7 +139,7 @@ static int tegra_update_cpu_speed(unsigned long rate)
freqs
.
old
,
freqs
.
new
);
#endif
ret
=
clk_set_rate
(
cpu_clk
,
freqs
.
new
*
1000
);
ret
=
tegra_cpu_clk_set_rate
(
freqs
.
new
*
1000
);
if
(
ret
)
{
pr_err
(
"cpu-tegra: Failed to set cpu frequency to %d kHz
\n
"
,
freqs
.
new
);
...
...
@@ -183,6 +221,14 @@ static int tegra_cpu_init(struct cpufreq_policy *policy)
if
(
IS_ERR
(
cpu_clk
))
return
PTR_ERR
(
cpu_clk
);
pll_x_clk
=
clk_get_sys
(
NULL
,
"pll_x"
);
if
(
IS_ERR
(
pll_x_clk
))
return
PTR_ERR
(
pll_x_clk
);
pll_p_clk
=
clk_get_sys
(
NULL
,
"pll_p"
);
if
(
IS_ERR
(
pll_p_clk
))
return
PTR_ERR
(
pll_p_clk
);
emc_clk
=
clk_get_sys
(
"cpu"
,
"emc"
);
if
(
IS_ERR
(
emc_clk
))
{
clk_put
(
cpu_clk
);
...
...
arch/arm/mach-tegra/include/mach/clk.h
浏览文件 @
f49540d1
...
...
@@ -34,7 +34,10 @@ enum tegra_clk_ex_param {
void
tegra_periph_reset_deassert
(
struct
clk
*
c
);
void
tegra_periph_reset_assert
(
struct
clk
*
c
);
#ifndef CONFIG_COMMON_CLK
unsigned
long
clk_get_rate_all_locked
(
struct
clk
*
c
);
#endif
void
tegra2_sdmmc_tap_delay
(
struct
clk
*
c
,
int
delay
);
int
tegra_clk_cfg_ex
(
struct
clk
*
c
,
enum
tegra_clk_ex_param
p
,
u32
setting
);
...
...
arch/arm/mach-tegra/tegra2_clocks.c
→
arch/arm/mach-tegra/tegra2
0
_clocks.c
浏览文件 @
f49540d1
此差异已折叠。
点击以展开。
arch/arm/mach-tegra/tegra20_clocks.h
0 → 100644
浏览文件 @
f49540d1
/*
* Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __MACH_TEGRA20_CLOCK_H
#define __MACH_TEGRA20_CLOCK_H
extern
struct
clk_ops
tegra_clk_32k_ops
;
extern
struct
clk_ops
tegra_pll_ops
;
extern
struct
clk_ops
tegra_clk_m_ops
;
extern
struct
clk_ops
tegra_pll_div_ops
;
extern
struct
clk_ops
tegra_pllx_ops
;
extern
struct
clk_ops
tegra_plle_ops
;
extern
struct
clk_ops
tegra_clk_double_ops
;
extern
struct
clk_ops
tegra_cdev_clk_ops
;
extern
struct
clk_ops
tegra_audio_sync_clk_ops
;
extern
struct
clk_ops
tegra_super_ops
;
extern
struct
clk_ops
tegra_cpu_ops
;
extern
struct
clk_ops
tegra_twd_ops
;
extern
struct
clk_ops
tegra_cop_ops
;
extern
struct
clk_ops
tegra_bus_ops
;
extern
struct
clk_ops
tegra_blink_clk_ops
;
extern
struct
clk_ops
tegra_emc_clk_ops
;
extern
struct
clk_ops
tegra_periph_clk_ops
;
extern
struct
clk_ops
tegra_clk_shared_bus_ops
;
void
tegra2_periph_clk_reset
(
struct
clk_hw
*
hw
,
bool
assert
);
void
tegra2_cop_clk_reset
(
struct
clk_hw
*
hw
,
bool
assert
);
#endif
arch/arm/mach-tegra/tegra20_clocks_data.c
0 → 100644
浏览文件 @
f49540d1
此差异已折叠。
点击以展开。
arch/arm/mach-tegra/tegra30_clocks.c
浏览文件 @
f49540d1
此差异已折叠。
点击以展开。
arch/arm/mach-tegra/tegra30_clocks.h
0 → 100644
浏览文件 @
f49540d1
/*
* Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __MACH_TEGRA30_CLOCK_H
#define __MACH_TEGRA30_CLOCK_H
extern
struct
clk_ops
tegra30_clk_32k_ops
;
extern
struct
clk_ops
tegra30_clk_m_ops
;
extern
struct
clk_ops
tegra_clk_m_div_ops
;
extern
struct
clk_ops
tegra_pll_ref_ops
;
extern
struct
clk_ops
tegra30_pll_ops
;
extern
struct
clk_ops
tegra30_pll_div_ops
;
extern
struct
clk_ops
tegra_plld_ops
;
extern
struct
clk_ops
tegra30_plle_ops
;
extern
struct
clk_ops
tegra_cml_clk_ops
;
extern
struct
clk_ops
tegra_pciex_clk_ops
;
extern
struct
clk_ops
tegra_sync_source_ops
;
extern
struct
clk_ops
tegra30_audio_sync_clk_ops
;
extern
struct
clk_ops
tegra30_clk_double_ops
;
extern
struct
clk_ops
tegra_clk_out_ops
;
extern
struct
clk_ops
tegra30_super_ops
;
extern
struct
clk_ops
tegra30_blink_clk_ops
;
extern
struct
clk_ops
tegra30_twd_ops
;
extern
struct
clk_ops
tegra30_periph_clk_ops
;
extern
struct
clk_ops
tegra30_dsib_clk_ops
;
extern
struct
clk_ops
tegra_nand_clk_ops
;
extern
struct
clk_ops
tegra_vi_clk_ops
;
extern
struct
clk_ops
tegra_dtv_clk_ops
;
extern
struct
clk_ops
tegra_clk_shared_bus_ops
;
int
tegra30_plld_clk_cfg_ex
(
struct
clk_hw
*
hw
,
enum
tegra_clk_ex_param
p
,
u32
setting
);
void
tegra30_periph_clk_reset
(
struct
clk_hw
*
hw
,
bool
assert
);
int
tegra30_vi_clk_cfg_ex
(
struct
clk_hw
*
hw
,
enum
tegra_clk_ex_param
p
,
u32
setting
);
int
tegra30_nand_clk_cfg_ex
(
struct
clk_hw
*
hw
,
enum
tegra_clk_ex_param
p
,
u32
setting
);
int
tegra30_dtv_clk_cfg_ex
(
struct
clk_hw
*
hw
,
enum
tegra_clk_ex_param
p
,
u32
setting
);
#endif
arch/arm/mach-tegra/tegra30_clocks_data.c
0 → 100644
浏览文件 @
f49540d1
此差异已折叠。
点击以展开。
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录