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
Kirill Smelkov
linux
Commits
4f6029da
Commit
4f6029da
authored
Nov 16, 2012
by
Ben Skeggs
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
drm/nv50-nvc0: switch to common disp impl, removing previous version
Signed-off-by:
Ben Skeggs
<
bskeggs@redhat.com
>
parent
f9887d09
Changes
17
Show whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
31 additions
and
2700 deletions
+31
-2700
drivers/gpu/drm/nouveau/Makefile
drivers/gpu/drm/nouveau/Makefile
+2
-4
drivers/gpu/drm/nouveau/nouveau_connector.h
drivers/gpu/drm/nouveau/nouveau_connector.h
+16
-0
drivers/gpu/drm/nouveau/nouveau_crtc.h
drivers/gpu/drm/nouveau/nouveau_crtc.h
+0
-3
drivers/gpu/drm/nouveau/nouveau_display.c
drivers/gpu/drm/nouveau/nouveau_display.c
+6
-12
drivers/gpu/drm/nouveau/nouveau_hdmi.c
drivers/gpu/drm/nouveau/nouveau_hdmi.c
+0
-123
drivers/gpu/drm/nouveau/nv50_crtc.c
drivers/gpu/drm/nouveau/nv50_crtc.c
+0
-753
drivers/gpu/drm/nouveau/nv50_cursor.c
drivers/gpu/drm/nouveau/nv50_cursor.c
+0
-132
drivers/gpu/drm/nouveau/nv50_dac.c
drivers/gpu/drm/nouveau/nv50_dac.c
+0
-276
drivers/gpu/drm/nouveau/nv50_display.c
drivers/gpu/drm/nouveau/nv50_display.c
+0
-462
drivers/gpu/drm/nouveau/nv50_display.h
drivers/gpu/drm/nouveau/nv50_display.h
+0
-60
drivers/gpu/drm/nouveau/nv50_evo.c
drivers/gpu/drm/nouveau/nv50_evo.c
+0
-396
drivers/gpu/drm/nouveau/nv50_evo.h
drivers/gpu/drm/nouveau/nv50_evo.h
+0
-120
drivers/gpu/drm/nouveau/nv50_fence.c
drivers/gpu/drm/nouveau/nv50_fence.c
+1
-1
drivers/gpu/drm/nouveau/nv50_pm.c
drivers/gpu/drm/nouveau/nv50_pm.c
+1
-1
drivers/gpu/drm/nouveau/nv50_sor.c
drivers/gpu/drm/nouveau/nv50_sor.c
+0
-339
drivers/gpu/drm/nouveau/nv84_fence.c
drivers/gpu/drm/nouveau/nv84_fence.c
+1
-1
drivers/gpu/drm/nouveau/nvc0_fence.c
drivers/gpu/drm/nouveau/nvc0_fence.c
+4
-17
No files found.
drivers/gpu/drm/nouveau/Makefile
View file @
4f6029da
...
...
@@ -192,7 +192,7 @@ nouveau-y += nv04_fence.o nv10_fence.o nv50_fence.o nv84_fence.o nvc0_fence.o
# drm/kms
nouveau-y
+=
nouveau_bios.o nouveau_fbcon.o nouveau_display.o
nouveau-y
+=
nouveau_connector.o nouveau_
hdmi.o nouveau_
dp.o
nouveau-y
+=
nouveau_connector.o nouveau_dp.o
nouveau-y
+=
nv04_fbcon.o nv50_fbcon.o nvc0_fbcon.o
# drm/kms/nv04:nv50
...
...
@@ -201,9 +201,7 @@ nouveau-y += nv04_dac.o nv04_dfp.o nv04_tv.o nv17_tv.o nv17_tv_modes.o
nouveau-y
+=
nv04_crtc.o nv04_display.o nv04_cursor.o
# drm/kms/nv50-
nouveau-y
+=
nv50_display.o nvd0_display.o
nouveau-y
+=
nv50_crtc.o nv50_dac.o nv50_sor.o nv50_cursor.o
nouveau-y
+=
nv50_evo.o
nouveau-y
+=
nvd0_display.o
# drm/pm
nouveau-y
+=
nouveau_pm.o nouveau_volt.o nouveau_perf.o
...
...
drivers/gpu/drm/nouveau/nouveau_connector.h
View file @
4f6029da
...
...
@@ -28,6 +28,7 @@
#define __NOUVEAU_CONNECTOR_H__
#include <drm/drm_edid.h>
#include "nouveau_crtc.h"
struct
nouveau_i2c_port
;
...
...
@@ -80,6 +81,21 @@ static inline struct nouveau_connector *nouveau_connector(
return
container_of
(
con
,
struct
nouveau_connector
,
base
);
}
static
inline
struct
nouveau_connector
*
nouveau_crtc_connector_get
(
struct
nouveau_crtc
*
nv_crtc
)
{
struct
drm_device
*
dev
=
nv_crtc
->
base
.
dev
;
struct
drm_connector
*
connector
;
struct
drm_crtc
*
crtc
=
to_drm_crtc
(
nv_crtc
);
list_for_each_entry
(
connector
,
&
dev
->
mode_config
.
connector_list
,
head
)
{
if
(
connector
->
encoder
&&
connector
->
encoder
->
crtc
==
crtc
)
return
nouveau_connector
(
connector
);
}
return
NULL
;
}
struct
drm_connector
*
nouveau_connector_create
(
struct
drm_device
*
,
int
index
);
...
...
drivers/gpu/drm/nouveau/nouveau_crtc.h
View file @
4f6029da
...
...
@@ -91,7 +91,4 @@ int nv50_crtc_cursor_move(struct drm_crtc *drm_crtc, int x, int y);
int
nv04_cursor_init
(
struct
nouveau_crtc
*
);
int
nv50_cursor_init
(
struct
nouveau_crtc
*
);
struct
nouveau_connector
*
nouveau_crtc_connector_get
(
struct
nouveau_crtc
*
crtc
);
#endif
/* __NOUVEAU_CRTC_H__ */
drivers/gpu/drm/nouveau/nouveau_display.c
View file @
4f6029da
...
...
@@ -98,12 +98,12 @@ nouveau_framebuffer_init(struct drm_device *dev,
nv_fb
->
r_dma
=
NvEvoVRAM_LP
;
switch
(
fb
->
depth
)
{
case
8
:
nv_fb
->
r_format
=
NV50_EVO_CRTC_FB_DEPTH_8
;
break
;
case
15
:
nv_fb
->
r_format
=
NV50_EVO_CRTC_FB_DEPTH_15
;
break
;
case
16
:
nv_fb
->
r_format
=
NV50_EVO_CRTC_FB_DEPTH_16
;
break
;
case
8
:
nv_fb
->
r_format
=
0x1e00
;
break
;
case
15
:
nv_fb
->
r_format
=
0xe900
;
break
;
case
16
:
nv_fb
->
r_format
=
0xe800
;
break
;
case
24
:
case
32
:
nv_fb
->
r_format
=
NV50_EVO_CRTC_FB_DEPTH_24
;
break
;
case
30
:
nv_fb
->
r_format
=
NV50_EVO_CRTC_FB_DEPTH_3
0
;
break
;
case
32
:
nv_fb
->
r_format
=
0xcf00
;
break
;
case
30
:
nv_fb
->
r_format
=
0xd10
0
;
break
;
default:
NV_ERROR
(
drm
,
"unknown depth %d
\n
"
,
fb
->
depth
);
return
-
EINVAL
;
...
...
@@ -365,9 +365,6 @@ nouveau_display_create(struct drm_device *dev)
(
nouveau_modeset
<
0
&&
pclass
==
PCI_CLASS_DISPLAY_VGA
))
{
if
(
nv_device
(
drm
->
device
)
->
card_type
<
NV_50
)
ret
=
nv04_display_create
(
dev
);
else
if
(
nv_device
(
drm
->
device
)
->
card_type
<
NV_D0
)
ret
=
nv50_display_create
(
dev
);
else
ret
=
nvd0_display_create
(
dev
);
if
(
ret
)
...
...
@@ -660,10 +657,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
/* Emit a page flip */
if
(
nv_device
(
drm
->
device
)
->
card_type
>=
NV_50
)
{
if
(
nv_device
(
drm
->
device
)
->
card_type
>=
NV_D0
)
ret
=
nvd0_display_flip_next
(
crtc
,
fb
,
chan
,
0
);
else
ret
=
nv50_display_flip_next
(
crtc
,
fb
,
chan
);
if
(
ret
)
{
mutex_unlock
(
&
chan
->
cli
->
mutex
);
goto
fail_unreserve
;
...
...
drivers/gpu/drm/nouveau/nouveau_hdmi.c
deleted
100644 → 0
View file @
f9887d09
/*
* Copyright 2011 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs
*/
#include <drm/drmP.h>
#include "nouveau_drm.h"
#include "nouveau_connector.h"
#include "nouveau_encoder.h"
#include "nouveau_crtc.h"
#include <core/class.h>
#include "nv50_display.h"
static
bool
hdmi_sor
(
struct
drm_encoder
*
encoder
)
{
struct
nouveau_drm
*
drm
=
nouveau_drm
(
encoder
->
dev
);
if
(
nv_device
(
drm
->
device
)
->
chipset
<
0xa3
||
nv_device
(
drm
->
device
)
->
chipset
==
0xaa
||
nv_device
(
drm
->
device
)
->
chipset
==
0xac
)
return
false
;
return
true
;
}
static
void
nouveau_audio_disconnect
(
struct
drm_encoder
*
encoder
)
{
struct
nv50_display
*
priv
=
nv50_display
(
encoder
->
dev
);
struct
nouveau_encoder
*
nv_encoder
=
nouveau_encoder
(
encoder
);
u32
or
=
nv_encoder
->
or
;
if
(
hdmi_sor
(
encoder
))
nv_exec
(
priv
->
core
,
NVA3_DISP_SOR_HDA_ELD
+
or
,
NULL
,
0
);
}
static
void
nouveau_audio_mode_set
(
struct
drm_encoder
*
encoder
,
struct
drm_display_mode
*
mode
)
{
struct
nv50_display
*
priv
=
nv50_display
(
encoder
->
dev
);
struct
nouveau_encoder
*
nv_encoder
=
nouveau_encoder
(
encoder
);
struct
nouveau_connector
*
nv_connector
;
nv_connector
=
nouveau_encoder_connector_get
(
nv_encoder
);
if
(
!
drm_detect_monitor_audio
(
nv_connector
->
edid
))
{
nouveau_audio_disconnect
(
encoder
);
return
;
}
if
(
hdmi_sor
(
encoder
))
{
drm_edid_to_eld
(
&
nv_connector
->
base
,
nv_connector
->
edid
);
nv_exec
(
priv
->
core
,
NVA3_DISP_SOR_HDA_ELD
+
nv_encoder
->
or
,
nv_connector
->
base
.
eld
,
nv_connector
->
base
.
eld
[
2
]
*
4
);
}
}
static
void
nouveau_hdmi_disconnect
(
struct
drm_encoder
*
encoder
)
{
struct
nouveau_encoder
*
nv_encoder
=
nouveau_encoder
(
encoder
);
struct
nouveau_crtc
*
nv_crtc
=
nouveau_crtc
(
nv_encoder
->
crtc
);
struct
nv50_display
*
priv
=
nv50_display
(
encoder
->
dev
);
const
u32
moff
=
(
nv_crtc
->
index
<<
3
)
|
nv_encoder
->
or
;
nouveau_audio_disconnect
(
encoder
);
nv_call
(
priv
->
core
,
NV84_DISP_SOR_HDMI_PWR
+
moff
,
0x00000000
);
}
void
nouveau_hdmi_mode_set
(
struct
drm_encoder
*
encoder
,
struct
drm_display_mode
*
mode
)
{
struct
nouveau_encoder
*
nv_encoder
=
nouveau_encoder
(
encoder
);
struct
nouveau_crtc
*
nv_crtc
=
nouveau_crtc
(
nv_encoder
->
crtc
);
struct
nv50_display
*
priv
=
nv50_display
(
encoder
->
dev
);
const
u32
moff
=
(
nv_crtc
->
index
<<
3
)
|
nv_encoder
->
or
;
struct
nouveau_connector
*
nv_connector
;
u32
max_ac_packet
,
rekey
;
nv_connector
=
nouveau_encoder_connector_get
(
nv_encoder
);
if
(
!
mode
||
!
nv_connector
||
!
nv_connector
->
edid
||
!
drm_detect_hdmi_monitor
(
nv_connector
->
edid
))
{
nouveau_hdmi_disconnect
(
encoder
);
return
;
}
/* value matches nvidia binary driver, and tegra constant */
rekey
=
56
;
max_ac_packet
=
mode
->
htotal
-
mode
->
hdisplay
;
max_ac_packet
-=
rekey
;
max_ac_packet
-=
18
;
/* constant from tegra */
max_ac_packet
/=
32
;
nv_call
(
priv
->
core
,
NV84_DISP_SOR_HDMI_PWR
+
moff
,
NV84_DISP_SOR_HDMI_PWR_STATE_ON
|
(
max_ac_packet
<<
16
)
|
rekey
);
nouveau_audio_mode_set
(
encoder
,
mode
);
}
drivers/gpu/drm/nouveau/nv50_crtc.c
deleted
100644 → 0
View file @
f9887d09
/*
* Copyright (C) 2008 Maarten Maathuis.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
#include "nouveau_reg.h"
#include "nouveau_drm.h"
#include "nouveau_dma.h"
#include "nouveau_gem.h"
#include "nouveau_hw.h"
#include "nouveau_encoder.h"
#include "nouveau_crtc.h"
#include "nouveau_connector.h"
#include "nv50_display.h"
#include <subdev/clock.h>
static
void
nv50_crtc_lut_load
(
struct
drm_crtc
*
crtc
)
{
struct
nouveau_crtc
*
nv_crtc
=
nouveau_crtc
(
crtc
);
void
__iomem
*
lut
=
nvbo_kmap_obj_iovirtual
(
nv_crtc
->
lut
.
nvbo
);
int
i
;
for
(
i
=
0
;
i
<
256
;
i
++
)
{
writew
(
nv_crtc
->
lut
.
r
[
i
]
>>
2
,
lut
+
8
*
i
+
0
);
writew
(
nv_crtc
->
lut
.
g
[
i
]
>>
2
,
lut
+
8
*
i
+
2
);
writew
(
nv_crtc
->
lut
.
b
[
i
]
>>
2
,
lut
+
8
*
i
+
4
);
}
if
(
nv_crtc
->
lut
.
depth
==
30
)
{
writew
(
nv_crtc
->
lut
.
r
[
i
-
1
]
>>
2
,
lut
+
8
*
i
+
0
);
writew
(
nv_crtc
->
lut
.
g
[
i
-
1
]
>>
2
,
lut
+
8
*
i
+
2
);
writew
(
nv_crtc
->
lut
.
b
[
i
-
1
]
>>
2
,
lut
+
8
*
i
+
4
);
}
}
int
nv50_crtc_blank
(
struct
nouveau_crtc
*
nv_crtc
,
bool
blanked
)
{
struct
drm_device
*
dev
=
nv_crtc
->
base
.
dev
;
struct
nouveau_drm
*
drm
=
nouveau_drm
(
dev
);
struct
nouveau_channel
*
evo
=
nv50_display
(
dev
)
->
master
;
int
index
=
nv_crtc
->
index
,
ret
;
NV_DEBUG
(
drm
,
"index %d
\n
"
,
nv_crtc
->
index
);
NV_DEBUG
(
drm
,
"%s
\n
"
,
blanked
?
"blanked"
:
"unblanked"
);
if
(
blanked
)
{
nv_crtc
->
cursor
.
hide
(
nv_crtc
,
false
);
ret
=
RING_SPACE
(
evo
,
nv_device
(
drm
->
device
)
->
chipset
!=
0x50
?
7
:
5
);
if
(
ret
)
{
NV_ERROR
(
drm
,
"no space while blanking crtc
\n
"
);
return
ret
;
}
BEGIN_NV04
(
evo
,
0
,
NV50_EVO_CRTC
(
index
,
CLUT_MODE
),
2
);
OUT_RING
(
evo
,
NV50_EVO_CRTC_CLUT_MODE_BLANK
);
OUT_RING
(
evo
,
0
);
if
(
nv_device
(
drm
->
device
)
->
chipset
!=
0x50
)
{
BEGIN_NV04
(
evo
,
0
,
NV84_EVO_CRTC
(
index
,
CLUT_DMA
),
1
);
OUT_RING
(
evo
,
NV84_EVO_CRTC_CLUT_DMA_HANDLE_NONE
);
}
BEGIN_NV04
(
evo
,
0
,
NV50_EVO_CRTC
(
index
,
FB_DMA
),
1
);
OUT_RING
(
evo
,
NV50_EVO_CRTC_FB_DMA_HANDLE_NONE
);
}
else
{
if
(
nv_crtc
->
cursor
.
visible
)
nv_crtc
->
cursor
.
show
(
nv_crtc
,
false
);
else
nv_crtc
->
cursor
.
hide
(
nv_crtc
,
false
);
ret
=
RING_SPACE
(
evo
,
nv_device
(
drm
->
device
)
->
chipset
!=
0x50
?
10
:
8
);
if
(
ret
)
{
NV_ERROR
(
drm
,
"no space while unblanking crtc
\n
"
);
return
ret
;
}
BEGIN_NV04
(
evo
,
0
,
NV50_EVO_CRTC
(
index
,
CLUT_MODE
),
2
);
OUT_RING
(
evo
,
nv_crtc
->
lut
.
depth
==
8
?
NV50_EVO_CRTC_CLUT_MODE_OFF
:
NV50_EVO_CRTC_CLUT_MODE_ON
);
OUT_RING
(
evo
,
nv_crtc
->
lut
.
nvbo
->
bo
.
offset
>>
8
);
if
(
nv_device
(
drm
->
device
)
->
chipset
!=
0x50
)
{
BEGIN_NV04
(
evo
,
0
,
NV84_EVO_CRTC
(
index
,
CLUT_DMA
),
1
);
OUT_RING
(
evo
,
NvEvoVRAM
);
}
BEGIN_NV04
(
evo
,
0
,
NV50_EVO_CRTC
(
index
,
FB_OFFSET
),
2
);
OUT_RING
(
evo
,
nv_crtc
->
fb
.
offset
>>
8
);
OUT_RING
(
evo
,
0
);
BEGIN_NV04
(
evo
,
0
,
NV50_EVO_CRTC
(
index
,
FB_DMA
),
1
);
if
(
nv_device
(
drm
->
device
)
->
chipset
!=
0x50
)
if
(
nv_crtc
->
fb
.
tile_flags
==
0x7a00
||
nv_crtc
->
fb
.
tile_flags
==
0xfe00
)
OUT_RING
(
evo
,
NvEvoFB32
);
else
if
(
nv_crtc
->
fb
.
tile_flags
==
0x7000
)
OUT_RING
(
evo
,
NvEvoFB16
);
else
OUT_RING
(
evo
,
NvEvoVRAM_LP
);
else
OUT_RING
(
evo
,
NvEvoVRAM_LP
);
}
nv_crtc
->
fb
.
blanked
=
blanked
;
return
0
;
}
static
int
nv50_crtc_set_dither
(
struct
nouveau_crtc
*
nv_crtc
,
bool
update
)
{
struct
nouveau_channel
*
evo
=
nv50_display
(
nv_crtc
->
base
.
dev
)
->
master
;
struct
nouveau_connector
*
nv_connector
;
struct
drm_connector
*
connector
;
int
head
=
nv_crtc
->
index
,
ret
;
u32
mode
=
0x00
;
nv_connector
=
nouveau_crtc_connector_get
(
nv_crtc
);
connector
=
&
nv_connector
->
base
;
if
(
nv_connector
->
dithering_mode
==
DITHERING_MODE_AUTO
)
{
if
(
nv_crtc
->
base
.
fb
->
depth
>
connector
->
display_info
.
bpc
*
3
)
mode
=
DITHERING_MODE_DYNAMIC2X2
;
}
else
{
mode
=
nv_connector
->
dithering_mode
;
}
if
(
nv_connector
->
dithering_depth
==
DITHERING_DEPTH_AUTO
)
{
if
(
connector
->
display_info
.
bpc
>=
8
)
mode
|=
DITHERING_DEPTH_8BPC
;
}
else
{
mode
|=
nv_connector
->
dithering_depth
;
}
ret
=
RING_SPACE
(
evo
,
2
+
(
update
?
2
:
0
));
if
(
ret
==
0
)
{
BEGIN_NV04
(
evo
,
0
,
NV50_EVO_CRTC
(
head
,
DITHER_CTRL
),
1
);
OUT_RING
(
evo
,
mode
);
if
(
update
)
{
BEGIN_NV04
(
evo
,
0
,
NV50_EVO_UPDATE
,
1
);
OUT_RING
(
evo
,
0
);
FIRE_RING
(
evo
);
}
}
return
ret
;
}
static
int
nv50_crtc_set_color_vibrance
(
struct
nouveau_crtc
*
nv_crtc
,
bool
update
)
{
struct
drm_device
*
dev
=
nv_crtc
->
base
.
dev
;
struct
nouveau_drm
*
drm
=
nouveau_drm
(
dev
);
struct
nouveau_channel
*
evo
=
nv50_display
(
dev
)
->
master
;
int
ret
;
int
adj
;
u32
hue
,
vib
;
NV_DEBUG
(
drm
,
"vibrance = %i, hue = %i
\n
"
,
nv_crtc
->
color_vibrance
,
nv_crtc
->
vibrant_hue
);
ret
=
RING_SPACE
(
evo
,
2
+
(
update
?
2
:
0
));
if
(
ret
)
{
NV_ERROR
(
drm
,
"no space while setting color vibrance
\n
"
);
return
ret
;
}
adj
=
(
nv_crtc
->
color_vibrance
>
0
)
?
50
:
0
;
vib
=
((
nv_crtc
->
color_vibrance
*
2047
+
adj
)
/
100
)
&
0xfff
;
hue
=
((
nv_crtc
->
vibrant_hue
*
2047
)
/
100
)
&
0xfff
;
BEGIN_NV04
(
evo
,
0
,
NV50_EVO_CRTC
(
nv_crtc
->
index
,
COLOR_CTRL
),
1
);
OUT_RING
(
evo
,
(
hue
<<
20
)
|
(
vib
<<
8
));
if
(
update
)
{
BEGIN_NV04
(
evo
,
0
,
NV50_EVO_UPDATE
,
1
);
OUT_RING
(
evo
,
0
);
FIRE_RING
(
evo
);
}
return
0
;
}
struct
nouveau_connector
*
nouveau_crtc_connector_get
(
struct
nouveau_crtc
*
nv_crtc
)
{
struct
drm_device
*
dev
=
nv_crtc
->
base
.
dev
;
struct
drm_connector
*
connector
;
struct
drm_crtc
*
crtc
=
to_drm_crtc
(
nv_crtc
);
/* The safest approach is to find an encoder with the right crtc, that
* is also linked to a connector. */
list_for_each_entry
(
connector
,
&
dev
->
mode_config
.
connector_list
,
head
)
{
if
(
connector
->
encoder
)
if
(
connector
->
encoder
->
crtc
==
crtc
)
return
nouveau_connector
(
connector
);
}
return
NULL
;
}
static
int
nv50_crtc_set_scale
(
struct
nouveau_crtc
*
nv_crtc
,
bool
update
)
{
struct
nouveau_connector
*
nv_connector
;
struct
drm_crtc
*
crtc
=
&
nv_crtc
->
base
;
struct
drm_device
*
dev
=
crtc
->
dev
;
struct
nouveau_drm
*
drm
=
nouveau_drm
(
dev
);
struct
nouveau_channel
*
evo
=
nv50_display
(
dev
)
->
master
;
struct
drm_display_mode
*
umode
=
&
crtc
->
mode
;
struct
drm_display_mode
*
omode
;
int
scaling_mode
,
ret
;
u32
ctrl
=
0
,
oX
,
oY
;
nv_connector
=
nouveau_crtc_connector_get
(
nv_crtc
);
if
(
!
nv_connector
||
!
nv_connector
->
native_mode
)
{
NV_ERROR
(
drm
,
"no native mode, forcing panel scaling
\n
"
);
scaling_mode
=
DRM_MODE_SCALE_NONE
;
}
else
{
scaling_mode
=
nv_connector
->
scaling_mode
;
}
/* start off at the resolution we programmed the crtc for, this
* effectively handles NONE/FULL scaling
*/
if
(
scaling_mode
!=
DRM_MODE_SCALE_NONE
)
omode
=
nv_connector
->
native_mode
;
else
omode
=
umode
;
oX
=
omode
->
hdisplay
;
oY
=
omode
->
vdisplay
;
if
(
omode
->
flags
&
DRM_MODE_FLAG_DBLSCAN
)
oY
*=
2
;
/* add overscan compensation if necessary, will keep the aspect
* ratio the same as the backend mode unless overridden by the
* user setting both hborder and vborder properties.
*/
if
(
nv_connector
&&
(
nv_connector
->
underscan
==
UNDERSCAN_ON
||
(
nv_connector
->
underscan
==
UNDERSCAN_AUTO
&&
nv_connector
->
edid
&&
drm_detect_hdmi_monitor
(
nv_connector
->
edid
))))
{
u32
bX
=
nv_connector
->
underscan_hborder
;
u32
bY
=
nv_connector
->
underscan_vborder
;
u32
aspect
=
(
oY
<<
19
)
/
oX
;
if
(
bX
)
{
oX
-=
(
bX
*
2
);
if
(
bY
)
oY
-=
(
bY
*
2
);
else
oY
=
((
oX
*
aspect
)
+
(
aspect
/
2
))
>>
19
;
}
else
{
oX
-=
(
oX
>>
4
)
+
32
;
if
(
bY
)
oY
-=
(
bY
*
2
);
else
oY
=
((
oX
*
aspect
)
+
(
aspect
/
2
))
>>
19
;
}
}
/* handle CENTER/ASPECT scaling, taking into account the areas
* removed already for overscan compensation
*/
switch
(
scaling_mode
)
{
case
DRM_MODE_SCALE_CENTER
:
oX
=
min
((
u32
)
umode
->
hdisplay
,
oX
);
oY
=
min
((
u32
)
umode
->
vdisplay
,
oY
);
/* fall-through */
case
DRM_MODE_SCALE_ASPECT
:
if
(
oY
<
oX
)
{
u32
aspect
=
(
umode
->
hdisplay
<<
19
)
/
umode
->
vdisplay
;
oX
=
((
oY
*
aspect
)
+
(
aspect
/
2
))
>>
19
;
}
else
{
u32
aspect
=
(
umode
->
vdisplay
<<
19
)
/
umode
->
hdisplay
;
oY
=
((
oX
*
aspect
)
+
(
aspect
/
2
))
>>
19
;
}
break
;
default:
break
;
}
if
(
umode
->
hdisplay
!=
oX
||
umode
->
vdisplay
!=
oY
||
umode
->
flags
&
DRM_MODE_FLAG_INTERLACE
||
umode
->
flags
&
DRM_MODE_FLAG_DBLSCAN
)
ctrl
|=
NV50_EVO_CRTC_SCALE_CTRL_ACTIVE
;
ret
=
RING_SPACE
(
evo
,
5
);
if
(
ret
)
return
ret
;
BEGIN_NV04
(
evo
,
0
,
NV50_EVO_CRTC
(
nv_crtc
->
index
,
SCALE_CTRL
),
1
);
OUT_RING
(
evo
,
ctrl
);
BEGIN_NV04
(
evo
,
0
,
NV50_EVO_CRTC
(
nv_crtc
->
index
,
SCALE_RES1
),
2
);
OUT_RING
(
evo
,
oY
<<
16
|
oX
);
OUT_RING
(
evo
,
oY
<<
16
|
oX
);
if
(
update
)
{
nv50_display_flip_stop
(
crtc
);
nv50_display_sync
(
dev
);
nv50_display_flip_next
(
crtc
,
crtc
->
fb
,
NULL
);
}
return
0
;
}
int
nv50_crtc_set_clock
(
struct
drm_device
*
dev
,
int
head
,
int
pclk
)
{
struct
nouveau_device
*
device
=
nouveau_dev
(
dev
);
struct
nouveau_clock
*
clk
=
nouveau_clock
(
device
);
return
clk
->
pll_set
(
clk
,
PLL_VPLL0
+
head
,
pclk
);
}
static
void
nv50_crtc_destroy
(
struct
drm_crtc
*
crtc
)
{
struct
nouveau_crtc
*
nv_crtc
=
nouveau_crtc
(
crtc
);
nouveau_bo_unmap
(
nv_crtc
->
lut
.
nvbo
);
nouveau_bo_ref
(
NULL
,
&
nv_crtc
->
lut
.
nvbo
);
nouveau_bo_unmap
(
nv_crtc
->
cursor
.
nvbo
);
nouveau_bo_ref
(
NULL
,
&
nv_crtc
->
cursor
.
nvbo
);
drm_crtc_cleanup
(
&
nv_crtc
->
base
);
kfree
(
nv_crtc
);
}
int
nv50_crtc_cursor_set
(
struct
drm_crtc
*
crtc
,
struct
drm_file
*
file_priv
,
uint32_t
buffer_handle
,
uint32_t
width
,
uint32_t
height
)
{
struct
drm_device
*
dev
=
crtc
->
dev
;
struct
nouveau_crtc
*
nv_crtc
=
nouveau_crtc
(
crtc
);
struct
nouveau_bo
*
cursor
=
NULL
;
struct
drm_gem_object
*
gem
;
int
ret
=
0
,
i
;
if
(
!
buffer_handle
)
{
nv_crtc
->
cursor
.
hide
(
nv_crtc
,
true
);
return
0
;
}
if
(
width
!=
64
||
height
!=
64
)
return
-
EINVAL
;
gem
=
drm_gem_object_lookup
(
dev
,
file_priv
,
buffer_handle
);
if
(
!
gem
)
return
-
ENOENT
;
cursor
=
nouveau_gem_object
(
gem
);
ret
=
nouveau_bo_map
(
cursor
);
if
(
ret
)
goto
out
;
/* The simple will do for now. */
for
(
i
=
0
;
i
<
64
*
64
;
i
++
)
nouveau_bo_wr32
(
nv_crtc
->
cursor
.
nvbo
,
i
,
nouveau_bo_rd32
(
cursor
,
i
));
nouveau_bo_unmap
(
cursor
);
nv_crtc
->
cursor
.
set_offset
(
nv_crtc
,
nv_crtc
->
cursor
.
nvbo
->
bo
.
offset
);
nv_crtc
->
cursor
.
show
(
nv_crtc
,
true
);
out:
drm_gem_object_unreference_unlocked
(
gem
);
return
ret
;
}
int
nv50_crtc_cursor_move
(
struct
drm_crtc
*
crtc
,
int
x
,
int
y
)
{
struct
nouveau_crtc
*
nv_crtc
=
nouveau_crtc
(
crtc
);
nv_crtc
->
cursor
.
set_pos
(
nv_crtc
,
x
,
y
);
return
0
;
}
static
void
nv50_crtc_gamma_set
(
struct
drm_crtc
*
crtc
,
u16
*
r
,
u16
*
g
,
u16
*
b
,
uint32_t
start
,
uint32_t
size
)
{
int
end
=
(
start
+
size
>
256
)
?
256
:
start
+
size
,
i
;
struct
nouveau_crtc
*
nv_crtc
=
nouveau_crtc
(
crtc
);
for
(
i
=
start
;
i
<
end
;
i
++
)
{
nv_crtc
->
lut
.
r
[
i
]
=
r
[
i
];
nv_crtc
->
lut
.
g
[
i
]
=
g
[
i
];
nv_crtc
->
lut
.
b
[
i
]
=
b
[
i
];
}
/* We need to know the depth before we upload, but it's possible to
* get called before a framebuffer is bound. If this is the case,
* mark the lut values as dirty by setting depth==0, and it'll be
* uploaded on the first mode_set_base()
*/
if
(
!
nv_crtc
->
base
.
fb
)
{
nv_crtc
->
lut
.
depth
=
0
;
return
;
}
nv50_crtc_lut_load
(
crtc
);
}
static
void
nv50_crtc_save
(
struct
drm_crtc
*
crtc
)
{
struct
nouveau_drm
*
drm
=
nouveau_drm
(
crtc
->
dev
);
NV_ERROR
(
drm
,
"!!
\n
"
);
}
static
void
nv50_crtc_restore
(
struct
drm_crtc
*
crtc
)
{
struct
nouveau_drm
*
drm
=
nouveau_drm
(
crtc
->
dev
);
NV_ERROR
(
drm
,
"!!
\n
"
);
}
static
const
struct
drm_crtc_funcs
nv50_crtc_funcs
=
{
.
save
=
nv50_crtc_save
,
.
restore
=
nv50_crtc_restore
,
.
cursor_set
=
nv50_crtc_cursor_set
,
.
cursor_move
=
nv50_crtc_cursor_move
,
.
gamma_set
=
nv50_crtc_gamma_set
,
.
set_config
=
drm_crtc_helper_set_config
,
.
page_flip
=
nouveau_crtc_page_flip
,
.
destroy
=
nv50_crtc_destroy
,
};
static
void
nv50_crtc_dpms
(
struct
drm_crtc
*
crtc
,
int
mode
)
{
}
static
void
nv50_crtc_prepare
(
struct
drm_crtc
*
crtc
)
{
struct
nouveau_crtc
*
nv_crtc
=
nouveau_crtc
(
crtc
);
struct
drm_device
*
dev
=
crtc
->
dev
;
struct
nouveau_drm
*
drm
=
nouveau_drm
(
dev
);
NV_DEBUG
(
drm
,
"index %d
\n
"
,
nv_crtc
->
index
);
nv50_display_flip_stop
(
crtc
);
drm_vblank_pre_modeset
(
dev
,
nv_crtc
->
index
);
nv50_crtc_blank
(
nv_crtc
,
true
);
}
static
void
nv50_crtc_commit
(
struct
drm_crtc
*
crtc
)
{
struct
drm_device
*
dev
=
crtc
->
dev
;
struct
nouveau_drm
*
drm
=
nouveau_drm
(
dev
);
struct
nouveau_crtc
*
nv_crtc
=
nouveau_crtc
(
crtc
);
NV_DEBUG
(
drm
,
"index %d
\n
"
,
nv_crtc
->
index
);
nv50_crtc_blank
(
nv_crtc
,
false
);
drm_vblank_post_modeset
(
dev
,
nv_crtc
->
index
);
nv50_display_sync
(
dev
);
nv50_display_flip_next
(
crtc
,
crtc
->
fb
,
NULL
);
}
static
bool
nv50_crtc_mode_fixup
(
struct
drm_crtc
*
crtc
,
const
struct
drm_display_mode
*
mode
,
struct
drm_display_mode
*
adjusted_mode
)
{
return
true
;
}
static
int
nv50_crtc_do_mode_set_base
(
struct
drm_crtc
*
crtc
,
struct
drm_framebuffer
*
passed_fb
,
int
x
,
int
y
,
bool
atomic
)
{
struct
nouveau_crtc
*
nv_crtc
=
nouveau_crtc
(
crtc
);
struct
drm_device
*
dev
=
nv_crtc
->
base
.
dev
;
struct
nouveau_drm
*
drm
=
nouveau_drm
(
dev
);
struct
nouveau_channel
*
evo
=
nv50_display
(
dev
)
->
master
;
struct
drm_framebuffer
*
drm_fb
;
struct
nouveau_framebuffer
*
fb
;
int
ret
;
NV_DEBUG
(
drm
,
"index %d
\n
"
,
nv_crtc
->
index
);
/* no fb bound */
if
(
!
atomic
&&
!
crtc
->
fb
)
{
NV_DEBUG
(
drm
,
"No FB bound
\n
"
);
return
0
;
}
/* If atomic, we want to switch to the fb we were passed, so
* now we update pointers to do that. (We don't pin; just
* assume we're already pinned and update the base address.)
*/
if
(
atomic
)
{
drm_fb
=
passed_fb
;
fb
=
nouveau_framebuffer
(
passed_fb
);
}
else
{
drm_fb
=
crtc
->
fb
;
fb
=
nouveau_framebuffer
(
crtc
->
fb
);
/* If not atomic, we can go ahead and pin, and unpin the
* old fb we were passed.
*/
ret
=
nouveau_bo_pin
(
fb
->
nvbo
,
TTM_PL_FLAG_VRAM
);
if
(
ret
)
return
ret
;
if
(
passed_fb
)
{
struct
nouveau_framebuffer
*
ofb
=
nouveau_framebuffer
(
passed_fb
);
nouveau_bo_unpin
(
ofb
->
nvbo
);
}
}
nv_crtc
->
fb
.
offset
=
fb
->
nvbo
->
bo
.
offset
;
nv_crtc
->
fb
.
tile_flags
=
nouveau_bo_tile_layout
(
fb
->
nvbo
);
nv_crtc
->
fb
.
cpp
=
drm_fb
->
bits_per_pixel
/
8
;
if
(
!
nv_crtc
->
fb
.
blanked
&&
nv_device
(
drm
->
device
)
->
chipset
!=
0x50
)
{
ret
=
RING_SPACE
(
evo
,
2
);
if
(
ret
)
return
ret
;
BEGIN_NV04
(
evo
,
0
,
NV50_EVO_CRTC
(
nv_crtc
->
index
,
FB_DMA
),
1
);
OUT_RING
(
evo
,
fb
->
r_dma
);
}
ret
=
RING_SPACE
(
evo
,
12
);
if
(
ret
)
return
ret
;
BEGIN_NV04
(
evo
,
0
,
NV50_EVO_CRTC
(
nv_crtc
->
index
,
FB_OFFSET
),
5
);
OUT_RING
(
evo
,
nv_crtc
->
fb
.
offset
>>
8
);
OUT_RING
(
evo
,
0
);
OUT_RING
(
evo
,
(
drm_fb
->
height
<<
16
)
|
drm_fb
->
width
);
OUT_RING
(
evo
,
fb
->
r_pitch
);
OUT_RING
(
evo
,
fb
->
r_format
);
BEGIN_NV04
(
evo
,
0
,
NV50_EVO_CRTC
(
nv_crtc
->
index
,
CLUT_MODE
),
1
);
OUT_RING
(
evo
,
fb
->
base
.
depth
==
8
?
NV50_EVO_CRTC_CLUT_MODE_OFF
:
NV50_EVO_CRTC_CLUT_MODE_ON
);
BEGIN_NV04
(
evo
,
0
,
NV50_EVO_CRTC
(
nv_crtc
->
index
,
FB_POS
),
1
);
OUT_RING
(
evo
,
(
y
<<
16
)
|
x
);
if
(
nv_crtc
->
lut
.
depth
!=
fb
->
base
.
depth
)
{
nv_crtc
->
lut
.
depth
=
fb
->
base
.
depth
;
nv50_crtc_lut_load
(
crtc
);
}
return
0
;
}
static
int
nv50_crtc_mode_set
(
struct
drm_crtc
*
crtc
,
struct
drm_display_mode
*
umode
,
struct
drm_display_mode
*
mode
,
int
x
,
int
y
,
struct
drm_framebuffer
*
old_fb
)
{
struct
drm_device
*
dev
=
crtc
->
dev
;
struct
nouveau_channel
*
evo
=
nv50_display
(
dev
)
->
master
;
struct
nouveau_crtc
*
nv_crtc
=
nouveau_crtc
(
crtc
);
u32
head
=
nv_crtc
->
index
*
0x400
;
u32
ilace
=
(
mode
->
flags
&
DRM_MODE_FLAG_INTERLACE
)
?
2
:
1
;
u32
vscan
=
(
mode
->
flags
&
DRM_MODE_FLAG_DBLSCAN
)
?
2
:
1
;
u32
hactive
,
hsynce
,
hbackp
,
hfrontp
,
hblanke
,
hblanks
;
u32
vactive
,
vsynce
,
vbackp
,
vfrontp
,
vblanke
,
vblanks
;
u32
vblan2e
=
0
,
vblan2s
=
1
;
int
ret
;
/* hw timing description looks like this:
*
* <sync> <back porch> <---------display---------> <front porch>
* ______
* |____________|---------------------------|____________|
*
* ^ synce ^ blanke ^ blanks ^ active
*
* interlaced modes also have 2 additional values pointing at the end
* and start of the next field's blanking period.
*/
hactive
=
mode
->
htotal
;
hsynce
=
mode
->
hsync_end
-
mode
->
hsync_start
-
1
;
hbackp
=
mode
->
htotal
-
mode
->
hsync_end
;
hblanke
=
hsynce
+
hbackp
;
hfrontp
=
mode
->
hsync_start
-
mode
->
hdisplay
;
hblanks
=
mode
->
htotal
-
hfrontp
-
1
;
vactive
=
mode
->
vtotal
*
vscan
/
ilace
;
vsynce
=
((
mode
->
vsync_end
-
mode
->
vsync_start
)
*
vscan
/
ilace
)
-
1
;
vbackp
=
(
mode
->
vtotal
-
mode
->
vsync_end
)
*
vscan
/
ilace
;
vblanke
=
vsynce
+
vbackp
;
vfrontp
=
(
mode
->
vsync_start
-
mode
->
vdisplay
)
*
vscan
/
ilace
;
vblanks
=
vactive
-
vfrontp
-
1
;
if
(
mode
->
flags
&
DRM_MODE_FLAG_INTERLACE
)
{
vblan2e
=
vactive
+
vsynce
+
vbackp
;
vblan2s
=
vblan2e
+
(
mode
->
vdisplay
*
vscan
/
ilace
);
vactive
=
(
vactive
*
2
)
+
1
;
}
ret
=
RING_SPACE
(
evo
,
18
);
if
(
ret
==
0
)
{
BEGIN_NV04
(
evo
,
0
,
0x0804
+
head
,
2
);
OUT_RING
(
evo
,
0x00800000
|
mode
->
clock
);
OUT_RING
(
evo
,
(
ilace
==
2
)
?
2
:
0
);
BEGIN_NV04
(
evo
,
0
,
0x0810
+
head
,
6
);
OUT_RING
(
evo
,
0x00000000
);
/* border colour */
OUT_RING
(
evo
,
(
vactive
<<
16
)
|
hactive
);
OUT_RING
(
evo
,
(
vsynce
<<
16
)
|
hsynce
);
OUT_RING
(
evo
,
(
vblanke
<<
16
)
|
hblanke
);
OUT_RING
(
evo
,
(
vblanks
<<
16
)
|
hblanks
);
OUT_RING
(
evo
,
(
vblan2e
<<
16
)
|
vblan2s
);
BEGIN_NV04
(
evo
,
0
,
0x082c
+
head
,
1
);
OUT_RING
(
evo
,
0x00000000
);
BEGIN_NV04
(
evo
,
0
,
0x0900
+
head
,
1
);
OUT_RING
(
evo
,
0x00000311
);
/* makes sync channel work */
BEGIN_NV04
(
evo
,
0
,
0x08c8
+
head
,
1
);
OUT_RING
(
evo
,
(
umode
->
vdisplay
<<
16
)
|
umode
->
hdisplay
);
BEGIN_NV04
(
evo
,
0
,
0x08d4
+
head
,
1
);
OUT_RING
(
evo
,
0x00000000
);
/* screen position */
}
nv_crtc
->
set_dither
(
nv_crtc
,
false
);
nv_crtc
->
set_scale
(
nv_crtc
,
false
);
nv_crtc
->
set_color_vibrance
(
nv_crtc
,
false
);
return
nv50_crtc_do_mode_set_base
(
crtc
,
old_fb
,
x
,
y
,
false
);
}
static
int
nv50_crtc_mode_set_base
(
struct
drm_crtc
*
crtc
,
int
x
,
int
y
,
struct
drm_framebuffer
*
old_fb
)
{
int
ret
;
nv50_display_flip_stop
(
crtc
);
ret
=
nv50_crtc_do_mode_set_base
(
crtc
,
old_fb
,
x
,
y
,
false
);
if
(
ret
)
return
ret
;
ret
=
nv50_display_sync
(
crtc
->
dev
);
if
(
ret
)
return
ret
;
return
nv50_display_flip_next
(
crtc
,
crtc
->
fb
,
NULL
);
}
static
int
nv50_crtc_mode_set_base_atomic
(
struct
drm_crtc
*
crtc
,
struct
drm_framebuffer
*
fb
,
int
x
,
int
y
,
enum
mode_set_atomic
state
)
{
int
ret
;
nv50_display_flip_stop
(
crtc
);
ret
=
nv50_crtc_do_mode_set_base
(
crtc
,
fb
,
x
,
y
,
true
);
if
(
ret
)
return
ret
;
return
nv50_display_sync
(
crtc
->
dev
);
}
static
const
struct
drm_crtc_helper_funcs
nv50_crtc_helper_funcs
=
{
.
dpms
=
nv50_crtc_dpms
,
.
prepare
=
nv50_crtc_prepare
,
.
commit
=
nv50_crtc_commit
,
.
mode_fixup
=
nv50_crtc_mode_fixup
,
.
mode_set
=
nv50_crtc_mode_set
,
.
mode_set_base
=
nv50_crtc_mode_set_base
,
.
mode_set_base_atomic
=
nv50_crtc_mode_set_base_atomic
,
.
load_lut
=
nv50_crtc_lut_load
,
};
int
nv50_crtc_create
(
struct
drm_device
*
dev
,
int
index
)
{
struct
nouveau_crtc
*
nv_crtc
=
NULL
;
int
ret
,
i
;
nv_crtc
=
kzalloc
(
sizeof
(
*
nv_crtc
),
GFP_KERNEL
);
if
(
!
nv_crtc
)
return
-
ENOMEM
;
nv_crtc
->
index
=
index
;
nv_crtc
->
set_dither
=
nv50_crtc_set_dither
;
nv_crtc
->
set_scale
=
nv50_crtc_set_scale
;
nv_crtc
->
set_color_vibrance
=
nv50_crtc_set_color_vibrance
;
nv_crtc
->
color_vibrance
=
50
;
nv_crtc
->
vibrant_hue
=
0
;
nv_crtc
->
lut
.
depth
=
0
;
for
(
i
=
0
;
i
<
256
;
i
++
)
{
nv_crtc
->
lut
.
r
[
i
]
=
i
<<
8
;
nv_crtc
->
lut
.
g
[
i
]
=
i
<<
8
;
nv_crtc
->
lut
.
b
[
i
]
=
i
<<
8
;
}
drm_crtc_init
(
dev
,
&
nv_crtc
->
base
,
&
nv50_crtc_funcs
);
drm_crtc_helper_add
(
&
nv_crtc
->
base
,
&
nv50_crtc_helper_funcs
);
drm_mode_crtc_set_gamma_size
(
&
nv_crtc
->
base
,
256
);
ret
=
nouveau_bo_new
(
dev
,
4096
,
0x100
,
TTM_PL_FLAG_VRAM
,
0
,
0x0000
,
NULL
,
&
nv_crtc
->
lut
.
nvbo
);
if
(
!
ret
)
{
ret
=
nouveau_bo_pin
(
nv_crtc
->
lut
.
nvbo
,
TTM_PL_FLAG_VRAM
);
if
(
!
ret
)
ret
=
nouveau_bo_map
(
nv_crtc
->
lut
.
nvbo
);
if
(
ret
)
nouveau_bo_ref
(
NULL
,
&
nv_crtc
->
lut
.
nvbo
);
}
if
(
ret
)
goto
out
;
ret
=
nouveau_bo_new
(
dev
,
64
*
64
*
4
,
0x100
,
TTM_PL_FLAG_VRAM
,
0
,
0x0000
,
NULL
,
&
nv_crtc
->
cursor
.
nvbo
);
if
(
!
ret
)
{
ret
=
nouveau_bo_pin
(
nv_crtc
->
cursor
.
nvbo
,
TTM_PL_FLAG_VRAM
);
if
(
!
ret
)
ret
=
nouveau_bo_map
(
nv_crtc
->
cursor
.
nvbo
);
if
(
ret
)
nouveau_bo_ref
(
NULL
,
&
nv_crtc
->
cursor
.
nvbo
);
}
if
(
ret
)
goto
out
;
nv50_cursor_init
(
nv_crtc
);
out:
if
(
ret
)
nv50_crtc_destroy
(
&
nv_crtc
->
base
);
return
ret
;
}
drivers/gpu/drm/nouveau/nv50_cursor.c
deleted
100644 → 0
View file @
f9887d09
/*
* Copyright (C) 2008 Maarten Maathuis.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include <drm/drmP.h>
#include "nouveau_drm.h"
#include "nouveau_dma.h"
#include "nouveau_crtc.h"
#include "nv50_display.h"
static
void
nv50_cursor_show
(
struct
nouveau_crtc
*
nv_crtc
,
bool
update
)
{
struct
drm_device
*
dev
=
nv_crtc
->
base
.
dev
;
struct
nouveau_drm
*
drm
=
nouveau_drm
(
dev
);
struct
nouveau_channel
*
evo
=
nv50_display
(
dev
)
->
master
;
int
ret
;
if
(
update
&&
nv_crtc
->
cursor
.
visible
)
return
;
ret
=
RING_SPACE
(
evo
,
(
nv_device
(
drm
->
device
)
->
chipset
!=
0x50
?
5
:
3
)
+
update
*
2
);
if
(
ret
)
{
NV_ERROR
(
drm
,
"no space while unhiding cursor
\n
"
);
return
;
}
if
(
nv_device
(
drm
->
device
)
->
chipset
!=
0x50
)
{
BEGIN_NV04
(
evo
,
0
,
NV84_EVO_CRTC
(
nv_crtc
->
index
,
CURSOR_DMA
),
1
);
OUT_RING
(
evo
,
NvEvoVRAM
);
}
BEGIN_NV04
(
evo
,
0
,
NV50_EVO_CRTC
(
nv_crtc
->
index
,
CURSOR_CTRL
),
2
);
OUT_RING
(
evo
,
NV50_EVO_CRTC_CURSOR_CTRL_SHOW
);
OUT_RING
(
evo
,
nv_crtc
->
cursor
.
offset
>>
8
);
if
(
update
)
{
BEGIN_NV04
(
evo
,
0
,
NV50_EVO_UPDATE
,
1
);
OUT_RING
(
evo
,
0
);
FIRE_RING
(
evo
);
nv_crtc
->
cursor
.
visible
=
true
;
}
}
static
void
nv50_cursor_hide
(
struct
nouveau_crtc
*
nv_crtc
,
bool
update
)
{
struct
drm_device
*
dev
=
nv_crtc
->
base
.
dev
;
struct
nouveau_drm
*
drm
=
nouveau_drm
(
dev
);
struct
nouveau_channel
*
evo
=
nv50_display
(
dev
)
->
master
;
int
ret
;
if
(
update
&&
!
nv_crtc
->
cursor
.
visible
)
return
;
ret
=
RING_SPACE
(
evo
,
(
nv_device
(
drm
->
device
)
->
chipset
!=
0x50
?
5
:
3
)
+
update
*
2
);
if
(
ret
)
{
NV_ERROR
(
drm
,
"no space while hiding cursor
\n
"
);
return
;
}
BEGIN_NV04
(
evo
,
0
,
NV50_EVO_CRTC
(
nv_crtc
->
index
,
CURSOR_CTRL
),
2
);
OUT_RING
(
evo
,
NV50_EVO_CRTC_CURSOR_CTRL_HIDE
);
OUT_RING
(
evo
,
0
);
if
(
nv_device
(
drm
->
device
)
->
chipset
!=
0x50
)
{
BEGIN_NV04
(
evo
,
0
,
NV84_EVO_CRTC
(
nv_crtc
->
index
,
CURSOR_DMA
),
1
);
OUT_RING
(
evo
,
NV84_EVO_CRTC_CURSOR_DMA_HANDLE_NONE
);
}
if
(
update
)
{
BEGIN_NV04
(
evo
,
0
,
NV50_EVO_UPDATE
,
1
);
OUT_RING
(
evo
,
0
);
FIRE_RING
(
evo
);
nv_crtc
->
cursor
.
visible
=
false
;
}
}
static
void
nv50_cursor_set_pos
(
struct
nouveau_crtc
*
nv_crtc
,
int
x
,
int
y
)
{
struct
nouveau_device
*
device
=
nouveau_dev
(
nv_crtc
->
base
.
dev
);
nv_crtc
->
cursor_saved_x
=
x
;
nv_crtc
->
cursor_saved_y
=
y
;
nv_wr32
(
device
,
NV50_PDISPLAY_CURSOR_USER_POS
(
nv_crtc
->
index
),
((
y
&
0xFFFF
)
<<
16
)
|
(
x
&
0xFFFF
));
/* Needed to make the cursor move. */
nv_wr32
(
device
,
NV50_PDISPLAY_CURSOR_USER_POS_CTRL
(
nv_crtc
->
index
),
0
);
}
static
void
nv50_cursor_set_offset
(
struct
nouveau_crtc
*
nv_crtc
,
uint32_t
offset
)
{
if
(
offset
==
nv_crtc
->
cursor
.
offset
)
return
;
nv_crtc
->
cursor
.
offset
=
offset
;
if
(
nv_crtc
->
cursor
.
visible
)
{
nv_crtc
->
cursor
.
visible
=
false
;
nv_crtc
->
cursor
.
show
(
nv_crtc
,
true
);
}
}
int
nv50_cursor_init
(
struct
nouveau_crtc
*
nv_crtc
)
{
nv_crtc
->
cursor
.
set_offset
=
nv50_cursor_set_offset
;
nv_crtc
->
cursor
.
set_pos
=
nv50_cursor_set_pos
;
nv_crtc
->
cursor
.
hide
=
nv50_cursor_hide
;
nv_crtc
->
cursor
.
show
=
nv50_cursor_show
;
return
0
;
}
drivers/gpu/drm/nouveau/nv50_dac.c
deleted
100644 → 0
View file @
f9887d09
/*
* Copyright (C) 2008 Maarten Maathuis.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
#define NOUVEAU_DMA_DEBUG (nouveau_reg_debug & NOUVEAU_REG_DEBUG_EVO)
#include "nouveau_reg.h"
#include "nouveau_drm.h"
#include "nouveau_dma.h"
#include "nouveau_encoder.h"
#include "nouveau_connector.h"
#include "nouveau_crtc.h"
#include "nv50_display.h"
#include <core/class.h>
#include <subdev/timer.h>
static
void
nv50_dac_disconnect
(
struct
drm_encoder
*
encoder
)
{
struct
nouveau_encoder
*
nv_encoder
=
nouveau_encoder
(
encoder
);
struct
drm_device
*
dev
=
encoder
->
dev
;
struct
nouveau_drm
*
drm
=
nouveau_drm
(
dev
);
struct
nouveau_channel
*
evo
=
nv50_display
(
dev
)
->
master
;
int
ret
;
if
(
!
nv_encoder
->
crtc
)
return
;
nv50_crtc_blank
(
nouveau_crtc
(
nv_encoder
->
crtc
),
true
);
NV_DEBUG
(
drm
,
"Disconnecting DAC %d
\n
"
,
nv_encoder
->
or
);
ret
=
RING_SPACE
(
evo
,
4
);
if
(
ret
)
{
NV_ERROR
(
drm
,
"no space while disconnecting DAC
\n
"
);
return
;
}
BEGIN_NV04
(
evo
,
0
,
NV50_EVO_DAC
(
nv_encoder
->
or
,
MODE_CTRL
),
1
);
OUT_RING
(
evo
,
0
);
BEGIN_NV04
(
evo
,
0
,
NV50_EVO_UPDATE
,
1
);
OUT_RING
(
evo
,
0
);
nv_encoder
->
crtc
=
NULL
;
}
static
enum
drm_connector_status
nv50_dac_detect
(
struct
drm_encoder
*
encoder
,
struct
drm_connector
*
connector
)
{
struct
nv50_display
*
priv
=
nv50_display
(
encoder
->
dev
);
struct
nouveau_encoder
*
nv_encoder
=
nouveau_encoder
(
encoder
);
struct
nouveau_drm
*
drm
=
nouveau_drm
(
encoder
->
dev
);
int
or
=
nv_encoder
->
or
,
ret
;
u32
load
;
if
(
drm
->
vbios
.
dactestval
)
load
=
drm
->
vbios
.
dactestval
;
else
load
=
340
;
ret
=
nv_exec
(
priv
->
core
,
NV50_DISP_DAC_LOAD
+
or
,
&
load
,
sizeof
(
load
));
if
(
ret
||
load
!=
7
)
return
connector_status_disconnected
;
return
connector_status_connected
;
}
static
void
nv50_dac_dpms
(
struct
drm_encoder
*
encoder
,
int
mode
)
{
struct
nv50_display
*
priv
=
nv50_display
(
encoder
->
dev
);
struct
nouveau_drm
*
drm
=
nouveau_drm
(
encoder
->
dev
);
struct
nouveau_encoder
*
nv_encoder
=
nouveau_encoder
(
encoder
);
uint32_t
val
;
int
or
=
nv_encoder
->
or
;
NV_DEBUG
(
drm
,
"or %d mode %d
\n
"
,
or
,
mode
);
if
(
mode
!=
DRM_MODE_DPMS_ON
)
val
=
NV50_PDISPLAY_DAC_DPMS_CTRL_BLANKED
;
else
val
=
0
;
switch
(
mode
)
{
case
DRM_MODE_DPMS_STANDBY
:
val
|=
NV50_PDISPLAY_DAC_DPMS_CTRL_HSYNC_OFF
;
break
;
case
DRM_MODE_DPMS_SUSPEND
:
val
|=
NV50_PDISPLAY_DAC_DPMS_CTRL_VSYNC_OFF
;
break
;
case
DRM_MODE_DPMS_OFF
:
val
|=
NV50_PDISPLAY_DAC_DPMS_CTRL_OFF
;
val
|=
NV50_PDISPLAY_DAC_DPMS_CTRL_HSYNC_OFF
;
val
|=
NV50_PDISPLAY_DAC_DPMS_CTRL_VSYNC_OFF
;
break
;
default:
break
;
}
nv_call
(
priv
->
core
,
NV50_DISP_DAC_PWR
+
or
,
val
);
}
static
void
nv50_dac_save
(
struct
drm_encoder
*
encoder
)
{
struct
nouveau_drm
*
drm
=
nouveau_drm
(
encoder
->
dev
);
NV_ERROR
(
drm
,
"!!
\n
"
);
}
static
void
nv50_dac_restore
(
struct
drm_encoder
*
encoder
)
{
struct
nouveau_drm
*
drm
=
nouveau_drm
(
encoder
->
dev
);
NV_ERROR
(
drm
,
"!!
\n
"
);
}
static
bool
nv50_dac_mode_fixup
(
struct
drm_encoder
*
encoder
,
const
struct
drm_display_mode
*
mode
,
struct
drm_display_mode
*
adjusted_mode
)
{
struct
nouveau_drm
*
drm
=
nouveau_drm
(
encoder
->
dev
);
struct
nouveau_encoder
*
nv_encoder
=
nouveau_encoder
(
encoder
);
struct
nouveau_connector
*
connector
;
NV_DEBUG
(
drm
,
"or %d
\n
"
,
nv_encoder
->
or
);
connector
=
nouveau_encoder_connector_get
(
nv_encoder
);
if
(
!
connector
)
{
NV_ERROR
(
drm
,
"Encoder has no connector
\n
"
);
return
false
;
}
if
(
connector
->
scaling_mode
!=
DRM_MODE_SCALE_NONE
&&
connector
->
native_mode
)
drm_mode_copy
(
adjusted_mode
,
connector
->
native_mode
);
return
true
;
}
static
void
nv50_dac_commit
(
struct
drm_encoder
*
encoder
)
{
}
static
void
nv50_dac_mode_set
(
struct
drm_encoder
*
encoder
,
struct
drm_display_mode
*
mode
,
struct
drm_display_mode
*
adjusted_mode
)
{
struct
nouveau_encoder
*
nv_encoder
=
nouveau_encoder
(
encoder
);
struct
nouveau_drm
*
drm
=
nouveau_drm
(
encoder
->
dev
);
struct
drm_device
*
dev
=
encoder
->
dev
;
struct
nouveau_channel
*
evo
=
nv50_display
(
dev
)
->
master
;
struct
nouveau_crtc
*
crtc
=
nouveau_crtc
(
encoder
->
crtc
);
uint32_t
mode_ctl
=
0
,
mode_ctl2
=
0
;
int
ret
;
NV_DEBUG
(
drm
,
"or %d type %d crtc %d
\n
"
,
nv_encoder
->
or
,
nv_encoder
->
dcb
->
type
,
crtc
->
index
);
nv50_dac_dpms
(
encoder
,
DRM_MODE_DPMS_ON
);
if
(
crtc
->
index
==
1
)
mode_ctl
|=
NV50_EVO_DAC_MODE_CTRL_CRTC1
;
else
mode_ctl
|=
NV50_EVO_DAC_MODE_CTRL_CRTC0
;
/* Lacking a working tv-out, this is not a 100% sure. */
if
(
nv_encoder
->
dcb
->
type
==
DCB_OUTPUT_ANALOG
)
mode_ctl
|=
0x40
;
else
if
(
nv_encoder
->
dcb
->
type
==
DCB_OUTPUT_TV
)
mode_ctl
|=
0x100
;
if
(
adjusted_mode
->
flags
&
DRM_MODE_FLAG_NHSYNC
)
mode_ctl2
|=
NV50_EVO_DAC_MODE_CTRL2_NHSYNC
;
if
(
adjusted_mode
->
flags
&
DRM_MODE_FLAG_NVSYNC
)
mode_ctl2
|=
NV50_EVO_DAC_MODE_CTRL2_NVSYNC
;
ret
=
RING_SPACE
(
evo
,
3
);
if
(
ret
)
{
NV_ERROR
(
drm
,
"no space while connecting DAC
\n
"
);
return
;
}
BEGIN_NV04
(
evo
,
0
,
NV50_EVO_DAC
(
nv_encoder
->
or
,
MODE_CTRL
),
2
);
OUT_RING
(
evo
,
mode_ctl
);
OUT_RING
(
evo
,
mode_ctl2
);
nv_encoder
->
crtc
=
encoder
->
crtc
;
}
static
struct
drm_crtc
*
nv50_dac_crtc_get
(
struct
drm_encoder
*
encoder
)
{
return
nouveau_encoder
(
encoder
)
->
crtc
;
}
static
const
struct
drm_encoder_helper_funcs
nv50_dac_helper_funcs
=
{
.
dpms
=
nv50_dac_dpms
,
.
save
=
nv50_dac_save
,
.
restore
=
nv50_dac_restore
,
.
mode_fixup
=
nv50_dac_mode_fixup
,
.
prepare
=
nv50_dac_disconnect
,
.
commit
=
nv50_dac_commit
,
.
mode_set
=
nv50_dac_mode_set
,
.
get_crtc
=
nv50_dac_crtc_get
,
.
detect
=
nv50_dac_detect
,
.
disable
=
nv50_dac_disconnect
};
static
void
nv50_dac_destroy
(
struct
drm_encoder
*
encoder
)
{
struct
nouveau_encoder
*
nv_encoder
=
nouveau_encoder
(
encoder
);
if
(
!
encoder
)
return
;
drm_encoder_cleanup
(
encoder
);
kfree
(
nv_encoder
);
}
static
const
struct
drm_encoder_funcs
nv50_dac_encoder_funcs
=
{
.
destroy
=
nv50_dac_destroy
,
};
int
nv50_dac_create
(
struct
drm_connector
*
connector
,
struct
dcb_output
*
entry
)
{
struct
nouveau_encoder
*
nv_encoder
;
struct
drm_encoder
*
encoder
;
nv_encoder
=
kzalloc
(
sizeof
(
*
nv_encoder
),
GFP_KERNEL
);
if
(
!
nv_encoder
)
return
-
ENOMEM
;
encoder
=
to_drm_encoder
(
nv_encoder
);
nv_encoder
->
dcb
=
entry
;
nv_encoder
->
or
=
ffs
(
entry
->
or
)
-
1
;
drm_encoder_init
(
connector
->
dev
,
encoder
,
&
nv50_dac_encoder_funcs
,
DRM_MODE_ENCODER_DAC
);
drm_encoder_helper_add
(
encoder
,
&
nv50_dac_helper_funcs
);
encoder
->
possible_crtcs
=
entry
->
heads
;
encoder
->
possible_clones
=
0
;
drm_mode_connector_attach_encoder
(
connector
,
encoder
);
return
0
;
}
drivers/gpu/drm/nouveau/nv50_display.c
deleted
100644 → 0
View file @
f9887d09
/*
* Copyright (C) 2008 Maarten Maathuis.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "nouveau_drm.h"
#include "nouveau_dma.h"
#include "nv50_display.h"
#include "nouveau_crtc.h"
#include "nouveau_encoder.h"
#include "nouveau_connector.h"
#include "nouveau_fbcon.h"
#include <drm/drm_crtc_helper.h>
#include "nouveau_fence.h"
#include <core/gpuobj.h>
#include <core/class.h>
#include <subdev/timer.h>
static
inline
int
nv50_sor_nr
(
struct
drm_device
*
dev
)
{
struct
nouveau_device
*
device
=
nouveau_dev
(
dev
);
if
(
device
->
chipset
<
0x90
||
device
->
chipset
==
0x92
||
device
->
chipset
==
0xa0
)
return
2
;
return
4
;
}
u32
nv50_display_active_crtcs
(
struct
drm_device
*
dev
)
{
struct
nouveau_device
*
device
=
nouveau_dev
(
dev
);
u32
mask
=
0
;
int
i
;
if
(
device
->
chipset
<
0x90
||
device
->
chipset
==
0x92
||
device
->
chipset
==
0xa0
)
{
for
(
i
=
0
;
i
<
2
;
i
++
)
mask
|=
nv_rd32
(
device
,
NV50_PDISPLAY_SOR_MODE_CTRL_C
(
i
));
}
else
{
for
(
i
=
0
;
i
<
4
;
i
++
)
mask
|=
nv_rd32
(
device
,
NV90_PDISPLAY_SOR_MODE_CTRL_C
(
i
));
}
for
(
i
=
0
;
i
<
3
;
i
++
)
mask
|=
nv_rd32
(
device
,
NV50_PDISPLAY_DAC_MODE_CTRL_C
(
i
));
return
mask
&
3
;
}
int
nv50_display_early_init
(
struct
drm_device
*
dev
)
{
return
0
;
}
void
nv50_display_late_takedown
(
struct
drm_device
*
dev
)
{
}
int
nv50_display_sync
(
struct
drm_device
*
dev
)
{
struct
nv50_display
*
disp
=
nv50_display
(
dev
);
struct
nouveau_channel
*
evo
=
disp
->
master
;
int
ret
;
ret
=
RING_SPACE
(
evo
,
6
);
if
(
ret
==
0
)
{
BEGIN_NV04
(
evo
,
0
,
0x0084
,
1
);
OUT_RING
(
evo
,
0x80000000
);
BEGIN_NV04
(
evo
,
0
,
0x0080
,
1
);
OUT_RING
(
evo
,
0
);
BEGIN_NV04
(
evo
,
0
,
0x0084
,
1
);
OUT_RING
(
evo
,
0x00000000
);
nv_wo32
(
disp
->
ramin
,
0x2000
,
0x00000000
);
FIRE_RING
(
evo
);
if
(
nv_wait_ne
(
disp
->
ramin
,
0x2000
,
0xffffffff
,
0x00000000
))
return
0
;
}
return
0
;
}
int
nv50_display_init
(
struct
drm_device
*
dev
)
{
struct
nouveau_drm
*
drm
=
nouveau_drm
(
dev
);
struct
nouveau_device
*
device
=
nouveau_dev
(
dev
);
struct
nouveau_channel
*
evo
;
int
ret
,
i
;
for
(
i
=
0
;
i
<
3
;
i
++
)
{
nv_wr32
(
device
,
NV50_PDISPLAY_DAC_DPMS_CTRL
(
i
),
0x00550000
|
NV50_PDISPLAY_DAC_DPMS_CTRL_PENDING
);
nv_wr32
(
device
,
NV50_PDISPLAY_DAC_CLK_CTRL1
(
i
),
0x00000001
);
}
for
(
i
=
0
;
i
<
2
;
i
++
)
{
nv_wr32
(
device
,
NV50_PDISPLAY_CURSOR_CURSOR_CTRL2
(
i
),
0x2000
);
if
(
!
nv_wait
(
device
,
NV50_PDISPLAY_CURSOR_CURSOR_CTRL2
(
i
),
NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS
,
0
))
{
NV_ERROR
(
drm
,
"timeout: CURSOR_CTRL2_STATUS == 0
\n
"
);
NV_ERROR
(
drm
,
"CURSOR_CTRL2 = 0x%08x
\n
"
,
nv_rd32
(
device
,
NV50_PDISPLAY_CURSOR_CURSOR_CTRL2
(
i
)));
return
-
EBUSY
;
}
nv_wr32
(
device
,
NV50_PDISPLAY_CURSOR_CURSOR_CTRL2
(
i
),
NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_ON
);
if
(
!
nv_wait
(
device
,
NV50_PDISPLAY_CURSOR_CURSOR_CTRL2
(
i
),
NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS
,
NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS_ACTIVE
))
{
NV_ERROR
(
drm
,
"timeout: "
"CURSOR_CTRL2_STATUS_ACTIVE(%d)
\n
"
,
i
);
NV_ERROR
(
drm
,
"CURSOR_CTRL2(%d) = 0x%08x
\n
"
,
i
,
nv_rd32
(
device
,
NV50_PDISPLAY_CURSOR_CURSOR_CTRL2
(
i
)));
return
-
EBUSY
;
}
}
ret
=
nv50_evo_init
(
dev
);
if
(
ret
)
return
ret
;
evo
=
nv50_display
(
dev
)
->
master
;
ret
=
RING_SPACE
(
evo
,
3
);
if
(
ret
)
return
ret
;
BEGIN_NV04
(
evo
,
0
,
NV50_EVO_UNK84
,
2
);
OUT_RING
(
evo
,
NV50_EVO_UNK84_NOTIFY_DISABLED
);
OUT_RING
(
evo
,
NvEvoSync
);
return
nv50_display_sync
(
dev
);
}
void
nv50_display_fini
(
struct
drm_device
*
dev
)
{
struct
nouveau_drm
*
drm
=
nouveau_drm
(
dev
);
struct
nouveau_device
*
device
=
nouveau_dev
(
dev
);
struct
nv50_display
*
disp
=
nv50_display
(
dev
);
struct
nouveau_channel
*
evo
=
disp
->
master
;
struct
drm_crtc
*
drm_crtc
;
int
ret
,
i
;
list_for_each_entry
(
drm_crtc
,
&
dev
->
mode_config
.
crtc_list
,
head
)
{
struct
nouveau_crtc
*
crtc
=
nouveau_crtc
(
drm_crtc
);
nv50_crtc_blank
(
crtc
,
true
);
}
ret
=
RING_SPACE
(
evo
,
2
);
if
(
ret
==
0
)
{
BEGIN_NV04
(
evo
,
0
,
NV50_EVO_UPDATE
,
1
);
OUT_RING
(
evo
,
0
);
}
FIRE_RING
(
evo
);
/* Almost like ack'ing a vblank interrupt, maybe in the spirit of
* cleaning up?
*/
list_for_each_entry
(
drm_crtc
,
&
dev
->
mode_config
.
crtc_list
,
head
)
{
struct
nouveau_crtc
*
crtc
=
nouveau_crtc
(
drm_crtc
);
uint32_t
mask
=
NV50_PDISPLAY_INTR_1_VBLANK_CRTC_
(
crtc
->
index
);
if
(
!
crtc
->
base
.
enabled
)
continue
;
nv_wr32
(
device
,
NV50_PDISPLAY_INTR_1
,
mask
);
if
(
!
nv_wait
(
device
,
NV50_PDISPLAY_INTR_1
,
mask
,
mask
))
{
NV_ERROR
(
drm
,
"timeout: (0x610024 & 0x%08x) == "
"0x%08x
\n
"
,
mask
,
mask
);
NV_ERROR
(
drm
,
"0x610024 = 0x%08x
\n
"
,
nv_rd32
(
device
,
NV50_PDISPLAY_INTR_1
));
}
}
for
(
i
=
0
;
i
<
2
;
i
++
)
{
nv_wr32
(
device
,
NV50_PDISPLAY_CURSOR_CURSOR_CTRL2
(
i
),
0
);
if
(
!
nv_wait
(
device
,
NV50_PDISPLAY_CURSOR_CURSOR_CTRL2
(
i
),
NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS
,
0
))
{
NV_ERROR
(
drm
,
"timeout: CURSOR_CTRL2_STATUS == 0
\n
"
);
NV_ERROR
(
drm
,
"CURSOR_CTRL2 = 0x%08x
\n
"
,
nv_rd32
(
device
,
NV50_PDISPLAY_CURSOR_CURSOR_CTRL2
(
i
)));
}
}
nv50_evo_fini
(
dev
);
for
(
i
=
0
;
i
<
3
;
i
++
)
{
if
(
!
nv_wait
(
device
,
NV50_PDISPLAY_SOR_DPMS_STATE
(
i
),
NV50_PDISPLAY_SOR_DPMS_STATE_WAIT
,
0
))
{
NV_ERROR
(
drm
,
"timeout: SOR_DPMS_STATE_WAIT(%d) == 0
\n
"
,
i
);
NV_ERROR
(
drm
,
"SOR_DPMS_STATE(%d) = 0x%08x
\n
"
,
i
,
nv_rd32
(
device
,
NV50_PDISPLAY_SOR_DPMS_STATE
(
i
)));
}
}
}
int
nv50_display_create
(
struct
drm_device
*
dev
)
{
static
const
u16
oclass
[]
=
{
NVA3_DISP_CLASS
,
NV94_DISP_CLASS
,
NVA0_DISP_CLASS
,
NV84_DISP_CLASS
,
NV50_DISP_CLASS
,
};
struct
nouveau_drm
*
drm
=
nouveau_drm
(
dev
);
struct
dcb_table
*
dcb
=
&
drm
->
vbios
.
dcb
;
struct
drm_connector
*
connector
,
*
ct
;
struct
nv50_display
*
priv
;
int
ret
,
i
;
priv
=
kzalloc
(
sizeof
(
*
priv
),
GFP_KERNEL
);
if
(
!
priv
)
return
-
ENOMEM
;
nouveau_display
(
dev
)
->
priv
=
priv
;
nouveau_display
(
dev
)
->
dtor
=
nv50_display_destroy
;
nouveau_display
(
dev
)
->
init
=
nv50_display_init
;
nouveau_display
(
dev
)
->
fini
=
nv50_display_fini
;
/* attempt to allocate a supported evo display class */
ret
=
-
ENODEV
;
for
(
i
=
0
;
ret
&&
i
<
ARRAY_SIZE
(
oclass
);
i
++
)
{
ret
=
nouveau_object_new
(
nv_object
(
drm
),
NVDRM_DEVICE
,
0xd1500000
,
oclass
[
i
],
NULL
,
0
,
&
priv
->
core
);
}
if
(
ret
)
return
ret
;
/* Create CRTC objects */
for
(
i
=
0
;
i
<
2
;
i
++
)
{
ret
=
nv50_crtc_create
(
dev
,
i
);
if
(
ret
)
return
ret
;
}
/* We setup the encoders from the BIOS table */
for
(
i
=
0
;
i
<
dcb
->
entries
;
i
++
)
{
struct
dcb_output
*
entry
=
&
dcb
->
entry
[
i
];
if
(
entry
->
location
!=
DCB_LOC_ON_CHIP
)
{
NV_WARN
(
drm
,
"Off-chip encoder %d/%d unsupported
\n
"
,
entry
->
type
,
ffs
(
entry
->
or
)
-
1
);
continue
;
}
connector
=
nouveau_connector_create
(
dev
,
entry
->
connector
);
if
(
IS_ERR
(
connector
))
continue
;
switch
(
entry
->
type
)
{
case
DCB_OUTPUT_TMDS
:
case
DCB_OUTPUT_LVDS
:
case
DCB_OUTPUT_DP
:
nv50_sor_create
(
connector
,
entry
);
break
;
case
DCB_OUTPUT_ANALOG
:
nv50_dac_create
(
connector
,
entry
);
break
;
default:
NV_WARN
(
drm
,
"DCB encoder %d unknown
\n
"
,
entry
->
type
);
continue
;
}
}
list_for_each_entry_safe
(
connector
,
ct
,
&
dev
->
mode_config
.
connector_list
,
head
)
{
if
(
!
connector
->
encoder_ids
[
0
])
{
NV_WARN
(
drm
,
"%s has no encoders, removing
\n
"
,
drm_get_connector_name
(
connector
));
connector
->
funcs
->
destroy
(
connector
);
}
}
ret
=
nv50_evo_create
(
dev
);
if
(
ret
)
{
nv50_display_destroy
(
dev
);
return
ret
;
}
return
0
;
}
void
nv50_display_destroy
(
struct
drm_device
*
dev
)
{
struct
nv50_display
*
disp
=
nv50_display
(
dev
);
nv50_evo_destroy
(
dev
);
kfree
(
disp
);
}
struct
nouveau_bo
*
nv50_display_crtc_sema
(
struct
drm_device
*
dev
,
int
crtc
)
{
return
nv50_display
(
dev
)
->
crtc
[
crtc
].
sem
.
bo
;
}
void
nv50_display_flip_stop
(
struct
drm_crtc
*
crtc
)
{
struct
nv50_display
*
disp
=
nv50_display
(
crtc
->
dev
);
struct
nouveau_crtc
*
nv_crtc
=
nouveau_crtc
(
crtc
);
struct
nv50_display_crtc
*
dispc
=
&
disp
->
crtc
[
nv_crtc
->
index
];
struct
nouveau_channel
*
evo
=
dispc
->
sync
;
int
ret
;
ret
=
RING_SPACE
(
evo
,
8
);
if
(
ret
)
{
WARN_ON
(
1
);
return
;
}
BEGIN_NV04
(
evo
,
0
,
0x0084
,
1
);
OUT_RING
(
evo
,
0x00000000
);
BEGIN_NV04
(
evo
,
0
,
0x0094
,
1
);
OUT_RING
(
evo
,
0x00000000
);
BEGIN_NV04
(
evo
,
0
,
0x00c0
,
1
);
OUT_RING
(
evo
,
0x00000000
);
BEGIN_NV04
(
evo
,
0
,
0x0080
,
1
);
OUT_RING
(
evo
,
0x00000000
);
FIRE_RING
(
evo
);
}
int
nv50_display_flip_next
(
struct
drm_crtc
*
crtc
,
struct
drm_framebuffer
*
fb
,
struct
nouveau_channel
*
chan
)
{
struct
nouveau_drm
*
drm
=
nouveau_drm
(
crtc
->
dev
);
struct
nouveau_framebuffer
*
nv_fb
=
nouveau_framebuffer
(
fb
);
struct
nv50_display
*
disp
=
nv50_display
(
crtc
->
dev
);
struct
nouveau_crtc
*
nv_crtc
=
nouveau_crtc
(
crtc
);
struct
nv50_display_crtc
*
dispc
=
&
disp
->
crtc
[
nv_crtc
->
index
];
struct
nouveau_channel
*
evo
=
dispc
->
sync
;
int
ret
;
ret
=
RING_SPACE
(
evo
,
chan
?
25
:
27
);
if
(
unlikely
(
ret
))
return
ret
;
/* synchronise with the rendering channel, if necessary */
if
(
likely
(
chan
))
{
ret
=
RING_SPACE
(
chan
,
10
);
if
(
ret
)
{
WIND_RING
(
evo
);
return
ret
;
}
if
(
nv_device
(
drm
->
device
)
->
chipset
<
0xc0
)
{
BEGIN_NV04
(
chan
,
0
,
0x0060
,
2
);
OUT_RING
(
chan
,
NvEvoSema0
+
nv_crtc
->
index
);
OUT_RING
(
chan
,
dispc
->
sem
.
offset
);
BEGIN_NV04
(
chan
,
0
,
0x006c
,
1
);
OUT_RING
(
chan
,
0xf00d0000
|
dispc
->
sem
.
value
);
BEGIN_NV04
(
chan
,
0
,
0x0064
,
2
);
OUT_RING
(
chan
,
dispc
->
sem
.
offset
^
0x10
);
OUT_RING
(
chan
,
0x74b1e000
);
BEGIN_NV04
(
chan
,
0
,
0x0060
,
1
);
if
(
nv_device
(
drm
->
device
)
->
chipset
<
0x84
)
OUT_RING
(
chan
,
NvSema
);
else
OUT_RING
(
chan
,
chan
->
vram
);
}
else
{
u64
offset
=
nvc0_fence_crtc
(
chan
,
nv_crtc
->
index
);
offset
+=
dispc
->
sem
.
offset
;
BEGIN_NVC0
(
chan
,
0
,
0x0010
,
4
);
OUT_RING
(
chan
,
upper_32_bits
(
offset
));
OUT_RING
(
chan
,
lower_32_bits
(
offset
));
OUT_RING
(
chan
,
0xf00d0000
|
dispc
->
sem
.
value
);
OUT_RING
(
chan
,
0x1002
);
BEGIN_NVC0
(
chan
,
0
,
0x0010
,
4
);
OUT_RING
(
chan
,
upper_32_bits
(
offset
));
OUT_RING
(
chan
,
lower_32_bits
(
offset
^
0x10
));
OUT_RING
(
chan
,
0x74b1e000
);
OUT_RING
(
chan
,
0x1001
);
}
FIRE_RING
(
chan
);
}
else
{
nouveau_bo_wr32
(
dispc
->
sem
.
bo
,
dispc
->
sem
.
offset
/
4
,
0xf00d0000
|
dispc
->
sem
.
value
);
}
/* queue the flip on the crtc's "display sync" channel */
BEGIN_NV04
(
evo
,
0
,
0x0100
,
1
);
OUT_RING
(
evo
,
0xfffe0000
);
if
(
chan
)
{
BEGIN_NV04
(
evo
,
0
,
0x0084
,
1
);
OUT_RING
(
evo
,
0x00000100
);
}
else
{
BEGIN_NV04
(
evo
,
0
,
0x0084
,
1
);
OUT_RING
(
evo
,
0x00000010
);
/* allows gamma somehow, PDISP will bitch at you if
* you don't wait for vblank before changing this..
*/
BEGIN_NV04
(
evo
,
0
,
0x00e0
,
1
);
OUT_RING
(
evo
,
0x40000000
);
}
BEGIN_NV04
(
evo
,
0
,
0x0088
,
4
);
OUT_RING
(
evo
,
dispc
->
sem
.
offset
);
OUT_RING
(
evo
,
0xf00d0000
|
dispc
->
sem
.
value
);
OUT_RING
(
evo
,
0x74b1e000
);
OUT_RING
(
evo
,
NvEvoSync
);
BEGIN_NV04
(
evo
,
0
,
0x00a0
,
2
);
OUT_RING
(
evo
,
0x00000000
);
OUT_RING
(
evo
,
0x00000000
);
BEGIN_NV04
(
evo
,
0
,
0x00c0
,
1
);
OUT_RING
(
evo
,
nv_fb
->
r_dma
);
BEGIN_NV04
(
evo
,
0
,
0x0110
,
2
);
OUT_RING
(
evo
,
0x00000000
);
OUT_RING
(
evo
,
0x00000000
);
BEGIN_NV04
(
evo
,
0
,
0x0800
,
5
);
OUT_RING
(
evo
,
nv_fb
->
nvbo
->
bo
.
offset
>>
8
);
OUT_RING
(
evo
,
0
);
OUT_RING
(
evo
,
(
fb
->
height
<<
16
)
|
fb
->
width
);
OUT_RING
(
evo
,
nv_fb
->
r_pitch
);
OUT_RING
(
evo
,
nv_fb
->
r_format
);
BEGIN_NV04
(
evo
,
0
,
0x0080
,
1
);
OUT_RING
(
evo
,
0x00000000
);
FIRE_RING
(
evo
);
dispc
->
sem
.
offset
^=
0x10
;
dispc
->
sem
.
value
++
;
return
0
;
}
drivers/gpu/drm/nouveau/nv50_display.h
View file @
4f6029da
...
...
@@ -30,65 +30,6 @@
#include "nouveau_display.h"
#include "nouveau_crtc.h"
#include "nouveau_reg.h"
#include "nv50_evo.h"
struct
nv50_display_crtc
{
struct
nouveau_channel
*
sync
;
struct
{
struct
nouveau_bo
*
bo
;
u32
offset
;
u16
value
;
}
sem
;
};
struct
nv50_display
{
struct
nouveau_channel
*
master
;
struct
nouveau_object
*
core
;
struct
nouveau_gpuobj
*
ramin
;
u32
dmao
;
u32
hash
;
struct
nv50_display_crtc
crtc
[
2
];
struct
tasklet_struct
tasklet
;
struct
{
struct
dcb_output
*
dcb
;
u16
script
;
u32
pclk
;
}
irq
;
};
static
inline
struct
nv50_display
*
nv50_display
(
struct
drm_device
*
dev
)
{
return
nouveau_display
(
dev
)
->
priv
;
}
int
nv50_display_early_init
(
struct
drm_device
*
dev
);
void
nv50_display_late_takedown
(
struct
drm_device
*
dev
);
int
nv50_display_create
(
struct
drm_device
*
dev
);
int
nv50_display_init
(
struct
drm_device
*
dev
);
void
nv50_display_fini
(
struct
drm_device
*
dev
);
void
nv50_display_destroy
(
struct
drm_device
*
dev
);
int
nv50_crtc_blank
(
struct
nouveau_crtc
*
,
bool
blank
);
int
nv50_crtc_set_clock
(
struct
drm_device
*
,
int
head
,
int
pclk
);
u32
nv50_display_active_crtcs
(
struct
drm_device
*
);
int
nv50_display_sync
(
struct
drm_device
*
);
int
nv50_display_flip_next
(
struct
drm_crtc
*
,
struct
drm_framebuffer
*
,
struct
nouveau_channel
*
chan
);
void
nv50_display_flip_stop
(
struct
drm_crtc
*
);
int
nv50_evo_create
(
struct
drm_device
*
dev
);
void
nv50_evo_destroy
(
struct
drm_device
*
dev
);
int
nv50_evo_init
(
struct
drm_device
*
dev
);
void
nv50_evo_fini
(
struct
drm_device
*
dev
);
void
nv50_evo_dmaobj_init
(
struct
nouveau_gpuobj
*
,
u32
memtype
,
u64
base
,
u64
size
);
int
nv50_evo_dmaobj_new
(
struct
nouveau_channel
*
,
u32
handle
,
u32
memtype
,
u64
base
,
u64
size
,
struct
nouveau_gpuobj
**
);
int
nvd0_display_create
(
struct
drm_device
*
);
void
nvd0_display_destroy
(
struct
drm_device
*
);
...
...
@@ -99,7 +40,6 @@ void nvd0_display_flip_stop(struct drm_crtc *);
int
nvd0_display_flip_next
(
struct
drm_crtc
*
,
struct
drm_framebuffer
*
,
struct
nouveau_channel
*
,
u32
swap_interval
);
struct
nouveau_bo
*
nv50_display_crtc_sema
(
struct
drm_device
*
,
int
head
);
struct
nouveau_bo
*
nvd0_display_crtc_sema
(
struct
drm_device
*
,
int
head
);
#endif
/* __NV50_DISPLAY_H__ */
drivers/gpu/drm/nouveau/nv50_evo.c
deleted
100644 → 0
View file @
f9887d09
/*
* Copyright 2010 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs
*/
#include <drm/drmP.h>
#include "nouveau_drm.h"
#include "nouveau_dma.h"
#include "nv50_display.h"
#include <core/gpuobj.h>
#include <subdev/timer.h>
#include <subdev/fb.h>
static
u32
nv50_evo_rd32
(
struct
nouveau_object
*
object
,
u64
addr
)
{
void
__iomem
*
iomem
=
object
->
oclass
->
ofuncs
->
rd08
;
return
ioread32_native
(
iomem
+
addr
);
}
static
void
nv50_evo_wr32
(
struct
nouveau_object
*
object
,
u64
addr
,
u32
data
)
{
void
__iomem
*
iomem
=
object
->
oclass
->
ofuncs
->
rd08
;
iowrite32_native
(
data
,
iomem
+
addr
);
}
static
void
nv50_evo_channel_del
(
struct
nouveau_channel
**
pevo
)
{
struct
nouveau_channel
*
evo
=
*
pevo
;
if
(
!
evo
)
return
;
*
pevo
=
NULL
;
nouveau_bo_unmap
(
evo
->
push
.
buffer
);
nouveau_bo_ref
(
NULL
,
&
evo
->
push
.
buffer
);
if
(
evo
->
object
)
iounmap
(
evo
->
object
->
oclass
->
ofuncs
);
kfree
(
evo
);
}
int
nv50_evo_dmaobj_new
(
struct
nouveau_channel
*
evo
,
u32
handle
,
u32
memtype
,
u64
base
,
u64
size
,
struct
nouveau_gpuobj
**
pobj
)
{
struct
drm_device
*
dev
=
evo
->
fence
;
struct
nouveau_drm
*
drm
=
nouveau_drm
(
dev
);
struct
nv50_display
*
disp
=
nv50_display
(
dev
);
u32
dmao
=
disp
->
dmao
;
u32
hash
=
disp
->
hash
;
u32
flags5
;
if
(
nv_device
(
drm
->
device
)
->
chipset
<
0xc0
)
{
/* not supported on 0x50, specified in format mthd */
if
(
nv_device
(
drm
->
device
)
->
chipset
==
0x50
)
memtype
=
0
;
flags5
=
0x00010000
;
}
else
{
if
(
memtype
&
0x80000000
)
flags5
=
0x00000000
;
/* large pages */
else
flags5
=
0x00020000
;
}
nv_wo32
(
disp
->
ramin
,
dmao
+
0x00
,
0x0019003d
|
(
memtype
<<
22
));
nv_wo32
(
disp
->
ramin
,
dmao
+
0x04
,
lower_32_bits
(
base
+
size
-
1
));
nv_wo32
(
disp
->
ramin
,
dmao
+
0x08
,
lower_32_bits
(
base
));
nv_wo32
(
disp
->
ramin
,
dmao
+
0x0c
,
upper_32_bits
(
base
+
size
-
1
)
<<
24
|
upper_32_bits
(
base
));
nv_wo32
(
disp
->
ramin
,
dmao
+
0x10
,
0x00000000
);
nv_wo32
(
disp
->
ramin
,
dmao
+
0x14
,
flags5
);
nv_wo32
(
disp
->
ramin
,
hash
+
0x00
,
handle
);
nv_wo32
(
disp
->
ramin
,
hash
+
0x04
,
(
evo
->
handle
<<
28
)
|
(
dmao
<<
10
)
|
evo
->
handle
);
disp
->
dmao
+=
0x20
;
disp
->
hash
+=
0x08
;
return
0
;
}
static
int
nv50_evo_channel_new
(
struct
drm_device
*
dev
,
int
chid
,
struct
nouveau_channel
**
pevo
)
{
struct
nouveau_drm
*
drm
=
nouveau_drm
(
dev
);
struct
nv50_display
*
disp
=
nv50_display
(
dev
);
struct
nouveau_channel
*
evo
;
int
ret
;
evo
=
kzalloc
(
sizeof
(
struct
nouveau_channel
),
GFP_KERNEL
);
if
(
!
evo
)
return
-
ENOMEM
;
*
pevo
=
evo
;
evo
->
drm
=
drm
;
evo
->
handle
=
chid
;
evo
->
fence
=
dev
;
evo
->
user_get
=
4
;
evo
->
user_put
=
0
;
ret
=
nouveau_bo_new
(
dev
,
4096
,
0
,
TTM_PL_FLAG_VRAM
,
0
,
0
,
NULL
,
&
evo
->
push
.
buffer
);
if
(
ret
==
0
)
ret
=
nouveau_bo_pin
(
evo
->
push
.
buffer
,
TTM_PL_FLAG_VRAM
);
if
(
ret
)
{
NV_ERROR
(
drm
,
"Error creating EVO DMA push buffer: %d
\n
"
,
ret
);
nv50_evo_channel_del
(
pevo
);
return
ret
;
}
ret
=
nouveau_bo_map
(
evo
->
push
.
buffer
);
if
(
ret
)
{
NV_ERROR
(
drm
,
"Error mapping EVO DMA push buffer: %d
\n
"
,
ret
);
nv50_evo_channel_del
(
pevo
);
return
ret
;
}
evo
->
object
=
kzalloc
(
sizeof
(
*
evo
->
object
),
GFP_KERNEL
);
#ifdef NOUVEAU_OBJECT_MAGIC
evo
->
object
->
_magic
=
NOUVEAU_OBJECT_MAGIC
;
#endif
evo
->
object
->
parent
=
nv_object
(
disp
->
ramin
)
->
parent
;
evo
->
object
->
engine
=
nv_object
(
disp
->
ramin
)
->
engine
;
evo
->
object
->
oclass
=
kzalloc
(
sizeof
(
*
evo
->
object
->
oclass
),
GFP_KERNEL
);
evo
->
object
->
oclass
->
ofuncs
=
kzalloc
(
sizeof
(
*
evo
->
object
->
oclass
->
ofuncs
),
GFP_KERNEL
);
evo
->
object
->
oclass
->
ofuncs
->
rd32
=
nv50_evo_rd32
;
evo
->
object
->
oclass
->
ofuncs
->
wr32
=
nv50_evo_wr32
;
evo
->
object
->
oclass
->
ofuncs
->
rd08
=
ioremap
(
pci_resource_start
(
dev
->
pdev
,
0
)
+
NV50_PDISPLAY_USER
(
evo
->
handle
),
PAGE_SIZE
);
return
0
;
}
static
int
nv50_evo_channel_init
(
struct
nouveau_channel
*
evo
)
{
struct
nouveau_drm
*
drm
=
evo
->
drm
;
struct
nouveau_device
*
device
=
nv_device
(
drm
->
device
);
int
id
=
evo
->
handle
,
ret
,
i
;
u64
pushbuf
=
evo
->
push
.
buffer
->
bo
.
offset
;
u32
tmp
;
tmp
=
nv_rd32
(
device
,
NV50_PDISPLAY_EVO_CTRL
(
id
));
if
((
tmp
&
0x009f0000
)
==
0x00020000
)
nv_wr32
(
device
,
NV50_PDISPLAY_EVO_CTRL
(
id
),
tmp
|
0x00800000
);
tmp
=
nv_rd32
(
device
,
NV50_PDISPLAY_EVO_CTRL
(
id
));
if
((
tmp
&
0x003f0000
)
==
0x00030000
)
nv_wr32
(
device
,
NV50_PDISPLAY_EVO_CTRL
(
id
),
tmp
|
0x00600000
);
/* initialise fifo */
nv_wr32
(
device
,
NV50_PDISPLAY_EVO_DMA_CB
(
id
),
pushbuf
>>
8
|
NV50_PDISPLAY_EVO_DMA_CB_LOCATION_VRAM
|
NV50_PDISPLAY_EVO_DMA_CB_VALID
);
nv_wr32
(
device
,
NV50_PDISPLAY_EVO_UNK2
(
id
),
0x00010000
);
nv_wr32
(
device
,
NV50_PDISPLAY_EVO_HASH_TAG
(
id
),
id
);
nv_mask
(
device
,
NV50_PDISPLAY_EVO_CTRL
(
id
),
NV50_PDISPLAY_EVO_CTRL_DMA
,
NV50_PDISPLAY_EVO_CTRL_DMA_ENABLED
);
nv_wr32
(
device
,
NV50_PDISPLAY_USER_PUT
(
id
),
0x00000000
);
nv_wr32
(
device
,
NV50_PDISPLAY_EVO_CTRL
(
id
),
0x01000003
|
NV50_PDISPLAY_EVO_CTRL_DMA_ENABLED
);
if
(
!
nv_wait
(
device
,
NV50_PDISPLAY_EVO_CTRL
(
id
),
0x80000000
,
0x00000000
))
{
NV_ERROR
(
drm
,
"EvoCh %d init timeout: 0x%08x
\n
"
,
id
,
nv_rd32
(
device
,
NV50_PDISPLAY_EVO_CTRL
(
id
)));
return
-
EBUSY
;
}
/* enable error reporting on the channel */
nv_mask
(
device
,
0x610028
,
0x00000000
,
0x00010001
<<
id
);
evo
->
dma
.
max
=
(
4096
/
4
)
-
2
;
evo
->
dma
.
max
&=
~
7
;
evo
->
dma
.
put
=
0
;
evo
->
dma
.
cur
=
evo
->
dma
.
put
;
evo
->
dma
.
free
=
evo
->
dma
.
max
-
evo
->
dma
.
cur
;
ret
=
RING_SPACE
(
evo
,
NOUVEAU_DMA_SKIPS
);
if
(
ret
)
return
ret
;
for
(
i
=
0
;
i
<
NOUVEAU_DMA_SKIPS
;
i
++
)
OUT_RING
(
evo
,
0
);
return
0
;
}
static
void
nv50_evo_channel_fini
(
struct
nouveau_channel
*
evo
)
{
struct
nouveau_drm
*
drm
=
evo
->
drm
;
struct
nouveau_device
*
device
=
nv_device
(
drm
->
device
);
int
id
=
evo
->
handle
;
nv_mask
(
device
,
0x610028
,
0x00010001
<<
id
,
0x00000000
);
nv_mask
(
device
,
NV50_PDISPLAY_EVO_CTRL
(
id
),
0x00001010
,
0x00001000
);
nv_wr32
(
device
,
NV50_PDISPLAY_INTR_0
,
(
1
<<
id
));
nv_mask
(
device
,
NV50_PDISPLAY_EVO_CTRL
(
id
),
0x00000003
,
0x00000000
);
if
(
!
nv_wait
(
device
,
NV50_PDISPLAY_EVO_CTRL
(
id
),
0x001e0000
,
0x00000000
))
{
NV_ERROR
(
drm
,
"EvoCh %d takedown timeout: 0x%08x
\n
"
,
id
,
nv_rd32
(
device
,
NV50_PDISPLAY_EVO_CTRL
(
id
)));
}
}
void
nv50_evo_destroy
(
struct
drm_device
*
dev
)
{
struct
nv50_display
*
disp
=
nv50_display
(
dev
);
int
i
;
for
(
i
=
0
;
i
<
2
;
i
++
)
{
if
(
disp
->
crtc
[
i
].
sem
.
bo
)
{
nouveau_bo_unmap
(
disp
->
crtc
[
i
].
sem
.
bo
);
nouveau_bo_ref
(
NULL
,
&
disp
->
crtc
[
i
].
sem
.
bo
);
}
nv50_evo_channel_del
(
&
disp
->
crtc
[
i
].
sync
);
}
nv50_evo_channel_del
(
&
disp
->
master
);
}
int
nv50_evo_create
(
struct
drm_device
*
dev
)
{
struct
nouveau_drm
*
drm
=
nouveau_drm
(
dev
);
struct
nouveau_fb
*
pfb
=
nouveau_fb
(
drm
->
device
);
struct
nv50_display
*
disp
=
nv50_display
(
dev
);
struct
nouveau_channel
*
evo
;
int
ret
,
i
,
j
;
/* setup object management on it, any other evo channel will
* use this also as there's no per-channel support on the
* hardware
*/
disp
->
ramin
=
nv_gpuobj
(
disp
->
core
->
parent
);
disp
->
hash
=
0x0000
;
disp
->
dmao
=
0x1000
;
/* create primary evo channel, the one we use for modesetting
* purporses
*/
ret
=
nv50_evo_channel_new
(
dev
,
0
,
&
disp
->
master
);
if
(
ret
)
return
ret
;
evo
=
disp
->
master
;
ret
=
nv50_evo_dmaobj_new
(
disp
->
master
,
NvEvoSync
,
0x0000
,
disp
->
ramin
->
addr
+
0x2000
,
0x1000
,
NULL
);
if
(
ret
)
goto
err
;
/* create some default objects for the scanout memtypes we support */
ret
=
nv50_evo_dmaobj_new
(
disp
->
master
,
NvEvoVRAM
,
0x0000
,
0
,
pfb
->
ram
.
size
,
NULL
);
if
(
ret
)
goto
err
;
ret
=
nv50_evo_dmaobj_new
(
disp
->
master
,
NvEvoVRAM_LP
,
0x80000000
,
0
,
pfb
->
ram
.
size
,
NULL
);
if
(
ret
)
goto
err
;
ret
=
nv50_evo_dmaobj_new
(
disp
->
master
,
NvEvoFB32
,
0x80000000
|
(
nv_device
(
drm
->
device
)
->
chipset
<
0xc0
?
0x7a
:
0xfe
),
0
,
pfb
->
ram
.
size
,
NULL
);
if
(
ret
)
goto
err
;
ret
=
nv50_evo_dmaobj_new
(
disp
->
master
,
NvEvoFB16
,
0x80000000
|
(
nv_device
(
drm
->
device
)
->
chipset
<
0xc0
?
0x70
:
0xfe
),
0
,
pfb
->
ram
.
size
,
NULL
);
if
(
ret
)
goto
err
;
/* create "display sync" channels and other structures we need
* to implement page flipping
*/
for
(
i
=
0
;
i
<
2
;
i
++
)
{
struct
nv50_display_crtc
*
dispc
=
&
disp
->
crtc
[
i
];
u64
offset
;
ret
=
nv50_evo_channel_new
(
dev
,
1
+
i
,
&
dispc
->
sync
);
if
(
ret
)
goto
err
;
ret
=
nouveau_bo_new
(
dev
,
4096
,
0x1000
,
TTM_PL_FLAG_VRAM
,
0
,
0x0000
,
NULL
,
&
dispc
->
sem
.
bo
);
if
(
!
ret
)
{
ret
=
nouveau_bo_pin
(
dispc
->
sem
.
bo
,
TTM_PL_FLAG_VRAM
);
if
(
!
ret
)
ret
=
nouveau_bo_map
(
dispc
->
sem
.
bo
);
if
(
ret
)
nouveau_bo_ref
(
NULL
,
&
dispc
->
sem
.
bo
);
offset
=
dispc
->
sem
.
bo
->
bo
.
offset
;
}
if
(
ret
)
goto
err
;
ret
=
nv50_evo_dmaobj_new
(
dispc
->
sync
,
NvEvoSync
,
0x0000
,
offset
,
4096
,
NULL
);
if
(
ret
)
goto
err
;
ret
=
nv50_evo_dmaobj_new
(
dispc
->
sync
,
NvEvoVRAM_LP
,
0x80000000
,
0
,
pfb
->
ram
.
size
,
NULL
);
if
(
ret
)
goto
err
;
ret
=
nv50_evo_dmaobj_new
(
dispc
->
sync
,
NvEvoFB32
,
0x80000000
|
(
nv_device
(
drm
->
device
)
->
chipset
<
0xc0
?
0x7a
:
0xfe
),
0
,
pfb
->
ram
.
size
,
NULL
);
if
(
ret
)
goto
err
;
ret
=
nv50_evo_dmaobj_new
(
dispc
->
sync
,
NvEvoFB16
,
0x80000000
|
(
nv_device
(
drm
->
device
)
->
chipset
<
0xc0
?
0x70
:
0xfe
),
0
,
pfb
->
ram
.
size
,
NULL
);
if
(
ret
)
goto
err
;
for
(
j
=
0
;
j
<
4096
;
j
+=
4
)
nouveau_bo_wr32
(
dispc
->
sem
.
bo
,
j
/
4
,
0x74b1e000
);
dispc
->
sem
.
offset
=
0
;
}
return
0
;
err:
nv50_evo_destroy
(
dev
);
return
ret
;
}
int
nv50_evo_init
(
struct
drm_device
*
dev
)
{
struct
nv50_display
*
disp
=
nv50_display
(
dev
);
int
ret
,
i
;
ret
=
nv50_evo_channel_init
(
disp
->
master
);
if
(
ret
)
return
ret
;
for
(
i
=
0
;
i
<
2
;
i
++
)
{
ret
=
nv50_evo_channel_init
(
disp
->
crtc
[
i
].
sync
);
if
(
ret
)
return
ret
;
}
return
0
;
}
void
nv50_evo_fini
(
struct
drm_device
*
dev
)
{
struct
nv50_display
*
disp
=
nv50_display
(
dev
);
int
i
;
for
(
i
=
0
;
i
<
2
;
i
++
)
{
if
(
disp
->
crtc
[
i
].
sync
)
nv50_evo_channel_fini
(
disp
->
crtc
[
i
].
sync
);
}
if
(
disp
->
master
)
nv50_evo_channel_fini
(
disp
->
master
);
}
drivers/gpu/drm/nouveau/nv50_evo.h
deleted
100644 → 0
View file @
f9887d09
/*
* Copyright (C) 2008 Maarten Maathuis.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __NV50_EVO_H__
#define __NV50_EVO_H__
#define NV50_EVO_UPDATE 0x00000080
#define NV50_EVO_UNK84 0x00000084
#define NV50_EVO_UNK84_NOTIFY 0x40000000
#define NV50_EVO_UNK84_NOTIFY_DISABLED 0x00000000
#define NV50_EVO_UNK84_NOTIFY_ENABLED 0x40000000
#define NV50_EVO_DMA_NOTIFY 0x00000088
#define NV50_EVO_DMA_NOTIFY_HANDLE 0xffffffff
#define NV50_EVO_DMA_NOTIFY_HANDLE_NONE 0x00000000
#define NV50_EVO_UNK8C 0x0000008C
#define NV50_EVO_DAC(n, r) ((n) * 0x80 + NV50_EVO_DAC_##r)
#define NV50_EVO_DAC_MODE_CTRL 0x00000400
#define NV50_EVO_DAC_MODE_CTRL_CRTC0 0x00000001
#define NV50_EVO_DAC_MODE_CTRL_CRTC1 0x00000002
#define NV50_EVO_DAC_MODE_CTRL2 0x00000404
#define NV50_EVO_DAC_MODE_CTRL2_NHSYNC 0x00000001
#define NV50_EVO_DAC_MODE_CTRL2_NVSYNC 0x00000002
#define NV50_EVO_SOR(n, r) ((n) * 0x40 + NV50_EVO_SOR_##r)
#define NV50_EVO_SOR_MODE_CTRL 0x00000600
#define NV50_EVO_SOR_MODE_CTRL_CRTC0 0x00000001
#define NV50_EVO_SOR_MODE_CTRL_CRTC1 0x00000002
#define NV50_EVO_SOR_MODE_CTRL_TMDS 0x00000100
#define NV50_EVO_SOR_MODE_CTRL_TMDS_DUAL_LINK 0x00000400
#define NV50_EVO_SOR_MODE_CTRL_NHSYNC 0x00001000
#define NV50_EVO_SOR_MODE_CTRL_NVSYNC 0x00002000
#define NV50_EVO_CRTC(n, r) ((n) * 0x400 + NV50_EVO_CRTC_##r)
#define NV84_EVO_CRTC(n, r) ((n) * 0x400 + NV84_EVO_CRTC_##r)
#define NV50_EVO_CRTC_UNK0800 0x00000800
#define NV50_EVO_CRTC_CLOCK 0x00000804
#define NV50_EVO_CRTC_INTERLACE 0x00000808
#define NV50_EVO_CRTC_DISPLAY_START 0x00000810
#define NV50_EVO_CRTC_DISPLAY_TOTAL 0x00000814
#define NV50_EVO_CRTC_SYNC_DURATION 0x00000818
#define NV50_EVO_CRTC_SYNC_START_TO_BLANK_END 0x0000081c
#define NV50_EVO_CRTC_UNK0820 0x00000820
#define NV50_EVO_CRTC_UNK0824 0x00000824
#define NV50_EVO_CRTC_UNK082C 0x0000082c
#define NV50_EVO_CRTC_CLUT_MODE 0x00000840
/* You can't have a palette in 8 bit mode (=OFF) */
#define NV50_EVO_CRTC_CLUT_MODE_BLANK 0x00000000
#define NV50_EVO_CRTC_CLUT_MODE_OFF 0x80000000
#define NV50_EVO_CRTC_CLUT_MODE_ON 0xC0000000
#define NV50_EVO_CRTC_CLUT_OFFSET 0x00000844
#define NV84_EVO_CRTC_CLUT_DMA 0x0000085C
#define NV84_EVO_CRTC_CLUT_DMA_HANDLE 0xffffffff
#define NV84_EVO_CRTC_CLUT_DMA_HANDLE_NONE 0x00000000
#define NV50_EVO_CRTC_FB_OFFSET 0x00000860
#define NV50_EVO_CRTC_FB_SIZE 0x00000868
#define NV50_EVO_CRTC_FB_CONFIG 0x0000086c
#define NV50_EVO_CRTC_FB_CONFIG_MODE 0x00100000
#define NV50_EVO_CRTC_FB_CONFIG_MODE_TILE 0x00000000
#define NV50_EVO_CRTC_FB_CONFIG_MODE_PITCH 0x00100000
#define NV50_EVO_CRTC_FB_DEPTH 0x00000870
#define NV50_EVO_CRTC_FB_DEPTH_8 0x00001e00
#define NV50_EVO_CRTC_FB_DEPTH_15 0x0000e900
#define NV50_EVO_CRTC_FB_DEPTH_16 0x0000e800
#define NV50_EVO_CRTC_FB_DEPTH_24 0x0000cf00
#define NV50_EVO_CRTC_FB_DEPTH_30 0x0000d100
#define NV50_EVO_CRTC_FB_DMA 0x00000874
#define NV50_EVO_CRTC_FB_DMA_HANDLE 0xffffffff
#define NV50_EVO_CRTC_FB_DMA_HANDLE_NONE 0x00000000
#define NV50_EVO_CRTC_CURSOR_CTRL 0x00000880
#define NV50_EVO_CRTC_CURSOR_CTRL_HIDE 0x05000000
#define NV50_EVO_CRTC_CURSOR_CTRL_SHOW 0x85000000
#define NV50_EVO_CRTC_CURSOR_OFFSET 0x00000884
#define NV84_EVO_CRTC_CURSOR_DMA 0x0000089c
#define NV84_EVO_CRTC_CURSOR_DMA_HANDLE 0xffffffff
#define NV84_EVO_CRTC_CURSOR_DMA_HANDLE_NONE 0x00000000
#define NV50_EVO_CRTC_DITHER_CTRL 0x000008a0
#define NV50_EVO_CRTC_DITHER_CTRL_OFF 0x00000000
#define NV50_EVO_CRTC_DITHER_CTRL_ON 0x00000011
#define NV50_EVO_CRTC_SCALE_CTRL 0x000008a4
#define NV50_EVO_CRTC_SCALE_CTRL_INACTIVE 0x00000000
#define NV50_EVO_CRTC_SCALE_CTRL_ACTIVE 0x00000009
#define NV50_EVO_CRTC_COLOR_CTRL 0x000008a8
#define NV50_EVO_CRTC_COLOR_CTRL_VIBRANCE 0x000fff00
#define NV50_EVO_CRTC_COLOR_CTRL_HUE 0xfff00000
#define NV50_EVO_CRTC_FB_POS 0x000008c0
#define NV50_EVO_CRTC_REAL_RES 0x000008c8
#define NV50_EVO_CRTC_SCALE_CENTER_OFFSET 0x000008d4
#define NV50_EVO_CRTC_SCALE_CENTER_OFFSET_VAL(x, y) \
((((unsigned)y << 16) & 0xFFFF0000) | (((unsigned)x) & 0x0000FFFF))
/* Both of these are needed, otherwise nothing happens. */
#define NV50_EVO_CRTC_SCALE_RES1 0x000008d8
#define NV50_EVO_CRTC_SCALE_RES2 0x000008dc
#define NV50_EVO_CRTC_UNK900 0x00000900
#define NV50_EVO_CRTC_UNK904 0x00000904
#endif
drivers/gpu/drm/nouveau/nv50_fence.c
View file @
4f6029da
...
...
@@ -70,7 +70,7 @@ nv50_fence_context_new(struct nouveau_channel *chan)
/* dma objects for display sync channel semaphore blocks */
for
(
i
=
0
;
!
ret
&&
i
<
dev
->
mode_config
.
num_crtc
;
i
++
)
{
struct
nouveau_bo
*
bo
=
nv
5
0_display_crtc_sema
(
dev
,
i
);
struct
nouveau_bo
*
bo
=
nv
d
0_display_crtc_sema
(
dev
,
i
);
ret
=
nouveau_object_new
(
nv_object
(
chan
->
cli
),
chan
->
handle
,
NvEvoSema0
+
i
,
0x003d
,
...
...
drivers/gpu/drm/nouveau/nv50_pm.c
View file @
4f6029da
...
...
@@ -546,7 +546,7 @@ calc_mclk(struct drm_device *dev, struct nouveau_pm_level *perflvl,
{
struct
nouveau_drm
*
drm
=
nouveau_drm
(
dev
);
struct
nouveau_device
*
device
=
nouveau_dev
(
dev
);
u32
crtc_mask
=
nv50_display_active_crtcs
(
dev
);
u32
crtc_mask
=
0
;
/*XXX: nv50_display_active_crtcs(dev); */
struct
nouveau_mem_exec_func
exec
=
{
.
dev
=
dev
,
.
precharge
=
mclk_precharge
,
...
...
drivers/gpu/drm/nouveau/nv50_sor.c
deleted
100644 → 0
View file @
f9887d09
/*
* Copyright (C) 2008 Maarten Maathuis.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
#define NOUVEAU_DMA_DEBUG (nouveau_reg_debug & NOUVEAU_REG_DEBUG_EVO)
#include "nouveau_reg.h"
#include "nouveau_drm.h"
#include "nouveau_dma.h"
#include "nouveau_encoder.h"
#include "nouveau_connector.h"
#include "nouveau_crtc.h"
#include "nv50_display.h"
#include <core/class.h>
#include <subdev/timer.h>
static
void
nv50_sor_disconnect
(
struct
drm_encoder
*
encoder
)
{
struct
nouveau_encoder
*
nv_encoder
=
nouveau_encoder
(
encoder
);
struct
nouveau_drm
*
drm
=
nouveau_drm
(
encoder
->
dev
);
struct
drm_device
*
dev
=
encoder
->
dev
;
struct
nouveau_channel
*
evo
=
nv50_display
(
dev
)
->
master
;
int
ret
;
if
(
!
nv_encoder
->
crtc
)
return
;
nv50_crtc_blank
(
nouveau_crtc
(
nv_encoder
->
crtc
),
true
);
NV_DEBUG
(
drm
,
"Disconnecting SOR %d
\n
"
,
nv_encoder
->
or
);
ret
=
RING_SPACE
(
evo
,
4
);
if
(
ret
)
{
NV_ERROR
(
drm
,
"no space while disconnecting SOR
\n
"
);
return
;
}
BEGIN_NV04
(
evo
,
0
,
NV50_EVO_SOR
(
nv_encoder
->
or
,
MODE_CTRL
),
1
);
OUT_RING
(
evo
,
0
);
BEGIN_NV04
(
evo
,
0
,
NV50_EVO_UPDATE
,
1
);
OUT_RING
(
evo
,
0
);
nouveau_hdmi_mode_set
(
encoder
,
NULL
);
nv_encoder
->
crtc
=
NULL
;
nv_encoder
->
last_dpms
=
DRM_MODE_DPMS_OFF
;
}
static
void
nv50_sor_dpms
(
struct
drm_encoder
*
encoder
,
int
mode
)
{
struct
nv50_display
*
priv
=
nv50_display
(
encoder
->
dev
);
struct
nouveau_drm
*
drm
=
nouveau_drm
(
encoder
->
dev
);
struct
drm_device
*
dev
=
encoder
->
dev
;
struct
nouveau_encoder
*
nv_encoder
=
nouveau_encoder
(
encoder
);
struct
drm_encoder
*
enc
;
int
or
=
nv_encoder
->
or
;
NV_DEBUG
(
drm
,
"or %d type %d mode %d
\n
"
,
or
,
nv_encoder
->
dcb
->
type
,
mode
);
nv_encoder
->
last_dpms
=
mode
;
list_for_each_entry
(
enc
,
&
dev
->
mode_config
.
encoder_list
,
head
)
{
struct
nouveau_encoder
*
nvenc
=
nouveau_encoder
(
enc
);
if
(
nvenc
==
nv_encoder
||
(
nvenc
->
dcb
->
type
!=
DCB_OUTPUT_TMDS
&&
nvenc
->
dcb
->
type
!=
DCB_OUTPUT_LVDS
&&
nvenc
->
dcb
->
type
!=
DCB_OUTPUT_DP
)
||
nvenc
->
dcb
->
or
!=
nv_encoder
->
dcb
->
or
)
continue
;
if
(
nvenc
->
last_dpms
==
DRM_MODE_DPMS_ON
)
return
;
}
nv_call
(
priv
->
core
,
NV50_DISP_SOR_PWR
+
or
,
(
mode
==
DRM_MODE_DPMS_ON
));
if
(
nv_encoder
->
dcb
->
type
==
DCB_OUTPUT_DP
)
nouveau_dp_dpms
(
encoder
,
mode
,
nv_encoder
->
dp
.
datarate
,
priv
->
core
);
}
static
void
nv50_sor_save
(
struct
drm_encoder
*
encoder
)
{
struct
nouveau_drm
*
drm
=
nouveau_drm
(
encoder
->
dev
);
NV_ERROR
(
drm
,
"!!
\n
"
);
}
static
void
nv50_sor_restore
(
struct
drm_encoder
*
encoder
)
{
struct
nouveau_drm
*
drm
=
nouveau_drm
(
encoder
->
dev
);
NV_ERROR
(
drm
,
"!!
\n
"
);
}
static
bool
nv50_sor_mode_fixup
(
struct
drm_encoder
*
encoder
,
const
struct
drm_display_mode
*
mode
,
struct
drm_display_mode
*
adjusted_mode
)
{
struct
nouveau_drm
*
drm
=
nouveau_drm
(
encoder
->
dev
);
struct
nouveau_encoder
*
nv_encoder
=
nouveau_encoder
(
encoder
);
struct
nouveau_connector
*
connector
;
NV_DEBUG
(
drm
,
"or %d
\n
"
,
nv_encoder
->
or
);
connector
=
nouveau_encoder_connector_get
(
nv_encoder
);
if
(
!
connector
)
{
NV_ERROR
(
drm
,
"Encoder has no connector
\n
"
);
return
false
;
}
if
(
connector
->
scaling_mode
!=
DRM_MODE_SCALE_NONE
&&
connector
->
native_mode
)
drm_mode_copy
(
adjusted_mode
,
connector
->
native_mode
);
return
true
;
}
static
void
nv50_sor_prepare
(
struct
drm_encoder
*
encoder
)
{
struct
nouveau_encoder
*
nv_encoder
=
nouveau_encoder
(
encoder
);
nv50_sor_disconnect
(
encoder
);
if
(
nv_encoder
->
dcb
->
type
==
DCB_OUTPUT_DP
)
{
/* avoid race between link training and supervisor intr */
nv50_display_sync
(
encoder
->
dev
);
}
}
static
void
nv50_sor_commit
(
struct
drm_encoder
*
encoder
)
{
}
static
void
nv50_sor_mode_set
(
struct
drm_encoder
*
encoder
,
struct
drm_display_mode
*
umode
,
struct
drm_display_mode
*
mode
)
{
struct
nouveau_channel
*
evo
=
nv50_display
(
encoder
->
dev
)
->
master
;
struct
nouveau_encoder
*
nv_encoder
=
nouveau_encoder
(
encoder
);
struct
nouveau_drm
*
drm
=
nouveau_drm
(
encoder
->
dev
);
struct
nouveau_crtc
*
crtc
=
nouveau_crtc
(
encoder
->
crtc
);
struct
nouveau_connector
*
nv_connector
;
struct
nv50_display
*
disp
=
nv50_display
(
encoder
->
dev
);
struct
nvbios
*
bios
=
&
drm
->
vbios
;
uint32_t
mode_ctl
=
0
,
script
;
int
ret
;
NV_DEBUG
(
drm
,
"or %d type %d -> crtc %d
\n
"
,
nv_encoder
->
or
,
nv_encoder
->
dcb
->
type
,
crtc
->
index
);
nv_encoder
->
crtc
=
encoder
->
crtc
;
switch
(
nv_encoder
->
dcb
->
type
)
{
case
DCB_OUTPUT_TMDS
:
if
(
nv_encoder
->
dcb
->
sorconf
.
link
&
1
)
{
if
(
mode
->
clock
<
165000
)
mode_ctl
=
0x0100
;
else
mode_ctl
=
0x0500
;
}
else
mode_ctl
=
0x0200
;
nouveau_hdmi_mode_set
(
encoder
,
mode
);
break
;
case
DCB_OUTPUT_LVDS
:
script
=
0x0000
;
if
(
bios
->
fp_no_ddc
)
{
if
(
bios
->
fp
.
dual_link
)
script
|=
0x0100
;
if
(
bios
->
fp
.
if_is_24bit
)
script
|=
0x0200
;
}
else
{
/* determine number of lvds links */
nv_connector
=
nouveau_encoder_connector_get
(
nv_encoder
);
if
(
nv_connector
&&
nv_connector
->
edid
&&
nv_connector
->
type
==
DCB_CONNECTOR_LVDS_SPWG
)
{
/* http://www.spwg.org */
if
(((
u8
*
)
nv_connector
->
edid
)[
121
]
==
2
)
script
|=
0x0100
;
}
else
if
(
mode
->
clock
>=
bios
->
fp
.
duallink_transition_clk
)
{
script
|=
0x0100
;
}
/* determine panel depth */
if
(
script
&
0x0100
)
{
if
(
bios
->
fp
.
strapless_is_24bit
&
2
)
script
|=
0x0200
;
}
else
{
if
(
bios
->
fp
.
strapless_is_24bit
&
1
)
script
|=
0x0200
;
}
if
(
nv_connector
&&
nv_connector
->
edid
&&
(
nv_connector
->
edid
->
revision
>=
4
)
&&
(
nv_connector
->
edid
->
input
&
0x70
)
>=
0x20
)
script
|=
0x0200
;
}
nv_call
(
disp
->
core
,
NV50_DISP_SOR_LVDS_SCRIPT
+
nv_encoder
->
or
,
script
);
break
;
case
DCB_OUTPUT_DP
:
nv_connector
=
nouveau_encoder_connector_get
(
nv_encoder
);
if
(
nv_connector
&&
nv_connector
->
base
.
display_info
.
bpc
==
6
)
{
nv_encoder
->
dp
.
datarate
=
mode
->
clock
*
18
/
8
;
mode_ctl
|=
0x00020000
;
}
else
{
nv_encoder
->
dp
.
datarate
=
mode
->
clock
*
24
/
8
;
mode_ctl
|=
0x00050000
;
}
if
(
nv_encoder
->
dcb
->
sorconf
.
link
&
1
)
mode_ctl
|=
0x00000800
;
else
mode_ctl
|=
0x00000900
;
break
;
default:
break
;
}
if
(
crtc
->
index
==
1
)
mode_ctl
|=
NV50_EVO_SOR_MODE_CTRL_CRTC1
;
else
mode_ctl
|=
NV50_EVO_SOR_MODE_CTRL_CRTC0
;
if
(
mode
->
flags
&
DRM_MODE_FLAG_NHSYNC
)
mode_ctl
|=
NV50_EVO_SOR_MODE_CTRL_NHSYNC
;
if
(
mode
->
flags
&
DRM_MODE_FLAG_NVSYNC
)
mode_ctl
|=
NV50_EVO_SOR_MODE_CTRL_NVSYNC
;
nv50_sor_dpms
(
encoder
,
DRM_MODE_DPMS_ON
);
ret
=
RING_SPACE
(
evo
,
2
);
if
(
ret
)
{
NV_ERROR
(
drm
,
"no space while connecting SOR
\n
"
);
nv_encoder
->
crtc
=
NULL
;
return
;
}
BEGIN_NV04
(
evo
,
0
,
NV50_EVO_SOR
(
nv_encoder
->
or
,
MODE_CTRL
),
1
);
OUT_RING
(
evo
,
mode_ctl
);
}
static
struct
drm_crtc
*
nv50_sor_crtc_get
(
struct
drm_encoder
*
encoder
)
{
return
nouveau_encoder
(
encoder
)
->
crtc
;
}
static
const
struct
drm_encoder_helper_funcs
nv50_sor_helper_funcs
=
{
.
dpms
=
nv50_sor_dpms
,
.
save
=
nv50_sor_save
,
.
restore
=
nv50_sor_restore
,
.
mode_fixup
=
nv50_sor_mode_fixup
,
.
prepare
=
nv50_sor_prepare
,
.
commit
=
nv50_sor_commit
,
.
mode_set
=
nv50_sor_mode_set
,
.
get_crtc
=
nv50_sor_crtc_get
,
.
detect
=
NULL
,
.
disable
=
nv50_sor_disconnect
};
static
void
nv50_sor_destroy
(
struct
drm_encoder
*
encoder
)
{
struct
nouveau_encoder
*
nv_encoder
=
nouveau_encoder
(
encoder
);
drm_encoder_cleanup
(
encoder
);
kfree
(
nv_encoder
);
}
static
const
struct
drm_encoder_funcs
nv50_sor_encoder_funcs
=
{
.
destroy
=
nv50_sor_destroy
,
};
int
nv50_sor_create
(
struct
drm_connector
*
connector
,
struct
dcb_output
*
entry
)
{
struct
nouveau_encoder
*
nv_encoder
=
NULL
;
struct
drm_device
*
dev
=
connector
->
dev
;
struct
drm_encoder
*
encoder
;
int
type
;
switch
(
entry
->
type
)
{
case
DCB_OUTPUT_TMDS
:
case
DCB_OUTPUT_DP
:
type
=
DRM_MODE_ENCODER_TMDS
;
break
;
case
DCB_OUTPUT_LVDS
:
type
=
DRM_MODE_ENCODER_LVDS
;
break
;
default:
return
-
EINVAL
;
}
nv_encoder
=
kzalloc
(
sizeof
(
*
nv_encoder
),
GFP_KERNEL
);
if
(
!
nv_encoder
)
return
-
ENOMEM
;
encoder
=
to_drm_encoder
(
nv_encoder
);
nv_encoder
->
dcb
=
entry
;
nv_encoder
->
or
=
ffs
(
entry
->
or
)
-
1
;
nv_encoder
->
last_dpms
=
DRM_MODE_DPMS_OFF
;
drm_encoder_init
(
dev
,
encoder
,
&
nv50_sor_encoder_funcs
,
type
);
drm_encoder_helper_add
(
encoder
,
&
nv50_sor_helper_funcs
);
encoder
->
possible_crtcs
=
entry
->
heads
;
encoder
->
possible_clones
=
0
;
drm_mode_connector_attach_encoder
(
connector
,
encoder
);
return
0
;
}
drivers/gpu/drm/nouveau/nv84_fence.c
View file @
4f6029da
...
...
@@ -127,7 +127,7 @@ nv84_fence_context_new(struct nouveau_channel *chan)
/* dma objects for display sync channel semaphore blocks */
for
(
i
=
0
;
!
ret
&&
i
<
dev
->
mode_config
.
num_crtc
;
i
++
)
{
struct
nouveau_bo
*
bo
=
nv
5
0_display_crtc_sema
(
dev
,
i
);
struct
nouveau_bo
*
bo
=
nv
d
0_display_crtc_sema
(
dev
,
i
);
ret
=
nouveau_object_new
(
nv_object
(
chan
->
cli
),
chan
->
handle
,
NvEvoSema0
+
i
,
0x003d
,
...
...
drivers/gpu/drm/nouveau/nvc0_fence.c
View file @
4f6029da
...
...
@@ -114,18 +114,10 @@ nvc0_fence_context_del(struct nouveau_channel *chan)
struct
nvc0_fence_chan
*
fctx
=
chan
->
fence
;
int
i
;
if
(
nv_device
(
chan
->
drm
->
device
)
->
card_type
>=
NV_D0
)
{
for
(
i
=
0
;
i
<
dev
->
mode_config
.
num_crtc
;
i
++
)
{
struct
nouveau_bo
*
bo
=
nvd0_display_crtc_sema
(
dev
,
i
);
nouveau_bo_vma_del
(
bo
,
&
fctx
->
dispc_vma
[
i
]);
}
}
else
if
(
nv_device
(
chan
->
drm
->
device
)
->
card_type
>=
NV_50
)
{
for
(
i
=
0
;
i
<
dev
->
mode_config
.
num_crtc
;
i
++
)
{
struct
nouveau_bo
*
bo
=
nv50_display_crtc_sema
(
dev
,
i
);
nouveau_bo_vma_del
(
bo
,
&
fctx
->
dispc_vma
[
i
]);
}
}
nouveau_bo_vma_del
(
priv
->
bo
,
&
fctx
->
vma
);
nouveau_fence_context_del
(
&
fctx
->
base
);
...
...
@@ -154,12 +146,7 @@ nvc0_fence_context_new(struct nouveau_channel *chan)
/* map display semaphore buffers into channel's vm */
for
(
i
=
0
;
!
ret
&&
i
<
chan
->
drm
->
dev
->
mode_config
.
num_crtc
;
i
++
)
{
struct
nouveau_bo
*
bo
;
if
(
nv_device
(
chan
->
drm
->
device
)
->
card_type
>=
NV_D0
)
bo
=
nvd0_display_crtc_sema
(
chan
->
drm
->
dev
,
i
);
else
bo
=
nv50_display_crtc_sema
(
chan
->
drm
->
dev
,
i
);
struct
nouveau_bo
*
bo
=
nvd0_display_crtc_sema
(
chan
->
drm
->
dev
,
i
);
ret
=
nouveau_bo_vma_add
(
bo
,
client
->
vm
,
&
fctx
->
dispc_vma
[
i
]);
}
...
...
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