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
2eff0b33
Commit
2eff0b33
authored
Jul 05, 2013
by
Patrik Jakobsson
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
drm/gma500: Add generic pipe/crtc functions
Signed-off-by:
Patrik Jakobsson
<
patrik.r.jakobsson@gmail.com
>
parent
f0e9d89b
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
340 additions
and
0 deletions
+340
-0
drivers/gpu/drm/gma500/gma_display.c
drivers/gpu/drm/gma500/gma_display.c
+326
-0
drivers/gpu/drm/gma500/gma_display.h
drivers/gpu/drm/gma500/gma_display.h
+14
-0
No files found.
drivers/gpu/drm/gma500/gma_display.c
View file @
2eff0b33
...
@@ -24,6 +24,7 @@
...
@@ -24,6 +24,7 @@
#include "psb_intel_drv.h"
#include "psb_intel_drv.h"
#include "psb_intel_reg.h"
#include "psb_intel_reg.h"
#include "psb_drv.h"
#include "psb_drv.h"
#include "framebuffer.h"
/**
/**
* Returns whether any output on the specified pipe is of the specified type
* Returns whether any output on the specified pipe is of the specified type
...
@@ -46,6 +47,331 @@ bool gma_pipe_has_type(struct drm_crtc *crtc, int type)
...
@@ -46,6 +47,331 @@ bool gma_pipe_has_type(struct drm_crtc *crtc, int type)
return
false
;
return
false
;
}
}
void
gma_wait_for_vblank
(
struct
drm_device
*
dev
)
{
/* Wait for 20ms, i.e. one cycle at 50hz. */
mdelay
(
20
);
}
int
gma_pipe_set_base
(
struct
drm_crtc
*
crtc
,
int
x
,
int
y
,
struct
drm_framebuffer
*
old_fb
)
{
struct
drm_device
*
dev
=
crtc
->
dev
;
struct
drm_psb_private
*
dev_priv
=
dev
->
dev_private
;
struct
psb_intel_crtc
*
psb_intel_crtc
=
to_psb_intel_crtc
(
crtc
);
struct
psb_framebuffer
*
psbfb
=
to_psb_fb
(
crtc
->
fb
);
int
pipe
=
psb_intel_crtc
->
pipe
;
const
struct
psb_offset
*
map
=
&
dev_priv
->
regmap
[
pipe
];
unsigned
long
start
,
offset
;
u32
dspcntr
;
int
ret
=
0
;
if
(
!
gma_power_begin
(
dev
,
true
))
return
0
;
/* no fb bound */
if
(
!
crtc
->
fb
)
{
dev_err
(
dev
->
dev
,
"No FB bound
\n
"
);
goto
gma_pipe_cleaner
;
}
/* We are displaying this buffer, make sure it is actually loaded
into the GTT */
ret
=
psb_gtt_pin
(
psbfb
->
gtt
);
if
(
ret
<
0
)
goto
gma_pipe_set_base_exit
;
start
=
psbfb
->
gtt
->
offset
;
offset
=
y
*
crtc
->
fb
->
pitches
[
0
]
+
x
*
(
crtc
->
fb
->
bits_per_pixel
/
8
);
REG_WRITE
(
map
->
stride
,
crtc
->
fb
->
pitches
[
0
]);
dspcntr
=
REG_READ
(
map
->
cntr
);
dspcntr
&=
~
DISPPLANE_PIXFORMAT_MASK
;
switch
(
crtc
->
fb
->
bits_per_pixel
)
{
case
8
:
dspcntr
|=
DISPPLANE_8BPP
;
break
;
case
16
:
if
(
crtc
->
fb
->
depth
==
15
)
dspcntr
|=
DISPPLANE_15_16BPP
;
else
dspcntr
|=
DISPPLANE_16BPP
;
break
;
case
24
:
case
32
:
dspcntr
|=
DISPPLANE_32BPP_NO_ALPHA
;
break
;
default:
dev_err
(
dev
->
dev
,
"Unknown color depth
\n
"
);
ret
=
-
EINVAL
;
goto
gma_pipe_set_base_exit
;
}
REG_WRITE
(
map
->
cntr
,
dspcntr
);
dev_dbg
(
dev
->
dev
,
"Writing base %08lX %08lX %d %d
\n
"
,
start
,
offset
,
x
,
y
);
/* FIXME: Investigate whether this really is the base for psb and why
the linear offset is named base for the other chips. map->surf
should be the base and map->linoff the offset for all chips */
if
(
IS_PSB
(
dev
))
{
REG_WRITE
(
map
->
base
,
offset
+
start
);
REG_READ
(
map
->
base
);
}
else
{
REG_WRITE
(
map
->
base
,
offset
);
REG_READ
(
map
->
base
);
REG_WRITE
(
map
->
surf
,
start
);
REG_READ
(
map
->
surf
);
}
gma_pipe_cleaner:
/* If there was a previous display we can now unpin it */
if
(
old_fb
)
psb_gtt_unpin
(
to_psb_fb
(
old_fb
)
->
gtt
);
gma_pipe_set_base_exit:
gma_power_end
(
dev
);
return
ret
;
}
/* Loads the palette/gamma unit for the CRTC with the prepared values */
void
gma_crtc_load_lut
(
struct
drm_crtc
*
crtc
)
{
struct
drm_device
*
dev
=
crtc
->
dev
;
struct
drm_psb_private
*
dev_priv
=
dev
->
dev_private
;
struct
psb_intel_crtc
*
psb_intel_crtc
=
to_psb_intel_crtc
(
crtc
);
const
struct
psb_offset
*
map
=
&
dev_priv
->
regmap
[
psb_intel_crtc
->
pipe
];
int
palreg
=
map
->
palette
;
int
i
;
/* The clocks have to be on to load the palette. */
if
(
!
crtc
->
enabled
)
return
;
if
(
gma_power_begin
(
dev
,
false
))
{
for
(
i
=
0
;
i
<
256
;
i
++
)
{
REG_WRITE
(
palreg
+
4
*
i
,
((
psb_intel_crtc
->
lut_r
[
i
]
+
psb_intel_crtc
->
lut_adj
[
i
])
<<
16
)
|
((
psb_intel_crtc
->
lut_g
[
i
]
+
psb_intel_crtc
->
lut_adj
[
i
])
<<
8
)
|
(
psb_intel_crtc
->
lut_b
[
i
]
+
psb_intel_crtc
->
lut_adj
[
i
]));
}
gma_power_end
(
dev
);
}
else
{
for
(
i
=
0
;
i
<
256
;
i
++
)
{
/* FIXME: Why pipe[0] and not pipe[..._crtc->pipe]? */
dev_priv
->
regs
.
pipe
[
0
].
palette
[
i
]
=
((
psb_intel_crtc
->
lut_r
[
i
]
+
psb_intel_crtc
->
lut_adj
[
i
])
<<
16
)
|
((
psb_intel_crtc
->
lut_g
[
i
]
+
psb_intel_crtc
->
lut_adj
[
i
])
<<
8
)
|
(
psb_intel_crtc
->
lut_b
[
i
]
+
psb_intel_crtc
->
lut_adj
[
i
]);
}
}
}
void
gma_crtc_gamma_set
(
struct
drm_crtc
*
crtc
,
u16
*
red
,
u16
*
green
,
u16
*
blue
,
u32
start
,
u32
size
)
{
struct
psb_intel_crtc
*
psb_intel_crtc
=
to_psb_intel_crtc
(
crtc
);
int
i
;
int
end
=
(
start
+
size
>
256
)
?
256
:
start
+
size
;
for
(
i
=
start
;
i
<
end
;
i
++
)
{
psb_intel_crtc
->
lut_r
[
i
]
=
red
[
i
]
>>
8
;
psb_intel_crtc
->
lut_g
[
i
]
=
green
[
i
]
>>
8
;
psb_intel_crtc
->
lut_b
[
i
]
=
blue
[
i
]
>>
8
;
}
gma_crtc_load_lut
(
crtc
);
}
/**
* Sets the power management mode of the pipe and plane.
*
* This code should probably grow support for turning the cursor off and back
* on appropriately at the same time as we're turning the pipe off/on.
*/
void
gma_crtc_dpms
(
struct
drm_crtc
*
crtc
,
int
mode
)
{
struct
drm_device
*
dev
=
crtc
->
dev
;
struct
drm_psb_private
*
dev_priv
=
dev
->
dev_private
;
struct
psb_intel_crtc
*
psb_intel_crtc
=
to_psb_intel_crtc
(
crtc
);
int
pipe
=
psb_intel_crtc
->
pipe
;
const
struct
psb_offset
*
map
=
&
dev_priv
->
regmap
[
pipe
];
u32
temp
;
/* XXX: When our outputs are all unaware of DPMS modes other than off
* and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC.
*/
/* FIXME: Uncomment this when we move cdv to generic dpms
if (IS_CDV(dev))
cdv_intel_disable_self_refresh(dev);
*/
switch
(
mode
)
{
case
DRM_MODE_DPMS_ON
:
case
DRM_MODE_DPMS_STANDBY
:
case
DRM_MODE_DPMS_SUSPEND
:
if
(
psb_intel_crtc
->
active
)
break
;
psb_intel_crtc
->
active
=
true
;
/* Enable the DPLL */
temp
=
REG_READ
(
map
->
dpll
);
if
((
temp
&
DPLL_VCO_ENABLE
)
==
0
)
{
REG_WRITE
(
map
->
dpll
,
temp
);
REG_READ
(
map
->
dpll
);
/* Wait for the clocks to stabilize. */
udelay
(
150
);
REG_WRITE
(
map
->
dpll
,
temp
|
DPLL_VCO_ENABLE
);
REG_READ
(
map
->
dpll
);
/* Wait for the clocks to stabilize. */
udelay
(
150
);
REG_WRITE
(
map
->
dpll
,
temp
|
DPLL_VCO_ENABLE
);
REG_READ
(
map
->
dpll
);
/* Wait for the clocks to stabilize. */
udelay
(
150
);
}
/* Enable the plane */
temp
=
REG_READ
(
map
->
cntr
);
if
((
temp
&
DISPLAY_PLANE_ENABLE
)
==
0
)
{
REG_WRITE
(
map
->
cntr
,
temp
|
DISPLAY_PLANE_ENABLE
);
/* Flush the plane changes */
REG_WRITE
(
map
->
base
,
REG_READ
(
map
->
base
));
}
udelay
(
150
);
/* Enable the pipe */
temp
=
REG_READ
(
map
->
conf
);
if
((
temp
&
PIPEACONF_ENABLE
)
==
0
)
REG_WRITE
(
map
->
conf
,
temp
|
PIPEACONF_ENABLE
);
temp
=
REG_READ
(
map
->
status
);
temp
&=
~
(
0xFFFF
);
temp
|=
PIPE_FIFO_UNDERRUN
;
REG_WRITE
(
map
->
status
,
temp
);
REG_READ
(
map
->
status
);
gma_crtc_load_lut
(
crtc
);
/* Give the overlay scaler a chance to enable
* if it's on this pipe */
/* psb_intel_crtc_dpms_video(crtc, true); TODO */
break
;
case
DRM_MODE_DPMS_OFF
:
if
(
!
psb_intel_crtc
->
active
)
break
;
psb_intel_crtc
->
active
=
false
;
/* Give the overlay scaler a chance to disable
* if it's on this pipe */
/* psb_intel_crtc_dpms_video(crtc, FALSE); TODO */
/* Disable the VGA plane that we never use */
REG_WRITE
(
VGACNTRL
,
VGA_DISP_DISABLE
);
/* Turn off vblank interrupts */
drm_vblank_off
(
dev
,
pipe
);
/* Wait for vblank for the disable to take effect */
gma_wait_for_vblank
(
dev
);
/* Disable plane */
temp
=
REG_READ
(
map
->
cntr
);
if
((
temp
&
DISPLAY_PLANE_ENABLE
)
!=
0
)
{
REG_WRITE
(
map
->
cntr
,
temp
&
~
DISPLAY_PLANE_ENABLE
);
/* Flush the plane changes */
REG_WRITE
(
map
->
base
,
REG_READ
(
map
->
base
));
REG_READ
(
map
->
base
);
}
/* Disable pipe */
temp
=
REG_READ
(
map
->
conf
);
if
((
temp
&
PIPEACONF_ENABLE
)
!=
0
)
{
REG_WRITE
(
map
->
conf
,
temp
&
~
PIPEACONF_ENABLE
);
REG_READ
(
map
->
conf
);
}
/* Wait for vblank for the disable to take effect. */
gma_wait_for_vblank
(
dev
);
udelay
(
150
);
/* Disable DPLL */
temp
=
REG_READ
(
map
->
dpll
);
if
((
temp
&
DPLL_VCO_ENABLE
)
!=
0
)
{
REG_WRITE
(
map
->
dpll
,
temp
&
~
DPLL_VCO_ENABLE
);
REG_READ
(
map
->
dpll
);
}
/* Wait for the clocks to turn off. */
udelay
(
150
);
break
;
}
/* FIXME: Uncomment this when we move cdv to generic dpms
if (IS_CDV(dev))
cdv_intel_update_watermark(dev, crtc);
*/
/* Set FIFO watermarks */
REG_WRITE
(
DSPARB
,
0x3F3E
);
}
bool
gma_crtc_mode_fixup
(
struct
drm_crtc
*
crtc
,
const
struct
drm_display_mode
*
mode
,
struct
drm_display_mode
*
adjusted_mode
)
{
return
true
;
}
void
gma_crtc_prepare
(
struct
drm_crtc
*
crtc
)
{
struct
drm_crtc_helper_funcs
*
crtc_funcs
=
crtc
->
helper_private
;
crtc_funcs
->
dpms
(
crtc
,
DRM_MODE_DPMS_OFF
);
}
void
gma_crtc_commit
(
struct
drm_crtc
*
crtc
)
{
struct
drm_crtc_helper_funcs
*
crtc_funcs
=
crtc
->
helper_private
;
crtc_funcs
->
dpms
(
crtc
,
DRM_MODE_DPMS_ON
);
}
void
gma_crtc_disable
(
struct
drm_crtc
*
crtc
)
{
struct
gtt_range
*
gt
;
struct
drm_crtc_helper_funcs
*
crtc_funcs
=
crtc
->
helper_private
;
crtc_funcs
->
dpms
(
crtc
,
DRM_MODE_DPMS_OFF
);
if
(
crtc
->
fb
)
{
gt
=
to_psb_fb
(
crtc
->
fb
)
->
gtt
;
psb_gtt_unpin
(
gt
);
}
}
void
gma_crtc_destroy
(
struct
drm_crtc
*
crtc
)
{
struct
psb_intel_crtc
*
psb_intel_crtc
=
to_psb_intel_crtc
(
crtc
);
kfree
(
psb_intel_crtc
->
crtc_state
);
drm_crtc_cleanup
(
crtc
);
kfree
(
psb_intel_crtc
);
}
#define GMA_PLL_INVALID(s) {
/* DRM_ERROR(s); */
return false; }
#define GMA_PLL_INVALID(s) {
/* DRM_ERROR(s); */
return false; }
bool
gma_pll_is_valid
(
struct
drm_crtc
*
crtc
,
bool
gma_pll_is_valid
(
struct
drm_crtc
*
crtc
,
...
...
drivers/gpu/drm/gma500/gma_display.h
View file @
2eff0b33
...
@@ -61,6 +61,20 @@ struct gma_clock_funcs {
...
@@ -61,6 +61,20 @@ struct gma_clock_funcs {
/* Common pipe related functions */
/* Common pipe related functions */
extern
bool
gma_pipe_has_type
(
struct
drm_crtc
*
crtc
,
int
type
);
extern
bool
gma_pipe_has_type
(
struct
drm_crtc
*
crtc
,
int
type
);
extern
void
gma_wait_for_vblank
(
struct
drm_device
*
dev
);
extern
int
gma_pipe_set_base
(
struct
drm_crtc
*
crtc
,
int
x
,
int
y
,
struct
drm_framebuffer
*
old_fb
);
extern
void
gma_crtc_load_lut
(
struct
drm_crtc
*
crtc
);
extern
void
gma_crtc_gamma_set
(
struct
drm_crtc
*
crtc
,
u16
*
red
,
u16
*
green
,
u16
*
blue
,
u32
start
,
u32
size
);
extern
void
gma_crtc_dpms
(
struct
drm_crtc
*
crtc
,
int
mode
);
extern
bool
gma_crtc_mode_fixup
(
struct
drm_crtc
*
crtc
,
const
struct
drm_display_mode
*
mode
,
struct
drm_display_mode
*
adjusted_mode
);
extern
void
gma_crtc_prepare
(
struct
drm_crtc
*
crtc
);
extern
void
gma_crtc_commit
(
struct
drm_crtc
*
crtc
);
extern
void
gma_crtc_disable
(
struct
drm_crtc
*
crtc
);
extern
void
gma_crtc_destroy
(
struct
drm_crtc
*
crtc
);
/* Common clock related functions */
/* Common clock related functions */
extern
const
struct
gma_limit_t
*
gma_limit
(
struct
drm_crtc
*
crtc
,
int
refclk
);
extern
const
struct
gma_limit_t
*
gma_limit
(
struct
drm_crtc
*
crtc
,
int
refclk
);
...
...
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