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
3d62fe5b
Commit
3d62fe5b
authored
Apr 15, 2013
by
Tomi Valkeinen
Browse files
Options
Browse Files
Download
Plain Diff
OMAPDSS: Merge omapdss topic branches
parents
77ec05d0
6717cd29
b2c9c8ee
Changes
26
Hide whitespace changes
Inline
Side-by-side
Showing
26 changed files
with
1573 additions
and
1214 deletions
+1573
-1214
drivers/gpu/drm/omapdrm/omap_connector.c
drivers/gpu/drm/omapdrm/omap_connector.c
+25
-2
drivers/gpu/drm/omapdrm/omap_crtc.c
drivers/gpu/drm/omapdrm/omap_crtc.c
+14
-7
drivers/gpu/drm/omapdrm/omap_drv.c
drivers/gpu/drm/omapdrm/omap_drv.c
+133
-32
drivers/gpu/drm/omapdrm/omap_drv.h
drivers/gpu/drm/omapdrm/omap_drv.h
+4
-34
drivers/gpu/drm/omapdrm/omap_encoder.c
drivers/gpu/drm/omapdrm/omap_encoder.c
+22
-2
drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c
drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c
+1
-1
drivers/gpu/drm/omapdrm/omap_irq.c
drivers/gpu/drm/omapdrm/omap_irq.c
+11
-6
drivers/gpu/drm/omapdrm/omap_plane.c
drivers/gpu/drm/omapdrm/omap_plane.c
+6
-0
drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c
drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c
+16
-4
drivers/video/omap2/displays/panel-taal.c
drivers/video/omap2/displays/panel-taal.c
+29
-269
drivers/video/omap2/dss/apply.c
drivers/video/omap2/dss/apply.c
+11
-4
drivers/video/omap2/dss/core.c
drivers/video/omap2/dss/core.c
+1
-4
drivers/video/omap2/dss/dispc.c
drivers/video/omap2/dss/dispc.c
+114
-62
drivers/video/omap2/dss/dispc.h
drivers/video/omap2/dss/dispc.h
+1
-0
drivers/video/omap2/dss/dpi.c
drivers/video/omap2/dss/dpi.c
+242
-74
drivers/video/omap2/dss/dsi.c
drivers/video/omap2/dss/dsi.c
+742
-479
drivers/video/omap2/dss/dss.c
drivers/video/omap2/dss/dss.c
+49
-132
drivers/video/omap2/dss/dss.h
drivers/video/omap2/dss/dss.h
+21
-15
drivers/video/omap2/dss/dss_features.c
drivers/video/omap2/dss/dss_features.c
+4
-4
drivers/video/omap2/dss/hdmi.c
drivers/video/omap2/dss/hdmi.c
+9
-26
drivers/video/omap2/dss/output.c
drivers/video/omap2/dss/output.c
+1
-0
drivers/video/omap2/dss/rfbi.c
drivers/video/omap2/dss/rfbi.c
+2
-0
drivers/video/omap2/dss/sdi.c
drivers/video/omap2/dss/sdi.c
+69
-1
drivers/video/omap2/dss/venc.c
drivers/video/omap2/dss/venc.c
+3
-11
drivers/video/omap2/omapfb/omapfb-main.c
drivers/video/omap2/omapfb/omapfb-main.c
+1
-1
include/video/omapdss.h
include/video/omapdss.h
+42
-44
No files found.
drivers/gpu/drm/omapdrm/omap_connector.c
View file @
3d62fe5b
...
...
@@ -110,6 +110,11 @@ static enum drm_connector_status omap_connector_detect(
ret
=
connector_status_connected
;
else
ret
=
connector_status_disconnected
;
}
else
if
(
dssdev
->
type
==
OMAP_DISPLAY_TYPE_DPI
||
dssdev
->
type
==
OMAP_DISPLAY_TYPE_DBI
||
dssdev
->
type
==
OMAP_DISPLAY_TYPE_SDI
||
dssdev
->
type
==
OMAP_DISPLAY_TYPE_DSI
)
{
ret
=
connector_status_connected
;
}
else
{
ret
=
connector_status_unknown
;
}
...
...
@@ -189,12 +194,30 @@ static int omap_connector_mode_valid(struct drm_connector *connector,
struct
omap_video_timings
timings
=
{
0
};
struct
drm_device
*
dev
=
connector
->
dev
;
struct
drm_display_mode
*
new_mode
;
int
ret
=
MODE_BAD
;
int
r
,
r
et
=
MODE_BAD
;
copy_timings_drm_to_omap
(
&
timings
,
mode
);
mode
->
vrefresh
=
drm_mode_vrefresh
(
mode
);
if
(
!
dssdrv
->
check_timings
(
dssdev
,
&
timings
))
{
/*
* if the panel driver doesn't have a check_timings, it's most likely
* a fixed resolution panel, check if the timings match with the
* panel's timings
*/
if
(
dssdrv
->
check_timings
)
{
r
=
dssdrv
->
check_timings
(
dssdev
,
&
timings
);
}
else
{
struct
omap_video_timings
t
=
{
0
};
dssdrv
->
get_timings
(
dssdev
,
&
t
);
if
(
memcmp
(
&
timings
,
&
t
,
sizeof
(
struct
omap_video_timings
)))
r
=
-
EINVAL
;
else
r
=
0
;
}
if
(
!
r
)
{
/* check if vrefresh is still valid */
new_mode
=
drm_mode_duplicate
(
dev
,
mode
);
new_mode
->
clock
=
timings
.
pixel_clock
;
...
...
drivers/gpu/drm/omapdrm/omap_crtc.c
View file @
3d62fe5b
...
...
@@ -74,6 +74,13 @@ struct omap_crtc {
struct
work_struct
page_flip_work
;
};
uint32_t
pipe2vbl
(
struct
drm_crtc
*
crtc
)
{
struct
omap_crtc
*
omap_crtc
=
to_omap_crtc
(
crtc
);
return
dispc_mgr_get_vsync_irq
(
omap_crtc
->
channel
);
}
/*
* Manager-ops, callbacks from output when they need to configure
* the upstream part of the video pipe.
...
...
@@ -613,7 +620,13 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
omap_crtc
->
apply
.
pre_apply
=
omap_crtc_pre_apply
;
omap_crtc
->
apply
.
post_apply
=
omap_crtc_post_apply
;
omap_crtc
->
apply_irq
.
irqmask
=
pipe2vbl
(
id
);
omap_crtc
->
channel
=
channel
;
omap_crtc
->
plane
=
plane
;
omap_crtc
->
plane
->
crtc
=
crtc
;
omap_crtc
->
name
=
channel_names
[
channel
];
omap_crtc
->
pipe
=
id
;
omap_crtc
->
apply_irq
.
irqmask
=
pipe2vbl
(
crtc
);
omap_crtc
->
apply_irq
.
irq
=
omap_crtc_apply_irq
;
omap_crtc
->
error_irq
.
irqmask
=
...
...
@@ -621,12 +634,6 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
omap_crtc
->
error_irq
.
irq
=
omap_crtc_error_irq
;
omap_irq_register
(
dev
,
&
omap_crtc
->
error_irq
);
omap_crtc
->
channel
=
channel
;
omap_crtc
->
plane
=
plane
;
omap_crtc
->
plane
->
crtc
=
crtc
;
omap_crtc
->
name
=
channel_names
[
channel
];
omap_crtc
->
pipe
=
id
;
/* temporary: */
omap_crtc
->
mgr
.
id
=
channel
;
...
...
drivers/gpu/drm/omapdrm/omap_drv.c
View file @
3d62fe5b
...
...
@@ -74,54 +74,53 @@ static int get_connector_type(struct omap_dss_device *dssdev)
}
}
static
bool
channel_used
(
struct
drm_device
*
dev
,
enum
omap_channel
channel
)
{
struct
omap_drm_private
*
priv
=
dev
->
dev_private
;
int
i
;
for
(
i
=
0
;
i
<
priv
->
num_crtcs
;
i
++
)
{
struct
drm_crtc
*
crtc
=
priv
->
crtcs
[
i
];
if
(
omap_crtc_channel
(
crtc
)
==
channel
)
return
true
;
}
return
false
;
}
static
int
omap_modeset_init
(
struct
drm_device
*
dev
)
{
struct
omap_drm_private
*
priv
=
dev
->
dev_private
;
struct
omap_dss_device
*
dssdev
=
NULL
;
int
num_ovls
=
dss_feat_get_num_ovls
();
int
id
;
int
num_mgrs
=
dss_feat_get_num_mgrs
();
int
num_crtcs
;
int
i
,
id
=
0
;
drm_mode_config_init
(
dev
);
omap_drm_irq_install
(
dev
);
/*
* Create private planes and CRTCs for the last NUM_CRTCs overlay
* plus manager:
* We usually don't want to create a CRTC for each manager, at least
* not until we have a way to expose private planes to userspace.
* Otherwise there would not be enough video pipes left for drm planes.
* We use the num_crtc argument to limit the number of crtcs we create.
*/
for
(
id
=
0
;
id
<
min
(
num_crtc
,
num_ovls
);
id
++
)
{
struct
drm_plane
*
plane
;
struct
drm_crtc
*
crtc
;
plane
=
omap_plane_init
(
dev
,
id
,
true
);
crtc
=
omap_crtc_init
(
dev
,
plane
,
pipe2chan
(
id
),
id
);
num_crtcs
=
min3
(
num_crtc
,
num_mgrs
,
num_ovls
);
BUG_ON
(
priv
->
num_crtcs
>=
ARRAY_SIZE
(
priv
->
crtcs
));
priv
->
crtcs
[
id
]
=
crtc
;
priv
->
num_crtcs
++
;
priv
->
planes
[
id
]
=
plane
;
priv
->
num_planes
++
;
}
/*
* Create normal planes for the remaining overlays:
*/
for
(;
id
<
num_ovls
;
id
++
)
{
struct
drm_plane
*
plane
=
omap_plane_init
(
dev
,
id
,
false
);
BUG_ON
(
priv
->
num_planes
>=
ARRAY_SIZE
(
priv
->
planes
));
priv
->
planes
[
priv
->
num_planes
++
]
=
plane
;
}
dssdev
=
NULL
;
for_each_dss_dev
(
dssdev
)
{
struct
drm_connector
*
connector
;
struct
drm_encoder
*
encoder
;
enum
omap_channel
channel
;
if
(
!
dssdev
->
driver
)
{
dev_warn
(
dev
->
dev
,
"%s has no driver.. skipping it
\n
"
,
dssdev
->
name
);
return
0
;
continue
;
}
if
(
!
(
dssdev
->
driver
->
get_timings
||
...
...
@@ -129,7 +128,7 @@ static int omap_modeset_init(struct drm_device *dev)
dev_warn
(
dev
->
dev
,
"%s driver does not support "
"get_timings or read_edid.. skipping it!
\n
"
,
dssdev
->
name
);
return
0
;
continue
;
}
encoder
=
omap_encoder_init
(
dev
,
dssdev
);
...
...
@@ -157,16 +156,118 @@ static int omap_modeset_init(struct drm_device *dev)
drm_mode_connector_attach_encoder
(
connector
,
encoder
);
/*
* if we have reached the limit of the crtcs we are allowed to
* create, let's not try to look for a crtc for this
* panel/encoder and onwards, we will, of course, populate the
* the possible_crtcs field for all the encoders with the final
* set of crtcs we create
*/
if
(
id
==
num_crtcs
)
continue
;
/*
* get the recommended DISPC channel for this encoder. For now,
* we only try to get create a crtc out of the recommended, the
* other possible channels to which the encoder can connect are
* not considered.
*/
channel
=
dssdev
->
output
->
dispc_channel
;
/*
* if this channel hasn't already been taken by a previously
* allocated crtc, we create a new crtc for it
*/
if
(
!
channel_used
(
dev
,
channel
))
{
struct
drm_plane
*
plane
;
struct
drm_crtc
*
crtc
;
plane
=
omap_plane_init
(
dev
,
id
,
true
);
crtc
=
omap_crtc_init
(
dev
,
plane
,
channel
,
id
);
BUG_ON
(
priv
->
num_crtcs
>=
ARRAY_SIZE
(
priv
->
crtcs
));
priv
->
crtcs
[
id
]
=
crtc
;
priv
->
num_crtcs
++
;
priv
->
planes
[
id
]
=
plane
;
priv
->
num_planes
++
;
id
++
;
}
}
/*
* we have allocated crtcs according to the need of the panels/encoders,
* adding more crtcs here if needed
*/
for
(;
id
<
num_crtcs
;
id
++
)
{
/* find a free manager for this crtc */
for
(
i
=
0
;
i
<
num_mgrs
;
i
++
)
{
if
(
!
channel_used
(
dev
,
i
))
{
struct
drm_plane
*
plane
;
struct
drm_crtc
*
crtc
;
plane
=
omap_plane_init
(
dev
,
id
,
true
);
crtc
=
omap_crtc_init
(
dev
,
plane
,
i
,
id
);
BUG_ON
(
priv
->
num_crtcs
>=
ARRAY_SIZE
(
priv
->
crtcs
));
priv
->
crtcs
[
id
]
=
crtc
;
priv
->
num_crtcs
++
;
priv
->
planes
[
id
]
=
plane
;
priv
->
num_planes
++
;
break
;
}
else
{
continue
;
}
}
if
(
i
==
num_mgrs
)
{
/* this shouldn't really happen */
dev_err
(
dev
->
dev
,
"no managers left for crtc
\n
"
);
return
-
ENOMEM
;
}
}
/*
* Create normal planes for the remaining overlays:
*/
for
(;
id
<
num_ovls
;
id
++
)
{
struct
drm_plane
*
plane
=
omap_plane_init
(
dev
,
id
,
false
);
BUG_ON
(
priv
->
num_planes
>=
ARRAY_SIZE
(
priv
->
planes
));
priv
->
planes
[
priv
->
num_planes
++
]
=
plane
;
}
for
(
i
=
0
;
i
<
priv
->
num_encoders
;
i
++
)
{
struct
drm_encoder
*
encoder
=
priv
->
encoders
[
i
];
struct
omap_dss_device
*
dssdev
=
omap_encoder_get_dssdev
(
encoder
);
/* figure out which crtc's we can connect the encoder to: */
encoder
->
possible_crtcs
=
0
;
for
(
id
=
0
;
id
<
priv
->
num_crtcs
;
id
++
)
{
enum
omap_dss_output_id
supported_outputs
=
dss_feat_get_supported_outputs
(
pipe2chan
(
id
));
struct
drm_crtc
*
crtc
=
priv
->
crtcs
[
id
];
enum
omap_channel
crtc_channel
;
enum
omap_dss_output_id
supported_outputs
;
crtc_channel
=
omap_crtc_channel
(
crtc
);
supported_outputs
=
dss_feat_get_supported_outputs
(
crtc_channel
);
if
(
supported_outputs
&
dssdev
->
output
->
id
)
encoder
->
possible_crtcs
|=
(
1
<<
id
);
}
}
DBG
(
"registered %d planes, %d crtcs, %d encoders and %d connectors
\n
"
,
priv
->
num_planes
,
priv
->
num_crtcs
,
priv
->
num_encoders
,
priv
->
num_connectors
);
dev
->
mode_config
.
min_width
=
32
;
dev
->
mode_config
.
min_height
=
32
;
...
...
@@ -303,7 +404,7 @@ static int ioctl_gem_info(struct drm_device *dev, void *data,
return
ret
;
}
struct
drm_ioctl_desc
ioctls
[
DRM_COMMAND_END
-
DRM_COMMAND_BASE
]
=
{
st
atic
st
ruct
drm_ioctl_desc
ioctls
[
DRM_COMMAND_END
-
DRM_COMMAND_BASE
]
=
{
DRM_IOCTL_DEF_DRV
(
OMAP_GET_PARAM
,
ioctl_get_param
,
DRM_UNLOCKED
|
DRM_AUTH
),
DRM_IOCTL_DEF_DRV
(
OMAP_SET_PARAM
,
ioctl_set_param
,
DRM_UNLOCKED
|
DRM_AUTH
|
DRM_MASTER
|
DRM_ROOT_ONLY
),
DRM_IOCTL_DEF_DRV
(
OMAP_GEM_NEW
,
ioctl_gem_new
,
DRM_UNLOCKED
|
DRM_AUTH
),
...
...
@@ -567,7 +668,7 @@ static const struct dev_pm_ops omapdrm_pm_ops = {
};
#endif
struct
platform_driver
pdev
=
{
st
atic
st
ruct
platform_driver
pdev
=
{
.
driver
=
{
.
name
=
DRIVER_NAME
,
.
owner
=
THIS_MODULE
,
...
...
drivers/gpu/drm/omapdrm/omap_drv.h
View file @
3d62fe5b
...
...
@@ -139,8 +139,8 @@ void omap_gem_describe_objects(struct list_head *list, struct seq_file *m);
int
omap_gem_resume
(
struct
device
*
dev
);
#endif
int
omap_irq_enable_vblank
(
struct
drm_device
*
dev
,
int
crtc
);
void
omap_irq_disable_vblank
(
struct
drm_device
*
dev
,
int
crtc
);
int
omap_irq_enable_vblank
(
struct
drm_device
*
dev
,
int
crtc
_id
);
void
omap_irq_disable_vblank
(
struct
drm_device
*
dev
,
int
crtc
_id
);
irqreturn_t
omap_irq_handler
(
DRM_IRQ_ARGS
);
void
omap_irq_preinstall
(
struct
drm_device
*
dev
);
int
omap_irq_postinstall
(
struct
drm_device
*
dev
);
...
...
@@ -271,39 +271,9 @@ static inline int align_pitch(int pitch, int width, int bpp)
return
ALIGN
(
pitch
,
8
*
bytespp
);
}
static
inline
enum
omap_channel
pipe2chan
(
int
pipe
)
{
int
num_mgrs
=
dss_feat_get_num_mgrs
();
/*
* We usually don't want to create a CRTC for each manager,
* at least not until we have a way to expose private planes
* to userspace. Otherwise there would not be enough video
* pipes left for drm planes. The higher #'d managers tend
* to have more features so start in reverse order.
*/
return
num_mgrs
-
pipe
-
1
;
}
/* map crtc to vblank mask */
static
inline
uint32_t
pipe2vbl
(
int
crtc
)
{
enum
omap_channel
channel
=
pipe2chan
(
crtc
);
return
dispc_mgr_get_vsync_irq
(
channel
);
}
static
inline
int
crtc2pipe
(
struct
drm_device
*
dev
,
struct
drm_crtc
*
crtc
)
{
struct
omap_drm_private
*
priv
=
dev
->
dev_private
;
int
i
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
priv
->
crtcs
);
i
++
)
if
(
priv
->
crtcs
[
i
]
==
crtc
)
return
i
;
BUG
();
/* bogus CRTC ptr */
return
-
1
;
}
uint32_t
pipe2vbl
(
struct
drm_crtc
*
crtc
);
struct
omap_dss_device
*
omap_encoder_get_dssdev
(
struct
drm_encoder
*
encoder
);
/* should these be made into common util helpers?
*/
...
...
drivers/gpu/drm/omapdrm/omap_encoder.c
View file @
3d62fe5b
...
...
@@ -41,6 +41,13 @@ struct omap_encoder {
struct
omap_dss_device
*
dssdev
;
};
struct
omap_dss_device
*
omap_encoder_get_dssdev
(
struct
drm_encoder
*
encoder
)
{
struct
omap_encoder
*
omap_encoder
=
to_omap_encoder
(
encoder
);
return
omap_encoder
->
dssdev
;
}
static
void
omap_encoder_destroy
(
struct
drm_encoder
*
encoder
)
{
struct
omap_encoder
*
omap_encoder
=
to_omap_encoder
(
encoder
);
...
...
@@ -128,13 +135,26 @@ int omap_encoder_update(struct drm_encoder *encoder,
dssdev
->
output
->
manager
=
mgr
;
ret
=
dssdrv
->
check_timings
(
dssdev
,
timings
);
if
(
dssdrv
->
check_timings
)
{
ret
=
dssdrv
->
check_timings
(
dssdev
,
timings
);
}
else
{
struct
omap_video_timings
t
=
{
0
};
dssdrv
->
get_timings
(
dssdev
,
&
t
);
if
(
memcmp
(
timings
,
&
t
,
sizeof
(
struct
omap_video_timings
)))
ret
=
-
EINVAL
;
else
ret
=
0
;
}
if
(
ret
)
{
dev_err
(
dev
->
dev
,
"could not set timings: %d
\n
"
,
ret
);
return
ret
;
}
dssdrv
->
set_timings
(
dssdev
,
timings
);
if
(
dssdrv
->
set_timings
)
dssdrv
->
set_timings
(
dssdev
,
timings
);
return
0
;
}
...
...
drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c
View file @
3d62fe5b
...
...
@@ -178,7 +178,7 @@ static int omap_gem_dmabuf_mmap(struct dma_buf *buffer,
return
omap_gem_mmap_obj
(
obj
,
vma
);
}
struct
dma_buf_ops
omap_dmabuf_ops
=
{
st
atic
st
ruct
dma_buf_ops
omap_dmabuf_ops
=
{
.
map_dma_buf
=
omap_gem_map_dma_buf
,
.
unmap_dma_buf
=
omap_gem_unmap_dma_buf
,
.
release
=
omap_gem_dmabuf_release
,
...
...
drivers/gpu/drm/omapdrm/omap_irq.c
View file @
3d62fe5b
...
...
@@ -130,12 +130,13 @@ int omap_irq_wait(struct drm_device *dev, struct omap_irq_wait *wait,
* Zero on success, appropriate errno if the given @crtc's vblank
* interrupt cannot be enabled.
*/
int
omap_irq_enable_vblank
(
struct
drm_device
*
dev
,
int
crtc
)
int
omap_irq_enable_vblank
(
struct
drm_device
*
dev
,
int
crtc
_id
)
{
struct
omap_drm_private
*
priv
=
dev
->
dev_private
;
struct
drm_crtc
*
crtc
=
priv
->
crtcs
[
crtc_id
];
unsigned
long
flags
;
DBG
(
"dev=%p, crtc=%d"
,
dev
,
crtc
);
DBG
(
"dev=%p, crtc=%d"
,
dev
,
crtc
_id
);
dispc_runtime_get
();
spin_lock_irqsave
(
&
list_lock
,
flags
);
...
...
@@ -156,12 +157,13 @@ int omap_irq_enable_vblank(struct drm_device *dev, int crtc)
* a hardware vblank counter, this routine should be a no-op, since
* interrupts will have to stay on to keep the count accurate.
*/
void
omap_irq_disable_vblank
(
struct
drm_device
*
dev
,
int
crtc
)
void
omap_irq_disable_vblank
(
struct
drm_device
*
dev
,
int
crtc
_id
)
{
struct
omap_drm_private
*
priv
=
dev
->
dev_private
;
struct
drm_crtc
*
crtc
=
priv
->
crtcs
[
crtc_id
];
unsigned
long
flags
;
DBG
(
"dev=%p, crtc=%d"
,
dev
,
crtc
);
DBG
(
"dev=%p, crtc=%d"
,
dev
,
crtc
_id
);
dispc_runtime_get
();
spin_lock_irqsave
(
&
list_lock
,
flags
);
...
...
@@ -186,9 +188,12 @@ irqreturn_t omap_irq_handler(DRM_IRQ_ARGS)
VERB
(
"irqs: %08x"
,
irqstatus
);
for
(
id
=
0
;
id
<
priv
->
num_crtcs
;
id
++
)
if
(
irqstatus
&
pipe2vbl
(
id
))
for
(
id
=
0
;
id
<
priv
->
num_crtcs
;
id
++
)
{
struct
drm_crtc
*
crtc
=
priv
->
crtcs
[
id
];
if
(
irqstatus
&
pipe2vbl
(
crtc
))
drm_handle_vblank
(
dev
,
id
);
}
spin_lock_irqsave
(
&
list_lock
,
flags
);
list_for_each_entry_safe
(
handler
,
n
,
&
priv
->
irq_list
,
node
)
{
...
...
drivers/gpu/drm/omapdrm/omap_plane.c
View file @
3d62fe5b
...
...
@@ -247,6 +247,12 @@ static int omap_plane_update(struct drm_plane *plane,
{
struct
omap_plane
*
omap_plane
=
to_omap_plane
(
plane
);
omap_plane
->
enabled
=
true
;
if
(
plane
->
fb
)
drm_framebuffer_unreference
(
plane
->
fb
);
drm_framebuffer_reference
(
fb
);
return
omap_plane_mode_set
(
plane
,
crtc
,
fb
,
crtc_x
,
crtc_y
,
crtc_w
,
crtc_h
,
src_x
,
src_y
,
src_w
,
src_h
,
...
...
drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c
View file @
3d62fe5b
...
...
@@ -242,16 +242,22 @@ static int nec_8048_spi_remove(struct spi_device *spi)
return
0
;
}
static
int
nec_8048_spi_suspend
(
struct
spi_device
*
spi
,
pm_message_t
mesg
)
#ifdef CONFIG_PM_SLEEP
static
int
nec_8048_spi_suspend
(
struct
device
*
dev
)
{
struct
spi_device
*
spi
=
to_spi_device
(
dev
);
nec_8048_spi_send
(
spi
,
2
,
0x01
);
mdelay
(
40
);
return
0
;
}
static
int
nec_8048_spi_resume
(
struct
spi_device
*
spi
)
static
int
nec_8048_spi_resume
(
struct
device
*
dev
)
{
struct
spi_device
*
spi
=
to_spi_device
(
dev
);
/* reinitialize the panel */
spi_setup
(
spi
);
nec_8048_spi_send
(
spi
,
2
,
0x00
);
...
...
@@ -260,14 +266,20 @@ static int nec_8048_spi_resume(struct spi_device *spi)
return
0
;
}
static
SIMPLE_DEV_PM_OPS
(
nec_8048_spi_pm_ops
,
nec_8048_spi_suspend
,
nec_8048_spi_resume
);
#define NEC_8048_SPI_PM_OPS (&nec_8048_spi_pm_ops)
#else
#define NEC_8048_SPI_PM_OPS NULL
#endif
static
struct
spi_driver
nec_8048_spi_driver
=
{
.
probe
=
nec_8048_spi_probe
,
.
remove
=
nec_8048_spi_remove
,
.
suspend
=
nec_8048_spi_suspend
,
.
resume
=
nec_8048_spi_resume
,
.
driver
=
{
.
name
=
"nec_8048_spi"
,
.
owner
=
THIS_MODULE
,
.
pm
=
NEC_8048_SPI_PM_OPS
,
},
};
...
...
drivers/video/omap2/displays/panel-taal.c
View file @
3d62fe5b
...
...
@@ -54,61 +54,6 @@ static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable);
static
int
taal_panel_reset
(
struct
omap_dss_device
*
dssdev
);
/**
* struct panel_config - panel configuration
* @name: panel name
* @type: panel type
* @timings: panel resolution
* @sleep: various panel specific delays, passed to msleep() if non-zero
* @reset_sequence: reset sequence timings, passed to udelay() if non-zero
* @regulators: array of panel regulators
* @num_regulators: number of regulators in the array
*/
struct
panel_config
{
const
char
*
name
;
int
type
;
struct
omap_video_timings
timings
;
struct
{
unsigned
int
sleep_in
;
unsigned
int
sleep_out
;
unsigned
int
hw_reset
;
unsigned
int
enable_te
;
}
sleep
;
struct
{
unsigned
int
high
;
unsigned
int
low
;
}
reset_sequence
;
};
enum
{
PANEL_TAAL
,
};
static
struct
panel_config
panel_configs
[]
=
{
{
.
name
=
"taal"
,
.
type
=
PANEL_TAAL
,
.
timings
=
{
.
x_res
=
864
,
.
y_res
=
480
,
},
.
sleep
=
{
.
sleep_in
=
5
,
.
sleep_out
=
5
,
.
hw_reset
=
5
,
.
enable_te
=
100
,
/* possible panel bug */
},
.
reset_sequence
=
{
.
high
=
10
,
.
low
=
10
,
},
},
};
struct
taal_data
{
struct
mutex
lock
;
...
...
@@ -121,9 +66,6 @@ struct taal_data {
struct
omap_dss_device
*
dssdev
;
/* panel specific HW info */
struct
panel_config
*
panel_config
;
/* panel HW configuration from DT or platform data */
int
reset_gpio
;
int
ext_te_gpio
;
...
...
@@ -134,8 +76,6 @@ struct taal_data {
/* runtime variables */
bool
enabled
;
u8
rotate
;
bool
mirror
;
bool
te_enabled
;
...
...
@@ -221,8 +161,7 @@ static int taal_sleep_in(struct taal_data *td)
hw_guard_start
(
td
,
120
);
if
(
td
->
panel_config
->
sleep
.
sleep_in
)
msleep
(
td
->
panel_config
->
sleep
.
sleep_in
);
msleep
(
5
);
return
0
;
}
...
...
@@ -239,8 +178,7 @@ static int taal_sleep_out(struct taal_data *td)
hw_guard_start
(
td
,
120
);
if
(
td
->
panel_config
->
sleep
.
sleep_out
)
msleep
(
td
->
panel_config
->
sleep
.
sleep_out
);
msleep
(
5
);
return
0
;
}
...
...
@@ -262,49 +200,6 @@ static int taal_get_id(struct taal_data *td, u8 *id1, u8 *id2, u8 *id3)
return
0
;
}
static
int
taal_set_addr_mode
(
struct
taal_data
*
td
,
u8
rotate
,
bool
mirror
)
{
int
r
;
u8
mode
;
int
b5
,
b6
,
b7
;
r
=
taal_dcs_read_1
(
td
,
MIPI_DCS_GET_ADDRESS_MODE
,
&
mode
);
if
(
r
)
return
r
;
switch
(
rotate
)
{
default:
case
0
:
b7
=
0
;
b6
=
0
;
b5
=
0
;
break
;
case
1
:
b7
=
0
;
b6
=
1
;
b5
=
1
;
break
;
case
2
:
b7
=
1
;
b6
=
1
;
b5
=
0
;
break
;
case
3
:
b7
=
1
;
b6
=
0
;
b5
=
1
;
break
;
}
if
(
mirror
)
b6
=
!
b6
;
mode
&=
~
((
1
<<
7
)
|
(
1
<<
6
)
|
(
1
<<
5
));
mode
|=
(
b7
<<
7
)
|
(
b6
<<
6
)
|
(
b5
<<
5
);
return
taal_dcs_write_1
(
td
,
MIPI_DCS_SET_ADDRESS_MODE
,
mode
);
}
static
int
taal_set_update_window
(
struct
taal_data
*
td
,
u16
x
,
u16
y
,
u16
w
,
u16
h
)
{
...
...
@@ -515,15 +410,8 @@ static const struct backlight_ops taal_bl_ops = {
static
void
taal_get_resolution
(
struct
omap_dss_device
*
dssdev
,
u16
*
xres
,
u16
*
yres
)
{
struct
taal_data
*
td
=
dev_get_drvdata
(
&
dssdev
->
dev
);
if
(
td
->
rotate
==
0
||
td
->
rotate
==
2
)
{
*
xres
=
dssdev
->
panel
.
timings
.
x_res
;
*
yres
=
dssdev
->
panel
.
timings
.
y_res
;
}
else
{
*
yres
=
dssdev
->
panel
.
timings
.
x_res
;
*
xres
=
dssdev
->
panel
.
timings
.
y_res
;
}
*
xres
=
dssdev
->
panel
.
timings
.
x_res
;
*
yres
=
dssdev
->
panel
.
timings
.
y_res
;
}
static
ssize_t
taal_num_errors_show
(
struct
device
*
dev
,
...
...
@@ -845,17 +733,14 @@ static void taal_hw_reset(struct omap_dss_device *dssdev)
return
;
gpio_set_value
(
td
->
reset_gpio
,
1
);
if
(
td
->
panel_config
->
reset_sequence
.
high
)
udelay
(
td
->
panel_config
->
reset_sequence
.
high
);
udelay
(
10
);
/* reset the panel */
gpio_set_value
(
td
->
reset_gpio
,
0
);
/* assert reset */
if
(
td
->
panel_config
->
reset_sequence
.
low
)
udelay
(
td
->
panel_config
->
reset_sequence
.
low
);
udelay
(
10
);
gpio_set_value
(
td
->
reset_gpio
,
1
);
/* wait after releasing reset */
if
(
td
->
panel_config
->
sleep
.
hw_reset
)
msleep
(
td
->
panel_config
->
sleep
.
hw_reset
);
msleep
(
5
);
}
static
void
taal_probe_pdata
(
struct
taal_data
*
td
,
...
...
@@ -881,8 +766,7 @@ static int taal_probe(struct omap_dss_device *dssdev)
struct
backlight_properties
props
;
struct
taal_data
*
td
;
struct
backlight_device
*
bldev
=
NULL
;
int
r
,
i
;
const
char
*
panel_name
;
int
r
;
dev_dbg
(
&
dssdev
->
dev
,
"probe
\n
"
);
...
...
@@ -897,26 +781,13 @@ static int taal_probe(struct omap_dss_device *dssdev)
const
struct
nokia_dsi_panel_data
*
pdata
=
dssdev
->
data
;
taal_probe_pdata
(
td
,
pdata
);
panel_name
=
pdata
->
name
;
}
else
{
return
-
ENODEV
;
}
if
(
panel_name
==
NULL
)
return
-
EINVAL
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
panel_configs
);
i
++
)
{
if
(
strcmp
(
panel_name
,
panel_configs
[
i
].
name
)
==
0
)
{
td
->
panel_config
=
&
panel_configs
[
i
];
break
;
}
}
if
(
!
td
->
panel_config
)
return
-
EINVAL
;
dssdev
->
panel
.
timings
=
td
->
panel_config
->
timings
;
dssdev
->
panel
.
timings
.
x_res
=
864
;
dssdev
->
panel
.
timings
.
y_res
=
480
;
dssdev
->
panel
.
timings
.
pixel_clock
=
DIV_ROUND_UP
(
864
*
480
*
60
,
1000
);
dssdev
->
panel
.
dsi_pix_fmt
=
OMAP_DSS_DSI_FMT_RGB888
;
dssdev
->
caps
=
OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE
|
OMAP_DSS_DISPLAY_CAP_TEAR_ELIM
;
...
...
@@ -1049,6 +920,15 @@ static int taal_power_on(struct omap_dss_device *dssdev)
struct
taal_data
*
td
=
dev_get_drvdata
(
&
dssdev
->
dev
);
u8
id1
,
id2
,
id3
;
int
r
;
struct
omap_dss_dsi_config
dsi_config
=
{
.
mode
=
OMAP_DSS_DSI_CMD_MODE
,
.
pixel_format
=
OMAP_DSS_DSI_FMT_RGB888
,
.
timings
=
&
dssdev
->
panel
.
timings
,
.
hs_clk_min
=
150000000
,
.
hs_clk_max
=
300000000
,
.
lp_clk_min
=
7000000
,
.
lp_clk_max
=
10000000
,
};
r
=
omapdss_dsi_configure_pins
(
dssdev
,
&
td
->
pin_config
);
if
(
r
)
{
...
...
@@ -1056,14 +936,9 @@ static int taal_power_on(struct omap_dss_device *dssdev)
goto
err0
;
};
omapdss_dsi_set_size
(
dssdev
,
dssdev
->
panel
.
timings
.
x_res
,
dssdev
->
panel
.
timings
.
y_res
);
omapdss_dsi_set_pixel_format
(
dssdev
,
OMAP_DSS_DSI_FMT_RGB888
);
omapdss_dsi_set_operation_mode
(
dssdev
,
OMAP_DSS_DSI_CMD_MODE
);
r
=
omapdss_dsi_set_clocks
(
dssdev
,
216000000
,
10000000
);
r
=
omapdss_dsi_set_config
(
dssdev
,
&
dsi_config
);
if
(
r
)
{
dev_err
(
&
dssdev
->
dev
,
"failed to
set HS and LP clocks
\n
"
);
dev_err
(
&
dssdev
->
dev
,
"failed to
configure DSI
\n
"
);
goto
err0
;
}
...
...
@@ -1086,8 +961,7 @@ static int taal_power_on(struct omap_dss_device *dssdev)
goto
err
;
/* on early Taal revisions CABC is broken */
if
(
td
->
panel_config
->
type
==
PANEL_TAAL
&&
(
id2
==
0x00
||
id2
==
0xff
||
id2
==
0x81
))
if
(
id2
==
0x00
||
id2
==
0xff
||
id2
==
0x81
)
td
->
cabc_broken
=
true
;
r
=
taal_dcs_write_1
(
td
,
DCS_BRIGHTNESS
,
0xff
);
...
...
@@ -1104,10 +978,6 @@ static int taal_power_on(struct omap_dss_device *dssdev)
if
(
r
)
goto
err
;
r
=
taal_set_addr_mode
(
td
,
td
->
rotate
,
td
->
mirror
);
if
(
r
)
goto
err
;
if
(
!
td
->
cabc_broken
)
{
r
=
taal_dcs_write_1
(
td
,
DCS_WRITE_CABC
,
td
->
cabc_mode
);
if
(
r
)
...
...
@@ -1129,8 +999,8 @@ static int taal_power_on(struct omap_dss_device *dssdev)
td
->
enabled
=
1
;
if
(
!
td
->
intro_printed
)
{
dev_info
(
&
dssdev
->
dev
,
"
%s
panel revision %02x.%02x.%02x
\n
"
,
td
->
panel_config
->
name
,
id1
,
id2
,
id3
);
dev_info
(
&
dssdev
->
dev
,
"panel revision %02x.%02x.%02x
\n
"
,
id1
,
id2
,
id3
);
if
(
td
->
cabc_broken
)
dev_info
(
&
dssdev
->
dev
,
"old Taal version, CABC disabled
\n
"
);
...
...
@@ -1311,8 +1181,8 @@ static int taal_update(struct omap_dss_device *dssdev,
/* XXX no need to send this every frame, but dsi break if not done */
r
=
taal_set_update_window
(
td
,
0
,
0
,
td
->
panel_config
->
timings
.
x_res
,
td
->
panel_config
->
timings
.
y_res
);
dssdev
->
panel
.
timings
.
x_res
,
dssdev
->
panel
.
timings
.
y_res
);
if
(
r
)
goto
err
;
...
...
@@ -1365,8 +1235,8 @@ static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable)
if
(
!
gpio_is_valid
(
td
->
ext_te_gpio
))
omapdss_dsi_enable_te
(
dssdev
,
enable
);
if
(
td
->
panel_config
->
sleep
.
enable_te
)
msleep
(
td
->
panel_config
->
sleep
.
enable_te
);
/* possible panel bug */
msleep
(
100
);
return
r
;
}
...
...
@@ -1419,112 +1289,6 @@ static int taal_get_te(struct omap_dss_device *dssdev)
return
r
;
}
static
int
taal_rotate
(
struct
omap_dss_device
*
dssdev
,
u8
rotate
)
{
struct
taal_data
*
td
=
dev_get_drvdata
(
&
dssdev
->
dev
);
u16
dw
,
dh
;
int
r
;
dev_dbg
(
&
dssdev
->
dev
,
"rotate %d
\n
"
,
rotate
);
mutex_lock
(
&
td
->
lock
);
if
(
td
->
rotate
==
rotate
)
goto
end
;
dsi_bus_lock
(
dssdev
);
if
(
td
->
enabled
)
{
r
=
taal_wake_up
(
dssdev
);
if
(
r
)
goto
err
;
r
=
taal_set_addr_mode
(
td
,
rotate
,
td
->
mirror
);
if
(
r
)
goto
err
;
}
if
(
rotate
==
0
||
rotate
==
2
)
{
dw
=
dssdev
->
panel
.
timings
.
x_res
;
dh
=
dssdev
->
panel
.
timings
.
y_res
;
}
else
{
dw
=
dssdev
->
panel
.
timings
.
y_res
;
dh
=
dssdev
->
panel
.
timings
.
x_res
;
}
omapdss_dsi_set_size
(
dssdev
,
dw
,
dh
);
td
->
rotate
=
rotate
;
dsi_bus_unlock
(
dssdev
);
end:
mutex_unlock
(
&
td
->
lock
);
return
0
;
err:
dsi_bus_unlock
(
dssdev
);
mutex_unlock
(
&
td
->
lock
);
return
r
;
}
static
u8
taal_get_rotate
(
struct
omap_dss_device
*
dssdev
)
{
struct
taal_data
*
td
=
dev_get_drvdata
(
&
dssdev
->
dev
);
int
r
;
mutex_lock
(
&
td
->
lock
);
r
=
td
->
rotate
;
mutex_unlock
(
&
td
->
lock
);
return
r
;
}
static
int
taal_mirror
(
struct
omap_dss_device
*
dssdev
,
bool
enable
)
{
struct
taal_data
*
td
=
dev_get_drvdata
(
&
dssdev
->
dev
);
int
r
;
dev_dbg
(
&
dssdev
->
dev
,
"mirror %d
\n
"
,
enable
);
mutex_lock
(
&
td
->
lock
);
if
(
td
->
mirror
==
enable
)
goto
end
;
dsi_bus_lock
(
dssdev
);
if
(
td
->
enabled
)
{
r
=
taal_wake_up
(
dssdev
);
if
(
r
)
goto
err
;
r
=
taal_set_addr_mode
(
td
,
td
->
rotate
,
enable
);
if
(
r
)
goto
err
;
}
td
->
mirror
=
enable
;
dsi_bus_unlock
(
dssdev
);
end:
mutex_unlock
(
&
td
->
lock
);
return
0
;
err:
dsi_bus_unlock
(
dssdev
);
mutex_unlock
(
&
td
->
lock
);
return
r
;
}
static
bool
taal_get_mirror
(
struct
omap_dss_device
*
dssdev
)
{
struct
taal_data
*
td
=
dev_get_drvdata
(
&
dssdev
->
dev
);
int
r
;
mutex_lock
(
&
td
->
lock
);
r
=
td
->
mirror
;
mutex_unlock
(
&
td
->
lock
);
return
r
;
}
static
int
taal_run_test
(
struct
omap_dss_device
*
dssdev
,
int
test_num
)
{
struct
taal_data
*
td
=
dev_get_drvdata
(
&
dssdev
->
dev
);
...
...
@@ -1758,10 +1522,6 @@ static struct omap_dss_driver taal_driver = {
.
enable_te
=
taal_enable_te
,
.
get_te
=
taal_get_te
,
.
set_rotate
=
taal_rotate
,
.
get_rotate
=
taal_get_rotate
,
.
set_mirror
=
taal_mirror
,
.
get_mirror
=
taal_get_mirror
,
.
run_test
=
taal_run_test
,
.
memory_read
=
taal_memory_read
,
...
...
drivers/video/omap2/dss/apply.c
View file @
3d62fe5b
...
...
@@ -435,20 +435,27 @@ static inline struct omap_dss_device *dss_mgr_get_device(struct omap_overlay_man
static
int
dss_mgr_wait_for_vsync
(
struct
omap_overlay_manager
*
mgr
)
{
unsigned
long
timeout
=
msecs_to_jiffies
(
500
);
struct
omap_dss_device
*
dssdev
=
mgr
->
get_device
(
mgr
);
u32
irq
;
int
r
;
if
(
mgr
->
output
==
NULL
)
return
-
ENODEV
;
r
=
dispc_runtime_get
();
if
(
r
)
return
r
;
if
(
dssdev
->
type
==
OMAP_DISPLAY_TYPE_VENC
)
switch
(
mgr
->
output
->
id
)
{
case
OMAP_DSS_OUTPUT_VENC
:
irq
=
DISPC_IRQ_EVSYNC_ODD
;
else
if
(
dssdev
->
type
==
OMAP_DISPLAY_TYPE_HDMI
)
break
;
case
OMAP_DSS_OUTPUT_HDMI
:
irq
=
DISPC_IRQ_EVSYNC_EVEN
;
else
break
;
default:
irq
=
dispc_mgr_get_vsync_irq
(
mgr
->
id
);
break
;
}
r
=
omap_dispc_wait_for_irq_interruptible_timeout
(
irq
,
timeout
);
...
...
drivers/video/omap2/dss/core.c
View file @
3d62fe5b
...
...
@@ -181,10 +181,7 @@ int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *))
d
=
debugfs_create_file
(
name
,
S_IRUGO
,
dss_debugfs_dir
,
write
,
&
dss_debug_fops
);
if
(
IS_ERR
(
d
))
return
PTR_ERR
(
d
);
return
0
;
return
PTR_RET
(
d
);
}
#else
/* CONFIG_OMAP2_DSS_DEBUGFS */
static
inline
int
dss_initialize_debugfs
(
void
)
...
...
drivers/video/omap2/dss/dispc.c
View file @
3d62fe5b
...
...
@@ -69,6 +69,8 @@ struct dispc_features {
u8
mgr_height_start
;
u16
mgr_width_max
;
u16
mgr_height_max
;
unsigned
long
max_lcd_pclk
;
unsigned
long
max_tv_pclk
;
int
(
*
calc_scaling
)
(
unsigned
long
pclk
,
unsigned
long
lclk
,
const
struct
omap_video_timings
*
mgr_timings
,
u16
width
,
u16
height
,
u16
out_width
,
u16
out_height
,
...
...
@@ -85,6 +87,9 @@ struct dispc_features {
/* no DISPC_IRQ_FRAMEDONETV on this SoC */
bool
no_framedone_tv
:
1
;
/* revert to the OMAP4 mechanism of DISPC Smart Standby operation */
bool
mstandby_workaround
:
1
;
};
#define DISPC_MAX_NR_FIFOS 5
...
...
@@ -97,6 +102,8 @@ static struct {
int
irq
;
unsigned
long
core_clk_rate
;
u32
fifo_size
[
DISPC_MAX_NR_FIFOS
];
/* maps which plane is using a fifo. fifo-id -> plane-id */
int
fifo_assignment
[
DISPC_MAX_NR_FIFOS
];
...
...
@@ -1584,6 +1591,7 @@ static void dispc_ovl_set_scaling(enum omap_plane plane,
}
static
void
dispc_ovl_set_rotation_attrs
(
enum
omap_plane
plane
,
u8
rotation
,
enum
omap_dss_rotation_type
rotation_type
,
bool
mirroring
,
enum
omap_color_mode
color_mode
)
{
bool
row_repeat
=
false
;
...
...
@@ -1634,6 +1642,15 @@ static void dispc_ovl_set_rotation_attrs(enum omap_plane plane, u8 rotation,
if
(
dss_has_feature
(
FEAT_ROWREPEATENABLE
))
REG_FLD_MOD
(
DISPC_OVL_ATTRIBUTES
(
plane
),
row_repeat
?
1
:
0
,
18
,
18
);
if
(
color_mode
==
OMAP_DSS_COLOR_NV12
)
{
bool
doublestride
=
(
rotation_type
==
OMAP_DSS_ROT_TILER
)
&&
(
rotation
==
OMAP_DSS_ROT_0
||
rotation
==
OMAP_DSS_ROT_180
);
/* DOUBLESTRIDE */
REG_FLD_MOD
(
DISPC_OVL_ATTRIBUTES
(
plane
),
doublestride
,
22
,
22
);
}
}
static
int
color_mode_to_bpp
(
enum
omap_color_mode
color_mode
)
...
...
@@ -2512,7 +2529,8 @@ static int dispc_ovl_setup_common(enum omap_plane plane,
dispc_ovl_set_vid_color_conv
(
plane
,
cconv
);
}
dispc_ovl_set_rotation_attrs
(
plane
,
rotation
,
mirror
,
color_mode
);
dispc_ovl_set_rotation_attrs
(
plane
,
rotation
,
rotation_type
,
mirror
,
color_mode
);
dispc_ovl_set_zorder
(
plane
,
caps
,
zorder
);
dispc_ovl_set_pre_mult_alpha
(
plane
,
caps
,
pre_mult_alpha
);
...
...
@@ -2823,6 +2841,15 @@ static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp,
return
true
;
}
static
bool
_dispc_mgr_pclk_ok
(
enum
omap_channel
channel
,
unsigned
long
pclk
)
{
if
(
dss_mgr_is_lcd
(
channel
))
return
pclk
<=
dispc
.
feat
->
max_lcd_pclk
?
true
:
false
;
else
return
pclk
<=
dispc
.
feat
->
max_tv_pclk
?
true
:
false
;
}
bool
dispc_mgr_timings_ok
(
enum
omap_channel
channel
,
const
struct
omap_video_timings
*
timings
)
{
...
...
@@ -2830,11 +2857,13 @@ bool dispc_mgr_timings_ok(enum omap_channel channel,
timings_ok
=
_dispc_mgr_size_ok
(
timings
->
x_res
,
timings
->
y_res
);
if
(
dss_mgr_is_lcd
(
channel
))
timings_ok
=
timings_ok
&&
_dispc_lcd_timings_ok
(
timings
->
hsw
,
timings
->
hfp
,
timings
->
hbp
,
timings
->
vsw
,
timings
->
vfp
,
timings
->
vbp
);
timings_ok
&=
_dispc_mgr_pclk_ok
(
channel
,
timings
->
pixel_clock
*
1000
);
if
(
dss_mgr_is_lcd
(
channel
))
{
timings_ok
&=
_dispc_lcd_timings_ok
(
timings
->
hsw
,
timings
->
hfp
,
timings
->
hbp
,
timings
->
vsw
,
timings
->
vfp
,
timings
->
vbp
);
}
return
timings_ok
;
}
...
...
@@ -2951,6 +2980,10 @@ static void dispc_mgr_set_lcd_divisor(enum omap_channel channel, u16 lck_div,
dispc_write_reg
(
DISPC_DIVISORo
(
channel
),
FLD_VAL
(
lck_div
,
23
,
16
)
|
FLD_VAL
(
pck_div
,
7
,
0
));
if
(
dss_has_feature
(
FEAT_CORE_CLK_DIV
)
==
false
&&
channel
==
OMAP_DSS_CHANNEL_LCD
)
dispc
.
core_clk_rate
=
dispc_fclk_rate
()
/
lck_div
;
}
static
void
dispc_mgr_get_lcd_divisor
(
enum
omap_channel
channel
,
int
*
lck_div
,
...
...
@@ -3056,15 +3089,7 @@ unsigned long dispc_mgr_pclk_rate(enum omap_channel channel)
unsigned
long
dispc_core_clk_rate
(
void
)
{
int
lcd
;
unsigned
long
fclk
=
dispc_fclk_rate
();
if
(
dss_has_feature
(
FEAT_CORE_CLK_DIV
))
lcd
=
REG_GET
(
DISPC_DIVISOR
,
23
,
16
);
else
lcd
=
REG_GET
(
DISPC_DIVISORo
(
OMAP_DSS_CHANNEL_LCD
),
23
,
16
);
return
fclk
/
lcd
;
return
dispc
.
core_clk_rate
;
}
static
unsigned
long
dispc_plane_pclk_rate
(
enum
omap_plane
plane
)
...
...
@@ -3313,67 +3338,79 @@ static void dispc_dump_regs(struct seq_file *s)
#undef DUMPREG
}
/*
with fck as input clock rate, find dispc dividers that produce req_pck
*/
void
dispc_find_clk_divs
(
unsigned
long
req_pck
,
unsigned
long
fck
,
/*
calculate clock rates using dividers in cinfo
*/
int
dispc_calc_clock_rates
(
unsigned
long
dispc_fclk_rate
,
struct
dispc_clock_info
*
cinfo
)
{
u16
pcd_min
,
pcd_max
;
unsigned
long
best_pck
;
u16
best_ld
,
cur_ld
;
u16
best_pd
,
cur_pd
;
if
(
cinfo
->
lck_div
>
255
||
cinfo
->
lck_div
==
0
)
return
-
EINVAL
;
if
(
cinfo
->
pck_div
<
1
||
cinfo
->
pck_div
>
255
)
return
-
EINVAL
;
pcd_min
=
dss_feat_get_param_min
(
FEAT_PARAM_DSS_PCD
)
;
pcd_max
=
dss_feat_get_param_max
(
FEAT_PARAM_DSS_PCD
)
;
cinfo
->
lck
=
dispc_fclk_rate
/
cinfo
->
lck_div
;
cinfo
->
pck
=
cinfo
->
lck
/
cinfo
->
pck_div
;
best_pck
=
0
;
best_ld
=
0
;
best_pd
=
0
;
return
0
;
}
for
(
cur_ld
=
1
;
cur_ld
<=
255
;
++
cur_ld
)
{
unsigned
long
lck
=
fck
/
cur_ld
;
bool
dispc_div_calc
(
unsigned
long
dispc
,
unsigned
long
pck_min
,
unsigned
long
pck_max
,
dispc_div_calc_func
func
,
void
*
data
)
{
int
lckd
,
lckd_start
,
lckd_stop
;
int
pckd
,
pckd_start
,
pckd_stop
;
unsigned
long
pck
,
lck
;
unsigned
long
lck_max
;
unsigned
long
pckd_hw_min
,
pckd_hw_max
;
unsigned
min_fck_per_pck
;
unsigned
long
fck
;
for
(
cur_pd
=
pcd_min
;
cur_pd
<=
pcd_max
;
++
cur_pd
)
{
unsigned
long
pck
=
lck
/
cur_pd
;
long
old_delta
=
abs
(
best_pck
-
req_pck
);
long
new_delta
=
abs
(
pck
-
req_pck
);
#ifdef CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK
min_fck_per_pck
=
CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK
;
#else
min_fck_per_pck
=
0
;
#endif
if
(
best_pck
==
0
||
new_delta
<
old_delta
)
{
best_pck
=
pck
;
best_ld
=
cur_ld
;
best_pd
=
cur_pd
;
pckd_hw_min
=
dss_feat_get_param_min
(
FEAT_PARAM_DSS_PCD
);
pckd_hw_max
=
dss_feat_get_param_max
(
FEAT_PARAM_DSS_PCD
);
if
(
pck
==
req_pck
)
goto
found
;
}
lck_max
=
dss_feat_get_param_max
(
FEAT_PARAM_DSS_FCK
);
if
(
pck
<
req_pck
)
break
;
}
pck_min
=
pck_min
?
pck_min
:
1
;
pck_max
=
pck_max
?
pck_max
:
ULONG_MAX
;
if
(
lck
/
pcd_min
<
req_pck
)
break
;
}
lckd_start
=
max
(
DIV_ROUND_UP
(
dispc
,
lck_max
),
1ul
);
lckd_stop
=
min
(
dispc
/
pck_min
,
255ul
);
found:
cinfo
->
lck_div
=
best_ld
;
cinfo
->
pck_div
=
best_pd
;
cinfo
->
lck
=
fck
/
cinfo
->
lck_div
;
cinfo
->
pck
=
cinfo
->
lck
/
cinfo
->
pck_div
;
}
for
(
lckd
=
lckd_start
;
lckd
<=
lckd_stop
;
++
lckd
)
{
lck
=
dispc
/
lckd
;
/* calculate clock rates using dividers in cinfo */
int
dispc_calc_clock_rates
(
unsigned
long
dispc_fclk_rate
,
struct
dispc_clock_info
*
cinfo
)
{
if
(
cinfo
->
lck_div
>
255
||
cinfo
->
lck_div
==
0
)
return
-
EINVAL
;
if
(
cinfo
->
pck_div
<
1
||
cinfo
->
pck_div
>
255
)
return
-
EINVAL
;
pckd_start
=
max
(
DIV_ROUND_UP
(
lck
,
pck_max
),
pckd_hw_min
);
pckd_stop
=
min
(
lck
/
pck_min
,
pckd_hw_max
);
cinfo
->
lck
=
dispc_fclk_rate
/
cinfo
->
lck_div
;
cinfo
->
pck
=
cinfo
->
lck
/
cinfo
->
pck_div
;
for
(
pckd
=
pckd_start
;
pckd
<=
pckd_stop
;
++
pckd
)
{
pck
=
lck
/
pckd
;
return
0
;
/*
* For OMAP2/3 the DISPC fclk is the same as LCD's logic
* clock, which means we're configuring DISPC fclk here
* also. Thus we need to use the calculated lck. For
* OMAP4+ the DISPC fclk is a separate clock.
*/
if
(
dss_has_feature
(
FEAT_CORE_CLK_DIV
))
fck
=
dispc_core_clk_rate
();
else
fck
=
lck
;
if
(
fck
<
pck
*
min_fck_per_pck
)
continue
;
if
(
func
(
lckd
,
pckd
,
lck
,
pck
,
data
))
return
true
;
}
}
return
false
;
}
void
dispc_mgr_set_clock_div
(
enum
omap_channel
channel
,
...
...
@@ -3451,6 +3488,8 @@ static void _omap_dispc_initial_config(void)
l
=
FLD_MOD
(
l
,
1
,
0
,
0
);
l
=
FLD_MOD
(
l
,
1
,
23
,
16
);
dispc_write_reg
(
DISPC_DIVISOR
,
l
);
dispc
.
core_clk_rate
=
dispc_fclk_rate
();
}
/* FUNCGATED */
...
...
@@ -3466,6 +3505,9 @@ static void _omap_dispc_initial_config(void)
dispc_configure_burst_sizes
();
dispc_ovl_enable_zorder_planes
();
if
(
dispc
.
feat
->
mstandby_workaround
)
REG_FLD_MOD
(
DISPC_MSTANDBY_CTRL
,
1
,
0
,
0
);
}
static
const
struct
dispc_features
omap24xx_dispc_feats
__initconst
=
{
...
...
@@ -3479,6 +3521,7 @@ static const struct dispc_features omap24xx_dispc_feats __initconst = {
.
mgr_height_start
=
26
,
.
mgr_width_max
=
2048
,
.
mgr_height_max
=
2048
,
.
max_lcd_pclk
=
66500000
,
.
calc_scaling
=
dispc_ovl_calc_scaling_24xx
,
.
calc_core_clk
=
calc_core_clk_24xx
,
.
num_fifos
=
3
,
...
...
@@ -3496,6 +3539,8 @@ static const struct dispc_features omap34xx_rev1_0_dispc_feats __initconst = {
.
mgr_height_start
=
26
,
.
mgr_width_max
=
2048
,
.
mgr_height_max
=
2048
,
.
max_lcd_pclk
=
173000000
,
.
max_tv_pclk
=
59000000
,
.
calc_scaling
=
dispc_ovl_calc_scaling_34xx
,
.
calc_core_clk
=
calc_core_clk_34xx
,
.
num_fifos
=
3
,
...
...
@@ -3513,6 +3558,8 @@ static const struct dispc_features omap34xx_rev3_0_dispc_feats __initconst = {
.
mgr_height_start
=
26
,
.
mgr_width_max
=
2048
,
.
mgr_height_max
=
2048
,
.
max_lcd_pclk
=
173000000
,
.
max_tv_pclk
=
59000000
,
.
calc_scaling
=
dispc_ovl_calc_scaling_34xx
,
.
calc_core_clk
=
calc_core_clk_34xx
,
.
num_fifos
=
3
,
...
...
@@ -3530,6 +3577,8 @@ static const struct dispc_features omap44xx_dispc_feats __initconst = {
.
mgr_height_start
=
26
,
.
mgr_width_max
=
2048
,
.
mgr_height_max
=
2048
,
.
max_lcd_pclk
=
170000000
,
.
max_tv_pclk
=
185625000
,
.
calc_scaling
=
dispc_ovl_calc_scaling_44xx
,
.
calc_core_clk
=
calc_core_clk_44xx
,
.
num_fifos
=
5
,
...
...
@@ -3547,10 +3596,13 @@ static const struct dispc_features omap54xx_dispc_feats __initconst = {
.
mgr_height_start
=
27
,
.
mgr_width_max
=
4096
,
.
mgr_height_max
=
4096
,
.
max_lcd_pclk
=
170000000
,
.
max_tv_pclk
=
186000000
,
.
calc_scaling
=
dispc_ovl_calc_scaling_44xx
,
.
calc_core_clk
=
calc_core_clk_44xx
,
.
num_fifos
=
5
,
.
gfx_fifo_workaround
=
true
,
.
mstandby_workaround
=
true
,
};
static
int
__init
dispc_init_features
(
struct
platform_device
*
pdev
)
...
...
drivers/video/omap2/dss/dispc.h
View file @
3d62fe5b
...
...
@@ -39,6 +39,7 @@
#define DISPC_GLOBAL_BUFFER 0x0800
#define DISPC_CONTROL3 0x0848
#define DISPC_CONFIG3 0x084C
#define DISPC_MSTANDBY_CTRL 0x0858
/* DISPC overlay registers */
#define DISPC_OVL_BA0(n) (DISPC_OVL_BASE(n) + \
...
...
drivers/video/omap2/dss/dpi.c
View file @
3d62fe5b
...
...
@@ -63,15 +63,29 @@ static struct platform_device *dpi_get_dsidev(enum omap_channel channel)
case
OMAPDSS_VER_OMAP3630
:
case
OMAPDSS_VER_AM35xx
:
return
NULL
;
default:
break
;
}
switch
(
channel
)
{
case
OMAP_DSS_CHANNEL_LCD
:
return
dsi_get_dsidev_from_id
(
0
);
case
OMAP_DSS_CHANNEL_LCD2
:
return
dsi_get_dsidev_from_id
(
1
);
case
OMAPDSS_VER_OMAP4430_ES1
:
case
OMAPDSS_VER_OMAP4430_ES2
:
case
OMAPDSS_VER_OMAP4
:
switch
(
channel
)
{
case
OMAP_DSS_CHANNEL_LCD
:
return
dsi_get_dsidev_from_id
(
0
);
case
OMAP_DSS_CHANNEL_LCD2
:
return
dsi_get_dsidev_from_id
(
1
);
default:
return
NULL
;
}
case
OMAPDSS_VER_OMAP5
:
switch
(
channel
)
{
case
OMAP_DSS_CHANNEL_LCD
:
return
dsi_get_dsidev_from_id
(
0
);
case
OMAP_DSS_CHANNEL_LCD3
:
return
dsi_get_dsidev_from_id
(
1
);
default:
return
NULL
;
}
default:
return
NULL
;
}
...
...
@@ -91,75 +105,211 @@ static enum omap_dss_clk_source dpi_get_alt_clk_src(enum omap_channel channel)
}
}
static
int
dpi_set_dsi_clk
(
struct
omap_dss_device
*
dssdev
,
struct
dpi_clk_calc_ctx
{
struct
platform_device
*
dsidev
;
/* inputs */
unsigned
long
pck_min
,
pck_max
;
/* outputs */
struct
dsi_clock_info
dsi_cinfo
;
struct
dss_clock_info
dss_cinfo
;
struct
dispc_clock_info
dispc_cinfo
;
};
static
bool
dpi_calc_dispc_cb
(
int
lckd
,
int
pckd
,
unsigned
long
lck
,
unsigned
long
pck
,
void
*
data
)
{
struct
dpi_clk_calc_ctx
*
ctx
=
data
;
/*
* Odd dividers give us uneven duty cycle, causing problem when level
* shifted. So skip all odd dividers when the pixel clock is on the
* higher side.
*/
if
(
ctx
->
pck_min
>=
1000000
)
{
if
(
lckd
>
1
&&
lckd
%
2
!=
0
)
return
false
;
if
(
pckd
>
1
&&
pckd
%
2
!=
0
)
return
false
;
}
ctx
->
dispc_cinfo
.
lck_div
=
lckd
;
ctx
->
dispc_cinfo
.
pck_div
=
pckd
;
ctx
->
dispc_cinfo
.
lck
=
lck
;
ctx
->
dispc_cinfo
.
pck
=
pck
;
return
true
;
}
static
bool
dpi_calc_hsdiv_cb
(
int
regm_dispc
,
unsigned
long
dispc
,
void
*
data
)
{
struct
dpi_clk_calc_ctx
*
ctx
=
data
;
/*
* Odd dividers give us uneven duty cycle, causing problem when level
* shifted. So skip all odd dividers when the pixel clock is on the
* higher side.
*/
if
(
regm_dispc
>
1
&&
regm_dispc
%
2
!=
0
&&
ctx
->
pck_min
>=
1000000
)
return
false
;
ctx
->
dsi_cinfo
.
regm_dispc
=
regm_dispc
;
ctx
->
dsi_cinfo
.
dsi_pll_hsdiv_dispc_clk
=
dispc
;
return
dispc_div_calc
(
dispc
,
ctx
->
pck_min
,
ctx
->
pck_max
,
dpi_calc_dispc_cb
,
ctx
);
}
static
bool
dpi_calc_pll_cb
(
int
regn
,
int
regm
,
unsigned
long
fint
,
unsigned
long
pll
,
void
*
data
)
{
struct
dpi_clk_calc_ctx
*
ctx
=
data
;
ctx
->
dsi_cinfo
.
regn
=
regn
;
ctx
->
dsi_cinfo
.
regm
=
regm
;
ctx
->
dsi_cinfo
.
fint
=
fint
;
ctx
->
dsi_cinfo
.
clkin4ddr
=
pll
;
return
dsi_hsdiv_calc
(
ctx
->
dsidev
,
pll
,
ctx
->
pck_min
,
dpi_calc_hsdiv_cb
,
ctx
);
}
static
bool
dpi_calc_dss_cb
(
int
fckd
,
unsigned
long
fck
,
void
*
data
)
{
struct
dpi_clk_calc_ctx
*
ctx
=
data
;
ctx
->
dss_cinfo
.
fck
=
fck
;
ctx
->
dss_cinfo
.
fck_div
=
fckd
;
return
dispc_div_calc
(
fck
,
ctx
->
pck_min
,
ctx
->
pck_max
,
dpi_calc_dispc_cb
,
ctx
);
}
static
bool
dpi_dsi_clk_calc
(
unsigned
long
pck
,
struct
dpi_clk_calc_ctx
*
ctx
)
{
unsigned
long
clkin
;
unsigned
long
pll_min
,
pll_max
;
clkin
=
dsi_get_pll_clkin
(
dpi
.
dsidev
);
memset
(
ctx
,
0
,
sizeof
(
*
ctx
));
ctx
->
dsidev
=
dpi
.
dsidev
;
ctx
->
pck_min
=
pck
-
1000
;
ctx
->
pck_max
=
pck
+
1000
;
ctx
->
dsi_cinfo
.
clkin
=
clkin
;
pll_min
=
0
;
pll_max
=
0
;
return
dsi_pll_calc
(
dpi
.
dsidev
,
clkin
,
pll_min
,
pll_max
,
dpi_calc_pll_cb
,
ctx
);
}
static
bool
dpi_dss_clk_calc
(
unsigned
long
pck
,
struct
dpi_clk_calc_ctx
*
ctx
)
{
int
i
;
/*
* DSS fck gives us very few possibilities, so finding a good pixel
* clock may not be possible. We try multiple times to find the clock,
* each time widening the pixel clock range we look for, up to
* +/- ~15MHz.
*/
for
(
i
=
0
;
i
<
25
;
++
i
)
{
bool
ok
;
memset
(
ctx
,
0
,
sizeof
(
*
ctx
));
if
(
pck
>
1000
*
i
*
i
*
i
)
ctx
->
pck_min
=
max
(
pck
-
1000
*
i
*
i
*
i
,
0lu
);
else
ctx
->
pck_min
=
0
;
ctx
->
pck_max
=
pck
+
1000
*
i
*
i
*
i
;
ok
=
dss_div_calc
(
ctx
->
pck_min
,
dpi_calc_dss_cb
,
ctx
);
if
(
ok
)
return
ok
;
}
return
false
;
}
static
int
dpi_set_dsi_clk
(
enum
omap_channel
channel
,
unsigned
long
pck_req
,
unsigned
long
*
fck
,
int
*
lck_div
,
int
*
pck_div
)
{
struct
omap_overlay_manager
*
mgr
=
dssdev
->
output
->
manager
;
struct
dsi_clock_info
dsi_cinfo
;
struct
dispc_clock_info
dispc_cinfo
;
struct
dpi_clk_calc_ctx
ctx
;
int
r
;
bool
ok
;
r
=
dsi_pll_calc_clock_div_pck
(
dpi
.
dsidev
,
pck_req
,
&
dsi_cinfo
,
&
dispc_cinfo
);
if
(
r
)
return
r
;
ok
=
dpi_dsi_clk_calc
(
pck_req
,
&
ctx
);
if
(
!
ok
)
return
-
EINVAL
;
r
=
dsi_pll_set_clock_div
(
dpi
.
dsidev
,
&
dsi_cinfo
);
r
=
dsi_pll_set_clock_div
(
dpi
.
dsidev
,
&
ctx
.
dsi_cinfo
);
if
(
r
)
return
r
;
dss_select_lcd_clk_source
(
mgr
->
id
,
dpi_get_alt_clk_src
(
mgr
->
id
));
dss_select_lcd_clk_source
(
channel
,
dpi_get_alt_clk_src
(
channel
));
dpi
.
mgr_config
.
clock_info
=
dispc_cinfo
;
dpi
.
mgr_config
.
clock_info
=
ctx
.
dispc_cinfo
;
*
fck
=
dsi_cinfo
.
dsi_pll_hsdiv_dispc_clk
;
*
lck_div
=
dispc_cinfo
.
lck_div
;
*
pck_div
=
dispc_cinfo
.
pck_div
;
*
fck
=
ctx
.
dsi_cinfo
.
dsi_pll_hsdiv_dispc_clk
;
*
lck_div
=
ctx
.
dispc_cinfo
.
lck_div
;
*
pck_div
=
ctx
.
dispc_cinfo
.
pck_div
;
return
0
;
}
static
int
dpi_set_dispc_clk
(
struct
omap_dss_device
*
dssdev
,
unsigned
long
pck_req
,
unsigned
long
*
fck
,
int
*
lck_div
,
int
*
pck_div
)
static
int
dpi_set_dispc_clk
(
unsigned
long
pck_req
,
unsigned
long
*
fck
,
int
*
lck_div
,
int
*
pck_div
)
{
struct
dss_clock_info
dss_cinfo
;
struct
dispc_clock_info
dispc_cinfo
;
struct
dpi_clk_calc_ctx
ctx
;
int
r
;
bool
ok
;
r
=
dss_calc_clock_div
(
pck_req
,
&
dss_cinfo
,
&
dispc_cinfo
);
if
(
r
)
return
r
;
ok
=
dpi_dss_clk_calc
(
pck_req
,
&
ctx
);
if
(
!
ok
)
return
-
EINVAL
;
r
=
dss_set_clock_div
(
&
dss_cinfo
);
r
=
dss_set_clock_div
(
&
ctx
.
dss_cinfo
);
if
(
r
)
return
r
;
dpi
.
mgr_config
.
clock_info
=
dispc_cinfo
;
dpi
.
mgr_config
.
clock_info
=
ctx
.
dispc_cinfo
;
*
fck
=
dss_cinfo
.
fck
;
*
lck_div
=
dispc_cinfo
.
lck_div
;
*
pck_div
=
dispc_cinfo
.
pck_div
;
*
fck
=
ctx
.
dss_cinfo
.
fck
;
*
lck_div
=
ctx
.
dispc_cinfo
.
lck_div
;
*
pck_div
=
ctx
.
dispc_cinfo
.
pck_div
;
return
0
;
}
static
int
dpi_set_mode
(
struct
omap_
dss_device
*
dssdev
)
static
int
dpi_set_mode
(
struct
omap_
overlay_manager
*
mgr
)
{
struct
omap_video_timings
*
t
=
&
dpi
.
timings
;
struct
omap_overlay_manager
*
mgr
=
dssdev
->
output
->
manager
;
int
lck_div
=
0
,
pck_div
=
0
;
unsigned
long
fck
=
0
;
unsigned
long
pck
;
int
r
=
0
;
if
(
dpi
.
dsidev
)
r
=
dpi_set_dsi_clk
(
dssdev
,
t
->
pixel_clock
*
1000
,
&
fck
,
r
=
dpi_set_dsi_clk
(
mgr
->
id
,
t
->
pixel_clock
*
1000
,
&
fck
,
&
lck_div
,
&
pck_div
);
else
r
=
dpi_set_dispc_clk
(
dssdev
,
t
->
pixel_clock
*
1000
,
&
fck
,
r
=
dpi_set_dispc_clk
(
t
->
pixel_clock
*
1000
,
&
fck
,
&
lck_div
,
&
pck_div
);
if
(
r
)
return
r
;
...
...
@@ -179,10 +329,8 @@ static int dpi_set_mode(struct omap_dss_device *dssdev)
return
0
;
}
static
void
dpi_config_lcd_manager
(
struct
omap_
dss_device
*
dssdev
)
static
void
dpi_config_lcd_manager
(
struct
omap_
overlay_manager
*
mgr
)
{
struct
omap_overlay_manager
*
mgr
=
dssdev
->
output
->
manager
;
dpi
.
mgr_config
.
io_pad_mode
=
DSS_IO_PAD_MODE_BYPASS
;
dpi
.
mgr_config
.
stallmode
=
false
;
...
...
@@ -197,7 +345,7 @@ static void dpi_config_lcd_manager(struct omap_dss_device *dssdev)
int
omapdss_dpi_display_enable
(
struct
omap_dss_device
*
dssdev
)
{
struct
omap_dss_output
*
out
=
dssdev
->
output
;
struct
omap_dss_output
*
out
=
&
dpi
.
output
;
int
r
;
mutex_lock
(
&
dpi
.
lock
);
...
...
@@ -230,7 +378,7 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
if
(
r
)
goto
err_get_dispc
;
r
=
dss_dpi_select_source
(
dssdev
->
channel
);
r
=
dss_dpi_select_source
(
out
->
manager
->
id
);
if
(
r
)
goto
err_src_sel
;
...
...
@@ -244,11 +392,11 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
goto
err_dsi_pll_init
;
}
r
=
dpi_set_mode
(
dssdev
);
r
=
dpi_set_mode
(
out
->
manager
);
if
(
r
)
goto
err_set_mode
;
dpi_config_lcd_manager
(
dssdev
);
dpi_config_lcd_manager
(
out
->
manager
);
mdelay
(
2
);
...
...
@@ -285,7 +433,7 @@ EXPORT_SYMBOL(omapdss_dpi_display_enable);
void
omapdss_dpi_display_disable
(
struct
omap_dss_device
*
dssdev
)
{
struct
omap_overlay_manager
*
mgr
=
d
ssdev
->
output
->
manager
;
struct
omap_overlay_manager
*
mgr
=
d
pi
.
output
.
manager
;
mutex_lock
(
&
dpi
.
lock
);
...
...
@@ -324,12 +472,12 @@ EXPORT_SYMBOL(omapdss_dpi_set_timings);
int
dpi_check_timings
(
struct
omap_dss_device
*
dssdev
,
struct
omap_video_timings
*
timings
)
{
int
r
;
struct
omap_overlay_manager
*
mgr
=
dssdev
->
output
->
manager
;
struct
omap_overlay_manager
*
mgr
=
dpi
.
output
.
manager
;
int
lck_div
,
pck_div
;
unsigned
long
fck
;
unsigned
long
pck
;
struct
dispc_clock_info
dispc_cinfo
;
struct
dpi_clk_calc_ctx
ctx
;
bool
ok
;
if
(
mgr
&&
!
dispc_mgr_timings_ok
(
mgr
->
id
,
timings
))
return
-
EINVAL
;
...
...
@@ -338,28 +486,21 @@ int dpi_check_timings(struct omap_dss_device *dssdev,
return
-
EINVAL
;
if
(
dpi
.
dsidev
)
{
struct
dsi_clock_info
dsi_cinfo
;
r
=
dsi_pll_calc_clock_div_pck
(
dpi
.
dsidev
,
timings
->
pixel_clock
*
1000
,
&
dsi_cinfo
,
&
dispc_cinfo
);
if
(
r
)
return
r
;
ok
=
dpi_dsi_clk_calc
(
timings
->
pixel_clock
*
1000
,
&
ctx
);
if
(
!
ok
)
return
-
EINVAL
;
fck
=
dsi_cinfo
.
dsi_pll_hsdiv_dispc_clk
;
fck
=
ctx
.
dsi_cinfo
.
dsi_pll_hsdiv_dispc_clk
;
}
else
{
struct
dss_clock_info
dss_cinfo
;
r
=
dss_calc_clock_div
(
timings
->
pixel_clock
*
1000
,
&
dss_cinfo
,
&
dispc_cinfo
)
;
ok
=
dpi_dss_clk_calc
(
timings
->
pixel_clock
*
1000
,
&
ctx
)
;
if
(
!
ok
)
return
-
EINVAL
;
if
(
r
)
return
r
;
fck
=
dss_cinfo
.
fck
;
fck
=
ctx
.
dss_cinfo
.
fck
;
}
lck_div
=
dispc_cinfo
.
lck_div
;
pck_div
=
dispc_cinfo
.
pck_div
;
lck_div
=
ctx
.
dispc_cinfo
.
lck_div
;
pck_div
=
ctx
.
dispc_cinfo
.
pck_div
;
pck
=
fck
/
lck_div
/
pck_div
/
1000
;
...
...
@@ -401,6 +542,36 @@ static int __init dpi_verify_dsi_pll(struct platform_device *dsidev)
return
0
;
}
/*
* Return a hardcoded channel for the DPI output. This should work for
* current use cases, but this can be later expanded to either resolve
* the channel in some more dynamic manner, or get the channel as a user
* parameter.
*/
static
enum
omap_channel
dpi_get_channel
(
void
)
{
switch
(
omapdss_get_version
())
{
case
OMAPDSS_VER_OMAP24xx
:
case
OMAPDSS_VER_OMAP34xx_ES1
:
case
OMAPDSS_VER_OMAP34xx_ES3
:
case
OMAPDSS_VER_OMAP3630
:
case
OMAPDSS_VER_AM35xx
:
return
OMAP_DSS_CHANNEL_LCD
;
case
OMAPDSS_VER_OMAP4430_ES1
:
case
OMAPDSS_VER_OMAP4430_ES2
:
case
OMAPDSS_VER_OMAP4
:
return
OMAP_DSS_CHANNEL_LCD2
;
case
OMAPDSS_VER_OMAP5
:
return
OMAP_DSS_CHANNEL_LCD3
;
default:
DSSWARN
(
"unsupported DSS version
\n
"
);
return
OMAP_DSS_CHANNEL_LCD
;
}
}
static
int
__init
dpi_init_display
(
struct
omap_dss_device
*
dssdev
)
{
struct
platform_device
*
dsidev
;
...
...
@@ -421,12 +592,7 @@ static int __init dpi_init_display(struct omap_dss_device *dssdev)
dpi
.
vdds_dsi_reg
=
vdds_dsi
;
}
/*
* XXX We shouldn't need dssdev->channel for this. The dsi pll clock
* source for DPI is SoC integration detail, not something that should
* be configured in the dssdev
*/
dsidev
=
dpi_get_dsidev
(
dssdev
->
channel
);
dsidev
=
dpi_get_dsidev
(
dpi
.
output
.
dispc_channel
);
if
(
dsidev
&&
dpi_verify_dsi_pll
(
dsidev
))
{
dsidev
=
NULL
;
...
...
@@ -517,6 +683,8 @@ static void __init dpi_init_output(struct platform_device *pdev)
out
->
pdev
=
pdev
;
out
->
id
=
OMAP_DSS_OUTPUT_DPI
;
out
->
type
=
OMAP_DISPLAY_TYPE_DPI
;
out
->
name
=
"dpi.0"
;
out
->
dispc_channel
=
dpi_get_channel
();
dss_register_output
(
out
);
}
...
...
drivers/video/omap2/dss/dsi.c
View file @
3d62fe5b
...
...
@@ -200,6 +200,11 @@ struct dsi_reg { u16 idx; };
typedef
void
(
*
omap_dsi_isr_t
)
(
void
*
arg
,
u32
mask
);
static
int
dsi_display_init_dispc
(
struct
platform_device
*
dsidev
,
struct
omap_overlay_manager
*
mgr
);
static
void
dsi_display_uninit_dispc
(
struct
platform_device
*
dsidev
,
struct
omap_overlay_manager
*
mgr
);
#define DSI_MAX_NR_ISRS 2
#define DSI_MAX_NR_LANES 5
...
...
@@ -250,6 +255,24 @@ struct dsi_isr_tables {
struct
dsi_isr_data
isr_table_cio
[
DSI_MAX_NR_ISRS
];
};
struct
dsi_clk_calc_ctx
{
struct
platform_device
*
dsidev
;
/* inputs */
const
struct
omap_dss_dsi_config
*
config
;
unsigned
long
req_pck_min
,
req_pck_nom
,
req_pck_max
;
/* outputs */
struct
dsi_clock_info
dsi_cinfo
;
struct
dispc_clock_info
dispc_cinfo
;
struct
omap_video_timings
dispc_vm
;
struct
omap_dss_dsi_videomode_timings
dsi_vm
;
};
struct
dsi_data
{
struct
platform_device
*
pdev
;
void
__iomem
*
base
;
...
...
@@ -261,6 +284,9 @@ struct dsi_data {
struct
clk
*
dss_clk
;
struct
clk
*
sys_clk
;
struct
dispc_clock_info
user_dispc_cinfo
;
struct
dsi_clock_info
user_dsi_cinfo
;
struct
dsi_clock_info
current_cinfo
;
bool
vdds_dsi_enabled
;
...
...
@@ -324,6 +350,7 @@ struct dsi_data {
unsigned
long
lpdiv_max
;
unsigned
num_lanes_supported
;
unsigned
line_buffer_size
;
struct
dsi_lane_config
lanes
[
DSI_MAX_NR_LANES
];
unsigned
num_lanes_used
;
...
...
@@ -1192,15 +1219,33 @@ static unsigned long dsi_fclk_rate(struct platform_device *dsidev)
return
r
;
}
static
int
dsi_set_lp_clk_divisor
(
struct
omap_dss_device
*
dssdev
)
static
int
dsi_lp_clock_calc
(
struct
dsi_clock_info
*
cinfo
,
unsigned
long
lp_clk_min
,
unsigned
long
lp_clk_max
)
{
unsigned
long
dsi_fclk
=
cinfo
->
dsi_pll_hsdiv_dsi_clk
;
unsigned
lp_clk_div
;
unsigned
long
lp_clk
;
lp_clk_div
=
DIV_ROUND_UP
(
dsi_fclk
,
lp_clk_max
*
2
);
lp_clk
=
dsi_fclk
/
2
/
lp_clk_div
;
if
(
lp_clk
<
lp_clk_min
||
lp_clk
>
lp_clk_max
)
return
-
EINVAL
;
cinfo
->
lp_clk_div
=
lp_clk_div
;
cinfo
->
lp_clk
=
lp_clk
;
return
0
;
}
static
int
dsi_set_lp_clk_divisor
(
struct
platform_device
*
dsidev
)
{
struct
platform_device
*
dsidev
=
dsi_get_dsidev_from_dssdev
(
dssdev
);
struct
dsi_data
*
dsi
=
dsi_get_dsidrv_data
(
dsidev
);
unsigned
long
dsi_fclk
;
unsigned
lp_clk_div
;
unsigned
long
lp_clk
;
lp_clk_div
=
ds
sdev
->
clocks
.
dsi
.
lp_clk_div
;
lp_clk_div
=
ds
i
->
user_dsi_cinfo
.
lp_clk_div
;
if
(
lp_clk_div
==
0
||
lp_clk_div
>
dsi
->
lpdiv_max
)
return
-
EINVAL
;
...
...
@@ -1272,6 +1317,75 @@ static int dsi_pll_power(struct platform_device *dsidev,
return
0
;
}
unsigned
long
dsi_get_pll_clkin
(
struct
platform_device
*
dsidev
)
{
struct
dsi_data
*
dsi
=
dsi_get_dsidrv_data
(
dsidev
);
return
clk_get_rate
(
dsi
->
sys_clk
);
}
bool
dsi_hsdiv_calc
(
struct
platform_device
*
dsidev
,
unsigned
long
pll
,
unsigned
long
out_min
,
dsi_hsdiv_calc_func
func
,
void
*
data
)
{
struct
dsi_data
*
dsi
=
dsi_get_dsidrv_data
(
dsidev
);
int
regm
,
regm_start
,
regm_stop
;
unsigned
long
out_max
;
unsigned
long
out
;
out_min
=
out_min
?
out_min
:
1
;
out_max
=
dss_feat_get_param_max
(
FEAT_PARAM_DSS_FCK
);
regm_start
=
max
(
DIV_ROUND_UP
(
pll
,
out_max
),
1ul
);
regm_stop
=
min
(
pll
/
out_min
,
dsi
->
regm_dispc_max
);
for
(
regm
=
regm_start
;
regm
<=
regm_stop
;
++
regm
)
{
out
=
pll
/
regm
;
if
(
func
(
regm
,
out
,
data
))
return
true
;
}
return
false
;
}
bool
dsi_pll_calc
(
struct
platform_device
*
dsidev
,
unsigned
long
clkin
,
unsigned
long
pll_min
,
unsigned
long
pll_max
,
dsi_pll_calc_func
func
,
void
*
data
)
{
struct
dsi_data
*
dsi
=
dsi_get_dsidrv_data
(
dsidev
);
int
regn
,
regn_start
,
regn_stop
;
int
regm
,
regm_start
,
regm_stop
;
unsigned
long
fint
,
pll
;
const
unsigned
long
pll_hw_max
=
1800000000
;
unsigned
long
fint_hw_min
,
fint_hw_max
;
fint_hw_min
=
dsi
->
fint_min
;
fint_hw_max
=
dsi
->
fint_max
;
regn_start
=
max
(
DIV_ROUND_UP
(
clkin
,
fint_hw_max
),
1ul
);
regn_stop
=
min
(
clkin
/
fint_hw_min
,
dsi
->
regn_max
);
pll_max
=
pll_max
?
pll_max
:
ULONG_MAX
;
for
(
regn
=
regn_start
;
regn
<=
regn_stop
;
++
regn
)
{
fint
=
clkin
/
regn
;
regm_start
=
max
(
DIV_ROUND_UP
(
DIV_ROUND_UP
(
pll_min
,
fint
),
2
),
1ul
);
regm_stop
=
min3
(
pll_max
/
fint
/
2
,
pll_hw_max
/
fint
/
2
,
dsi
->
regm_max
);
for
(
regm
=
regm_start
;
regm
<=
regm_stop
;
++
regm
)
{
pll
=
2
*
regm
*
fint
;
if
(
func
(
regn
,
regm
,
fint
,
pll
,
data
))
return
true
;
}
}
return
false
;
}
/* calculate clock rates using dividers in cinfo */
static
int
dsi_calc_clock_rates
(
struct
platform_device
*
dsidev
,
struct
dsi_clock_info
*
cinfo
)
...
...
@@ -1316,192 +1430,7 @@ static int dsi_calc_clock_rates(struct platform_device *dsidev,
return
0
;
}
int
dsi_pll_calc_clock_div_pck
(
struct
platform_device
*
dsidev
,
unsigned
long
req_pck
,
struct
dsi_clock_info
*
dsi_cinfo
,
struct
dispc_clock_info
*
dispc_cinfo
)
{
struct
dsi_data
*
dsi
=
dsi_get_dsidrv_data
(
dsidev
);
struct
dsi_clock_info
cur
,
best
;
struct
dispc_clock_info
best_dispc
;
int
min_fck_per_pck
;
int
match
=
0
;
unsigned
long
dss_sys_clk
,
max_dss_fck
;
dss_sys_clk
=
clk_get_rate
(
dsi
->
sys_clk
);
max_dss_fck
=
dss_feat_get_param_max
(
FEAT_PARAM_DSS_FCK
);
if
(
req_pck
==
dsi
->
cache_req_pck
&&
dsi
->
cache_cinfo
.
clkin
==
dss_sys_clk
)
{
DSSDBG
(
"DSI clock info found from cache
\n
"
);
*
dsi_cinfo
=
dsi
->
cache_cinfo
;
dispc_find_clk_divs
(
req_pck
,
dsi_cinfo
->
dsi_pll_hsdiv_dispc_clk
,
dispc_cinfo
);
return
0
;
}
min_fck_per_pck
=
CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK
;
if
(
min_fck_per_pck
&&
req_pck
*
min_fck_per_pck
>
max_dss_fck
)
{
DSSERR
(
"Requested pixel clock not possible with the current "
"OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning "
"the constraint off.
\n
"
);
min_fck_per_pck
=
0
;
}
DSSDBG
(
"dsi_pll_calc
\n
"
);
retry:
memset
(
&
best
,
0
,
sizeof
(
best
));
memset
(
&
best_dispc
,
0
,
sizeof
(
best_dispc
));
memset
(
&
cur
,
0
,
sizeof
(
cur
));
cur
.
clkin
=
dss_sys_clk
;
/* 0.75MHz < Fint = clkin / regn < 2.1MHz */
/* To reduce PLL lock time, keep Fint high (around 2 MHz) */
for
(
cur
.
regn
=
1
;
cur
.
regn
<
dsi
->
regn_max
;
++
cur
.
regn
)
{
cur
.
fint
=
cur
.
clkin
/
cur
.
regn
;
if
(
cur
.
fint
>
dsi
->
fint_max
||
cur
.
fint
<
dsi
->
fint_min
)
continue
;
/* DSIPHY(MHz) = (2 * regm / regn) * clkin */
for
(
cur
.
regm
=
1
;
cur
.
regm
<
dsi
->
regm_max
;
++
cur
.
regm
)
{
unsigned
long
a
,
b
;
a
=
2
*
cur
.
regm
*
(
cur
.
clkin
/
1000
);
b
=
cur
.
regn
;
cur
.
clkin4ddr
=
a
/
b
*
1000
;
if
(
cur
.
clkin4ddr
>
1800
*
1000
*
1000
)
break
;
/* dsi_pll_hsdiv_dispc_clk(MHz) =
* DSIPHY(MHz) / regm_dispc < 173MHz/186Mhz */
for
(
cur
.
regm_dispc
=
1
;
cur
.
regm_dispc
<
dsi
->
regm_dispc_max
;
++
cur
.
regm_dispc
)
{
struct
dispc_clock_info
cur_dispc
;
cur
.
dsi_pll_hsdiv_dispc_clk
=
cur
.
clkin4ddr
/
cur
.
regm_dispc
;
if
(
cur
.
regm_dispc
>
1
&&
cur
.
regm_dispc
%
2
!=
0
&&
req_pck
>=
1000000
)
continue
;
/* this will narrow down the search a bit,
* but still give pixclocks below what was
* requested */
if
(
cur
.
dsi_pll_hsdiv_dispc_clk
<
req_pck
)
break
;
if
(
cur
.
dsi_pll_hsdiv_dispc_clk
>
max_dss_fck
)
continue
;
if
(
min_fck_per_pck
&&
cur
.
dsi_pll_hsdiv_dispc_clk
<
req_pck
*
min_fck_per_pck
)
continue
;
match
=
1
;
dispc_find_clk_divs
(
req_pck
,
cur
.
dsi_pll_hsdiv_dispc_clk
,
&
cur_dispc
);
if
(
abs
(
cur_dispc
.
pck
-
req_pck
)
<
abs
(
best_dispc
.
pck
-
req_pck
))
{
best
=
cur
;
best_dispc
=
cur_dispc
;
if
(
cur_dispc
.
pck
==
req_pck
)
goto
found
;
}
}
}
}
found:
if
(
!
match
)
{
if
(
min_fck_per_pck
)
{
DSSERR
(
"Could not find suitable clock settings.
\n
"
"Turning FCK/PCK constraint off and"
"trying again.
\n
"
);
min_fck_per_pck
=
0
;
goto
retry
;
}
DSSERR
(
"Could not find suitable clock settings.
\n
"
);
return
-
EINVAL
;
}
/* dsi_pll_hsdiv_dsi_clk (regm_dsi) is not used */
best
.
regm_dsi
=
0
;
best
.
dsi_pll_hsdiv_dsi_clk
=
0
;
if
(
dsi_cinfo
)
*
dsi_cinfo
=
best
;
if
(
dispc_cinfo
)
*
dispc_cinfo
=
best_dispc
;
dsi
->
cache_req_pck
=
req_pck
;
dsi
->
cache_clk_freq
=
0
;
dsi
->
cache_cinfo
=
best
;
return
0
;
}
static
int
dsi_pll_calc_ddrfreq
(
struct
platform_device
*
dsidev
,
unsigned
long
req_clkin4ddr
,
struct
dsi_clock_info
*
cinfo
)
{
struct
dsi_data
*
dsi
=
dsi_get_dsidrv_data
(
dsidev
);
struct
dsi_clock_info
cur
,
best
;
DSSDBG
(
"dsi_pll_calc_ddrfreq
\n
"
);
memset
(
&
best
,
0
,
sizeof
(
best
));
memset
(
&
cur
,
0
,
sizeof
(
cur
));
cur
.
clkin
=
clk_get_rate
(
dsi
->
sys_clk
);
for
(
cur
.
regn
=
1
;
cur
.
regn
<
dsi
->
regn_max
;
++
cur
.
regn
)
{
cur
.
fint
=
cur
.
clkin
/
cur
.
regn
;
if
(
cur
.
fint
>
dsi
->
fint_max
||
cur
.
fint
<
dsi
->
fint_min
)
continue
;
/* DSIPHY(MHz) = (2 * regm / regn) * clkin */
for
(
cur
.
regm
=
1
;
cur
.
regm
<
dsi
->
regm_max
;
++
cur
.
regm
)
{
unsigned
long
a
,
b
;
a
=
2
*
cur
.
regm
*
(
cur
.
clkin
/
1000
);
b
=
cur
.
regn
;
cur
.
clkin4ddr
=
a
/
b
*
1000
;
if
(
cur
.
clkin4ddr
>
1800
*
1000
*
1000
)
break
;
if
(
abs
(
cur
.
clkin4ddr
-
req_clkin4ddr
)
<
abs
(
best
.
clkin4ddr
-
req_clkin4ddr
))
{
best
=
cur
;
DSSDBG
(
"best %ld
\n
"
,
best
.
clkin4ddr
);
}
if
(
cur
.
clkin4ddr
==
req_clkin4ddr
)
goto
found
;
}
}
found:
if
(
cinfo
)
*
cinfo
=
best
;
return
0
;
}
static
void
dsi_pll_calc_dsi_fck
(
struct
platform_device
*
dsidev
,
struct
dsi_clock_info
*
cinfo
)
static
void
dsi_pll_calc_dsi_fck
(
struct
dsi_clock_info
*
cinfo
)
{
unsigned
long
max_dsi_fck
;
...
...
@@ -1511,90 +1440,6 @@ static void dsi_pll_calc_dsi_fck(struct platform_device *dsidev,
cinfo
->
dsi_pll_hsdiv_dsi_clk
=
cinfo
->
clkin4ddr
/
cinfo
->
regm_dsi
;
}
static
int
dsi_pll_calc_dispc_fck
(
struct
platform_device
*
dsidev
,
unsigned
long
req_pck
,
struct
dsi_clock_info
*
cinfo
,
struct
dispc_clock_info
*
dispc_cinfo
)
{
struct
dsi_data
*
dsi
=
dsi_get_dsidrv_data
(
dsidev
);
unsigned
regm_dispc
,
best_regm_dispc
;
unsigned
long
dispc_clk
,
best_dispc_clk
;
int
min_fck_per_pck
;
unsigned
long
max_dss_fck
;
struct
dispc_clock_info
best_dispc
;
bool
match
;
max_dss_fck
=
dss_feat_get_param_max
(
FEAT_PARAM_DSS_FCK
);
min_fck_per_pck
=
CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK
;
if
(
min_fck_per_pck
&&
req_pck
*
min_fck_per_pck
>
max_dss_fck
)
{
DSSERR
(
"Requested pixel clock not possible with the current "
"OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning "
"the constraint off.
\n
"
);
min_fck_per_pck
=
0
;
}
retry:
best_regm_dispc
=
0
;
best_dispc_clk
=
0
;
memset
(
&
best_dispc
,
0
,
sizeof
(
best_dispc
));
match
=
false
;
for
(
regm_dispc
=
1
;
regm_dispc
<
dsi
->
regm_dispc_max
;
++
regm_dispc
)
{
struct
dispc_clock_info
cur_dispc
;
dispc_clk
=
cinfo
->
clkin4ddr
/
regm_dispc
;
/* this will narrow down the search a bit,
* but still give pixclocks below what was
* requested */
if
(
dispc_clk
<
req_pck
)
break
;
if
(
dispc_clk
>
max_dss_fck
)
continue
;
if
(
min_fck_per_pck
&&
dispc_clk
<
req_pck
*
min_fck_per_pck
)
continue
;
match
=
true
;
dispc_find_clk_divs
(
req_pck
,
dispc_clk
,
&
cur_dispc
);
if
(
abs
(
cur_dispc
.
pck
-
req_pck
)
<
abs
(
best_dispc
.
pck
-
req_pck
))
{
best_regm_dispc
=
regm_dispc
;
best_dispc_clk
=
dispc_clk
;
best_dispc
=
cur_dispc
;
if
(
cur_dispc
.
pck
==
req_pck
)
goto
found
;
}
}
if
(
!
match
)
{
if
(
min_fck_per_pck
)
{
DSSERR
(
"Could not find suitable clock settings.
\n
"
"Turning FCK/PCK constraint off and"
"trying again.
\n
"
);
min_fck_per_pck
=
0
;
goto
retry
;
}
DSSERR
(
"Could not find suitable clock settings.
\n
"
);
return
-
EINVAL
;
}
found:
cinfo
->
regm_dispc
=
best_regm_dispc
;
cinfo
->
dsi_pll_hsdiv_dispc_clk
=
best_dispc_clk
;
*
dispc_cinfo
=
best_dispc
;
return
0
;
}
int
dsi_pll_set_clock_div
(
struct
platform_device
*
dsidev
,
struct
dsi_clock_info
*
cinfo
)
{
...
...
@@ -2783,6 +2628,7 @@ static int dsi_vc_enable(struct platform_device *dsidev, int channel,
static
void
dsi_vc_initial_config
(
struct
platform_device
*
dsidev
,
int
channel
)
{
struct
dsi_data
*
dsi
=
dsi_get_dsidrv_data
(
dsidev
);
u32
r
;
DSSDBG
(
"Initial config of virtual channel %d"
,
channel
);
...
...
@@ -2807,6 +2653,8 @@ static void dsi_vc_initial_config(struct platform_device *dsidev, int channel)
r
=
FLD_MOD
(
r
,
4
,
23
,
21
);
/* DMA_TX_REQ_NB = no dma */
dsi_write_reg
(
dsidev
,
DSI_VC_CTRL
(
channel
),
r
);
dsi
->
vc
[
channel
].
source
=
DSI_VC_SOURCE_L4
;
}
static
int
dsi_vc_config_source
(
struct
platform_device
*
dsidev
,
int
channel
,
...
...
@@ -3777,13 +3625,12 @@ static void dsi_config_vp_num_line_buffers(struct platform_device *dsidev)
if
(
dsi
->
mode
==
OMAP_DSS_DSI_VIDEO_MODE
)
{
int
bpp
=
dsi_get_pixel_size
(
dsi
->
pix_fmt
);
unsigned
line_buf_size
=
dsi_get_line_buf_size
(
dsidev
);
struct
omap_video_timings
*
timings
=
&
dsi
->
timings
;
/*
* Don't use line buffers if width is greater than the video
* port's line buffer size
*/
if
(
line_buf
_size
<=
timings
->
x_res
*
bpp
/
8
)
if
(
dsi
->
line_buffer
_size
<=
timings
->
x_res
*
bpp
/
8
)
num_line_buffers
=
0
;
else
num_line_buffers
=
2
;
...
...
@@ -3799,18 +3646,22 @@ static void dsi_config_vp_num_line_buffers(struct platform_device *dsidev)
static
void
dsi_config_vp_sync_events
(
struct
platform_device
*
dsidev
)
{
struct
dsi_data
*
dsi
=
dsi_get_dsidrv_data
(
dsidev
);
bool
vsync_end
=
dsi
->
vm_timings
.
vp_vsync_end
;
bool
hsync_end
=
dsi
->
vm_timings
.
vp_hsync_end
;
bool
sync_end
;
u32
r
;
if
(
dsi
->
vm_timings
.
trans_mode
==
OMAP_DSS_DSI_PULSE_MODE
)
sync_end
=
true
;
else
sync_end
=
false
;
r
=
dsi_read_reg
(
dsidev
,
DSI_CTRL
);
r
=
FLD_MOD
(
r
,
1
,
9
,
9
);
/* VP_DE_POL */
r
=
FLD_MOD
(
r
,
1
,
10
,
10
);
/* VP_HSYNC_POL */
r
=
FLD_MOD
(
r
,
1
,
11
,
11
);
/* VP_VSYNC_POL */
r
=
FLD_MOD
(
r
,
1
,
15
,
15
);
/* VP_VSYNC_START */
r
=
FLD_MOD
(
r
,
v
sync_end
,
16
,
16
);
/* VP_VSYNC_END */
r
=
FLD_MOD
(
r
,
sync_end
,
16
,
16
);
/* VP_VSYNC_END */
r
=
FLD_MOD
(
r
,
1
,
17
,
17
);
/* VP_HSYNC_START */
r
=
FLD_MOD
(
r
,
h
sync_end
,
18
,
18
);
/* VP_HSYNC_END */
r
=
FLD_MOD
(
r
,
sync_end
,
18
,
18
);
/* VP_HSYNC_END */
dsi_write_reg
(
dsidev
,
DSI_CTRL
,
r
);
}
...
...
@@ -3897,9 +3748,8 @@ static int dsi_compute_interleave_lp(int blank, int enter_hs, int exit_hs,
return
max
(
lp_inter
,
0
);
}
static
void
dsi_config_cmd_mode_interleaving
(
struct
omap_dss_device
*
dss
dev
)
static
void
dsi_config_cmd_mode_interleaving
(
struct
platform_device
*
dsi
dev
)
{
struct
platform_device
*
dsidev
=
dsi_get_dsidev_from_dssdev
(
dssdev
);
struct
dsi_data
*
dsi
=
dsi_get_dsidrv_data
(
dsidev
);
int
blanking_mode
;
int
hfp_blanking_mode
,
hbp_blanking_mode
,
hsa_blanking_mode
;
...
...
@@ -3910,7 +3760,7 @@ static void dsi_config_cmd_mode_interleaving(struct omap_dss_device *dssdev)
struct
omap_video_timings
*
timings
=
&
dsi
->
timings
;
int
bpp
=
dsi_get_pixel_size
(
dsi
->
pix_fmt
);
int
ndl
=
dsi
->
num_lanes_used
-
1
;
int
dsi_fclk_hsdiv
=
ds
sdev
->
clocks
.
dsi
.
regm_dsi
+
1
;
int
dsi_fclk_hsdiv
=
ds
i
->
user_dsi_cinfo
.
regm_dsi
+
1
;
int
hsa_interleave_hs
=
0
,
hsa_interleave_lp
=
0
;
int
hfp_interleave_hs
=
0
,
hfp_interleave_lp
=
0
;
int
hbp_interleave_hs
=
0
,
hbp_interleave_lp
=
0
;
...
...
@@ -4015,9 +3865,8 @@ static void dsi_config_cmd_mode_interleaving(struct omap_dss_device *dssdev)
dsi_write_reg
(
dsidev
,
DSI_VM_TIMING6
,
r
);
}
static
int
dsi_proto_config
(
struct
omap_dss_device
*
dss
dev
)
static
int
dsi_proto_config
(
struct
platform_device
*
dsi
dev
)
{
struct
platform_device
*
dsidev
=
dsi_get_dsidev_from_dssdev
(
dssdev
);
struct
dsi_data
*
dsi
=
dsi_get_dsidrv_data
(
dsidev
);
u32
r
;
int
buswidth
=
0
;
...
...
@@ -4075,7 +3924,7 @@ static int dsi_proto_config(struct omap_dss_device *dssdev)
if
(
dsi
->
mode
==
OMAP_DSS_DSI_VIDEO_MODE
)
{
dsi_config_vp_sync_events
(
dsidev
);
dsi_config_blanking_modes
(
dsidev
);
dsi_config_cmd_mode_interleaving
(
ds
s
dev
);
dsi_config_cmd_mode_interleaving
(
ds
i
dev
);
}
dsi_vc_initial_config
(
dsidev
,
0
);
...
...
@@ -4159,11 +4008,12 @@ static void dsi_proto_timings(struct platform_device *dsidev)
int
vfp
=
dsi
->
vm_timings
.
vfp
;
int
vbp
=
dsi
->
vm_timings
.
vbp
;
int
window_sync
=
dsi
->
vm_timings
.
window_sync
;
bool
hsync_end
=
dsi
->
vm_timings
.
vp_hsync_end
;
bool
hsync_end
;
struct
omap_video_timings
*
timings
=
&
dsi
->
timings
;
int
bpp
=
dsi_get_pixel_size
(
dsi
->
pix_fmt
);
int
tl
,
t_he
,
width_bytes
;
hsync_end
=
dsi
->
vm_timings
.
trans_mode
==
OMAP_DSS_DSI_PULSE_MODE
;
t_he
=
hsync_end
?
((
hsa
==
0
&&
ndl
==
3
)
?
1
:
DIV_ROUND_UP
(
4
,
ndl
))
:
0
;
...
...
@@ -4266,82 +4116,26 @@ int omapdss_dsi_configure_pins(struct omap_dss_device *dssdev,
}
EXPORT_SYMBOL
(
omapdss_dsi_configure_pins
);
int
omapdss_dsi_set_clocks
(
struct
omap_dss_device
*
dssdev
,
unsigned
long
ddr_clk
,
unsigned
long
lp_clk
)
{
struct
platform_device
*
dsidev
=
dsi_get_dsidev_from_dssdev
(
dssdev
);
struct
dsi_data
*
dsi
=
dsi_get_dsidrv_data
(
dsidev
);
struct
dsi_clock_info
cinfo
;
struct
dispc_clock_info
dispc_cinfo
;
unsigned
lp_clk_div
;
unsigned
long
dsi_fclk
;
int
bpp
=
dsi_get_pixel_size
(
dssdev
->
panel
.
dsi_pix_fmt
);
unsigned
long
pck
;
int
r
;
DSSDBG
(
"Setting DSI clocks: ddr_clk %lu, lp_clk %lu"
,
ddr_clk
,
lp_clk
);
mutex_lock
(
&
dsi
->
lock
);
/* Calculate PLL output clock */
r
=
dsi_pll_calc_ddrfreq
(
dsidev
,
ddr_clk
*
4
,
&
cinfo
);
if
(
r
)
goto
err
;
/* Calculate PLL's DSI clock */
dsi_pll_calc_dsi_fck
(
dsidev
,
&
cinfo
);
/* Calculate PLL's DISPC clock and pck & lck divs */
pck
=
cinfo
.
clkin4ddr
/
16
*
(
dsi
->
num_lanes_used
-
1
)
*
8
/
bpp
;
DSSDBG
(
"finding dispc dividers for pck %lu
\n
"
,
pck
);
r
=
dsi_pll_calc_dispc_fck
(
dsidev
,
pck
,
&
cinfo
,
&
dispc_cinfo
);
if
(
r
)
goto
err
;
/* Calculate LP clock */
dsi_fclk
=
cinfo
.
dsi_pll_hsdiv_dsi_clk
;
lp_clk_div
=
DIV_ROUND_UP
(
dsi_fclk
,
lp_clk
*
2
);
dssdev
->
clocks
.
dsi
.
regn
=
cinfo
.
regn
;
dssdev
->
clocks
.
dsi
.
regm
=
cinfo
.
regm
;
dssdev
->
clocks
.
dsi
.
regm_dispc
=
cinfo
.
regm_dispc
;
dssdev
->
clocks
.
dsi
.
regm_dsi
=
cinfo
.
regm_dsi
;
dssdev
->
clocks
.
dsi
.
lp_clk_div
=
lp_clk_div
;
dssdev
->
clocks
.
dispc
.
channel
.
lck_div
=
dispc_cinfo
.
lck_div
;
dssdev
->
clocks
.
dispc
.
channel
.
pck_div
=
dispc_cinfo
.
pck_div
;
dssdev
->
clocks
.
dispc
.
dispc_fclk_src
=
OMAP_DSS_CLK_SRC_FCK
;
dssdev
->
clocks
.
dispc
.
channel
.
lcd_clk_src
=
dsi
->
module_id
==
0
?
OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC
:
OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC
;
dssdev
->
clocks
.
dsi
.
dsi_fclk_src
=
dsi
->
module_id
==
0
?
OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI
:
OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI
;
mutex_unlock
(
&
dsi
->
lock
);
return
0
;
err:
mutex_unlock
(
&
dsi
->
lock
);
return
r
;
}
EXPORT_SYMBOL
(
omapdss_dsi_set_clocks
);
int
dsi_enable_video_output
(
struct
omap_dss_device
*
dssdev
,
int
channel
)
{
struct
platform_device
*
dsidev
=
dsi_get_dsidev_from_dssdev
(
dssdev
);
struct
dsi_data
*
dsi
=
dsi_get_dsidrv_data
(
dsidev
);
struct
omap_overlay_manager
*
mgr
=
ds
sdev
->
output
->
manager
;
struct
omap_overlay_manager
*
mgr
=
ds
i
->
output
.
manager
;
int
bpp
=
dsi_get_pixel_size
(
dsi
->
pix_fmt
);
struct
omap_dss_output
*
out
=
&
dsi
->
output
;
u8
data_type
;
u16
word_count
;
int
r
;
if
(
out
==
NULL
||
out
->
manager
==
NULL
)
{
DSSERR
(
"failed to enable display: no output/manager
\n
"
);
return
-
ENODEV
;
}
r
=
dsi_display_init_dispc
(
dsidev
,
mgr
);
if
(
r
)
goto
err_init_dispc
;
if
(
dsi
->
mode
==
OMAP_DSS_DSI_VIDEO_MODE
)
{
switch
(
dsi
->
pix_fmt
)
{
case
OMAP_DSS_DSI_FMT_RGB888
:
...
...
@@ -4357,8 +4151,8 @@ int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel)
data_type
=
MIPI_DSI_PACKED_PIXEL_STREAM_16
;
break
;
default:
BUG
()
;
return
-
EINVAL
;
r
=
-
EINVAL
;
goto
err_pix_fmt
;
};
dsi_if_enable
(
dsidev
,
false
);
...
...
@@ -4377,16 +4171,20 @@ int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel)
}
r
=
dss_mgr_enable
(
mgr
);
if
(
r
)
{
if
(
dsi
->
mode
==
OMAP_DSS_DSI_VIDEO_MODE
)
{
dsi_if_enable
(
dsidev
,
false
);
dsi_vc_enable
(
dsidev
,
channel
,
false
);
}
return
r
;
}
if
(
r
)
goto
err_mgr_enable
;
return
0
;
err_mgr_enable:
if
(
dsi
->
mode
==
OMAP_DSS_DSI_VIDEO_MODE
)
{
dsi_if_enable
(
dsidev
,
false
);
dsi_vc_enable
(
dsidev
,
channel
,
false
);
}
err_pix_fmt:
dsi_display_uninit_dispc
(
dsidev
,
mgr
);
err_init_dispc:
return
r
;
}
EXPORT_SYMBOL
(
dsi_enable_video_output
);
...
...
@@ -4394,7 +4192,7 @@ void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel)
{
struct
platform_device
*
dsidev
=
dsi_get_dsidev_from_dssdev
(
dssdev
);
struct
dsi_data
*
dsi
=
dsi_get_dsidrv_data
(
dsidev
);
struct
omap_overlay_manager
*
mgr
=
ds
sdev
->
output
->
manager
;
struct
omap_overlay_manager
*
mgr
=
ds
i
->
output
.
manager
;
if
(
dsi
->
mode
==
OMAP_DSS_DSI_VIDEO_MODE
)
{
dsi_if_enable
(
dsidev
,
false
);
...
...
@@ -4408,14 +4206,15 @@ void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel)
}
dss_mgr_disable
(
mgr
);
dsi_display_uninit_dispc
(
dsidev
,
mgr
);
}
EXPORT_SYMBOL
(
dsi_disable_video_output
);
static
void
dsi_update_screen_dispc
(
struct
omap_dss_device
*
dss
dev
)
static
void
dsi_update_screen_dispc
(
struct
platform_device
*
dsi
dev
)
{
struct
platform_device
*
dsidev
=
dsi_get_dsidev_from_dssdev
(
dssdev
);
struct
dsi_data
*
dsi
=
dsi_get_dsidrv_data
(
dsidev
);
struct
omap_overlay_manager
*
mgr
=
ds
sdev
->
output
->
manager
;
struct
omap_overlay_manager
*
mgr
=
ds
i
->
output
.
manager
;
unsigned
bytespp
;
unsigned
bytespl
;
unsigned
bytespf
;
...
...
@@ -4425,7 +4224,7 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev)
u32
l
;
int
r
;
const
unsigned
channel
=
dsi
->
update_channel
;
const
unsigned
line_buf_size
=
dsi
_get_line_buf_size
(
dsidev
)
;
const
unsigned
line_buf_size
=
dsi
->
line_buffer_size
;
u16
w
=
dsi
->
timings
.
x_res
;
u16
h
=
dsi
->
timings
.
y_res
;
...
...
@@ -4571,7 +4370,7 @@ int omap_dsi_update(struct omap_dss_device *dssdev, int channel,
dsi
->
update_bytes
=
dw
*
dh
*
dsi_get_pixel_size
(
dsi
->
pix_fmt
)
/
8
;
#endif
dsi_update_screen_dispc
(
ds
s
dev
);
dsi_update_screen_dispc
(
ds
i
dev
);
return
0
;
}
...
...
@@ -4579,18 +4378,17 @@ EXPORT_SYMBOL(omap_dsi_update);
/* Display funcs */
static
int
dsi_configure_dispc_clocks
(
struct
omap_dss_device
*
dss
dev
)
static
int
dsi_configure_dispc_clocks
(
struct
platform_device
*
dsi
dev
)
{
struct
platform_device
*
dsidev
=
dsi_get_dsidev_from_dssdev
(
dssdev
);
struct
dsi_data
*
dsi
=
dsi_get_dsidrv_data
(
dsidev
);
struct
dispc_clock_info
dispc_cinfo
;
int
r
;
unsigned
long
long
fck
;
unsigned
long
fck
;
fck
=
dsi_get_pll_hsdiv_dispc_rate
(
dsidev
);
dispc_cinfo
.
lck_div
=
ds
sdev
->
clocks
.
dispc
.
channel
.
lck_div
;
dispc_cinfo
.
pck_div
=
ds
sdev
->
clocks
.
dispc
.
channel
.
pck_div
;
dispc_cinfo
.
lck_div
=
ds
i
->
user_dispc_cinfo
.
lck_div
;
dispc_cinfo
.
pck_div
=
ds
i
->
user_dispc_cinfo
.
pck_div
;
r
=
dispc_calc_clock_rates
(
fck
,
&
dispc_cinfo
);
if
(
r
)
{
...
...
@@ -4603,21 +4401,17 @@ static int dsi_configure_dispc_clocks(struct omap_dss_device *dssdev)
return
0
;
}
static
int
dsi_display_init_dispc
(
struct
omap_dss_device
*
dssdev
)
static
int
dsi_display_init_dispc
(
struct
platform_device
*
dsidev
,
struct
omap_overlay_manager
*
mgr
)
{
struct
platform_device
*
dsidev
=
dsi_get_dsidev_from_dssdev
(
dssdev
);
struct
dsi_data
*
dsi
=
dsi_get_dsidrv_data
(
dsidev
);
struct
omap_overlay_manager
*
mgr
=
dssdev
->
output
->
manager
;
int
r
;
if
(
dsi
->
mode
==
OMAP_DSS_DSI_CMD_MODE
)
{
dsi
->
timings
.
hsw
=
1
;
dsi
->
timings
.
hfp
=
1
;
dsi
->
timings
.
hbp
=
1
;
dsi
->
timings
.
vsw
=
1
;
dsi
->
timings
.
vfp
=
0
;
dsi
->
timings
.
vbp
=
0
;
dss_select_lcd_clk_source
(
mgr
->
id
,
dsi
->
module_id
==
0
?
OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC
:
OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC
);
if
(
dsi
->
mode
==
OMAP_DSS_DSI_CMD_MODE
)
{
r
=
dss_mgr_register_framedone_handler
(
mgr
,
dsi_framedone_irq_callback
,
dsidev
);
if
(
r
)
{
...
...
@@ -4645,7 +4439,7 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
dss_mgr_set_timings
(
mgr
,
&
dsi
->
timings
);
r
=
dsi_configure_dispc_clocks
(
ds
s
dev
);
r
=
dsi_configure_dispc_clocks
(
ds
i
dev
);
if
(
r
)
goto
err1
;
...
...
@@ -4662,30 +4456,30 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
dss_mgr_unregister_framedone_handler
(
mgr
,
dsi_framedone_irq_callback
,
dsidev
);
err:
dss_select_lcd_clk_source
(
mgr
->
id
,
OMAP_DSS_CLK_SRC_FCK
);
return
r
;
}
static
void
dsi_display_uninit_dispc
(
struct
omap_dss_device
*
dssdev
)
static
void
dsi_display_uninit_dispc
(
struct
platform_device
*
dsidev
,
struct
omap_overlay_manager
*
mgr
)
{
struct
platform_device
*
dsidev
=
dsi_get_dsidev_from_dssdev
(
dssdev
);
struct
dsi_data
*
dsi
=
dsi_get_dsidrv_data
(
dsidev
);
struct
omap_overlay_manager
*
mgr
=
dssdev
->
output
->
manager
;
if
(
dsi
->
mode
==
OMAP_DSS_DSI_CMD_MODE
)
dss_mgr_unregister_framedone_handler
(
mgr
,
dsi_framedone_irq_callback
,
dsidev
);
dss_select_lcd_clk_source
(
mgr
->
id
,
OMAP_DSS_CLK_SRC_FCK
);
}
static
int
dsi_configure_dsi_clocks
(
struct
omap_dss_device
*
dss
dev
)
static
int
dsi_configure_dsi_clocks
(
struct
platform_device
*
dsi
dev
)
{
struct
platform_device
*
dsidev
=
dsi_get_dsidev_from_dssdev
(
dss
dev
);
struct
dsi_data
*
dsi
=
dsi_get_dsidrv_data
(
dsi
dev
);
struct
dsi_clock_info
cinfo
;
int
r
;
cinfo
.
regn
=
dssdev
->
clocks
.
dsi
.
regn
;
cinfo
.
regm
=
dssdev
->
clocks
.
dsi
.
regm
;
cinfo
.
regm_dispc
=
dssdev
->
clocks
.
dsi
.
regm_dispc
;
cinfo
.
regm_dsi
=
dssdev
->
clocks
.
dsi
.
regm_dsi
;
cinfo
=
dsi
->
user_dsi_cinfo
;
r
=
dsi_calc_clock_rates
(
dsidev
,
&
cinfo
);
if
(
r
)
{
DSSERR
(
"Failed to calc dsi clocks
\n
"
);
...
...
@@ -4701,24 +4495,22 @@ static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev)
return
0
;
}
static
int
dsi_display_init_dsi
(
struct
omap_dss_device
*
dss
dev
)
static
int
dsi_display_init_dsi
(
struct
platform_device
*
dsi
dev
)
{
struct
platform_device
*
dsidev
=
dsi_get_dsidev_from_dssdev
(
dssdev
);
struct
dsi_data
*
dsi
=
dsi_get_dsidrv_data
(
dsidev
);
struct
omap_overlay_manager
*
mgr
=
dssdev
->
output
->
manager
;
int
r
;
r
=
dsi_pll_init
(
dsidev
,
true
,
true
);
if
(
r
)
goto
err0
;
r
=
dsi_configure_dsi_clocks
(
ds
s
dev
);
r
=
dsi_configure_dsi_clocks
(
ds
i
dev
);
if
(
r
)
goto
err1
;
dss_select_dsi_clk_source
(
dsi
->
module_id
,
ds
sdev
->
clocks
.
dsi
.
dsi_fclk_src
);
dss_select_lcd_clk_source
(
mgr
->
id
,
dssdev
->
clocks
.
dispc
.
channel
.
lcd_clk_src
);
dss_select_dsi_clk_source
(
dsi
->
module_id
,
ds
i
->
module_id
==
0
?
OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI
:
OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI
);
DSSDBG
(
"PLL OK
\n
"
);
...
...
@@ -4729,12 +4521,12 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
_dsi_print_reset_status
(
dsidev
);
dsi_proto_timings
(
dsidev
);
dsi_set_lp_clk_divisor
(
ds
s
dev
);
dsi_set_lp_clk_divisor
(
ds
i
dev
);
if
(
1
)
_dsi_print_reset_status
(
dsidev
);
r
=
dsi_proto_config
(
ds
s
dev
);
r
=
dsi_proto_config
(
ds
i
dev
);
if
(
r
)
goto
err3
;
...
...
@@ -4751,20 +4543,16 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
dsi_cio_uninit
(
dsidev
);
err2:
dss_select_dsi_clk_source
(
dsi
->
module_id
,
OMAP_DSS_CLK_SRC_FCK
);
dss_select_lcd_clk_source
(
mgr
->
id
,
OMAP_DSS_CLK_SRC_FCK
);
err1:
dsi_pll_uninit
(
dsidev
,
true
);
err0:
return
r
;
}
static
void
dsi_display_uninit_dsi
(
struct
omap_dss_device
*
dss
dev
,
static
void
dsi_display_uninit_dsi
(
struct
platform_device
*
dsi
dev
,
bool
disconnect_lanes
,
bool
enter_ulps
)
{
struct
platform_device
*
dsidev
=
dsi_get_dsidev_from_dssdev
(
dssdev
);
struct
dsi_data
*
dsi
=
dsi_get_dsidrv_data
(
dsidev
);
struct
omap_overlay_manager
*
mgr
=
dssdev
->
output
->
manager
;
if
(
enter_ulps
&&
!
dsi
->
ulps_enabled
)
dsi_enter_ulps
(
dsidev
);
...
...
@@ -4777,7 +4565,6 @@ static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev,
dsi_vc_enable
(
dsidev
,
3
,
0
);
dss_select_dsi_clk_source
(
dsi
->
module_id
,
OMAP_DSS_CLK_SRC_FCK
);
dss_select_lcd_clk_source
(
mgr
->
id
,
OMAP_DSS_CLK_SRC_FCK
);
dsi_cio_uninit
(
dsidev
);
dsi_pll_uninit
(
dsidev
,
disconnect_lanes
);
}
...
...
@@ -4786,7 +4573,6 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev)
{
struct
platform_device
*
dsidev
=
dsi_get_dsidev_from_dssdev
(
dssdev
);
struct
dsi_data
*
dsi
=
dsi_get_dsidrv_data
(
dsidev
);
struct
omap_dss_output
*
out
=
dssdev
->
output
;
int
r
=
0
;
DSSDBG
(
"dsi_display_enable
\n
"
);
...
...
@@ -4795,12 +4581,6 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev)
mutex_lock
(
&
dsi
->
lock
);
if
(
out
==
NULL
||
out
->
manager
==
NULL
)
{
DSSERR
(
"failed to enable display: no output/manager
\n
"
);
r
=
-
ENODEV
;
goto
err_start_dev
;
}
r
=
omap_dss_start_device
(
dssdev
);
if
(
r
)
{
DSSERR
(
"failed to start device
\n
"
);
...
...
@@ -4815,11 +4595,7 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev)
_dsi_initialize_irq
(
dsidev
);
r
=
dsi_display_init_dispc
(
dssdev
);
if
(
r
)
goto
err_init_dispc
;
r
=
dsi_display_init_dsi
(
dssdev
);
r
=
dsi_display_init_dsi
(
dsidev
);
if
(
r
)
goto
err_init_dsi
;
...
...
@@ -4828,8 +4604,6 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev)
return
0
;
err_init_dsi:
dsi_display_uninit_dispc
(
dssdev
);
err_init_dispc:
dsi_enable_pll_clock
(
dsidev
,
0
);
dsi_runtime_put
(
dsidev
);
err_get_dsi:
...
...
@@ -4858,9 +4632,7 @@ void omapdss_dsi_display_disable(struct omap_dss_device *dssdev,
dsi_sync_vc
(
dsidev
,
2
);
dsi_sync_vc
(
dsidev
,
3
);
dsi_display_uninit_dispc
(
dssdev
);
dsi_display_uninit_dsi
(
dssdev
,
disconnect_lanes
,
enter_ulps
);
dsi_display_uninit_dsi
(
dsidev
,
disconnect_lanes
,
enter_ulps
);
dsi_runtime_put
(
dsidev
);
dsi_enable_pll_clock
(
dsidev
,
0
);
...
...
@@ -4881,75 +4653,577 @@ int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable)
}
EXPORT_SYMBOL
(
omapdss_dsi_enable_te
);
void
omapdss_dsi_set_timings
(
struct
omap_dss_device
*
dssdev
,
struct
omap_video_timings
*
timings
)
#ifdef PRINT_VERBOSE_VM_TIMINGS
static
void
print_dsi_vm
(
const
char
*
str
,
const
struct
omap_dss_dsi_videomode_timings
*
t
)
{
unsigned
long
byteclk
=
t
->
hsclk
/
4
;
int
bl
,
wc
,
pps
,
tot
;
wc
=
DIV_ROUND_UP
(
t
->
hact
*
t
->
bitspp
,
8
);
pps
=
DIV_ROUND_UP
(
wc
+
6
,
t
->
ndl
);
/* pixel packet size */
bl
=
t
->
hss
+
t
->
hsa
+
t
->
hse
+
t
->
hbp
+
t
->
hfp
;
tot
=
bl
+
pps
;
#define TO_DSI_T(x) ((u32)div64_u64((u64)x * 1000000000llu, byteclk))
pr_debug
(
"%s bck %lu, %u/%u/%u/%u/%u/%u = %u+%u = %u, "
"%u/%u/%u/%u/%u/%u = %u + %u = %u
\n
"
,
str
,
byteclk
,
t
->
hss
,
t
->
hsa
,
t
->
hse
,
t
->
hbp
,
pps
,
t
->
hfp
,
bl
,
pps
,
tot
,
TO_DSI_T
(
t
->
hss
),
TO_DSI_T
(
t
->
hsa
),
TO_DSI_T
(
t
->
hse
),
TO_DSI_T
(
t
->
hbp
),
TO_DSI_T
(
pps
),
TO_DSI_T
(
t
->
hfp
),
TO_DSI_T
(
bl
),
TO_DSI_T
(
pps
),
TO_DSI_T
(
tot
));
#undef TO_DSI_T
}
static
void
print_dispc_vm
(
const
char
*
str
,
const
struct
omap_video_timings
*
t
)
{
unsigned
long
pck
=
t
->
pixel_clock
*
1000
;
int
hact
,
bl
,
tot
;
hact
=
t
->
x_res
;
bl
=
t
->
hsw
+
t
->
hbp
+
t
->
hfp
;
tot
=
hact
+
bl
;
#define TO_DISPC_T(x) ((u32)div64_u64((u64)x * 1000000000llu, pck))
pr_debug
(
"%s pck %lu, %u/%u/%u/%u = %u+%u = %u, "
"%u/%u/%u/%u = %u + %u = %u
\n
"
,
str
,
pck
,
t
->
hsw
,
t
->
hbp
,
hact
,
t
->
hfp
,
bl
,
hact
,
tot
,
TO_DISPC_T
(
t
->
hsw
),
TO_DISPC_T
(
t
->
hbp
),
TO_DISPC_T
(
hact
),
TO_DISPC_T
(
t
->
hfp
),
TO_DISPC_T
(
bl
),
TO_DISPC_T
(
hact
),
TO_DISPC_T
(
tot
));
#undef TO_DISPC_T
}
/* note: this is not quite accurate */
static
void
print_dsi_dispc_vm
(
const
char
*
str
,
const
struct
omap_dss_dsi_videomode_timings
*
t
)
{
struct
omap_video_timings
vm
=
{
0
};
unsigned
long
byteclk
=
t
->
hsclk
/
4
;
unsigned
long
pck
;
u64
dsi_tput
;
int
dsi_hact
,
dsi_htot
;
dsi_tput
=
(
u64
)
byteclk
*
t
->
ndl
*
8
;
pck
=
(
u32
)
div64_u64
(
dsi_tput
,
t
->
bitspp
);
dsi_hact
=
DIV_ROUND_UP
(
DIV_ROUND_UP
(
t
->
hact
*
t
->
bitspp
,
8
)
+
6
,
t
->
ndl
);
dsi_htot
=
t
->
hss
+
t
->
hsa
+
t
->
hse
+
t
->
hbp
+
dsi_hact
+
t
->
hfp
;
vm
.
pixel_clock
=
pck
/
1000
;
vm
.
hsw
=
div64_u64
((
u64
)(
t
->
hsa
+
t
->
hse
)
*
pck
,
byteclk
);
vm
.
hbp
=
div64_u64
((
u64
)
t
->
hbp
*
pck
,
byteclk
);
vm
.
hfp
=
div64_u64
((
u64
)
t
->
hfp
*
pck
,
byteclk
);
vm
.
x_res
=
t
->
hact
;
print_dispc_vm
(
str
,
&
vm
);
}
#endif
/* PRINT_VERBOSE_VM_TIMINGS */
static
bool
dsi_cm_calc_dispc_cb
(
int
lckd
,
int
pckd
,
unsigned
long
lck
,
unsigned
long
pck
,
void
*
data
)
{
struct
platform_device
*
dsidev
=
dsi_get_dsidev_from_dssdev
(
dssdev
)
;
struct
dsi_data
*
dsi
=
dsi_get_dsidrv_data
(
dsidev
)
;
struct
dsi_clk_calc_ctx
*
ctx
=
data
;
struct
omap_video_timings
*
t
=
&
ctx
->
dispc_vm
;
mutex_lock
(
&
dsi
->
lock
);
ctx
->
dispc_cinfo
.
lck_div
=
lckd
;
ctx
->
dispc_cinfo
.
pck_div
=
pckd
;
ctx
->
dispc_cinfo
.
lck
=
lck
;
ctx
->
dispc_cinfo
.
pck
=
pck
;
dsi
->
timings
=
*
timings
;
*
t
=
*
ctx
->
config
->
timings
;
t
->
pixel_clock
=
pck
/
1000
;
t
->
x_res
=
ctx
->
config
->
timings
->
x_res
;
t
->
y_res
=
ctx
->
config
->
timings
->
y_res
;
t
->
hsw
=
t
->
hfp
=
t
->
hbp
=
t
->
vsw
=
1
;
t
->
vfp
=
t
->
vbp
=
0
;
mutex_unlock
(
&
dsi
->
lock
)
;
return
true
;
}
EXPORT_SYMBOL
(
omapdss_dsi_set_timings
);
void
omapdss_dsi_set_size
(
struct
omap_dss_device
*
dssdev
,
u16
w
,
u16
h
)
static
bool
dsi_cm_calc_hsdiv_cb
(
int
regm_dispc
,
unsigned
long
dispc
,
void
*
data
)
{
struct
platform_device
*
dsidev
=
dsi_get_dsidev_from_dssdev
(
dssdev
);
struct
dsi_data
*
dsi
=
dsi_get_dsidrv_data
(
dsidev
);
struct
dsi_clk_calc_ctx
*
ctx
=
data
;
mutex_lock
(
&
dsi
->
lock
);
ctx
->
dsi_cinfo
.
regm_dispc
=
regm_dispc
;
ctx
->
dsi_cinfo
.
dsi_pll_hsdiv_dispc_clk
=
dispc
;
dsi
->
timings
.
x_res
=
w
;
dsi
->
timings
.
y_res
=
h
;
return
dispc_div_calc
(
dispc
,
ctx
->
req_pck_min
,
ctx
->
req_pck_max
,
dsi_cm_calc_dispc_cb
,
ctx
);
}
mutex_unlock
(
&
dsi
->
lock
);
static
bool
dsi_cm_calc_pll_cb
(
int
regn
,
int
regm
,
unsigned
long
fint
,
unsigned
long
pll
,
void
*
data
)
{
struct
dsi_clk_calc_ctx
*
ctx
=
data
;
ctx
->
dsi_cinfo
.
regn
=
regn
;
ctx
->
dsi_cinfo
.
regm
=
regm
;
ctx
->
dsi_cinfo
.
fint
=
fint
;
ctx
->
dsi_cinfo
.
clkin4ddr
=
pll
;
return
dsi_hsdiv_calc
(
ctx
->
dsidev
,
pll
,
ctx
->
req_pck_min
,
dsi_cm_calc_hsdiv_cb
,
ctx
);
}
EXPORT_SYMBOL
(
omapdss_dsi_set_size
);
void
omapdss_dsi_set_pixel_format
(
struct
omap_dss_device
*
dssdev
,
enum
omap_dss_dsi_pixel_format
fmt
)
static
bool
dsi_cm_calc
(
struct
dsi_data
*
dsi
,
const
struct
omap_dss_dsi_config
*
cfg
,
struct
dsi_clk_calc_ctx
*
ctx
)
{
struct
platform_device
*
dsidev
=
dsi_get_dsidev_from_dssdev
(
dssdev
);
struct
dsi_data
*
dsi
=
dsi_get_dsidrv_data
(
dsidev
);
unsigned
long
clkin
;
int
bitspp
,
ndl
;
unsigned
long
pll_min
,
pll_max
;
unsigned
long
pck
,
txbyteclk
;
mutex_lock
(
&
dsi
->
lock
);
clkin
=
clk_get_rate
(
dsi
->
sys_clk
);
bitspp
=
dsi_get_pixel_size
(
cfg
->
pixel_format
);
ndl
=
dsi
->
num_lanes_used
-
1
;
/*
* Here we should calculate minimum txbyteclk to be able to send the
* frame in time, and also to handle TE. That's not very simple, though,
* especially as we go to LP between each pixel packet due to HW
* "feature". So let's just estimate very roughly and multiply by 1.5.
*/
pck
=
cfg
->
timings
->
pixel_clock
*
1000
;
pck
=
pck
*
3
/
2
;
txbyteclk
=
pck
*
bitspp
/
8
/
ndl
;
dsi
->
pix_fmt
=
fmt
;
memset
(
ctx
,
0
,
sizeof
(
*
ctx
));
ctx
->
dsidev
=
dsi
->
pdev
;
ctx
->
config
=
cfg
;
ctx
->
req_pck_min
=
pck
;
ctx
->
req_pck_nom
=
pck
;
ctx
->
req_pck_max
=
pck
*
3
/
2
;
ctx
->
dsi_cinfo
.
clkin
=
clkin
;
mutex_unlock
(
&
dsi
->
lock
);
pll_min
=
max
(
cfg
->
hs_clk_min
*
4
,
txbyteclk
*
4
*
4
);
pll_max
=
cfg
->
hs_clk_max
*
4
;
return
dsi_pll_calc
(
dsi
->
pdev
,
clkin
,
pll_min
,
pll_max
,
dsi_cm_calc_pll_cb
,
ctx
);
}
EXPORT_SYMBOL
(
omapdss_dsi_set_pixel_format
);
void
omapdss_dsi_set_operation_mode
(
struct
omap_dss_device
*
dssdev
,
enum
omap_dss_dsi_mode
mode
)
static
bool
dsi_vm_calc_blanking
(
struct
dsi_clk_calc_ctx
*
ctx
)
{
struct
platform_device
*
dsidev
=
dsi_get_dsidev_from_dssdev
(
dssdev
);
struct
dsi_data
*
dsi
=
dsi_get_dsidrv_data
(
dsidev
);
struct
dsi_data
*
dsi
=
dsi_get_dsidrv_data
(
ctx
->
dsidev
);
const
struct
omap_dss_dsi_config
*
cfg
=
ctx
->
config
;
int
bitspp
=
dsi_get_pixel_size
(
cfg
->
pixel_format
);
int
ndl
=
dsi
->
num_lanes_used
-
1
;
unsigned
long
hsclk
=
ctx
->
dsi_cinfo
.
clkin4ddr
/
4
;
unsigned
long
byteclk
=
hsclk
/
4
;
mutex_lock
(
&
dsi
->
lock
);
unsigned
long
dispc_pck
,
req_pck_min
,
req_pck_nom
,
req_pck_max
;
int
xres
;
int
panel_htot
,
panel_hbl
;
/* pixels */
int
dispc_htot
,
dispc_hbl
;
/* pixels */
int
dsi_htot
,
dsi_hact
,
dsi_hbl
,
hss
,
hse
;
/* byteclks */
int
hfp
,
hsa
,
hbp
;
const
struct
omap_video_timings
*
req_vm
;
struct
omap_video_timings
*
dispc_vm
;
struct
omap_dss_dsi_videomode_timings
*
dsi_vm
;
u64
dsi_tput
,
dispc_tput
;
dsi
->
mode
=
mode
;
dsi
_tput
=
(
u64
)
byteclk
*
ndl
*
8
;
mutex_unlock
(
&
dsi
->
lock
);
req_vm
=
cfg
->
timings
;
req_pck_min
=
ctx
->
req_pck_min
;
req_pck_max
=
ctx
->
req_pck_max
;
req_pck_nom
=
ctx
->
req_pck_nom
;
dispc_pck
=
ctx
->
dispc_cinfo
.
pck
;
dispc_tput
=
(
u64
)
dispc_pck
*
bitspp
;
xres
=
req_vm
->
x_res
;
panel_hbl
=
req_vm
->
hfp
+
req_vm
->
hbp
+
req_vm
->
hsw
;
panel_htot
=
xres
+
panel_hbl
;
dsi_hact
=
DIV_ROUND_UP
(
DIV_ROUND_UP
(
xres
*
bitspp
,
8
)
+
6
,
ndl
);
/*
* When there are no line buffers, DISPC and DSI must have the
* same tput. Otherwise DISPC tput needs to be higher than DSI's.
*/
if
(
dsi
->
line_buffer_size
<
xres
*
bitspp
/
8
)
{
if
(
dispc_tput
!=
dsi_tput
)
return
false
;
}
else
{
if
(
dispc_tput
<
dsi_tput
)
return
false
;
}
/* DSI tput must be over the min requirement */
if
(
dsi_tput
<
(
u64
)
bitspp
*
req_pck_min
)
return
false
;
/* When non-burst mode, DSI tput must be below max requirement. */
if
(
cfg
->
trans_mode
!=
OMAP_DSS_DSI_BURST_MODE
)
{
if
(
dsi_tput
>
(
u64
)
bitspp
*
req_pck_max
)
return
false
;
}
hss
=
DIV_ROUND_UP
(
4
,
ndl
);
if
(
cfg
->
trans_mode
==
OMAP_DSS_DSI_PULSE_MODE
)
{
if
(
ndl
==
3
&&
req_vm
->
hsw
==
0
)
hse
=
1
;
else
hse
=
DIV_ROUND_UP
(
4
,
ndl
);
}
else
{
hse
=
0
;
}
/* DSI htot to match the panel's nominal pck */
dsi_htot
=
div64_u64
((
u64
)
panel_htot
*
byteclk
,
req_pck_nom
);
/* fail if there would be no time for blanking */
if
(
dsi_htot
<
hss
+
hse
+
dsi_hact
)
return
false
;
/* total DSI blanking needed to achieve panel's TL */
dsi_hbl
=
dsi_htot
-
dsi_hact
;
/* DISPC htot to match the DSI TL */
dispc_htot
=
div64_u64
((
u64
)
dsi_htot
*
dispc_pck
,
byteclk
);
/* verify that the DSI and DISPC TLs are the same */
if
((
u64
)
dsi_htot
*
dispc_pck
!=
(
u64
)
dispc_htot
*
byteclk
)
return
false
;
dispc_hbl
=
dispc_htot
-
xres
;
/* setup DSI videomode */
dsi_vm
=
&
ctx
->
dsi_vm
;
memset
(
dsi_vm
,
0
,
sizeof
(
*
dsi_vm
));
dsi_vm
->
hsclk
=
hsclk
;
dsi_vm
->
ndl
=
ndl
;
dsi_vm
->
bitspp
=
bitspp
;
if
(
cfg
->
trans_mode
!=
OMAP_DSS_DSI_PULSE_MODE
)
{
hsa
=
0
;
}
else
if
(
ndl
==
3
&&
req_vm
->
hsw
==
0
)
{
hsa
=
0
;
}
else
{
hsa
=
div64_u64
((
u64
)
req_vm
->
hsw
*
byteclk
,
req_pck_nom
);
hsa
=
max
(
hsa
-
hse
,
1
);
}
hbp
=
div64_u64
((
u64
)
req_vm
->
hbp
*
byteclk
,
req_pck_nom
);
hbp
=
max
(
hbp
,
1
);
hfp
=
dsi_hbl
-
(
hss
+
hsa
+
hse
+
hbp
);
if
(
hfp
<
1
)
{
int
t
;
/* we need to take cycles from hbp */
t
=
1
-
hfp
;
hbp
=
max
(
hbp
-
t
,
1
);
hfp
=
dsi_hbl
-
(
hss
+
hsa
+
hse
+
hbp
);
if
(
hfp
<
1
&&
hsa
>
0
)
{
/* we need to take cycles from hsa */
t
=
1
-
hfp
;
hsa
=
max
(
hsa
-
t
,
1
);
hfp
=
dsi_hbl
-
(
hss
+
hsa
+
hse
+
hbp
);
}
}
if
(
hfp
<
1
)
return
false
;
dsi_vm
->
hss
=
hss
;
dsi_vm
->
hsa
=
hsa
;
dsi_vm
->
hse
=
hse
;
dsi_vm
->
hbp
=
hbp
;
dsi_vm
->
hact
=
xres
;
dsi_vm
->
hfp
=
hfp
;
dsi_vm
->
vsa
=
req_vm
->
vsw
;
dsi_vm
->
vbp
=
req_vm
->
vbp
;
dsi_vm
->
vact
=
req_vm
->
y_res
;
dsi_vm
->
vfp
=
req_vm
->
vfp
;
dsi_vm
->
trans_mode
=
cfg
->
trans_mode
;
dsi_vm
->
blanking_mode
=
0
;
dsi_vm
->
hsa_blanking_mode
=
1
;
dsi_vm
->
hfp_blanking_mode
=
1
;
dsi_vm
->
hbp_blanking_mode
=
1
;
dsi_vm
->
ddr_clk_always_on
=
cfg
->
ddr_clk_always_on
;
dsi_vm
->
window_sync
=
4
;
/* setup DISPC videomode */
dispc_vm
=
&
ctx
->
dispc_vm
;
*
dispc_vm
=
*
req_vm
;
dispc_vm
->
pixel_clock
=
dispc_pck
/
1000
;
if
(
cfg
->
trans_mode
==
OMAP_DSS_DSI_PULSE_MODE
)
{
hsa
=
div64_u64
((
u64
)
req_vm
->
hsw
*
dispc_pck
,
req_pck_nom
);
hsa
=
max
(
hsa
,
1
);
}
else
{
hsa
=
1
;
}
hbp
=
div64_u64
((
u64
)
req_vm
->
hbp
*
dispc_pck
,
req_pck_nom
);
hbp
=
max
(
hbp
,
1
);
hfp
=
dispc_hbl
-
hsa
-
hbp
;
if
(
hfp
<
1
)
{
int
t
;
/* we need to take cycles from hbp */
t
=
1
-
hfp
;
hbp
=
max
(
hbp
-
t
,
1
);
hfp
=
dispc_hbl
-
hsa
-
hbp
;
if
(
hfp
<
1
)
{
/* we need to take cycles from hsa */
t
=
1
-
hfp
;
hsa
=
max
(
hsa
-
t
,
1
);
hfp
=
dispc_hbl
-
hsa
-
hbp
;
}
}
if
(
hfp
<
1
)
return
false
;
dispc_vm
->
hfp
=
hfp
;
dispc_vm
->
hsw
=
hsa
;
dispc_vm
->
hbp
=
hbp
;
return
true
;
}
static
bool
dsi_vm_calc_dispc_cb
(
int
lckd
,
int
pckd
,
unsigned
long
lck
,
unsigned
long
pck
,
void
*
data
)
{
struct
dsi_clk_calc_ctx
*
ctx
=
data
;
ctx
->
dispc_cinfo
.
lck_div
=
lckd
;
ctx
->
dispc_cinfo
.
pck_div
=
pckd
;
ctx
->
dispc_cinfo
.
lck
=
lck
;
ctx
->
dispc_cinfo
.
pck
=
pck
;
if
(
dsi_vm_calc_blanking
(
ctx
)
==
false
)
return
false
;
#ifdef PRINT_VERBOSE_VM_TIMINGS
print_dispc_vm
(
"dispc"
,
&
ctx
->
dispc_vm
);
print_dsi_vm
(
"dsi "
,
&
ctx
->
dsi_vm
);
print_dispc_vm
(
"req "
,
ctx
->
config
->
timings
);
print_dsi_dispc_vm
(
"act "
,
&
ctx
->
dsi_vm
);
#endif
return
true
;
}
static
bool
dsi_vm_calc_hsdiv_cb
(
int
regm_dispc
,
unsigned
long
dispc
,
void
*
data
)
{
struct
dsi_clk_calc_ctx
*
ctx
=
data
;
unsigned
long
pck_max
;
ctx
->
dsi_cinfo
.
regm_dispc
=
regm_dispc
;
ctx
->
dsi_cinfo
.
dsi_pll_hsdiv_dispc_clk
=
dispc
;
/*
* In burst mode we can let the dispc pck be arbitrarily high, but it
* limits our scaling abilities. So for now, don't aim too high.
*/
if
(
ctx
->
config
->
trans_mode
==
OMAP_DSS_DSI_BURST_MODE
)
pck_max
=
ctx
->
req_pck_max
+
10000000
;
else
pck_max
=
ctx
->
req_pck_max
;
return
dispc_div_calc
(
dispc
,
ctx
->
req_pck_min
,
pck_max
,
dsi_vm_calc_dispc_cb
,
ctx
);
}
static
bool
dsi_vm_calc_pll_cb
(
int
regn
,
int
regm
,
unsigned
long
fint
,
unsigned
long
pll
,
void
*
data
)
{
struct
dsi_clk_calc_ctx
*
ctx
=
data
;
ctx
->
dsi_cinfo
.
regn
=
regn
;
ctx
->
dsi_cinfo
.
regm
=
regm
;
ctx
->
dsi_cinfo
.
fint
=
fint
;
ctx
->
dsi_cinfo
.
clkin4ddr
=
pll
;
return
dsi_hsdiv_calc
(
ctx
->
dsidev
,
pll
,
ctx
->
req_pck_min
,
dsi_vm_calc_hsdiv_cb
,
ctx
);
}
static
bool
dsi_vm_calc
(
struct
dsi_data
*
dsi
,
const
struct
omap_dss_dsi_config
*
cfg
,
struct
dsi_clk_calc_ctx
*
ctx
)
{
const
struct
omap_video_timings
*
t
=
cfg
->
timings
;
unsigned
long
clkin
;
unsigned
long
pll_min
;
unsigned
long
pll_max
;
int
ndl
=
dsi
->
num_lanes_used
-
1
;
int
bitspp
=
dsi_get_pixel_size
(
cfg
->
pixel_format
);
unsigned
long
byteclk_min
;
clkin
=
clk_get_rate
(
dsi
->
sys_clk
);
memset
(
ctx
,
0
,
sizeof
(
*
ctx
));
ctx
->
dsidev
=
dsi
->
pdev
;
ctx
->
config
=
cfg
;
ctx
->
dsi_cinfo
.
clkin
=
clkin
;
/* these limits should come from the panel driver */
ctx
->
req_pck_min
=
t
->
pixel_clock
*
1000
-
1000
;
ctx
->
req_pck_nom
=
t
->
pixel_clock
*
1000
;
ctx
->
req_pck_max
=
t
->
pixel_clock
*
1000
+
1000
;
byteclk_min
=
div64_u64
((
u64
)
ctx
->
req_pck_min
*
bitspp
,
ndl
*
8
);
pll_min
=
max
(
cfg
->
hs_clk_min
*
4
,
byteclk_min
*
4
*
4
);
if
(
cfg
->
trans_mode
==
OMAP_DSS_DSI_BURST_MODE
)
{
pll_max
=
cfg
->
hs_clk_max
*
4
;
}
else
{
unsigned
long
byteclk_max
;
byteclk_max
=
div64_u64
((
u64
)
ctx
->
req_pck_max
*
bitspp
,
ndl
*
8
);
pll_max
=
byteclk_max
*
4
*
4
;
}
return
dsi_pll_calc
(
dsi
->
pdev
,
clkin
,
pll_min
,
pll_max
,
dsi_vm_calc_pll_cb
,
ctx
);
}
EXPORT_SYMBOL
(
omapdss_dsi_set_operation_mode
);
void
omapdss_dsi_set_videomode_timings
(
struct
omap_dss_device
*
dssdev
,
struct
omap_dss_dsi_videomode_timings
*
timings
)
int
omapdss_dsi_set_config
(
struct
omap_dss_device
*
dssdev
,
const
struct
omap_dss_dsi_config
*
config
)
{
struct
platform_device
*
dsidev
=
dsi_get_dsidev_from_dssdev
(
dssdev
);
struct
dsi_data
*
dsi
=
dsi_get_dsidrv_data
(
dsidev
);
struct
dsi_clk_calc_ctx
ctx
;
bool
ok
;
int
r
;
mutex_lock
(
&
dsi
->
lock
);
dsi
->
vm_timings
=
*
timings
;
dsi
->
pix_fmt
=
config
->
pixel_format
;
dsi
->
mode
=
config
->
mode
;
if
(
config
->
mode
==
OMAP_DSS_DSI_VIDEO_MODE
)
ok
=
dsi_vm_calc
(
dsi
,
config
,
&
ctx
);
else
ok
=
dsi_cm_calc
(
dsi
,
config
,
&
ctx
);
if
(
!
ok
)
{
DSSERR
(
"failed to find suitable DSI clock settings
\n
"
);
r
=
-
EINVAL
;
goto
err
;
}
dsi_pll_calc_dsi_fck
(
&
ctx
.
dsi_cinfo
);
r
=
dsi_lp_clock_calc
(
&
ctx
.
dsi_cinfo
,
config
->
lp_clk_min
,
config
->
lp_clk_max
);
if
(
r
)
{
DSSERR
(
"failed to find suitable DSI LP clock settings
\n
"
);
goto
err
;
}
dsi
->
user_dsi_cinfo
=
ctx
.
dsi_cinfo
;
dsi
->
user_dispc_cinfo
=
ctx
.
dispc_cinfo
;
dsi
->
timings
=
ctx
.
dispc_vm
;
dsi
->
vm_timings
=
ctx
.
dsi_vm
;
mutex_unlock
(
&
dsi
->
lock
);
return
0
;
err:
mutex_unlock
(
&
dsi
->
lock
);
return
r
;
}
EXPORT_SYMBOL
(
omapdss_dsi_set_config
);
/*
* Return a hardcoded channel for the DSI output. This should work for
* current use cases, but this can be later expanded to either resolve
* the channel in some more dynamic manner, or get the channel as a user
* parameter.
*/
static
enum
omap_channel
dsi_get_channel
(
int
module_id
)
{
switch
(
omapdss_get_version
())
{
case
OMAPDSS_VER_OMAP24xx
:
DSSWARN
(
"DSI not supported
\n
"
);
return
OMAP_DSS_CHANNEL_LCD
;
case
OMAPDSS_VER_OMAP34xx_ES1
:
case
OMAPDSS_VER_OMAP34xx_ES3
:
case
OMAPDSS_VER_OMAP3630
:
case
OMAPDSS_VER_AM35xx
:
return
OMAP_DSS_CHANNEL_LCD
;
case
OMAPDSS_VER_OMAP4430_ES1
:
case
OMAPDSS_VER_OMAP4430_ES2
:
case
OMAPDSS_VER_OMAP4
:
switch
(
module_id
)
{
case
0
:
return
OMAP_DSS_CHANNEL_LCD
;
case
1
:
return
OMAP_DSS_CHANNEL_LCD2
;
default:
DSSWARN
(
"unsupported module id
\n
"
);
return
OMAP_DSS_CHANNEL_LCD
;
}
case
OMAPDSS_VER_OMAP5
:
switch
(
module_id
)
{
case
0
:
return
OMAP_DSS_CHANNEL_LCD
;
case
1
:
return
OMAP_DSS_CHANNEL_LCD3
;
default:
DSSWARN
(
"unsupported module id
\n
"
);
return
OMAP_DSS_CHANNEL_LCD
;
}
default:
DSSWARN
(
"unsupported DSS version
\n
"
);
return
OMAP_DSS_CHANNEL_LCD
;
}
}
EXPORT_SYMBOL
(
omapdss_dsi_set_videomode_timings
);
static
int
__init
dsi_init_display
(
struct
omap_dss_device
*
dssdev
)
{
...
...
@@ -5073,7 +5347,7 @@ static int dsi_get_clocks(struct platform_device *dsidev)
struct
dsi_data
*
dsi
=
dsi_get_dsidrv_data
(
dsidev
);
struct
clk
*
clk
;
clk
=
clk_get
(
&
dsidev
->
dev
,
"fck"
);
clk
=
devm_
clk_get
(
&
dsidev
->
dev
,
"fck"
);
if
(
IS_ERR
(
clk
))
{
DSSERR
(
"can't get fck
\n
"
);
return
PTR_ERR
(
clk
);
...
...
@@ -5081,11 +5355,9 @@ static int dsi_get_clocks(struct platform_device *dsidev)
dsi
->
dss_clk
=
clk
;
clk
=
clk_get
(
&
dsidev
->
dev
,
"sys_clk"
);
clk
=
devm_
clk_get
(
&
dsidev
->
dev
,
"sys_clk"
);
if
(
IS_ERR
(
clk
))
{
DSSERR
(
"can't get sys_clk
\n
"
);
clk_put
(
dsi
->
dss_clk
);
dsi
->
dss_clk
=
NULL
;
return
PTR_ERR
(
clk
);
}
...
...
@@ -5094,16 +5366,6 @@ static int dsi_get_clocks(struct platform_device *dsidev)
return
0
;
}
static
void
dsi_put_clocks
(
struct
platform_device
*
dsidev
)
{
struct
dsi_data
*
dsi
=
dsi_get_dsidrv_data
(
dsidev
);
if
(
dsi
->
dss_clk
)
clk_put
(
dsi
->
dss_clk
);
if
(
dsi
->
sys_clk
)
clk_put
(
dsi
->
sys_clk
);
}
static
struct
omap_dss_device
*
__init
dsi_find_dssdev
(
struct
platform_device
*
pdev
)
{
struct
omap_dss_board_info
*
pdata
=
pdev
->
dev
.
platform_data
;
...
...
@@ -5188,6 +5450,8 @@ static void __init dsi_init_output(struct platform_device *dsidev)
OMAP_DSS_OUTPUT_DSI1
:
OMAP_DSS_OUTPUT_DSI2
;
out
->
type
=
OMAP_DISPLAY_TYPE_DSI
;
out
->
name
=
dsi
->
module_id
==
0
?
"dsi.0"
:
"dsi.1"
;
out
->
dispc_channel
=
dsi_get_channel
(
dsi
->
module_id
);
dss_register_output
(
out
);
}
...
...
@@ -5293,6 +5557,8 @@ static int __init omap_dsihw_probe(struct platform_device *dsidev)
else
dsi
->
num_lanes_supported
=
3
;
dsi
->
line_buffer_size
=
dsi_get_line_buf_size
(
dsidev
);
dsi_init_output
(
dsidev
);
dsi_probe_pdata
(
dsidev
);
...
...
@@ -5314,7 +5580,6 @@ static int __init omap_dsihw_probe(struct platform_device *dsidev)
err_runtime_get:
pm_runtime_disable
(
&
dsidev
->
dev
);
dsi_put_clocks
(
dsidev
);
return
r
;
}
...
...
@@ -5330,8 +5595,6 @@ static int __exit omap_dsihw_remove(struct platform_device *dsidev)
pm_runtime_disable
(
&
dsidev
->
dev
);
dsi_put_clocks
(
dsidev
);
if
(
dsi
->
vdds_dsi_reg
!=
NULL
)
{
if
(
dsi
->
vdds_dsi_enabled
)
{
regulator_disable
(
dsi
->
vdds_dsi_reg
);
...
...
drivers/video/omap2/dss/dss.c
View file @
3d62fe5b
...
...
@@ -473,6 +473,47 @@ int dss_calc_clock_rates(struct dss_clock_info *cinfo)
return
0
;
}
bool
dss_div_calc
(
unsigned
long
fck_min
,
dss_div_calc_func
func
,
void
*
data
)
{
int
fckd
,
fckd_start
,
fckd_stop
;
unsigned
long
fck
;
unsigned
long
fck_hw_max
;
unsigned
long
fckd_hw_max
;
unsigned
long
prate
;
unsigned
m
;
if
(
dss
.
dpll4_m4_ck
==
NULL
)
{
/*
* TODO: dss1_fclk can be changed on OMAP2, but the available
* dividers are not continuous. We just use the pre-set rate for
* now.
*/
fck
=
clk_get_rate
(
dss
.
dss_clk
);
fckd
=
1
;
return
func
(
fckd
,
fck
,
data
);
}
fck_hw_max
=
dss_feat_get_param_max
(
FEAT_PARAM_DSS_FCK
);
fckd_hw_max
=
dss
.
feat
->
fck_div_max
;
m
=
dss
.
feat
->
dss_fck_multiplier
;
prate
=
dss_get_dpll4_rate
();
fck_min
=
fck_min
?
fck_min
:
1
;
fckd_start
=
min
(
prate
*
m
/
fck_min
,
fckd_hw_max
);
fckd_stop
=
max
(
DIV_ROUND_UP
(
prate
*
m
,
fck_hw_max
),
1ul
);
for
(
fckd
=
fckd_start
;
fckd
>=
fckd_stop
;
--
fckd
)
{
fck
=
prate
/
fckd
*
m
;
if
(
func
(
fckd
,
fck
,
data
))
return
true
;
}
return
false
;
}
int
dss_set_clock_div
(
struct
dss_clock_info
*
cinfo
)
{
if
(
dss
.
dpll4_m4_ck
)
{
...
...
@@ -482,7 +523,8 @@ int dss_set_clock_div(struct dss_clock_info *cinfo)
prate
=
clk_get_rate
(
clk_get_parent
(
dss
.
dpll4_m4_ck
));
DSSDBG
(
"dpll4_m4 = %ld
\n
"
,
prate
);
r
=
clk_set_rate
(
dss
.
dpll4_m4_ck
,
prate
/
cinfo
->
fck_div
);
r
=
clk_set_rate
(
dss
.
dpll4_m4_ck
,
DIV_ROUND_UP
(
prate
,
cinfo
->
fck_div
));
if
(
r
)
return
r
;
}
else
{
...
...
@@ -492,7 +534,9 @@ int dss_set_clock_div(struct dss_clock_info *cinfo)
dss
.
dss_clk_rate
=
clk_get_rate
(
dss
.
dss_clk
);
WARN_ONCE
(
dss
.
dss_clk_rate
!=
cinfo
->
fck
,
"clk rate mismatch"
);
WARN_ONCE
(
dss
.
dss_clk_rate
!=
cinfo
->
fck
,
"clk rate mismatch: %lu != %lu"
,
dss
.
dss_clk_rate
,
cinfo
->
fck
);
DSSDBG
(
"fck = %ld (%d)
\n
"
,
cinfo
->
fck
,
cinfo
->
fck_div
);
...
...
@@ -542,121 +586,6 @@ static int dss_setup_default_clock(void)
return
0
;
}
int
dss_calc_clock_div
(
unsigned
long
req_pck
,
struct
dss_clock_info
*
dss_cinfo
,
struct
dispc_clock_info
*
dispc_cinfo
)
{
unsigned
long
prate
;
struct
dss_clock_info
best_dss
;
struct
dispc_clock_info
best_dispc
;
unsigned
long
fck
,
max_dss_fck
;
u16
fck_div
;
int
match
=
0
;
int
min_fck_per_pck
;
prate
=
dss_get_dpll4_rate
();
max_dss_fck
=
dss_feat_get_param_max
(
FEAT_PARAM_DSS_FCK
);
fck
=
clk_get_rate
(
dss
.
dss_clk
);
if
(
req_pck
==
dss
.
cache_req_pck
&&
prate
==
dss
.
cache_prate
&&
dss
.
cache_dss_cinfo
.
fck
==
fck
)
{
DSSDBG
(
"dispc clock info found from cache.
\n
"
);
*
dss_cinfo
=
dss
.
cache_dss_cinfo
;
*
dispc_cinfo
=
dss
.
cache_dispc_cinfo
;
return
0
;
}
min_fck_per_pck
=
CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK
;
if
(
min_fck_per_pck
&&
req_pck
*
min_fck_per_pck
>
max_dss_fck
)
{
DSSERR
(
"Requested pixel clock not possible with the current "
"OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning "
"the constraint off.
\n
"
);
min_fck_per_pck
=
0
;
}
retry:
memset
(
&
best_dss
,
0
,
sizeof
(
best_dss
));
memset
(
&
best_dispc
,
0
,
sizeof
(
best_dispc
));
if
(
dss
.
dpll4_m4_ck
==
NULL
)
{
struct
dispc_clock_info
cur_dispc
;
/* XXX can we change the clock on omap2? */
fck
=
clk_get_rate
(
dss
.
dss_clk
);
fck_div
=
1
;
dispc_find_clk_divs
(
req_pck
,
fck
,
&
cur_dispc
);
match
=
1
;
best_dss
.
fck
=
fck
;
best_dss
.
fck_div
=
fck_div
;
best_dispc
=
cur_dispc
;
goto
found
;
}
else
{
for
(
fck_div
=
dss
.
feat
->
fck_div_max
;
fck_div
>
0
;
--
fck_div
)
{
struct
dispc_clock_info
cur_dispc
;
fck
=
prate
/
fck_div
*
dss
.
feat
->
dss_fck_multiplier
;
if
(
fck
>
max_dss_fck
)
continue
;
if
(
min_fck_per_pck
&&
fck
<
req_pck
*
min_fck_per_pck
)
continue
;
match
=
1
;
dispc_find_clk_divs
(
req_pck
,
fck
,
&
cur_dispc
);
if
(
abs
(
cur_dispc
.
pck
-
req_pck
)
<
abs
(
best_dispc
.
pck
-
req_pck
))
{
best_dss
.
fck
=
fck
;
best_dss
.
fck_div
=
fck_div
;
best_dispc
=
cur_dispc
;
if
(
cur_dispc
.
pck
==
req_pck
)
goto
found
;
}
}
}
found:
if
(
!
match
)
{
if
(
min_fck_per_pck
)
{
DSSERR
(
"Could not find suitable clock settings.
\n
"
"Turning FCK/PCK constraint off and"
"trying again.
\n
"
);
min_fck_per_pck
=
0
;
goto
retry
;
}
DSSERR
(
"Could not find suitable clock settings.
\n
"
);
return
-
EINVAL
;
}
if
(
dss_cinfo
)
*
dss_cinfo
=
best_dss
;
if
(
dispc_cinfo
)
*
dispc_cinfo
=
best_dispc
;
dss
.
cache_req_pck
=
req_pck
;
dss
.
cache_prate
=
prate
;
dss
.
cache_dss_cinfo
=
best_dss
;
dss
.
cache_dispc_cinfo
=
best_dispc
;
return
0
;
}
void
dss_set_venc_output
(
enum
omap_dss_venc_type
type
)
{
int
l
=
0
;
...
...
@@ -767,13 +696,11 @@ int dss_dpi_select_source(enum omap_channel channel)
static
int
dss_get_clocks
(
void
)
{
struct
clk
*
clk
;
int
r
;
clk
=
clk_get
(
&
dss
.
pdev
->
dev
,
"fck"
);
clk
=
devm_
clk_get
(
&
dss
.
pdev
->
dev
,
"fck"
);
if
(
IS_ERR
(
clk
))
{
DSSERR
(
"can't get clock fck
\n
"
);
r
=
PTR_ERR
(
clk
);
goto
err
;
return
PTR_ERR
(
clk
);
}
dss
.
dss_clk
=
clk
;
...
...
@@ -782,8 +709,7 @@ static int dss_get_clocks(void)
clk
=
clk_get
(
NULL
,
dss
.
feat
->
clk_name
);
if
(
IS_ERR
(
clk
))
{
DSSERR
(
"Failed to get %s
\n
"
,
dss
.
feat
->
clk_name
);
r
=
PTR_ERR
(
clk
);
goto
err
;
return
PTR_ERR
(
clk
);
}
}
else
{
clk
=
NULL
;
...
...
@@ -792,21 +718,12 @@ static int dss_get_clocks(void)
dss
.
dpll4_m4_ck
=
clk
;
return
0
;
err:
if
(
dss
.
dss_clk
)
clk_put
(
dss
.
dss_clk
);
if
(
dss
.
dpll4_m4_ck
)
clk_put
(
dss
.
dpll4_m4_ck
);
return
r
;
}
static
void
dss_put_clocks
(
void
)
{
if
(
dss
.
dpll4_m4_ck
)
clk_put
(
dss
.
dpll4_m4_ck
);
clk_put
(
dss
.
dss_clk
);
}
static
int
dss_runtime_get
(
void
)
...
...
drivers/video/omap2/dss/dss.h
View file @
3d62fe5b
...
...
@@ -268,8 +268,9 @@ void dss_set_dac_pwrdn_bgz(bool enable);
unsigned
long
dss_get_dpll4_rate
(
void
);
int
dss_calc_clock_rates
(
struct
dss_clock_info
*
cinfo
);
int
dss_set_clock_div
(
struct
dss_clock_info
*
cinfo
);
int
dss_calc_clock_div
(
unsigned
long
req_pck
,
struct
dss_clock_info
*
dss_cinfo
,
struct
dispc_clock_info
*
dispc_cinfo
);
typedef
bool
(
*
dss_div_calc_func
)(
int
fckd
,
unsigned
long
fck
,
void
*
data
);
bool
dss_div_calc
(
unsigned
long
fck_min
,
dss_div_calc_func
func
,
void
*
data
);
/* SDI */
int
sdi_init_platform_driver
(
void
)
__init
;
...
...
@@ -292,12 +293,21 @@ void dsi_dump_clocks(struct seq_file *s);
void
dsi_irq_handler
(
void
);
u8
dsi_get_pixel_size
(
enum
omap_dss_dsi_pixel_format
fmt
);
unsigned
long
dsi_get_pll_clkin
(
struct
platform_device
*
dsidev
);
typedef
bool
(
*
dsi_pll_calc_func
)(
int
regn
,
int
regm
,
unsigned
long
fint
,
unsigned
long
pll
,
void
*
data
);
typedef
bool
(
*
dsi_hsdiv_calc_func
)(
int
regm_dispc
,
unsigned
long
dispc
,
void
*
data
);
bool
dsi_hsdiv_calc
(
struct
platform_device
*
dsidev
,
unsigned
long
pll
,
unsigned
long
out_min
,
dsi_hsdiv_calc_func
func
,
void
*
data
);
bool
dsi_pll_calc
(
struct
platform_device
*
dsidev
,
unsigned
long
clkin
,
unsigned
long
pll_min
,
unsigned
long
pll_max
,
dsi_pll_calc_func
func
,
void
*
data
);
unsigned
long
dsi_get_pll_hsdiv_dispc_rate
(
struct
platform_device
*
dsidev
);
int
dsi_pll_set_clock_div
(
struct
platform_device
*
dsidev
,
struct
dsi_clock_info
*
cinfo
);
int
dsi_pll_calc_clock_div_pck
(
struct
platform_device
*
dsidev
,
unsigned
long
req_pck
,
struct
dsi_clock_info
*
cinfo
,
struct
dispc_clock_info
*
dispc_cinfo
);
int
dsi_pll_init
(
struct
platform_device
*
dsidev
,
bool
enable_hsclk
,
bool
enable_hsdiv
);
void
dsi_pll_uninit
(
struct
platform_device
*
dsidev
,
bool
disconnect_lanes
);
...
...
@@ -328,14 +338,6 @@ static inline int dsi_pll_set_clock_div(struct platform_device *dsidev,
WARN
(
"%s: DSI not compiled in
\n
"
,
__func__
);
return
-
ENODEV
;
}
static
inline
int
dsi_pll_calc_clock_div_pck
(
struct
platform_device
*
dsidev
,
unsigned
long
req_pck
,
struct
dsi_clock_info
*
dsi_cinfo
,
struct
dispc_clock_info
*
dispc_cinfo
)
{
WARN
(
"%s: DSI not compiled in
\n
"
,
__func__
);
return
-
ENODEV
;
}
static
inline
int
dsi_pll_init
(
struct
platform_device
*
dsidev
,
bool
enable_hsclk
,
bool
enable_hsdiv
)
{
...
...
@@ -376,11 +378,15 @@ void dispc_enable_fifomerge(bool enable);
void
dispc_enable_gamma_table
(
bool
enable
);
void
dispc_set_loadmode
(
enum
omap_dss_load_mode
mode
);
typedef
bool
(
*
dispc_div_calc_func
)(
int
lckd
,
int
pckd
,
unsigned
long
lck
,
unsigned
long
pck
,
void
*
data
);
bool
dispc_div_calc
(
unsigned
long
dispc
,
unsigned
long
pck_min
,
unsigned
long
pck_max
,
dispc_div_calc_func
func
,
void
*
data
);
bool
dispc_mgr_timings_ok
(
enum
omap_channel
channel
,
const
struct
omap_video_timings
*
timings
);
unsigned
long
dispc_fclk_rate
(
void
);
void
dispc_find_clk_divs
(
unsigned
long
req_pck
,
unsigned
long
fck
,
struct
dispc_clock_info
*
cinfo
);
int
dispc_calc_clock_rates
(
unsigned
long
dispc_fclk_rate
,
struct
dispc_clock_info
*
cinfo
);
...
...
drivers/video/omap2/dss/dss_features.c
View file @
3d62fe5b
...
...
@@ -414,7 +414,7 @@ static const char * const omap5_dss_clk_source_names[] = {
};
static
const
struct
dss_param_range
omap2_dss_param_range
[]
=
{
[
FEAT_PARAM_DSS_FCK
]
=
{
0
,
1
7
3000000
},
[
FEAT_PARAM_DSS_FCK
]
=
{
0
,
1
3
3000000
},
[
FEAT_PARAM_DSS_PCD
]
=
{
2
,
255
},
[
FEAT_PARAM_DSIPLL_REGN
]
=
{
0
,
0
},
[
FEAT_PARAM_DSIPLL_REGM
]
=
{
0
,
0
},
...
...
@@ -459,15 +459,15 @@ static const struct dss_param_range omap4_dss_param_range[] = {
};
static
const
struct
dss_param_range
omap5_dss_param_range
[]
=
{
[
FEAT_PARAM_DSS_FCK
]
=
{
0
,
20
000
0000
},
[
FEAT_PARAM_DSS_FCK
]
=
{
0
,
20
925
0000
},
[
FEAT_PARAM_DSS_PCD
]
=
{
1
,
255
},
[
FEAT_PARAM_DSIPLL_REGN
]
=
{
0
,
(
1
<<
8
)
-
1
},
[
FEAT_PARAM_DSIPLL_REGM
]
=
{
0
,
(
1
<<
12
)
-
1
},
[
FEAT_PARAM_DSIPLL_REGM_DISPC
]
=
{
0
,
(
1
<<
5
)
-
1
},
[
FEAT_PARAM_DSIPLL_REGM_DSI
]
=
{
0
,
(
1
<<
5
)
-
1
},
[
FEAT_PARAM_DSIPLL_FINT
]
=
{
500000
,
25
00000
},
[
FEAT_PARAM_DSIPLL_FINT
]
=
{
150000
,
520
00000
},
[
FEAT_PARAM_DSIPLL_LPDIV
]
=
{
0
,
(
1
<<
13
)
-
1
},
[
FEAT_PARAM_DSI_FCK
]
=
{
0
,
17000
0000
},
[
FEAT_PARAM_DSI_FCK
]
=
{
0
,
20925
0000
},
[
FEAT_PARAM_DOWNSCALE
]
=
{
1
,
4
},
[
FEAT_PARAM_LINEWIDTH
]
=
{
1
,
2048
},
};
...
...
drivers/video/omap2/dss/hdmi.c
View file @
3d62fe5b
...
...
@@ -472,17 +472,12 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy,
* Input clock is predivided by N + 1
* out put of which is reference clk
*/
if
(
dssdev
->
clocks
.
hdmi
.
regn
==
0
)
pi
->
regn
=
HDMI_DEFAULT_REGN
;
else
pi
->
regn
=
dssdev
->
clocks
.
hdmi
.
regn
;
pi
->
regn
=
HDMI_DEFAULT_REGN
;
refclk
=
clkin
/
pi
->
regn
;
if
(
dssdev
->
clocks
.
hdmi
.
regm2
==
0
)
pi
->
regm2
=
HDMI_DEFAULT_REGM2
;
else
pi
->
regm2
=
dssdev
->
clocks
.
hdmi
.
regm2
;
pi
->
regm2
=
HDMI_DEFAULT_REGM2
;
/*
* multiplier is pixel_clk/ref_clk
...
...
@@ -804,7 +799,7 @@ static int hdmi_get_clocks(struct platform_device *pdev)
{
struct
clk
*
clk
;
clk
=
clk_get
(
&
pdev
->
dev
,
"sys_clk"
);
clk
=
devm_
clk_get
(
&
pdev
->
dev
,
"sys_clk"
);
if
(
IS_ERR
(
clk
))
{
DSSERR
(
"can't get sys_clk
\n
"
);
return
PTR_ERR
(
clk
);
...
...
@@ -815,12 +810,6 @@ static int hdmi_get_clocks(struct platform_device *pdev)
return
0
;
}
static
void
hdmi_put_clocks
(
void
)
{
if
(
hdmi
.
sys_clk
)
clk_put
(
hdmi
.
sys_clk
);
}
#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
int
hdmi_compute_acr
(
u32
sample_freq
,
u32
*
n
,
u32
*
cts
)
{
...
...
@@ -1017,8 +1006,6 @@ static void __init hdmi_probe_pdata(struct platform_device *pdev)
hdmi
.
ls_oe_gpio
=
priv
->
ls_oe_gpio
;
hdmi
.
hpd_gpio
=
priv
->
hpd_gpio
;
dssdev
->
channel
=
OMAP_DSS_CHANNEL_DIGIT
;
r
=
hdmi_init_display
(
dssdev
);
if
(
r
)
{
DSSERR
(
"device %s init failed: %d
\n
"
,
dssdev
->
name
,
r
);
...
...
@@ -1051,6 +1038,8 @@ static void __init hdmi_init_output(struct platform_device *pdev)
out
->
pdev
=
pdev
;
out
->
id
=
OMAP_DSS_OUTPUT_HDMI
;
out
->
type
=
OMAP_DISPLAY_TYPE_HDMI
;
out
->
name
=
"hdmi.0"
;
out
->
dispc_channel
=
OMAP_DSS_CHANNEL_DIGIT
;
dss_register_output
(
out
);
}
...
...
@@ -1097,23 +1086,19 @@ static int __init omapdss_hdmihw_probe(struct platform_device *pdev)
hdmi
.
ip_data
.
pll_offset
=
HDMI_PLLCTRL
;
hdmi
.
ip_data
.
phy_offset
=
HDMI_PHY
;
hdmi_init_output
(
pdev
);
r
=
hdmi_panel_init
();
if
(
r
)
{
DSSERR
(
"can't init panel
\n
"
);
goto
err_panel_init
;
return
r
;
}
dss_debugfs_create_file
(
"hdmi"
,
hdmi_dump_regs
);
hdmi_init_output
(
pdev
);
hdmi_probe_pdata
(
pdev
);
return
0
;
err_panel_init:
hdmi_put_clocks
();
return
r
;
}
static
int
__exit
hdmi_remove_child
(
struct
device
*
dev
,
void
*
data
)
...
...
@@ -1135,8 +1120,6 @@ static int __exit omapdss_hdmihw_remove(struct platform_device *pdev)
pm_runtime_disable
(
&
pdev
->
dev
);
hdmi_put_clocks
();
return
0
;
}
...
...
drivers/video/omap2/dss/output.c
View file @
3d62fe5b
...
...
@@ -113,6 +113,7 @@ struct omap_dss_output *omap_dss_get_output(enum omap_dss_output_id id)
return
NULL
;
}
EXPORT_SYMBOL
(
omap_dss_get_output
);
static
const
struct
dss_mgr_ops
*
dss_mgr_ops
;
...
...
drivers/video/omap2/dss/rfbi.c
View file @
3d62fe5b
...
...
@@ -1025,6 +1025,8 @@ static void __init rfbi_init_output(struct platform_device *pdev)
out
->
pdev
=
pdev
;
out
->
id
=
OMAP_DSS_OUTPUT_DBI
;
out
->
type
=
OMAP_DISPLAY_TYPE_DBI
;
out
->
name
=
"rfbi.0"
;
out
->
dispc_channel
=
OMAP_DSS_CHANNEL_LCD
;
dss_register_output
(
out
);
}
...
...
drivers/video/omap2/dss/sdi.c
View file @
3d62fe5b
...
...
@@ -41,6 +41,72 @@ static struct {
struct
omap_dss_output
output
;
}
sdi
;
struct
sdi_clk_calc_ctx
{
unsigned
long
pck_min
,
pck_max
;
struct
dss_clock_info
dss_cinfo
;
struct
dispc_clock_info
dispc_cinfo
;
};
static
bool
dpi_calc_dispc_cb
(
int
lckd
,
int
pckd
,
unsigned
long
lck
,
unsigned
long
pck
,
void
*
data
)
{
struct
sdi_clk_calc_ctx
*
ctx
=
data
;
ctx
->
dispc_cinfo
.
lck_div
=
lckd
;
ctx
->
dispc_cinfo
.
pck_div
=
pckd
;
ctx
->
dispc_cinfo
.
lck
=
lck
;
ctx
->
dispc_cinfo
.
pck
=
pck
;
return
true
;
}
static
bool
dpi_calc_dss_cb
(
int
fckd
,
unsigned
long
fck
,
void
*
data
)
{
struct
sdi_clk_calc_ctx
*
ctx
=
data
;
ctx
->
dss_cinfo
.
fck
=
fck
;
ctx
->
dss_cinfo
.
fck_div
=
fckd
;
return
dispc_div_calc
(
fck
,
ctx
->
pck_min
,
ctx
->
pck_max
,
dpi_calc_dispc_cb
,
ctx
);
}
static
int
sdi_calc_clock_div
(
unsigned
long
pclk
,
struct
dss_clock_info
*
dss_cinfo
,
struct
dispc_clock_info
*
dispc_cinfo
)
{
int
i
;
struct
sdi_clk_calc_ctx
ctx
;
/*
* DSS fclk gives us very few possibilities, so finding a good pixel
* clock may not be possible. We try multiple times to find the clock,
* each time widening the pixel clock range we look for, up to
* +/- 1MHz.
*/
for
(
i
=
0
;
i
<
10
;
++
i
)
{
bool
ok
;
memset
(
&
ctx
,
0
,
sizeof
(
ctx
));
if
(
pclk
>
1000
*
i
*
i
*
i
)
ctx
.
pck_min
=
max
(
pclk
-
1000
*
i
*
i
*
i
,
0lu
);
else
ctx
.
pck_min
=
0
;
ctx
.
pck_max
=
pclk
+
1000
*
i
*
i
*
i
;
ok
=
dss_div_calc
(
ctx
.
pck_min
,
dpi_calc_dss_cb
,
&
ctx
);
if
(
ok
)
{
*
dss_cinfo
=
ctx
.
dss_cinfo
;
*
dispc_cinfo
=
ctx
.
dispc_cinfo
;
return
0
;
}
}
return
-
EINVAL
;
}
static
void
sdi_config_lcd_manager
(
struct
omap_dss_device
*
dssdev
)
{
struct
omap_overlay_manager
*
mgr
=
dssdev
->
output
->
manager
;
...
...
@@ -88,7 +154,7 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
t
->
data_pclk_edge
=
OMAPDSS_DRIVE_SIG_RISING_EDGE
;
t
->
sync_pclk_edge
=
OMAPDSS_DRIVE_SIG_RISING_EDGE
;
r
=
dss
_calc_clock_div
(
t
->
pixel_clock
*
1000
,
&
dss_cinfo
,
&
dispc_cinfo
);
r
=
sdi
_calc_clock_div
(
t
->
pixel_clock
*
1000
,
&
dss_cinfo
,
&
dispc_cinfo
);
if
(
r
)
goto
err_calc_clock_div
;
...
...
@@ -278,6 +344,8 @@ static void __init sdi_init_output(struct platform_device *pdev)
out
->
pdev
=
pdev
;
out
->
id
=
OMAP_DSS_OUTPUT_SDI
;
out
->
type
=
OMAP_DISPLAY_TYPE_SDI
;
out
->
name
=
"sdi.0"
;
out
->
dispc_channel
=
OMAP_DSS_CHANNEL_LCD
;
dss_register_output
(
out
);
}
...
...
drivers/video/omap2/dss/venc.c
View file @
3d62fe5b
...
...
@@ -712,7 +712,7 @@ static int venc_get_clocks(struct platform_device *pdev)
struct
clk
*
clk
;
if
(
dss_has_feature
(
FEAT_VENC_REQUIRES_TV_DAC_CLK
))
{
clk
=
clk_get
(
&
pdev
->
dev
,
"tv_dac_clk"
);
clk
=
devm_
clk_get
(
&
pdev
->
dev
,
"tv_dac_clk"
);
if
(
IS_ERR
(
clk
))
{
DSSERR
(
"can't get tv_dac_clk
\n
"
);
return
PTR_ERR
(
clk
);
...
...
@@ -726,12 +726,6 @@ static int venc_get_clocks(struct platform_device *pdev)
return
0
;
}
static
void
venc_put_clocks
(
void
)
{
if
(
venc
.
tv_dac_clk
)
clk_put
(
venc
.
tv_dac_clk
);
}
static
struct
omap_dss_device
*
__init
venc_find_dssdev
(
struct
platform_device
*
pdev
)
{
struct
omap_dss_board_info
*
pdata
=
pdev
->
dev
.
platform_data
;
...
...
@@ -777,8 +771,6 @@ static void __init venc_probe_pdata(struct platform_device *vencdev)
dss_copy_device_pdata
(
dssdev
,
plat_dssdev
);
dssdev
->
channel
=
OMAP_DSS_CHANNEL_DIGIT
;
r
=
venc_init_display
(
dssdev
);
if
(
r
)
{
DSSERR
(
"device %s init failed: %d
\n
"
,
dssdev
->
name
,
r
);
...
...
@@ -810,6 +802,8 @@ static void __init venc_init_output(struct platform_device *pdev)
out
->
pdev
=
pdev
;
out
->
id
=
OMAP_DSS_OUTPUT_VENC
;
out
->
type
=
OMAP_DISPLAY_TYPE_VENC
;
out
->
name
=
"venc.0"
;
out
->
dispc_channel
=
OMAP_DSS_CHANNEL_DIGIT
;
dss_register_output
(
out
);
}
...
...
@@ -877,7 +871,6 @@ static int __init omap_venchw_probe(struct platform_device *pdev)
err_panel_init:
err_runtime_get:
pm_runtime_disable
(
&
pdev
->
dev
);
venc_put_clocks
();
return
r
;
}
...
...
@@ -895,7 +888,6 @@ static int __exit omap_venchw_remove(struct platform_device *pdev)
venc_uninit_output
(
pdev
);
pm_runtime_disable
(
&
pdev
->
dev
);
venc_put_clocks
();
return
0
;
}
...
...
drivers/video/omap2/omapfb/omapfb-main.c
View file @
3d62fe5b
...
...
@@ -2388,7 +2388,7 @@ static int omapfb_init_connections(struct omapfb2_device *fbdev,
struct
omap_dss_device
*
dssdev
=
fbdev
->
displays
[
i
].
dssdev
;
struct
omap_dss_output
*
out
=
dssdev
->
output
;
mgr
=
omap_dss_get_overlay_manager
(
dssdev
->
channel
);
mgr
=
omap_dss_get_overlay_manager
(
out
->
dispc_
channel
);
if
(
!
mgr
||
!
out
)
continue
;
...
...
include/video/omapdss.h
View file @
3d62fe5b
...
...
@@ -257,10 +257,31 @@ void rfbi_bus_unlock(void);
/* DSI */
enum
omap_dss_dsi_trans_mode
{
/* Sync Pulses: both sync start and end packets sent */
OMAP_DSS_DSI_PULSE_MODE
,
/* Sync Events: only sync start packets sent */
OMAP_DSS_DSI_EVENT_MODE
,
/* Burst: only sync start packets sent, pixels are time compressed */
OMAP_DSS_DSI_BURST_MODE
,
};
struct
omap_dss_dsi_videomode_timings
{
unsigned
long
hsclk
;
unsigned
ndl
;
unsigned
bitspp
;
/* pixels */
u16
hact
;
/* lines */
u16
vact
;
/* DSI video mode blanking data */
/* Unit: byte clock cycles */
u16
hss
;
u16
hsa
;
u16
hse
;
u16
hfp
;
u16
hbp
;
/* Unit: line clocks */
...
...
@@ -274,14 +295,24 @@ struct omap_dss_dsi_videomode_timings {
int
hbp_blanking_mode
;
int
hfp_blanking_mode
;
/* Video port sync events */
bool
vp_vsync_end
;
bool
vp_hsync_end
;
enum
omap_dss_dsi_trans_mode
trans_mode
;
bool
ddr_clk_always_on
;
int
window_sync
;
};
struct
omap_dss_dsi_config
{
enum
omap_dss_dsi_mode
mode
;
enum
omap_dss_dsi_pixel_format
pixel_format
;
const
struct
omap_video_timings
*
timings
;
unsigned
long
hs_clk_min
,
hs_clk_max
;
unsigned
long
lp_clk_min
,
lp_clk_max
;
bool
ddr_clk_always_on
;
enum
omap_dss_dsi_trans_mode
trans_mode
;
};
void
dsi_bus_lock
(
struct
omap_dss_device
*
dssdev
);
void
dsi_bus_unlock
(
struct
omap_dss_device
*
dssdev
);
int
dsi_vc_dcs_write
(
struct
omap_dss_device
*
dssdev
,
int
channel
,
u8
*
data
,
...
...
@@ -541,9 +572,14 @@ struct omap_dss_writeback_info {
struct
omap_dss_output
{
struct
list_head
list
;
const
char
*
name
;
/* display type supported by the output */
enum
omap_display_type
type
;
/* DISPC channel for this output */
enum
omap_channel
dispc_channel
;
/* output instance */
enum
omap_dss_output_id
id
;
...
...
@@ -561,6 +597,7 @@ struct omap_dss_device {
enum
omap_display_type
type
;
/* obsolete, to be removed */
enum
omap_channel
channel
;
union
{
...
...
@@ -590,41 +627,11 @@ struct omap_dss_device {
}
venc
;
}
phy
;
struct
{
struct
{
struct
{
u16
lck_div
;
u16
pck_div
;
enum
omap_dss_clk_source
lcd_clk_src
;
}
channel
;
enum
omap_dss_clk_source
dispc_fclk_src
;
}
dispc
;
struct
{
/* regn is one greater than TRM's REGN value */
u16
regn
;
u16
regm
;
u16
regm_dispc
;
u16
regm_dsi
;
u16
lp_clk_div
;
enum
omap_dss_clk_source
dsi_fclk_src
;
}
dsi
;
struct
{
/* regn is one greater than TRM's REGN value */
u16
regn
;
u16
regm2
;
}
hdmi
;
}
clocks
;
struct
{
struct
omap_video_timings
timings
;
enum
omap_dss_dsi_pixel_format
dsi_pix_fmt
;
enum
omap_dss_dsi_mode
dsi_mode
;
struct
omap_dss_dsi_videomode_timings
dsi_vm_timings
;
}
panel
;
struct
{
...
...
@@ -829,15 +836,8 @@ int dispc_ovl_setup(enum omap_plane plane, const struct omap_overlay_info *oi,
void
omapdss_dsi_vc_enable_hs
(
struct
omap_dss_device
*
dssdev
,
int
channel
,
bool
enable
);
int
omapdss_dsi_enable_te
(
struct
omap_dss_device
*
dssdev
,
bool
enable
);
void
omapdss_dsi_set_timings
(
struct
omap_dss_device
*
dssdev
,
struct
omap_video_timings
*
timings
);
void
omapdss_dsi_set_size
(
struct
omap_dss_device
*
dssdev
,
u16
w
,
u16
h
);
void
omapdss_dsi_set_pixel_format
(
struct
omap_dss_device
*
dssdev
,
enum
omap_dss_dsi_pixel_format
fmt
);
void
omapdss_dsi_set_operation_mode
(
struct
omap_dss_device
*
dssdev
,
enum
omap_dss_dsi_mode
mode
);
void
omapdss_dsi_set_videomode_timings
(
struct
omap_dss_device
*
dssdev
,
struct
omap_dss_dsi_videomode_timings
*
timings
);
int
omapdss_dsi_set_config
(
struct
omap_dss_device
*
dssdev
,
const
struct
omap_dss_dsi_config
*
config
);
int
omap_dsi_update
(
struct
omap_dss_device
*
dssdev
,
int
channel
,
void
(
*
callback
)(
int
,
void
*
),
void
*
data
);
...
...
@@ -846,8 +846,6 @@ int omap_dsi_set_vc_id(struct omap_dss_device *dssdev, int channel, int vc_id);
void
omap_dsi_release_vc
(
struct
omap_dss_device
*
dssdev
,
int
channel
);
int
omapdss_dsi_configure_pins
(
struct
omap_dss_device
*
dssdev
,
const
struct
omap_dsi_pin_config
*
pin_cfg
);
int
omapdss_dsi_set_clocks
(
struct
omap_dss_device
*
dssdev
,
unsigned
long
ddr_clk
,
unsigned
long
lp_clk
);
int
omapdss_dsi_display_enable
(
struct
omap_dss_device
*
dssdev
);
void
omapdss_dsi_display_disable
(
struct
omap_dss_device
*
dssdev
,
...
...
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