Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
4ea253ad
Commit
4ea253ad
authored
Feb 20, 2013
by
Ben Skeggs
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
drm/nvd0/disp: handle multiple actions from one set of supervisor intrs
Signed-off-by:
Ben Skeggs
<
bskeggs@redhat.com
>
parent
16d4c031
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
118 additions
and
103 deletions
+118
-103
drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
+118
-103
No files found.
drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
View file @
4ea253ad
...
...
@@ -623,13 +623,24 @@ exec_lookup(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl,
}
static
bool
exec_script
(
struct
nv50_disp_priv
*
priv
,
int
head
,
int
outp
,
u32
ctrl
,
int
id
)
exec_script
(
struct
nv50_disp_priv
*
priv
,
int
head
,
int
id
)
{
struct
nouveau_bios
*
bios
=
nouveau_bios
(
priv
);
struct
nvbios_outp
info
;
struct
dcb_output
dcb
;
u8
ver
,
hdr
,
cnt
,
len
;
u32
ctrl
=
0x00000000
;
u16
data
;
int
outp
;
for
(
outp
=
0
;
!
(
ctrl
&
(
1
<<
head
))
&&
outp
<
8
;
outp
++
)
{
ctrl
=
nv_rd32
(
priv
,
0x640180
+
(
outp
*
0x20
));
if
(
ctrl
&
(
1
<<
head
))
break
;
}
if
(
outp
==
8
)
return
false
;
data
=
exec_lookup
(
priv
,
head
,
outp
,
ctrl
,
&
dcb
,
&
ver
,
&
hdr
,
&
cnt
,
&
len
,
&
info
);
if
(
data
)
{
...
...
@@ -649,14 +660,25 @@ exec_script(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl, int id)
}
static
u32
exec_clkcmp
(
struct
nv50_disp_priv
*
priv
,
int
head
,
int
outp
,
u32
ctrl
,
int
id
,
u32
pclk
,
struct
dcb_output
*
dcb
)
exec_clkcmp
(
struct
nv50_disp_priv
*
priv
,
int
head
,
int
id
,
u32
pclk
,
struct
dcb_output
*
dcb
)
{
struct
nouveau_bios
*
bios
=
nouveau_bios
(
priv
);
struct
nvbios_outp
info1
;
struct
nvbios_ocfg
info2
;
u8
ver
,
hdr
,
cnt
,
len
;
u32
ctrl
=
0x00000000
;
u32
data
,
conf
=
~
0
;
int
outp
;
for
(
outp
=
0
;
!
(
ctrl
&
(
1
<<
head
))
&&
outp
<
8
;
outp
++
)
{
ctrl
=
nv_rd32
(
priv
,
0x660180
+
(
outp
*
0x20
));
if
(
ctrl
&
(
1
<<
head
))
break
;
}
if
(
outp
==
8
)
return
false
;
data
=
exec_lookup
(
priv
,
head
,
outp
,
ctrl
,
dcb
,
&
ver
,
&
hdr
,
&
cnt
,
&
len
,
&
info1
);
if
(
data
==
0x0000
)
...
...
@@ -701,24 +723,32 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int outp,
}
static
void
nvd0_disp
lay_unk1_handler
(
struct
nv50_disp_priv
*
priv
,
u32
head
,
u32
mask
)
nvd0_disp
_intr_unk1_0
(
struct
nv50_disp_priv
*
priv
,
int
head
)
{
int
i
;
exec_script
(
priv
,
head
,
1
);
}
for
(
i
=
0
;
mask
&&
i
<
8
;
i
++
)
{
u32
mcc
=
nv_rd32
(
priv
,
0x640180
+
(
i
*
0x20
));
if
(
mcc
&
(
1
<<
head
))
exec_script
(
priv
,
head
,
i
,
mcc
,
1
);
}
static
void
nvd0_disp_intr_unk2_0
(
struct
nv50_disp_priv
*
priv
,
int
head
)
{
exec_script
(
priv
,
head
,
2
);
}
nv_wr32
(
priv
,
0x6101d4
,
0x00000000
);
nv_wr32
(
priv
,
0x6109d4
,
0x00000000
);
nv_wr32
(
priv
,
0x6101d0
,
0x80000000
);
static
void
nvd0_disp_intr_unk2_1
(
struct
nv50_disp_priv
*
priv
,
int
head
)
{
struct
nouveau_clock
*
clk
=
nouveau_clock
(
priv
);
u32
pclk
=
nv_rd32
(
priv
,
0x660450
+
(
head
*
0x300
))
/
1000
;
if
(
pclk
)
clk
->
pll_set
(
clk
,
PLL_VPLL0
+
head
,
pclk
);
nv_wr32
(
priv
,
0x612200
+
(
head
*
0x800
),
0x00000000
);
}
static
void
nvd0_display_unk2_calc_tu
(
struct
nv50_disp_priv
*
priv
,
int
head
,
int
or
)
nvd0_disp_intr_unk2_2_tu
(
struct
nv50_disp_priv
*
priv
,
int
head
,
struct
dcb_output
*
outp
)
{
const
int
or
=
ffs
(
outp
->
or
)
-
1
;
const
u32
ctrl
=
nv_rd32
(
priv
,
0x660200
+
(
or
*
0x020
));
const
u32
conf
=
nv_rd32
(
priv
,
0x660404
+
(
head
*
0x300
));
const
u32
pclk
=
nv_rd32
(
priv
,
0x660450
+
(
head
*
0x300
))
/
1000
;
...
...
@@ -761,97 +791,51 @@ nvd0_display_unk2_calc_tu(struct nv50_disp_priv *priv, int head, int or)
}
static
void
nvd0_disp
lay_unk2_handler
(
struct
nv50_disp_priv
*
priv
,
u32
head
,
u32
mask
)
nvd0_disp
_intr_unk2_2
(
struct
nv50_disp_priv
*
priv
,
int
head
)
{
struct
dcb_output
outp
;
u32
pclk
;
int
i
;
for
(
i
=
0
;
mask
&&
i
<
8
;
i
++
)
{
u32
mcc
=
nv_rd32
(
priv
,
0x640180
+
(
i
*
0x20
));
if
(
mcc
&
(
1
<<
head
))
exec_script
(
priv
,
head
,
i
,
mcc
,
2
);
}
u32
pclk
=
nv_rd32
(
priv
,
0x660450
+
(
head
*
0x300
))
/
1000
;
u32
conf
=
exec_clkcmp
(
priv
,
head
,
0xff
,
pclk
,
&
outp
);
if
(
conf
!=
~
0
)
{
u32
addr
,
data
;
if
(
outp
.
type
==
DCB_OUTPUT_DP
)
{
u32
sync
=
nv_rd32
(
priv
,
0x660404
+
(
head
*
0x300
));
switch
((
sync
&
0x000003c0
)
>>
6
)
{
case
6
:
pclk
=
pclk
*
30
/
8
;
break
;
case
5
:
pclk
=
pclk
*
24
/
8
;
break
;
case
2
:
default:
pclk
=
pclk
*
18
/
8
;
break
;
}
pclk
=
nv_rd32
(
priv
,
0x660450
+
(
head
*
0x300
))
/
1000
;
nv_debug
(
priv
,
"head %d pclk %d mask 0x%08x
\n
"
,
head
,
pclk
,
mask
);
if
(
pclk
&&
(
mask
&
0x00010000
))
{
struct
nouveau_clock
*
clk
=
nouveau_clock
(
priv
);
clk
->
pll_set
(
clk
,
PLL_VPLL0
+
head
,
pclk
);
}
nouveau_dp_train
(
&
priv
->
base
,
priv
->
sor
.
dp
,
&
outp
,
head
,
pclk
);
}
nv_wr32
(
priv
,
0x612200
+
(
head
*
0x800
),
0x00000000
);
exec_clkcmp
(
priv
,
head
,
0
,
pclk
,
&
outp
);
for
(
i
=
0
;
mask
&&
i
<
8
;
i
++
)
{
u32
mcp
=
nv_rd32
(
priv
,
0x660180
+
(
i
*
0x20
));
if
(
mcp
&
(
1
<<
head
))
{
u32
cfg
=
exec_clkcmp
(
priv
,
head
,
i
,
mcp
,
0xff
,
pclk
,
&
outp
);
if
(
cfg
!=
~
0
)
{
u32
addr
,
mask
,
data
=
0x00000000
;
if
(
outp
.
type
==
DCB_OUTPUT_DP
)
{
switch
((
mcp
&
0x000f0000
)
>>
16
)
{
case
6
:
pclk
=
pclk
*
30
/
8
;
break
;
case
5
:
pclk
=
pclk
*
24
/
8
;
break
;
case
2
:
default:
pclk
=
pclk
*
18
/
8
;
break
;
}
nouveau_dp_train
(
&
priv
->
base
,
priv
->
sor
.
dp
,
&
outp
,
head
,
pclk
);
}
exec_clkcmp
(
priv
,
head
,
i
,
mcp
,
0
,
pclk
,
&
outp
);
if
(
i
<
4
)
{
addr
=
0x612280
+
((
i
-
0
)
*
0x800
);
mask
=
0xffffffff
;
}
else
{
switch
(
mcp
&
0x00000f00
)
{
case
0x00000800
:
case
0x00000900
:
nvd0_display_unk2_calc_tu
(
priv
,
head
,
i
-
4
);
break
;
default:
break
;
}
addr
=
0x612300
+
((
i
-
4
)
*
0x800
);
mask
=
0x00000707
;
if
(
cfg
&
0x00000100
)
data
=
0x00000101
;
}
nv_mask
(
priv
,
addr
,
mask
,
data
);
}
break
;
if
(
outp
.
type
==
DCB_OUTPUT_ANALOG
)
{
addr
=
0x612280
+
(
ffs
(
outp
.
or
)
-
1
)
*
0x800
;
data
=
0x00000000
;
}
else
{
if
(
outp
.
type
==
DCB_OUTPUT_DP
)
nvd0_disp_intr_unk2_2_tu
(
priv
,
head
,
&
outp
);
addr
=
0x612300
+
(
ffs
(
outp
.
or
)
-
1
)
*
0x800
;
data
=
(
conf
&
0x0100
)
?
0x00000101
:
0x00000000
;
}
}
nv_wr32
(
priv
,
0x6101d4
,
0x00000000
);
nv_wr32
(
priv
,
0x6109d4
,
0x00000000
);
nv_wr32
(
priv
,
0x6101d0
,
0x80000000
);
nv_mask
(
priv
,
addr
,
0x00000707
,
data
);
}
}
static
void
nvd0_disp
lay_unk4_handler
(
struct
nv50_disp_priv
*
priv
,
u32
head
,
u32
mask
)
nvd0_disp
_intr_unk4_0
(
struct
nv50_disp_priv
*
priv
,
int
head
)
{
struct
dcb_output
outp
;
int
pclk
,
i
;
pclk
=
nv_rd32
(
priv
,
0x660450
+
(
head
*
0x300
))
/
1000
;
for
(
i
=
0
;
mask
&&
i
<
8
;
i
++
)
{
u32
mcp
=
nv_rd32
(
priv
,
0x660180
+
(
i
*
0x20
));
if
(
mcp
&
(
1
<<
head
))
exec_clkcmp
(
priv
,
head
,
i
,
mcp
,
1
,
pclk
,
&
outp
);
}
nv_wr32
(
priv
,
0x6101d4
,
0x00000000
);
nv_wr32
(
priv
,
0x6109d4
,
0x00000000
);
nv_wr32
(
priv
,
0x6101d0
,
0x80000000
);
u32
pclk
=
nv_rd32
(
priv
,
0x660450
+
(
head
*
0x300
))
/
1000
;
exec_clkcmp
(
priv
,
head
,
1
,
pclk
,
&
outp
);
}
void
...
...
@@ -859,19 +843,50 @@ nvd0_disp_intr_supervisor(struct work_struct *work)
{
struct
nv50_disp_priv
*
priv
=
container_of
(
work
,
struct
nv50_disp_priv
,
supervisor
);
u32
mask
=
0
,
head
=
~
0
;
u32
mask
[
4
];
int
head
;
while
(
!
mask
&&
++
head
<
priv
->
head
.
nr
)
mask
=
nv_rd32
(
priv
,
0x6101d4
+
(
head
*
0x800
));
nv_debug
(
priv
,
"supervisor %08x
\n
"
,
priv
->
super
);
for
(
head
=
0
;
head
<
priv
->
head
.
nr
;
head
++
)
{
mask
[
head
]
=
nv_rd32
(
priv
,
0x6101d4
+
(
head
*
0x800
));
nv_debug
(
priv
,
"head %d: 0x%08x
\n
"
,
head
,
mask
[
head
]);
}
nv_debug
(
priv
,
"supervisor %08x %08x %d
\n
"
,
priv
->
super
,
mask
,
head
);
if
(
priv
->
super
&
0x00000001
)
{
for
(
head
=
0
;
head
<
priv
->
head
.
nr
;
head
++
)
{
if
(
!
(
mask
[
head
]
&
0x00001000
))
continue
;
nvd0_disp_intr_unk1_0
(
priv
,
head
);
}
}
else
if
(
priv
->
super
&
0x00000002
)
{
for
(
head
=
0
;
head
<
priv
->
head
.
nr
;
head
++
)
{
if
(
!
(
mask
[
head
]
&
0x00001000
))
continue
;
nvd0_disp_intr_unk2_0
(
priv
,
head
);
}
for
(
head
=
0
;
head
<
priv
->
head
.
nr
;
head
++
)
{
if
(
!
(
mask
[
head
]
&
0x00010000
))
continue
;
nvd0_disp_intr_unk2_1
(
priv
,
head
);
}
for
(
head
=
0
;
head
<
priv
->
head
.
nr
;
head
++
)
{
if
(
!
(
mask
[
head
]
&
0x00001000
))
continue
;
nvd0_disp_intr_unk2_2
(
priv
,
head
);
}
}
else
if
(
priv
->
super
&
0x00000004
)
{
for
(
head
=
0
;
head
<
priv
->
head
.
nr
;
head
++
)
{
if
(
!
(
mask
[
head
]
&
0x00001000
))
continue
;
nvd0_disp_intr_unk4_0
(
priv
,
head
);
}
}
if
(
priv
->
super
&
0x00000001
)
nvd0_display_unk1_handler
(
priv
,
head
,
mask
);
if
(
priv
->
super
&
0x00000002
)
nvd0_display_unk2_handler
(
priv
,
head
,
mask
);
if
(
priv
->
super
&
0x00000004
)
nvd0_display_unk4_handler
(
priv
,
head
,
mask
);
for
(
head
=
0
;
head
<
priv
->
head
.
nr
;
head
++
)
nv_wr32
(
priv
,
0x6101d4
+
(
head
*
0x800
),
0x00000000
);
nv_wr32
(
priv
,
0x6101d0
,
0x80000000
);
}
void
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment