Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
cloud-kernel
提交
045da4e5
cloud-kernel
项目概览
openanolis
/
cloud-kernel
大约 1 年 前同步成功
通知
158
Star
36
Fork
7
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
10
列表
看板
标记
里程碑
合并请求
2
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
cloud-kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
10
Issue
10
列表
看板
标记
里程碑
合并请求
2
合并请求
2
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
045da4e5
编写于
10月 29, 2011
作者:
B
Ben Skeggs
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
drm/nvc0/pm: initial engine reclocking
Signed-off-by:
N
Ben Skeggs
<
bskeggs@redhat.com
>
上级
52c4d767
变更
3
隐藏空白更改
内联
并排
Showing
3 changed file
with
243 addition
and
0 deletion
+243
-0
drivers/gpu/drm/nouveau/nouveau_pm.h
drivers/gpu/drm/nouveau/nouveau_pm.h
+2
-0
drivers/gpu/drm/nouveau/nouveau_state.c
drivers/gpu/drm/nouveau/nouveau_state.c
+4
-0
drivers/gpu/drm/nouveau/nvc0_pm.c
drivers/gpu/drm/nouveau/nvc0_pm.c
+237
-0
未找到文件。
drivers/gpu/drm/nouveau/nouveau_pm.h
浏览文件 @
045da4e5
...
...
@@ -72,6 +72,8 @@ int nva3_pm_clocks_set(struct drm_device *, void *);
/* nvc0_pm.c */
int
nvc0_pm_clocks_get
(
struct
drm_device
*
,
struct
nouveau_pm_level
*
);
void
*
nvc0_pm_clocks_pre
(
struct
drm_device
*
,
struct
nouveau_pm_level
*
);
int
nvc0_pm_clocks_set
(
struct
drm_device
*
,
void
*
);
/* nouveau_temp.c */
void
nouveau_temp_init
(
struct
drm_device
*
dev
);
...
...
drivers/gpu/drm/nouveau/nouveau_state.c
浏览文件 @
045da4e5
...
...
@@ -417,6 +417,8 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine
->
vram
.
flags_valid
=
nvc0_vram_flags_valid
;
engine
->
pm
.
temp_get
=
nv84_temp_get
;
engine
->
pm
.
clocks_get
=
nvc0_pm_clocks_get
;
engine
->
pm
.
clocks_pre
=
nvc0_pm_clocks_pre
;
engine
->
pm
.
clocks_set
=
nvc0_pm_clocks_set
;
engine
->
pm
.
voltage_get
=
nouveau_voltage_gpio_get
;
engine
->
pm
.
voltage_set
=
nouveau_voltage_gpio_set
;
engine
->
pm
.
pwm_get
=
nv50_pm_pwm_get
;
...
...
@@ -468,6 +470,8 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine
->
vram
.
flags_valid
=
nvc0_vram_flags_valid
;
engine
->
pm
.
temp_get
=
nv84_temp_get
;
engine
->
pm
.
clocks_get
=
nvc0_pm_clocks_get
;
engine
->
pm
.
clocks_pre
=
nvc0_pm_clocks_pre
;
engine
->
pm
.
clocks_set
=
nvc0_pm_clocks_set
;
engine
->
pm
.
voltage_get
=
nouveau_voltage_gpio_get
;
engine
->
pm
.
voltage_set
=
nouveau_voltage_gpio_set
;
break
;
...
...
drivers/gpu/drm/nouveau/nvc0_pm.c
浏览文件 @
045da4e5
...
...
@@ -153,3 +153,240 @@ nvc0_pm_clocks_get(struct drm_device *dev, struct nouveau_pm_level *perflvl)
perflvl
->
vdec
=
read_clk
(
dev
,
0x0e
);
return
0
;
}
struct
nvc0_pm_clock
{
u32
freq
;
u32
ssel
;
u32
mdiv
;
u32
dsrc
;
u32
ddiv
;
u32
coef
;
};
struct
nvc0_pm_state
{
struct
nvc0_pm_clock
eng
[
16
];
};
static
u32
calc_div
(
struct
drm_device
*
dev
,
int
clk
,
u32
ref
,
u32
freq
,
u32
*
ddiv
)
{
u32
div
=
min
((
ref
*
2
)
/
freq
,
(
u32
)
65
);
if
(
div
<
2
)
div
=
2
;
*
ddiv
=
div
-
2
;
return
(
ref
*
2
)
/
div
;
}
static
u32
calc_src
(
struct
drm_device
*
dev
,
int
clk
,
u32
freq
,
u32
*
dsrc
,
u32
*
ddiv
)
{
u32
sclk
;
/* use one of the fixed frequencies if possible */
*
ddiv
=
0x00000000
;
switch
(
freq
)
{
case
27000
:
case
108000
:
*
dsrc
=
0x00000000
;
if
(
freq
==
108000
)
*
dsrc
|=
0x00030000
;
return
freq
;
case
100000
:
*
dsrc
=
0x00000002
;
return
freq
;
default:
*
dsrc
=
0x00000003
;
break
;
}
/* otherwise, calculate the closest divider */
sclk
=
read_vco
(
dev
,
clk
);
if
(
clk
<
7
)
sclk
=
calc_div
(
dev
,
clk
,
sclk
,
freq
,
ddiv
);
return
sclk
;
}
static
u32
calc_pll
(
struct
drm_device
*
dev
,
int
clk
,
u32
freq
,
u32
*
coef
)
{
struct
pll_lims
limits
;
int
N
,
M
,
P
,
ret
;
ret
=
get_pll_limits
(
dev
,
0x137000
+
(
clk
*
0x20
),
&
limits
);
if
(
ret
)
return
0
;
limits
.
refclk
=
read_div
(
dev
,
clk
,
0x137120
,
0x137140
);
if
(
!
limits
.
refclk
)
return
0
;
ret
=
nva3_calc_pll
(
dev
,
&
limits
,
freq
,
&
N
,
NULL
,
&
M
,
&
P
);
if
(
ret
<=
0
)
return
0
;
*
coef
=
(
P
<<
16
)
|
(
N
<<
8
)
|
M
;
return
ret
;
}
/* A (likely rather simplified and incomplete) view of the clock tree
*
* Key:
*
* S: source select
* D: divider
* P: pll
* F: switch
*
* Engine clocks:
*
* 137250(D) ---- 137100(F0) ---- 137160(S)/1371d0(D) ------------------- ref
* (F1) ---- 1370X0(P) ---- 137120(S)/137140(D) ---- ref
*
* Not all registers exist for all clocks. For example: clocks >= 8 don't
* have their own PLL (all tied to clock 7's PLL when in PLL mode), nor do
* they have the divider at 1371d0, though the source selection at 137160
* still exists. You must use the divider at 137250 for these instead.
*
* Memory clock:
*
* TBD, read_mem() above is likely very wrong...
*
*/
static
int
calc_clk
(
struct
drm_device
*
dev
,
int
clk
,
struct
nvc0_pm_clock
*
info
,
u32
freq
)
{
u32
src0
,
div0
,
div1D
,
div1P
=
0
;
u32
clk0
,
clk1
=
0
;
/* invalid clock domain */
if
(
!
freq
)
return
0
;
/* first possible path, using only dividers */
clk0
=
calc_src
(
dev
,
clk
,
freq
,
&
src0
,
&
div0
);
clk0
=
calc_div
(
dev
,
clk
,
clk0
,
freq
,
&
div1D
);
/* see if we can get any closer using PLLs */
if
(
clk0
!=
freq
)
{
if
(
clk
<
7
)
clk1
=
calc_pll
(
dev
,
clk
,
freq
,
&
info
->
coef
);
else
clk1
=
read_pll
(
dev
,
0x1370e0
);
clk1
=
calc_div
(
dev
,
clk
,
clk1
,
freq
,
&
div1P
);
}
/* select the method which gets closest to target freq */
if
(
abs
((
int
)
freq
-
clk0
)
<=
abs
((
int
)
freq
-
clk1
))
{
info
->
dsrc
=
src0
;
if
(
div0
)
{
info
->
ddiv
|=
0x80000000
;
info
->
ddiv
|=
div0
<<
8
;
info
->
ddiv
|=
div0
;
}
if
(
div1D
)
{
info
->
mdiv
|=
0x80000000
;
info
->
mdiv
|=
div1D
;
}
info
->
ssel
=
0
;
info
->
freq
=
clk0
;
}
else
{
if
(
div1P
)
{
info
->
mdiv
|=
0x80000000
;
info
->
mdiv
|=
div1P
<<
8
;
}
info
->
ssel
=
(
1
<<
clk
);
info
->
freq
=
clk1
;
}
return
0
;
}
void
*
nvc0_pm_clocks_pre
(
struct
drm_device
*
dev
,
struct
nouveau_pm_level
*
perflvl
)
{
struct
drm_nouveau_private
*
dev_priv
=
dev
->
dev_private
;
struct
nvc0_pm_state
*
info
;
int
ret
;
info
=
kzalloc
(
sizeof
(
*
info
),
GFP_KERNEL
);
if
(
!
info
)
return
ERR_PTR
(
-
ENOMEM
);
/* NFI why this is still in the performance table, the ROPCs appear
* to get their clock from clock 2 ("hub07", actually hub05 on this
* chip, but, anyway...) as well. nvatiming confirms hub05 and ROP
* are always the same freq with the binary driver even when the
* performance table says they should differ.
*/
if
(
dev_priv
->
chipset
==
0xd9
)
perflvl
->
rop
=
0
;
if
((
ret
=
calc_clk
(
dev
,
0x00
,
&
info
->
eng
[
0x00
],
perflvl
->
shader
))
||
(
ret
=
calc_clk
(
dev
,
0x01
,
&
info
->
eng
[
0x01
],
perflvl
->
rop
))
||
(
ret
=
calc_clk
(
dev
,
0x02
,
&
info
->
eng
[
0x02
],
perflvl
->
hub07
))
||
(
ret
=
calc_clk
(
dev
,
0x07
,
&
info
->
eng
[
0x07
],
perflvl
->
hub06
))
||
(
ret
=
calc_clk
(
dev
,
0x08
,
&
info
->
eng
[
0x08
],
perflvl
->
hub01
))
||
(
ret
=
calc_clk
(
dev
,
0x09
,
&
info
->
eng
[
0x09
],
perflvl
->
copy
))
||
(
ret
=
calc_clk
(
dev
,
0x0c
,
&
info
->
eng
[
0x0c
],
perflvl
->
daemon
))
||
(
ret
=
calc_clk
(
dev
,
0x0e
,
&
info
->
eng
[
0x0e
],
perflvl
->
vdec
)))
{
kfree
(
info
);
return
ERR_PTR
(
ret
);
}
return
info
;
}
static
void
prog_clk
(
struct
drm_device
*
dev
,
int
clk
,
struct
nvc0_pm_clock
*
info
)
{
/* program dividers at 137160/1371d0 first */
if
(
clk
<
7
&&
!
info
->
ssel
)
{
nv_mask
(
dev
,
0x1371d0
+
(
clk
*
0x04
),
0x80003f3f
,
info
->
ddiv
);
nv_wr32
(
dev
,
0x137160
+
(
clk
*
0x04
),
info
->
dsrc
);
}
/* switch clock to non-pll mode */
nv_mask
(
dev
,
0x137100
,
(
1
<<
clk
),
0x00000000
);
nv_wait
(
dev
,
0x137100
,
(
1
<<
clk
),
0x00000000
);
/* reprogram pll */
if
(
clk
<
7
)
{
/* make sure it's disabled first... */
u32
base
=
0x137000
+
(
clk
*
0x20
);
u32
ctrl
=
nv_rd32
(
dev
,
base
+
0x00
);
if
(
ctrl
&
0x00000001
)
{
nv_mask
(
dev
,
base
+
0x00
,
0x00000004
,
0x00000000
);
nv_mask
(
dev
,
base
+
0x00
,
0x00000001
,
0x00000000
);
}
/* program it to new values, if necessary */
if
(
info
->
ssel
)
{
nv_wr32
(
dev
,
base
+
0x04
,
info
->
coef
);
nv_mask
(
dev
,
base
+
0x00
,
0x00000001
,
0x00000001
);
nv_wait
(
dev
,
base
+
0x00
,
0x00020000
,
0x00020000
);
nv_mask
(
dev
,
base
+
0x00
,
0x00020004
,
0x00000004
);
}
}
/* select pll/non-pll mode, and program final clock divider */
nv_mask
(
dev
,
0x137100
,
(
1
<<
clk
),
info
->
ssel
);
nv_wait
(
dev
,
0x137100
,
(
1
<<
clk
),
info
->
ssel
);
nv_mask
(
dev
,
0x137250
+
(
clk
*
0x04
),
0x00003f3f
,
info
->
mdiv
);
}
int
nvc0_pm_clocks_set
(
struct
drm_device
*
dev
,
void
*
data
)
{
struct
nvc0_pm_state
*
info
=
data
;
int
i
;
for
(
i
=
0
;
i
<
16
;
i
++
)
{
if
(
!
info
->
eng
[
i
].
freq
)
continue
;
prog_clk
(
dev
,
i
,
&
info
->
eng
[
i
]);
}
kfree
(
info
);
return
0
;
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录