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
8edbeb6e
Commit
8edbeb6e
authored
Aug 30, 2011
by
Florian Tobias Schandinat
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'sh-mobile-lcdc' of
git://linuxtv.org/pinchartl/fbdev
into fbdev-next
parents
d4a7dbfd
8a20974f
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
556 additions
and
427 deletions
+556
-427
arch/arm/mach-shmobile/board-mackerel.c
arch/arm/mach-shmobile/board-mackerel.c
+1
-0
drivers/video/sh_mobile_lcdcfb.c
drivers/video/sh_mobile_lcdcfb.c
+263
-329
drivers/video/sh_mobile_lcdcfb.h
drivers/video/sh_mobile_lcdcfb.h
+11
-1
drivers/video/sh_mobile_meram.c
drivers/video/sh_mobile_meram.c
+165
-37
drivers/video/sh_mobile_meram.h
drivers/video/sh_mobile_meram.h
+0
-41
include/video/sh_mobile_lcdc.h
include/video/sh_mobile_lcdc.h
+116
-19
No files found.
arch/arm/mach-shmobile/board-mackerel.c
View file @
8edbeb6e
...
...
@@ -1583,6 +1583,7 @@ static void __init mackerel_init(void)
sh7372_add_device_to_domain
(
&
sh7372_a4lc
,
&
lcdc_device
);
sh7372_add_device_to_domain
(
&
sh7372_a4lc
,
&
hdmi_lcdc_device
);
sh7372_add_device_to_domain
(
&
sh7372_a4lc
,
&
meram_device
);
sh7372_add_device_to_domain
(
&
sh7372_a4mp
,
&
fsi_device
);
hdmi_init_pm_clock
();
...
...
drivers/video/sh_mobile_lcdcfb.c
View file @
8edbeb6e
...
...
@@ -24,39 +24,14 @@
#include <linux/backlight.h>
#include <linux/gpio.h>
#include <video/sh_mobile_lcdc.h>
#include <video/sh_mobile_meram.h>
#include <linux/atomic.h>
#include "sh_mobile_lcdcfb.h"
#include "sh_mobile_meram.h"
#define SIDE_B_OFFSET 0x1000
#define MIRROR_OFFSET 0x2000
/* shared registers */
#define _LDDCKR 0x410
#define _LDDCKSTPR 0x414
#define _LDINTR 0x468
#define _LDSR 0x46c
#define _LDCNT1R 0x470
#define _LDCNT2R 0x474
#define _LDRCNTR 0x478
#define _LDDDSR 0x47c
#define _LDDWD0R 0x800
#define _LDDRDR 0x840
#define _LDDWAR 0x900
#define _LDDRAR 0x904
/* shared registers and their order for context save/restore */
static
int
lcdc_shared_regs
[]
=
{
_LDDCKR
,
_LDDCKSTPR
,
_LDINTR
,
_LDDDSR
,
_LDCNT1R
,
_LDCNT2R
,
};
#define NR_SHARED_REGS ARRAY_SIZE(lcdc_shared_regs)
#define MAX_XRES 1920
#define MAX_YRES 1080
...
...
@@ -98,22 +73,6 @@ static unsigned long lcdc_offs_sublcd[NR_CH_REGS] = {
[
LDPMR
]
=
0x63c
,
};
#define START_LCDC 0x00000001
#define LCDC_RESET 0x00000100
#define DISPLAY_BEU 0x00000008
#define LCDC_ENABLE 0x00000001
#define LDINTR_FE 0x00000400
#define LDINTR_VSE 0x00000200
#define LDINTR_VEE 0x00000100
#define LDINTR_FS 0x00000004
#define LDINTR_VSS 0x00000002
#define LDINTR_VES 0x00000001
#define LDRCNTR_SRS 0x00020000
#define LDRCNTR_SRC 0x00010000
#define LDRCNTR_MRS 0x00000002
#define LDRCNTR_MRC 0x00000001
#define LDSR_MRS 0x00000100
static
const
struct
fb_videomode
default_720p
=
{
.
name
=
"HDMI 720p"
,
.
xres
=
1280
,
...
...
@@ -141,7 +100,6 @@ struct sh_mobile_lcdc_priv {
unsigned
long
lddckr
;
struct
sh_mobile_lcdc_chan
ch
[
2
];
struct
notifier_block
notifier
;
unsigned
long
saved_shared_regs
[
NR_SHARED_REGS
];
int
started
;
int
forced_bpp
;
/* 2 channel LCDC must share bpp setting */
struct
sh_mobile_meram_info
*
meram_dev
;
...
...
@@ -218,33 +176,36 @@ static void lcdc_sys_write_index(void *handle, unsigned long data)
{
struct
sh_mobile_lcdc_chan
*
ch
=
handle
;
lcdc_write
(
ch
->
lcdc
,
_LDDWD0R
,
data
|
0x10000000
);
lcdc_wait_bit
(
ch
->
lcdc
,
_LDSR
,
2
,
0
);
lcdc_write
(
ch
->
lcdc
,
_LDDWAR
,
1
|
(
lcdc_chan_is_sublcd
(
ch
)
?
2
:
0
));
lcdc_wait_bit
(
ch
->
lcdc
,
_LDSR
,
2
,
0
);
lcdc_write
(
ch
->
lcdc
,
_LDDWD0R
,
data
|
LDDWDxR_WDACT
);
lcdc_wait_bit
(
ch
->
lcdc
,
_LDSR
,
LDSR_AS
,
0
);
lcdc_write
(
ch
->
lcdc
,
_LDDWAR
,
LDDWAR_WA
|
(
lcdc_chan_is_sublcd
(
ch
)
?
2
:
0
));
lcdc_wait_bit
(
ch
->
lcdc
,
_LDSR
,
LDSR_AS
,
0
);
}
static
void
lcdc_sys_write_data
(
void
*
handle
,
unsigned
long
data
)
{
struct
sh_mobile_lcdc_chan
*
ch
=
handle
;
lcdc_write
(
ch
->
lcdc
,
_LDDWD0R
,
data
|
0x11000000
);
lcdc_wait_bit
(
ch
->
lcdc
,
_LDSR
,
2
,
0
);
lcdc_write
(
ch
->
lcdc
,
_LDDWAR
,
1
|
(
lcdc_chan_is_sublcd
(
ch
)
?
2
:
0
));
lcdc_wait_bit
(
ch
->
lcdc
,
_LDSR
,
2
,
0
);
lcdc_write
(
ch
->
lcdc
,
_LDDWD0R
,
data
|
LDDWDxR_WDACT
|
LDDWDxR_RSW
);
lcdc_wait_bit
(
ch
->
lcdc
,
_LDSR
,
LDSR_AS
,
0
);
lcdc_write
(
ch
->
lcdc
,
_LDDWAR
,
LDDWAR_WA
|
(
lcdc_chan_is_sublcd
(
ch
)
?
2
:
0
));
lcdc_wait_bit
(
ch
->
lcdc
,
_LDSR
,
LDSR_AS
,
0
);
}
static
unsigned
long
lcdc_sys_read_data
(
void
*
handle
)
{
struct
sh_mobile_lcdc_chan
*
ch
=
handle
;
lcdc_write
(
ch
->
lcdc
,
_LDDRDR
,
0x01000000
);
lcdc_wait_bit
(
ch
->
lcdc
,
_LDSR
,
2
,
0
);
lcdc_write
(
ch
->
lcdc
,
_LDDRAR
,
1
|
(
lcdc_chan_is_sublcd
(
ch
)
?
2
:
0
));
lcdc_write
(
ch
->
lcdc
,
_LDDRDR
,
LDDRDR_RSR
);
lcdc_wait_bit
(
ch
->
lcdc
,
_LDSR
,
LDSR_AS
,
0
);
lcdc_write
(
ch
->
lcdc
,
_LDDRAR
,
LDDRAR_RA
|
(
lcdc_chan_is_sublcd
(
ch
)
?
2
:
0
));
udelay
(
1
);
lcdc_wait_bit
(
ch
->
lcdc
,
_LDSR
,
2
,
0
);
lcdc_wait_bit
(
ch
->
lcdc
,
_LDSR
,
LDSR_AS
,
0
);
return
lcdc_read
(
ch
->
lcdc
,
_LDDRDR
)
&
0x3ffff
;
return
lcdc_read
(
ch
->
lcdc
,
_LDDRDR
)
&
LDDRDR_DRD_MASK
;
}
struct
sh_mobile_lcdc_sys_bus_ops
sh_mobile_lcdc_sys_bus_ops
=
{
...
...
@@ -256,18 +217,22 @@ struct sh_mobile_lcdc_sys_bus_ops sh_mobile_lcdc_sys_bus_ops = {
static
void
sh_mobile_lcdc_clk_on
(
struct
sh_mobile_lcdc_priv
*
priv
)
{
if
(
atomic_inc_and_test
(
&
priv
->
hw_usecnt
))
{
pm_runtime_get_sync
(
priv
->
dev
);
if
(
priv
->
dot_clk
)
clk_enable
(
priv
->
dot_clk
);
pm_runtime_get_sync
(
priv
->
dev
);
if
(
priv
->
meram_dev
&&
priv
->
meram_dev
->
pdev
)
pm_runtime_get_sync
(
&
priv
->
meram_dev
->
pdev
->
dev
);
}
}
static
void
sh_mobile_lcdc_clk_off
(
struct
sh_mobile_lcdc_priv
*
priv
)
{
if
(
atomic_sub_return
(
1
,
&
priv
->
hw_usecnt
)
==
-
1
)
{
if
(
priv
->
meram_dev
&&
priv
->
meram_dev
->
pdev
)
pm_runtime_put_sync
(
&
priv
->
meram_dev
->
pdev
->
dev
);
pm_runtime_put
(
priv
->
dev
);
if
(
priv
->
dot_clk
)
clk_disable
(
priv
->
dot_clk
);
pm_runtime_put
(
priv
->
dev
);
}
}
...
...
@@ -319,13 +284,13 @@ static void sh_mobile_lcdc_deferred_io(struct fb_info *info,
if
(
bcfg
->
start_transfer
)
bcfg
->
start_transfer
(
bcfg
->
board_data
,
ch
,
&
sh_mobile_lcdc_sys_bus_ops
);
lcdc_write_chan
(
ch
,
LDSM2R
,
1
);
lcdc_write_chan
(
ch
,
LDSM2R
,
LDSM2R_OSTRG
);
dma_unmap_sg
(
info
->
dev
,
ch
->
sglist
,
nr_pages
,
DMA_TO_DEVICE
);
}
else
{
if
(
bcfg
->
start_transfer
)
bcfg
->
start_transfer
(
bcfg
->
board_data
,
ch
,
&
sh_mobile_lcdc_sys_bus_ops
);
lcdc_write_chan
(
ch
,
LDSM2R
,
1
);
lcdc_write_chan
(
ch
,
LDSM2R
,
LDSM2R_OSTRG
);
}
}
...
...
@@ -341,22 +306,16 @@ static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data)
{
struct
sh_mobile_lcdc_priv
*
priv
=
data
;
struct
sh_mobile_lcdc_chan
*
ch
;
unsigned
long
tmp
;
unsigned
long
ldintr
;
int
is_sub
;
int
k
;
/* acknowledge interrupt */
ldintr
=
tmp
=
lcdc_read
(
priv
,
_LDINTR
);
/*
* disable further VSYNC End IRQs, preserve all other enabled IRQs,
* write 0 to bits 0-6 to ack all triggered IRQs.
*/
tmp
&=
0xffffff00
&
~
LDINTR_VEE
;
lcdc_write
(
priv
,
_LDINTR
,
tmp
);
/* Acknowledge interrupts and disable further VSYNC End IRQs. */
ldintr
=
lcdc_read
(
priv
,
_LDINTR
);
lcdc_write
(
priv
,
_LDINTR
,
(
ldintr
^
LDINTR_STATUS_MASK
)
&
~
LDINTR_VEE
);
/* figure out if this interrupt is for main or sub lcd */
is_sub
=
(
lcdc_read
(
priv
,
_LDSR
)
&
(
1
<<
10
)
)
?
1
:
0
;
is_sub
=
(
lcdc_read
(
priv
,
_LDSR
)
&
LDSR_MSS
)
?
1
:
0
;
/* wake up channel and disable clocks */
for
(
k
=
0
;
k
<
ARRAY_SIZE
(
priv
->
ch
);
k
++
)
{
...
...
@@ -365,7 +324,7 @@ static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data)
if
(
!
ch
->
enabled
)
continue
;
/* Frame
Start
*/
/* Frame
End
*/
if
(
ldintr
&
LDINTR_FS
)
{
if
(
is_sub
==
lcdc_chan_is_sublcd
(
ch
))
{
ch
->
frame_end
=
1
;
...
...
@@ -391,16 +350,17 @@ static void sh_mobile_lcdc_start_stop(struct sh_mobile_lcdc_priv *priv,
/* start or stop the lcdc */
if
(
start
)
lcdc_write
(
priv
,
_LDCNT2R
,
tmp
|
START_LCDC
);
lcdc_write
(
priv
,
_LDCNT2R
,
tmp
|
LDCNT2R_DO
);
else
lcdc_write
(
priv
,
_LDCNT2R
,
tmp
&
~
START_LCDC
);
lcdc_write
(
priv
,
_LDCNT2R
,
tmp
&
~
LDCNT2R_DO
);
/* wait until power is applied/stopped on all channels */
for
(
k
=
0
;
k
<
ARRAY_SIZE
(
priv
->
ch
);
k
++
)
if
(
lcdc_read
(
priv
,
_LDCNT2R
)
&
priv
->
ch
[
k
].
enabled
)
while
(
1
)
{
tmp
=
lcdc_read_chan
(
&
priv
->
ch
[
k
],
LDPMR
)
&
3
;
if
(
start
&&
tmp
==
3
)
tmp
=
lcdc_read_chan
(
&
priv
->
ch
[
k
],
LDPMR
)
&
LDPMR_LPS
;
if
(
start
&&
tmp
==
LDPMR_LPS
)
break
;
if
(
!
start
&&
tmp
==
0
)
break
;
...
...
@@ -418,13 +378,13 @@ static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch)
u32
tmp
;
tmp
=
ch
->
ldmt1r_value
;
tmp
|=
(
var
->
sync
&
FB_SYNC_VERT_HIGH_ACT
)
?
0
:
1
<<
28
;
tmp
|=
(
var
->
sync
&
FB_SYNC_HOR_HIGH_ACT
)
?
0
:
1
<<
27
;
tmp
|=
(
ch
->
cfg
.
flags
&
LCDC_FLAGS_DWPOL
)
?
1
<<
26
:
0
;
tmp
|=
(
ch
->
cfg
.
flags
&
LCDC_FLAGS_DIPOL
)
?
1
<<
25
:
0
;
tmp
|=
(
ch
->
cfg
.
flags
&
LCDC_FLAGS_DAPOL
)
?
1
<<
24
:
0
;
tmp
|=
(
ch
->
cfg
.
flags
&
LCDC_FLAGS_HSCNT
)
?
1
<<
17
:
0
;
tmp
|=
(
ch
->
cfg
.
flags
&
LCDC_FLAGS_DWCNT
)
?
1
<<
16
:
0
;
tmp
|=
(
var
->
sync
&
FB_SYNC_VERT_HIGH_ACT
)
?
0
:
LDMT1R_VPOL
;
tmp
|=
(
var
->
sync
&
FB_SYNC_HOR_HIGH_ACT
)
?
0
:
LDMT1R_HPOL
;
tmp
|=
(
ch
->
cfg
.
flags
&
LCDC_FLAGS_DWPOL
)
?
LDMT1R_DWPOL
:
0
;
tmp
|=
(
ch
->
cfg
.
flags
&
LCDC_FLAGS_DIPOL
)
?
LDMT1R_DIPOL
:
0
;
tmp
|=
(
ch
->
cfg
.
flags
&
LCDC_FLAGS_DAPOL
)
?
LDMT1R_DAPOL
:
0
;
tmp
|=
(
ch
->
cfg
.
flags
&
LCDC_FLAGS_HSCNT
)
?
LDMT1R_HSCNT
:
0
;
tmp
|=
(
ch
->
cfg
.
flags
&
LCDC_FLAGS_DWCNT
)
?
LDMT1R_DWCNT
:
0
;
lcdc_write_chan
(
ch
,
LDMT1R
,
tmp
);
/* setup SYS bus */
...
...
@@ -463,242 +423,239 @@ static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch)
lcdc_write_chan
(
ch
,
LDHAJR
,
tmp
);
}
static
int
sh_mobile_lcdc_start
(
struct
sh_mobile_lcdc_priv
*
priv
)
/*
* __sh_mobile_lcdc_start - Configure and tart the LCDC
* @priv: LCDC device
*
* Configure all enabled channels and start the LCDC device. All external
* devices (clocks, MERAM, panels, ...) are not touched by this function.
*/
static
void
__sh_mobile_lcdc_start
(
struct
sh_mobile_lcdc_priv
*
priv
)
{
struct
sh_mobile_lcdc_chan
*
ch
;
struct
sh_mobile_lcdc_board_cfg
*
board_cfg
;
unsigned
long
tmp
;
int
bpp
=
0
;
unsigned
long
ldddsr
;
int
k
,
m
,
ret
;
/* enable clocks before accessing the hardware */
for
(
k
=
0
;
k
<
ARRAY_SIZE
(
priv
->
ch
);
k
++
)
{
if
(
priv
->
ch
[
k
].
enabled
)
{
sh_mobile_lcdc_clk_on
(
priv
);
if
(
!
bpp
)
bpp
=
priv
->
ch
[
k
].
info
->
var
.
bits_per_pixel
;
}
}
/* reset */
lcdc_write
(
priv
,
_LDCNT2R
,
lcdc_read
(
priv
,
_LDCNT2R
)
|
LCDC_RESET
);
lcdc_wait_bit
(
priv
,
_LDCNT2R
,
LCDC_RESET
,
0
);
/* enable LCDC channels */
tmp
=
lcdc_read
(
priv
,
_LDCNT2R
);
tmp
|=
priv
->
ch
[
0
].
enabled
;
tmp
|=
priv
->
ch
[
1
].
enabled
;
lcdc_write
(
priv
,
_LDCNT2R
,
tmp
);
int
k
,
m
;
/* read data from external memory, avoid using the BEU for now */
lcdc_write
(
priv
,
_LDCNT2R
,
lcdc_read
(
priv
,
_LDCNT2R
)
&
~
DISPLAY_BEU
);
/* Enable LCDC channels. Read data from external memory, avoid using the
* BEU for now.
*/
lcdc_write
(
priv
,
_LDCNT2R
,
priv
->
ch
[
0
].
enabled
|
priv
->
ch
[
1
].
enabled
);
/*
stop the lcdc first
*/
/*
Stop the LCDC first and disable all interrupts.
*/
sh_mobile_lcdc_start_stop
(
priv
,
0
);
lcdc_write
(
priv
,
_LDINTR
,
0
);
/*
configure clocks
*/
/*
Configure power supply, dot clocks and start them.
*/
tmp
=
priv
->
lddckr
;
for
(
k
=
0
;
k
<
ARRAY_SIZE
(
priv
->
ch
);
k
++
)
{
ch
=
&
priv
->
ch
[
k
];
if
(
!
priv
->
ch
[
k
].
enabled
)
if
(
!
ch
->
enabled
)
continue
;
if
(
!
bpp
)
bpp
=
ch
->
info
->
var
.
bits_per_pixel
;
/* Power supply */
lcdc_write_chan
(
ch
,
LDPMR
,
0
);
m
=
ch
->
cfg
.
clock_divider
;
if
(
!
m
)
continue
;
if
(
m
==
1
)
m
=
1
<<
6
;
tmp
|=
m
<<
(
lcdc_chan_is_sublcd
(
ch
)
?
8
:
0
);
/* FIXME: sh7724 can only use 42, 48, 54 and 60 for the divider denominator */
/* FIXME: sh7724 can only use 42, 48, 54 and 60 for the divider
* denominator.
*/
lcdc_write_chan
(
ch
,
LDDCKPAT1R
,
0
);
lcdc_write_chan
(
ch
,
LDDCKPAT2R
,
(
1
<<
(
m
/
2
))
-
1
);
if
(
m
==
1
)
m
=
LDDCKR_MOSEL
;
tmp
|=
m
<<
(
lcdc_chan_is_sublcd
(
ch
)
?
8
:
0
);
}
lcdc_write
(
priv
,
_LDDCKR
,
tmp
);
/* start dotclock again */
lcdc_write
(
priv
,
_LDDCKSTPR
,
0
);
lcdc_wait_bit
(
priv
,
_LDDCKSTPR
,
~
0
,
0
);
/* interrupts are disabled to begin with */
lcdc_write
(
priv
,
_LDINTR
,
0
);
/* Setup geometry, format, frame buffer memory and operation mode. */
for
(
k
=
0
;
k
<
ARRAY_SIZE
(
priv
->
ch
);
k
++
)
{
ch
=
&
priv
->
ch
[
k
];
if
(
!
ch
->
enabled
)
continue
;
sh_mobile_lcdc_geometry
(
ch
);
/* power supply */
lcdc_write_chan
(
ch
,
LDPMR
,
0
);
board_cfg
=
&
ch
->
cfg
.
board_cfg
;
if
(
board_cfg
->
setup_sys
)
{
ret
=
board_cfg
->
setup_sys
(
board_cfg
->
board_data
,
ch
,
&
sh_mobile_lcdc_sys_bus_ops
);
if
(
ret
)
return
ret
;
}
}
/* word and long word swap */
ldddsr
=
lcdc_read
(
priv
,
_LDDDSR
);
if
(
priv
->
ch
[
0
].
info
->
var
.
nonstd
)
lcdc_write
(
priv
,
_LDDDSR
,
ldddsr
|
7
);
else
{
switch
(
bpp
)
{
case
16
:
lcdc_write
(
priv
,
_LDDDSR
,
ldddsr
|
6
);
break
;
case
24
:
lcdc_write
(
priv
,
_LDDDSR
,
ldddsr
|
7
);
break
;
case
32
:
lcdc_write
(
priv
,
_LDDDSR
,
ldddsr
|
4
);
break
;
}
}
for
(
k
=
0
;
k
<
ARRAY_SIZE
(
priv
->
ch
);
k
++
)
{
unsigned
long
base_addr_y
;
unsigned
long
base_addr_c
=
0
;
int
pitch
;
ch
=
&
priv
->
ch
[
k
];
if
(
!
priv
->
ch
[
k
].
enabled
)
continue
;
/* set bpp format in PKF[4:0] */
tmp
=
lcdc_read_chan
(
ch
,
LDDFR
);
tmp
&=
~
0x0003031f
;
if
(
ch
->
info
->
var
.
nonstd
)
{
tmp
|
=
(
ch
->
info
->
var
.
nonstd
<<
16
);
tmp
=
(
ch
->
info
->
var
.
nonstd
<<
16
);
switch
(
ch
->
info
->
var
.
bits_per_pixel
)
{
case
12
:
tmp
|=
LDDFR_YF_420
;
break
;
case
16
:
tmp
|=
(
0x1
<<
8
)
;
tmp
|=
LDDFR_YF_422
;
break
;
case
24
:
tmp
|=
(
0x2
<<
8
);
default:
tmp
|=
LDDFR_YF_444
;
break
;
}
}
else
{
switch
(
ch
->
info
->
var
.
bits_per_pixel
)
{
case
16
:
tmp
|=
0x03
;
tmp
=
LDDFR_PKF_RGB16
;
break
;
case
24
:
tmp
|=
0x0b
;
tmp
=
LDDFR_PKF_RGB24
;
break
;
case
32
:
default:
tmp
=
LDDFR_PKF_ARGB32
;
break
;
}
}
lcdc_write_chan
(
ch
,
LDDFR
,
tmp
);
lcdc_write_chan
(
ch
,
LDMLSR
,
ch
->
pitch
);
lcdc_write_chan
(
ch
,
LDSA1R
,
ch
->
base_addr_y
);
if
(
ch
->
info
->
var
.
nonstd
)
lcdc_write_chan
(
ch
,
LDSA2R
,
ch
->
base_addr_c
);
base_addr_y
=
ch
->
info
->
fix
.
smem_start
;
base_addr_c
=
base_addr_y
+
ch
->
info
->
var
.
xres
*
ch
->
info
->
var
.
yres_virtual
;
pitch
=
ch
->
info
->
fix
.
line_length
;
/* When using deferred I/O mode, configure the LCDC for one-shot
* operation and enable the frame end interrupt. Otherwise use
* continuous read mode.
*/
if
(
ch
->
ldmt1r_value
&
LDMT1R_IFM
&&
ch
->
cfg
.
sys_bus_cfg
.
deferred_io_msec
)
{
lcdc_write_chan
(
ch
,
LDSM1R
,
LDSM1R_OS
);
lcdc_write
(
priv
,
_LDINTR
,
LDINTR_FE
);
}
else
{
lcdc_write_chan
(
ch
,
LDSM1R
,
0
);
}
}
/* test if we can enable meram */
if
(
ch
->
cfg
.
meram_cfg
&&
priv
->
meram_dev
&&
priv
->
meram_dev
->
ops
)
{
struct
sh_mobile_meram_cfg
*
cfg
;
struct
sh_mobile_meram_info
*
mdev
;
unsigned
long
icb_addr_y
,
icb_addr_c
;
int
icb_pitch
;
int
pf
;
/* Word and long word swap. */
if
(
priv
->
ch
[
0
].
info
->
var
.
nonstd
)
tmp
=
LDDDSR_LS
|
LDDDSR_WS
|
LDDDSR_BS
;
else
{
switch
(
bpp
)
{
case
16
:
tmp
=
LDDDSR_LS
|
LDDDSR_WS
;
break
;
case
24
:
tmp
=
LDDDSR_LS
|
LDDDSR_WS
|
LDDDSR_BS
;
break
;
case
32
:
default:
tmp
=
LDDDSR_LS
;
break
;
}
}
lcdc_write
(
priv
,
_LDDDSR
,
tmp
);
cfg
=
ch
->
cfg
.
meram_cfg
;
mdev
=
priv
->
meram_dev
;
/* we need to de-init configured ICBs before we
* we can re-initialize them.
*/
if
(
ch
->
meram_enabled
)
mdev
->
ops
->
meram_unregister
(
mdev
,
cfg
);
/* Enable the display output. */
lcdc_write
(
priv
,
_LDCNT1R
,
LDCNT1R_DE
);
sh_mobile_lcdc_start_stop
(
priv
,
1
);
priv
->
started
=
1
;
}
ch
->
meram_enabled
=
0
;
static
int
sh_mobile_lcdc_start
(
struct
sh_mobile_lcdc_priv
*
priv
)
{
struct
sh_mobile_meram_info
*
mdev
=
priv
->
meram_dev
;
struct
sh_mobile_lcdc_board_cfg
*
board_cfg
;
struct
sh_mobile_lcdc_chan
*
ch
;
unsigned
long
tmp
;
int
ret
;
int
k
;
if
(
ch
->
info
->
var
.
nonstd
)
{
if
(
ch
->
info
->
var
.
bits_per_pixel
==
24
)
pf
=
SH_MOBILE_MERAM_PF_NV24
;
else
pf
=
SH_MOBILE_MERAM_PF_NV
;
}
else
{
pf
=
SH_MOBILE_MERAM_PF_RGB
;
}
/* enable clocks before accessing the hardware */
for
(
k
=
0
;
k
<
ARRAY_SIZE
(
priv
->
ch
);
k
++
)
{
if
(
priv
->
ch
[
k
].
enabled
)
sh_mobile_lcdc_clk_on
(
priv
);
}
ret
=
mdev
->
ops
->
meram_register
(
mdev
,
cfg
,
pitch
,
ch
->
info
->
var
.
yres
,
pf
,
base_addr_y
,
base_addr_c
,
&
icb_addr_y
,
&
icb_addr_c
,
&
icb_pitch
);
if
(
!
ret
)
{
/* set LDSA1R value */
base_addr_y
=
icb_addr_y
;
pitch
=
icb_pitch
;
/* set LDSA2R value if required */
if
(
base_addr_c
)
base_addr_c
=
icb_addr_c
;
ch
->
meram_enabled
=
1
;
}
}
/* reset */
lcdc_write
(
priv
,
_LDCNT2R
,
lcdc_read
(
priv
,
_LDCNT2R
)
|
LDCNT2R_BR
);
lcdc_wait_bit
(
priv
,
_LDCNT2R
,
LDCNT2R_BR
,
0
);
/* point out our frame buffer */
lcdc_write_chan
(
ch
,
LDSA1R
,
base_addr_y
);
if
(
ch
->
info
->
var
.
nonstd
)
lcdc_write_chan
(
ch
,
LDSA2R
,
base_addr_c
);
for
(
k
=
0
;
k
<
ARRAY_SIZE
(
priv
->
ch
);
k
++
)
{
ch
=
&
priv
->
ch
[
k
];
/* set line size */
lcdc_write_chan
(
ch
,
LDMLSR
,
pitch
)
;
if
(
!
ch
->
enabled
)
continue
;
/* setup deferred io if SYS bus */
tmp
=
ch
->
cfg
.
sys_bus_cfg
.
deferred_io_msec
;
if
(
ch
->
ldmt1r_value
&
(
1
<<
12
)
&&
tmp
)
{
ch
->
defio
.
deferred_io
=
sh_mobile_lcdc_deferred_io
;
ch
->
defio
.
delay
=
msecs_to_jiffies
(
tmp
);
ch
->
info
->
fbdefio
=
&
ch
->
defio
;
fb_deferred_io_init
(
ch
->
info
);
board_cfg
=
&
ch
->
cfg
.
board_cfg
;
if
(
board_cfg
->
setup_sys
)
{
ret
=
board_cfg
->
setup_sys
(
board_cfg
->
board_data
,
ch
,
&
sh_mobile_lcdc_sys_bus_ops
);
if
(
ret
)
return
ret
;
}
}
/* one-shot mode */
lcdc_write_chan
(
ch
,
LDSM1R
,
1
);
/* Compute frame buffer base address and pitch for each channel. */
for
(
k
=
0
;
k
<
ARRAY_SIZE
(
priv
->
ch
);
k
++
)
{
struct
sh_mobile_meram_cfg
*
cfg
;
int
pixelformat
;
/* enable "Frame End Interrupt Enable" bit */
lcdc_write
(
priv
,
_LDINTR
,
LDINTR_FE
);
ch
=
&
priv
->
ch
[
k
];
if
(
!
ch
->
enabled
)
continue
;
}
else
{
/* continuous read mode */
lcdc_write_chan
(
ch
,
LDSM1R
,
0
);
ch
->
base_addr_y
=
ch
->
info
->
fix
.
smem_start
;
ch
->
base_addr_c
=
ch
->
base_addr_y
+
ch
->
info
->
var
.
xres
*
ch
->
info
->
var
.
yres_virtual
;
ch
->
pitch
=
ch
->
info
->
fix
.
line_length
;
/* Enable MERAM if possible. */
cfg
=
ch
->
cfg
.
meram_cfg
;
if
(
mdev
==
NULL
||
mdev
->
ops
==
NULL
||
cfg
==
NULL
)
continue
;
/* we need to de-init configured ICBs before we can
* re-initialize them.
*/
if
(
ch
->
meram_enabled
)
{
mdev
->
ops
->
meram_unregister
(
mdev
,
cfg
);
ch
->
meram_enabled
=
0
;
}
}
/* display output */
lcdc_write
(
priv
,
_LDCNT1R
,
LCDC_ENABLE
);
if
(
!
ch
->
info
->
var
.
nonstd
)
pixelformat
=
SH_MOBILE_MERAM_PF_RGB
;
else
if
(
ch
->
info
->
var
.
bits_per_pixel
==
24
)
pixelformat
=
SH_MOBILE_MERAM_PF_NV24
;
else
pixelformat
=
SH_MOBILE_MERAM_PF_NV
;
ret
=
mdev
->
ops
->
meram_register
(
mdev
,
cfg
,
ch
->
pitch
,
ch
->
info
->
var
.
yres
,
pixelformat
,
ch
->
base_addr_y
,
ch
->
base_addr_c
,
&
ch
->
base_addr_y
,
&
ch
->
base_addr_c
,
&
ch
->
pitch
);
if
(
!
ret
)
ch
->
meram_enabled
=
1
;
}
/* start the lcdc */
sh_mobile_lcdc_start_stop
(
priv
,
1
);
priv
->
started
=
1
;
/* Start the LCDC. */
__sh_mobile_lcdc_start
(
priv
);
/* tell the board code to enable the panel */
/* Setup deferred I/O, tell the board code to enable the panels, and
* turn backlight on.
*/
for
(
k
=
0
;
k
<
ARRAY_SIZE
(
priv
->
ch
);
k
++
)
{
ch
=
&
priv
->
ch
[
k
];
if
(
!
ch
->
enabled
)
continue
;
tmp
=
ch
->
cfg
.
sys_bus_cfg
.
deferred_io_msec
;
if
(
ch
->
ldmt1r_value
&
LDMT1R_IFM
&&
tmp
)
{
ch
->
defio
.
deferred_io
=
sh_mobile_lcdc_deferred_io
;
ch
->
defio
.
delay
=
msecs_to_jiffies
(
tmp
);
ch
->
info
->
fbdefio
=
&
ch
->
defio
;
fb_deferred_io_init
(
ch
->
info
);
}
board_cfg
=
&
ch
->
cfg
.
board_cfg
;
if
(
board_cfg
->
display_on
&&
try_module_get
(
board_cfg
->
owner
))
{
board_cfg
->
display_on
(
board_cfg
->
board_data
,
ch
->
info
);
...
...
@@ -776,42 +733,42 @@ static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv)
static
int
sh_mobile_lcdc_check_interface
(
struct
sh_mobile_lcdc_chan
*
ch
)
{
int
ifm
,
miftyp
;
switch
(
ch
->
cfg
.
interface_type
)
{
case
RGB8
:
ifm
=
0
;
miftyp
=
0
;
break
;
case
RGB9
:
ifm
=
0
;
miftyp
=
4
;
break
;
case
RGB12A
:
ifm
=
0
;
miftyp
=
5
;
break
;
case
RGB12B
:
ifm
=
0
;
miftyp
=
6
;
break
;
case
RGB16
:
ifm
=
0
;
miftyp
=
7
;
break
;
case
RGB18
:
ifm
=
0
;
miftyp
=
10
;
break
;
case
RGB24
:
ifm
=
0
;
miftyp
=
11
;
break
;
case
SYS8A
:
ifm
=
1
;
miftyp
=
0
;
break
;
case
SYS8B
:
ifm
=
1
;
miftyp
=
1
;
break
;
case
SYS8C
:
ifm
=
1
;
miftyp
=
2
;
break
;
case
SYS8D
:
ifm
=
1
;
miftyp
=
3
;
break
;
case
SYS9
:
ifm
=
1
;
miftyp
=
4
;
break
;
case
SYS12
:
ifm
=
1
;
miftyp
=
5
;
break
;
case
SYS16A
:
ifm
=
1
;
miftyp
=
7
;
break
;
case
SYS16B
:
ifm
=
1
;
miftyp
=
8
;
break
;
case
SYS16C
:
ifm
=
1
;
miftyp
=
9
;
break
;
case
SYS18
:
ifm
=
1
;
miftyp
=
10
;
break
;
case
SYS24
:
ifm
=
1
;
miftyp
=
11
;
break
;
default:
goto
bad
;
int
interface_type
=
ch
->
cfg
.
interface_type
;
switch
(
interface_type
)
{
case
RGB8
:
case
RGB9
:
case
RGB12A
:
case
RGB12B
:
case
RGB16
:
case
RGB18
:
case
RGB24
:
case
SYS8A
:
case
SYS8B
:
case
SYS8C
:
case
SYS8D
:
case
SYS9
:
case
SYS12
:
case
SYS16A
:
case
SYS16B
:
case
SYS16C
:
case
SYS18
:
case
SYS24
:
break
;
default:
return
-
EINVAL
;
}
/* SUBLCD only supports SYS interface */
if
(
lcdc_chan_is_sublcd
(
ch
))
{
if
(
ifm
==
0
)
goto
bad
;
else
ifm
=
0
;
if
(
!
(
interface_type
&
LDMT1R_IFM
)
)
return
-
EINVAL
;
interface_type
&=
~
LDMT1R_IFM
;
}
ch
->
ldmt1r_value
=
(
ifm
<<
12
)
|
miftyp
;
ch
->
ldmt1r_value
=
interface_type
;
return
0
;
bad:
return
-
EINVAL
;
}
static
int
sh_mobile_lcdc_setup_clocks
(
struct
platform_device
*
pdev
,
...
...
@@ -819,18 +776,24 @@ static int sh_mobile_lcdc_setup_clocks(struct platform_device *pdev,
struct
sh_mobile_lcdc_priv
*
priv
)
{
char
*
str
;
int
icksel
;
switch
(
clock_source
)
{
case
LCDC_CLK_BUS
:
str
=
"bus_clk"
;
icksel
=
0
;
break
;
case
LCDC_CLK_PERIPHERAL
:
str
=
"peripheral_clk"
;
icksel
=
1
;
break
;
case
LCDC_CLK_EXTERNAL
:
str
=
NULL
;
icksel
=
2
;
break
;
case
LCDC_CLK_BUS
:
str
=
"bus_clk"
;
priv
->
lddckr
=
LDDCKR_ICKSEL_BUS
;
break
;
case
LCDC_CLK_PERIPHERAL
:
str
=
"peripheral_clk"
;
priv
->
lddckr
=
LDDCKR_ICKSEL_MIPI
;
break
;
case
LCDC_CLK_EXTERNAL
:
str
=
NULL
;
priv
->
lddckr
=
LDDCKR_ICKSEL_HDMI
;
break
;
default:
return
-
EINVAL
;
}
priv
->
lddckr
=
icksel
<<
16
;
if
(
str
)
{
priv
->
dot_clk
=
clk_get
(
&
pdev
->
dev
,
str
);
if
(
IS_ERR
(
priv
->
dot_clk
))
{
...
...
@@ -940,32 +903,28 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var,
base_addr_c
+=
2
*
var
->
xoffset
;
else
base_addr_c
+=
var
->
xoffset
;
}
else
base_addr_c
=
0
;
}
if
(
!
ch
->
meram_enabled
)
{
lcdc_write_chan_mirror
(
ch
,
LDSA1R
,
base_addr_y
);
if
(
base_addr_c
)
lcdc_write_chan_mirror
(
ch
,
LDSA2R
,
base_addr_c
);
}
else
{
if
(
ch
->
meram_enabled
)
{
struct
sh_mobile_meram_cfg
*
cfg
;
struct
sh_mobile_meram_info
*
mdev
;
unsigned
long
icb_addr_y
,
icb_addr_c
;
int
ret
;
cfg
=
ch
->
cfg
.
meram_cfg
;
mdev
=
priv
->
meram_dev
;
ret
=
mdev
->
ops
->
meram_update
(
mdev
,
cfg
,
base_addr_y
,
base_addr_c
,
&
icb_addr_y
,
&
icb
_addr_c
);
&
base_addr_y
,
&
base
_addr_c
);
if
(
ret
)
return
ret
;
}
lcdc_write_chan_mirror
(
ch
,
LDSA1R
,
icb_addr_y
);
if
(
icb_addr_c
)
lcdc_write_chan_mirror
(
ch
,
LDSA2R
,
icb_addr_c
);
ch
->
base_addr_y
=
base_addr_y
;
ch
->
base_addr_c
=
base_addr_c
;
}
lcdc_write_chan_mirror
(
ch
,
LDSA1R
,
base_addr_y
);
if
(
var
->
nonstd
)
lcdc_write_chan_mirror
(
ch
,
LDSA2R
,
base_addr_c
);
if
(
lcdc_chan_is_sublcd
(
ch
))
lcdc_write
(
ch
->
lcdc
,
_LDRCNTR
,
ldrcntr
^
LDRCNTR_SRS
);
...
...
@@ -985,9 +944,11 @@ static int sh_mobile_wait_for_vsync(struct fb_info *info)
unsigned
long
ldintr
;
int
ret
;
/* Enable VSync End interrupt */
/* Enable VSync End interrupt and be careful not to acknowledge any
* pending interrupt.
*/
ldintr
=
lcdc_read
(
ch
->
lcdc
,
_LDINTR
);
ldintr
|=
LDINTR_VEE
;
ldintr
|=
LDINTR_VEE
|
LDINTR_STATUS_MASK
;
lcdc_write
(
ch
->
lcdc
,
_LDINTR
,
ldintr
);
ret
=
wait_for_completion_interruptible_timeout
(
&
ch
->
vsync_completion
,
...
...
@@ -1316,47 +1277,20 @@ static int sh_mobile_lcdc_resume(struct device *dev)
static
int
sh_mobile_lcdc_runtime_suspend
(
struct
device
*
dev
)
{
struct
platform_device
*
pdev
=
to_platform_device
(
dev
);
struct
sh_mobile_lcdc_priv
*
p
=
platform_get_drvdata
(
pdev
);
struct
sh_mobile_lcdc_chan
*
ch
;
int
k
,
n
;
/* save per-channel registers */
for
(
k
=
0
;
k
<
ARRAY_SIZE
(
p
->
ch
);
k
++
)
{
ch
=
&
p
->
ch
[
k
];
if
(
!
ch
->
enabled
)
continue
;
for
(
n
=
0
;
n
<
NR_CH_REGS
;
n
++
)
ch
->
saved_ch_regs
[
n
]
=
lcdc_read_chan
(
ch
,
n
);
}
/* save shared registers */
for
(
n
=
0
;
n
<
NR_SHARED_REGS
;
n
++
)
p
->
saved_shared_regs
[
n
]
=
lcdc_read
(
p
,
lcdc_shared_regs
[
n
]);
struct
sh_mobile_lcdc_priv
*
priv
=
platform_get_drvdata
(
pdev
);
/* turn off LCDC hardware */
lcdc_write
(
p
,
_LDCNT1R
,
0
);
lcdc_write
(
priv
,
_LDCNT1R
,
0
);
return
0
;
}
static
int
sh_mobile_lcdc_runtime_resume
(
struct
device
*
dev
)
{
struct
platform_device
*
pdev
=
to_platform_device
(
dev
);
struct
sh_mobile_lcdc_priv
*
p
=
platform_get_drvdata
(
pdev
);
struct
sh_mobile_lcdc_chan
*
ch
;
int
k
,
n
;
/* restore per-channel registers */
for
(
k
=
0
;
k
<
ARRAY_SIZE
(
p
->
ch
);
k
++
)
{
ch
=
&
p
->
ch
[
k
];
if
(
!
ch
->
enabled
)
continue
;
for
(
n
=
0
;
n
<
NR_CH_REGS
;
n
++
)
lcdc_write_chan
(
ch
,
n
,
ch
->
saved_ch_regs
[
n
]);
}
struct
sh_mobile_lcdc_priv
*
priv
=
platform_get_drvdata
(
pdev
);
/* restore shared registers */
for
(
n
=
0
;
n
<
NR_SHARED_REGS
;
n
++
)
lcdc_write
(
p
,
lcdc_shared_regs
[
n
],
p
->
saved_shared_regs
[
n
]);
__sh_mobile_lcdc_start
(
priv
);
return
0
;
}
...
...
@@ -1472,12 +1406,12 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
switch
(
pdata
->
ch
[
i
].
chan
)
{
case
LCDC_CHAN_MAINLCD
:
ch
->
enabled
=
1
<<
1
;
ch
->
enabled
=
LDCNT2R_ME
;
ch
->
reg_offs
=
lcdc_offs_mainlcd
;
j
++
;
break
;
case
LCDC_CHAN_SUBLCD
:
ch
->
enabled
=
1
<<
2
;
ch
->
enabled
=
LDCNT2R_SE
;
ch
->
reg_offs
=
lcdc_offs_sublcd
;
j
++
;
break
;
...
...
drivers/video/sh_mobile_lcdcfb.h
View file @
8edbeb6e
...
...
@@ -18,6 +18,13 @@ struct sh_mobile_lcdc_priv;
struct
fb_info
;
struct
backlight_device
;
/*
* struct sh_mobile_lcdc_chan - LCDC display channel
*
* @base_addr_y: Frame buffer viewport base address (luma component)
* @base_addr_c: Frame buffer viewport base address (chroma component)
* @pitch: Frame buffer line pitch
*/
struct
sh_mobile_lcdc_chan
{
struct
sh_mobile_lcdc_priv
*
lcdc
;
unsigned
long
*
reg_offs
;
...
...
@@ -25,7 +32,6 @@ struct sh_mobile_lcdc_chan {
unsigned
long
enabled
;
/* ME and SE in LDCNT2R */
struct
sh_mobile_lcdc_chan_cfg
cfg
;
u32
pseudo_palette
[
PALETTE_NR
];
unsigned
long
saved_ch_regs
[
NR_CH_REGS
];
struct
fb_info
*
info
;
struct
backlight_device
*
bl
;
dma_addr_t
dma_handle
;
...
...
@@ -40,6 +46,10 @@ struct sh_mobile_lcdc_chan {
int
blank_status
;
struct
mutex
open_lock
;
/* protects the use counter */
int
meram_enabled
;
unsigned
long
base_addr_y
;
unsigned
long
base_addr_c
;
unsigned
int
pitch
;
};
#endif
drivers/video/sh_mobile_meram.c
View file @
8edbeb6e
...
...
@@ -12,29 +12,103 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/pm_runtime.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include "sh_mobile_meram.h"
#include <video/sh_mobile_meram.h>
/* meram registers */
#define MExxCTL 0x0
#define MExxBSIZE 0x4
#define MExxMNCF 0x8
#define MExxSARA 0x10
#define MExxSARB 0x14
#define MExxSBSIZE 0x18
#define MERAM_MExxCTL_VAL(ctl, next_icb, addr) \
((ctl) | (((next_icb) & 0x1f) << 11) | (((addr) & 0x7ff) << 16))
#define MERAM_MExxBSIZE_VAL(a, b, c) \
(((a) << 28) | ((b) << 16) | (c))
#define MEVCR1 0x4
#define MEACTS 0x10
#define MEQSEL1 0x40
#define MEQSEL2 0x44
#define MEVCR1 0x4
#define MEVCR1_RST (1 << 31)
#define MEVCR1_WD (1 << 30)
#define MEVCR1_AMD1 (1 << 29)
#define MEVCR1_AMD0 (1 << 28)
#define MEQSEL1 0x40
#define MEQSEL2 0x44
#define MExxCTL 0x400
#define MExxCTL_BV (1 << 31)
#define MExxCTL_BSZ_SHIFT 28
#define MExxCTL_MSAR_MASK (0x7ff << MExxCTL_MSAR_SHIFT)
#define MExxCTL_MSAR_SHIFT 16
#define MExxCTL_NXT_MASK (0x1f << MExxCTL_NXT_SHIFT)
#define MExxCTL_NXT_SHIFT 11
#define MExxCTL_WD1 (1 << 10)
#define MExxCTL_WD0 (1 << 9)
#define MExxCTL_WS (1 << 8)
#define MExxCTL_CB (1 << 7)
#define MExxCTL_WBF (1 << 6)
#define MExxCTL_WF (1 << 5)
#define MExxCTL_RF (1 << 4)
#define MExxCTL_CM (1 << 3)
#define MExxCTL_MD_READ (1 << 0)
#define MExxCTL_MD_WRITE (2 << 0)
#define MExxCTL_MD_ICB_WB (3 << 0)
#define MExxCTL_MD_ICB (4 << 0)
#define MExxCTL_MD_FB (7 << 0)
#define MExxCTL_MD_MASK (7 << 0)
#define MExxBSIZE 0x404
#define MExxBSIZE_RCNT_SHIFT 28
#define MExxBSIZE_YSZM1_SHIFT 16
#define MExxBSIZE_XSZM1_SHIFT 0
#define MExxMNCF 0x408
#define MExxMNCF_KWBNM_SHIFT 28
#define MExxMNCF_KRBNM_SHIFT 24
#define MExxMNCF_BNM_SHIFT 16
#define MExxMNCF_XBV (1 << 15)
#define MExxMNCF_CPL_YCBCR444 (1 << 12)
#define MExxMNCF_CPL_YCBCR420 (2 << 12)
#define MExxMNCF_CPL_YCBCR422 (3 << 12)
#define MExxMNCF_CPL_MSK (3 << 12)
#define MExxMNCF_BL (1 << 2)
#define MExxMNCF_LNM_SHIFT 0
#define MExxSARA 0x410
#define MExxSARB 0x414
#define MExxSBSIZE 0x418
#define MExxSBSIZE_HDV (1 << 31)
#define MExxSBSIZE_HSZ16 (0 << 28)
#define MExxSBSIZE_HSZ32 (1 << 28)
#define MExxSBSIZE_HSZ64 (2 << 28)
#define MExxSBSIZE_HSZ128 (3 << 28)
#define MExxSBSIZE_SBSIZZ_SHIFT 0
#define MERAM_MExxCTL_VAL(next, addr) \
((((next) << MExxCTL_NXT_SHIFT) & MExxCTL_NXT_MASK) | \
(((addr) << MExxCTL_MSAR_SHIFT) & MExxCTL_MSAR_MASK))
#define MERAM_MExxBSIZE_VAL(rcnt, yszm1, xszm1) \
(((rcnt) << MExxBSIZE_RCNT_SHIFT) | \
((yszm1) << MExxBSIZE_YSZM1_SHIFT) | \
((xszm1) << MExxBSIZE_XSZM1_SHIFT))
#define SH_MOBILE_MERAM_ICB_NUM 32
static
unsigned
long
common_regs
[]
=
{
MEVCR1
,
MEQSEL1
,
MEQSEL2
,
};
#define CMN_REGS_SIZE ARRAY_SIZE(common_regs)
static
unsigned
long
icb_regs
[]
=
{
MExxCTL
,
MExxBSIZE
,
MExxMNCF
,
MExxSARA
,
MExxSARB
,
MExxSBSIZE
,
};
#define ICB_REGS_SIZE ARRAY_SIZE(icb_regs)
struct
sh_mobile_meram_priv
{
void
__iomem
*
base
;
struct
mutex
lock
;
unsigned
long
used_icb
;
int
used_meram_cache_regions
;
unsigned
long
used_meram_cache
[
SH_MOBILE_MERAM_ICB_NUM
];
unsigned
long
cmn_saved_regs
[
CMN_REGS_SIZE
];
unsigned
long
icb_saved_regs
[
ICB_REGS_SIZE
*
SH_MOBILE_MERAM_ICB_NUM
];
};
/* settings */
#define MERAM_SEC_LINE 15
...
...
@@ -44,8 +118,7 @@
* MERAM/ICB access functions
*/
#define MERAM_ICB_OFFSET(base, idx, off) \
((base) + (0x400 + ((idx) * 0x20) + (off)))
#define MERAM_ICB_OFFSET(base, idx, off) ((base) + (off) + (idx) * 0x20)
static
inline
void
meram_write_icb
(
void
__iomem
*
base
,
int
idx
,
int
off
,
unsigned
long
val
)
...
...
@@ -280,17 +353,18 @@ static int meram_init(struct sh_mobile_meram_priv *priv,
/*
* Set MERAM for framebuffer
*
* 0x70f: WD = 0x3, WS=0x1, CM=0x1, MD=FB mode
* we also chain the cache_icb and the marker_icb.
* we also split the allocated MERAM buffer between two ICBs.
*/
meram_write_icb
(
priv
->
base
,
icb
->
cache_icb
,
MExxCTL
,
MERAM_MExxCTL_VAL
(
0x70f
,
icb
->
marker_icb
,
icb
->
meram_offset
));
MERAM_MExxCTL_VAL
(
icb
->
marker_icb
,
icb
->
meram_offset
)
|
MExxCTL_WD1
|
MExxCTL_WD0
|
MExxCTL_WS
|
MExxCTL_CM
|
MExxCTL_MD_FB
);
meram_write_icb
(
priv
->
base
,
icb
->
marker_icb
,
MExxCTL
,
MERAM_MExxCTL_VAL
(
0x70f
,
icb
->
cache_icb
,
icb
->
meram_offset
+
icb
->
meram_size
/
2
));
MERAM_MExxCTL_VAL
(
icb
->
cache_icb
,
icb
->
meram_offset
+
icb
->
meram_size
/
2
)
|
MExxCTL_WD1
|
MExxCTL_WD0
|
MExxCTL_WS
|
MExxCTL_CM
|
MExxCTL_MD_FB
);
return
0
;
}
...
...
@@ -337,24 +411,22 @@ static int sh_mobile_meram_register(struct sh_mobile_meram_info *pdata,
xres
,
yres
,
(
!
pixelformat
)
?
"yuv"
:
"rgb"
,
base_addr_y
,
base_addr_c
);
mutex_lock
(
&
priv
->
lock
);
/* we can't handle wider than 8192px */
if
(
xres
>
8192
)
{
dev_err
(
&
pdev
->
dev
,
"width exceeding the limit (> 8192)."
);
error
=
-
EINVAL
;
goto
err
;
}
if
(
priv
->
used_meram_cache_regions
+
2
>
SH_MOBILE_MERAM_ICB_NUM
)
{
dev_err
(
&
pdev
->
dev
,
"no more ICB available."
);
error
=
-
EINVAL
;
goto
err
;
return
-
EINVAL
;
}
/* do we have at least one ICB config? */
if
(
cfg
->
icb
[
0
].
marker_icb
<
0
||
cfg
->
icb
[
0
].
cache_icb
<
0
)
{
dev_err
(
&
pdev
->
dev
,
"at least one ICB is required."
);
return
-
EINVAL
;
}
mutex_lock
(
&
priv
->
lock
);
if
(
priv
->
used_meram_cache_regions
+
2
>
SH_MOBILE_MERAM_ICB_NUM
)
{
dev_err
(
&
pdev
->
dev
,
"no more ICB available."
);
error
=
-
EINVAL
;
goto
err
;
}
...
...
@@ -460,6 +532,57 @@ static int sh_mobile_meram_update(struct sh_mobile_meram_info *pdata,
return
0
;
}
static
int
sh_mobile_meram_runtime_suspend
(
struct
device
*
dev
)
{
struct
platform_device
*
pdev
=
to_platform_device
(
dev
);
struct
sh_mobile_meram_priv
*
priv
=
platform_get_drvdata
(
pdev
);
int
k
,
j
;
for
(
k
=
0
;
k
<
CMN_REGS_SIZE
;
k
++
)
priv
->
cmn_saved_regs
[
k
]
=
meram_read_reg
(
priv
->
base
,
common_regs
[
k
]);
for
(
j
=
0
;
j
<
32
;
j
++
)
{
if
(
!
test_bit
(
j
,
&
priv
->
used_icb
))
continue
;
for
(
k
=
0
;
k
<
ICB_REGS_SIZE
;
k
++
)
{
priv
->
icb_saved_regs
[
j
*
ICB_REGS_SIZE
+
k
]
=
meram_read_icb
(
priv
->
base
,
j
,
icb_regs
[
k
]);
/* Reset ICB on resume */
if
(
icb_regs
[
k
]
==
MExxCTL
)
priv
->
icb_saved_regs
[
j
*
ICB_REGS_SIZE
+
k
]
|=
MExxCTL_WBF
|
MExxCTL_WF
|
MExxCTL_RF
;
}
}
return
0
;
}
static
int
sh_mobile_meram_runtime_resume
(
struct
device
*
dev
)
{
struct
platform_device
*
pdev
=
to_platform_device
(
dev
);
struct
sh_mobile_meram_priv
*
priv
=
platform_get_drvdata
(
pdev
);
int
k
,
j
;
for
(
j
=
0
;
j
<
32
;
j
++
)
{
if
(
!
test_bit
(
j
,
&
priv
->
used_icb
))
continue
;
for
(
k
=
0
;
k
<
ICB_REGS_SIZE
;
k
++
)
{
meram_write_icb
(
priv
->
base
,
j
,
icb_regs
[
k
],
priv
->
icb_saved_regs
[
j
*
ICB_REGS_SIZE
+
k
]);
}
}
for
(
k
=
0
;
k
<
CMN_REGS_SIZE
;
k
++
)
meram_write_reg
(
priv
->
base
,
common_regs
[
k
],
priv
->
cmn_saved_regs
[
k
]);
return
0
;
}
static
const
struct
dev_pm_ops
sh_mobile_meram_dev_pm_ops
=
{
.
runtime_suspend
=
sh_mobile_meram_runtime_suspend
,
.
runtime_resume
=
sh_mobile_meram_runtime_resume
,
};
static
struct
sh_mobile_meram_ops
sh_mobile_meram_ops
=
{
.
module
=
THIS_MODULE
,
.
meram_register
=
sh_mobile_meram_register
,
...
...
@@ -513,7 +636,9 @@ static int __devinit sh_mobile_meram_probe(struct platform_device *pdev)
/* initialize ICB addressing mode */
if
(
pdata
->
addr_mode
==
SH_MOBILE_MERAM_MODE1
)
meram_write_reg
(
priv
->
base
,
MEVCR1
,
1
<<
29
);
meram_write_reg
(
priv
->
base
,
MEVCR1
,
MEVCR1_AMD1
);
pm_runtime_enable
(
&
pdev
->
dev
);
dev_info
(
&
pdev
->
dev
,
"sh_mobile_meram initialized."
);
...
...
@@ -530,6 +655,8 @@ static int sh_mobile_meram_remove(struct platform_device *pdev)
{
struct
sh_mobile_meram_priv
*
priv
=
platform_get_drvdata
(
pdev
);
pm_runtime_disable
(
&
pdev
->
dev
);
if
(
priv
->
base
)
iounmap
(
priv
->
base
);
...
...
@@ -544,6 +671,7 @@ static struct platform_driver sh_mobile_meram_driver = {
.
driver
=
{
.
name
=
"sh_mobile_meram"
,
.
owner
=
THIS_MODULE
,
.
pm
=
&
sh_mobile_meram_dev_pm_ops
,
},
.
probe
=
sh_mobile_meram_probe
,
.
remove
=
sh_mobile_meram_remove
,
...
...
drivers/video/sh_mobile_meram.h
deleted
100644 → 0
View file @
d4a7dbfd
#ifndef __sh_mobile_meram_h__
#define __sh_mobile_meram_h__
#include <linux/mutex.h>
#include <video/sh_mobile_meram.h>
/*
* MERAM private
*/
#define MERAM_ICB_Y 0x1
#define MERAM_ICB_C 0x2
/* MERAM cache size */
#define SH_MOBILE_MERAM_ICB_NUM 32
#define SH_MOBILE_MERAM_CACHE_OFFSET(p) ((p) >> 16)
#define SH_MOBILE_MERAM_CACHE_SIZE(p) ((p) & 0xffff)
struct
sh_mobile_meram_priv
{
void
__iomem
*
base
;
struct
mutex
lock
;
unsigned
long
used_icb
;
int
used_meram_cache_regions
;
unsigned
long
used_meram_cache
[
SH_MOBILE_MERAM_ICB_NUM
];
};
int
sh_mobile_meram_alloc_icb
(
const
struct
sh_mobile_meram_cfg
*
cfg
,
int
xres
,
int
yres
,
unsigned
int
base_addr
,
int
yuv_mode
,
int
*
marker_icb
,
int
*
out_pitch
);
void
sh_mobile_meram_free_icb
(
int
marker_icb
);
#define SH_MOBILE_MERAM_START(ind, ab) \
(0xC0000000 | ((ab & 0x1) << 23) | ((ind & 0x1F) << 24))
#endif
/* !__sh_mobile_meram_h__ */
include/video/sh_mobile_lcdc.h
View file @
8edbeb6e
...
...
@@ -4,26 +4,123 @@
#include <linux/fb.h>
#include <video/sh_mobile_meram.h>
/* Register definitions */
#define _LDDCKR 0x410
#define LDDCKR_ICKSEL_BUS (0 << 16)
#define LDDCKR_ICKSEL_MIPI (1 << 16)
#define LDDCKR_ICKSEL_HDMI (2 << 16)
#define LDDCKR_ICKSEL_EXT (3 << 16)
#define LDDCKR_ICKSEL_MASK (7 << 16)
#define LDDCKR_MOSEL (1 << 6)
#define _LDDCKSTPR 0x414
#define _LDINTR 0x468
#define LDINTR_FE (1 << 10)
#define LDINTR_VSE (1 << 9)
#define LDINTR_VEE (1 << 8)
#define LDINTR_FS (1 << 2)
#define LDINTR_VSS (1 << 1)
#define LDINTR_VES (1 << 0)
#define LDINTR_STATUS_MASK (0xff << 0)
#define _LDSR 0x46c
#define LDSR_MSS (1 << 10)
#define LDSR_MRS (1 << 8)
#define LDSR_AS (1 << 1)
#define _LDCNT1R 0x470
#define LDCNT1R_DE (1 << 0)
#define _LDCNT2R 0x474
#define LDCNT2R_BR (1 << 8)
#define LDCNT2R_MD (1 << 3)
#define LDCNT2R_SE (1 << 2)
#define LDCNT2R_ME (1 << 1)
#define LDCNT2R_DO (1 << 0)
#define _LDRCNTR 0x478
#define LDRCNTR_SRS (1 << 17)
#define LDRCNTR_SRC (1 << 16)
#define LDRCNTR_MRS (1 << 1)
#define LDRCNTR_MRC (1 << 0)
#define _LDDDSR 0x47c
#define LDDDSR_LS (1 << 2)
#define LDDDSR_WS (1 << 1)
#define LDDDSR_BS (1 << 0)
#define LDMT1R_VPOL (1 << 28)
#define LDMT1R_HPOL (1 << 27)
#define LDMT1R_DWPOL (1 << 26)
#define LDMT1R_DIPOL (1 << 25)
#define LDMT1R_DAPOL (1 << 24)
#define LDMT1R_HSCNT (1 << 17)
#define LDMT1R_DWCNT (1 << 16)
#define LDMT1R_IFM (1 << 12)
#define LDMT1R_MIFTYP_RGB8 (0x0 << 0)
#define LDMT1R_MIFTYP_RGB9 (0x4 << 0)
#define LDMT1R_MIFTYP_RGB12A (0x5 << 0)
#define LDMT1R_MIFTYP_RGB12B (0x6 << 0)
#define LDMT1R_MIFTYP_RGB16 (0x7 << 0)
#define LDMT1R_MIFTYP_RGB18 (0xa << 0)
#define LDMT1R_MIFTYP_RGB24 (0xb << 0)
#define LDMT1R_MIFTYP_YCBCR (0xf << 0)
#define LDMT1R_MIFTYP_SYS8A (0x0 << 0)
#define LDMT1R_MIFTYP_SYS8B (0x1 << 0)
#define LDMT1R_MIFTYP_SYS8C (0x2 << 0)
#define LDMT1R_MIFTYP_SYS8D (0x3 << 0)
#define LDMT1R_MIFTYP_SYS9 (0x4 << 0)
#define LDMT1R_MIFTYP_SYS12 (0x5 << 0)
#define LDMT1R_MIFTYP_SYS16A (0x7 << 0)
#define LDMT1R_MIFTYP_SYS16B (0x8 << 0)
#define LDMT1R_MIFTYP_SYS16C (0x9 << 0)
#define LDMT1R_MIFTYP_SYS18 (0xa << 0)
#define LDMT1R_MIFTYP_SYS24 (0xb << 0)
#define LDMT1R_MIFTYP_MASK (0xf << 0)
#define LDDFR_CF1 (1 << 18)
#define LDDFR_CF0 (1 << 17)
#define LDDFR_CC (1 << 16)
#define LDDFR_YF_420 (0 << 8)
#define LDDFR_YF_422 (1 << 8)
#define LDDFR_YF_444 (2 << 8)
#define LDDFR_YF_MASK (3 << 8)
#define LDDFR_PKF_ARGB32 (0x00 << 0)
#define LDDFR_PKF_RGB16 (0x03 << 0)
#define LDDFR_PKF_RGB24 (0x0b << 0)
#define LDDFR_PKF_MASK (0x1f << 0)
#define LDSM1R_OS (1 << 0)
#define LDSM2R_OSTRG (1 << 0)
#define LDPMR_LPS (3 << 0)
#define _LDDWD0R 0x800
#define LDDWDxR_WDACT (1 << 28)
#define LDDWDxR_RSW (1 << 24)
#define _LDDRDR 0x840
#define LDDRDR_RSR (1 << 24)
#define LDDRDR_DRD_MASK (0x3ffff << 0)
#define _LDDWAR 0x900
#define LDDWAR_WA (1 << 0)
#define _LDDRAR 0x904
#define LDDRAR_RA (1 << 0)
enum
{
RGB8
,
/* 24bpp, 8:8:8 */
RGB9
,
/* 18bpp, 9:9 */
RGB12A
,
/* 24bpp, 12:12 */
RGB12B
,
/* 12bpp */
RGB16
,
/* 16bpp */
RGB18
,
/* 18bpp */
RGB24
,
/* 24bpp */
YUV422
,
/* 16bpp */
SYS8A
,
/* 24bpp, 8:8:8 */
SYS8B
,
/* 18bpp, 8:8:2 */
SYS8C
,
/* 18bpp, 2:8:8 */
SYS8D
,
/* 16bpp, 8:8 */
SYS9
,
/* 18bpp, 9:9 */
SYS12
,
/* 24bpp, 12:12 */
SYS16A
,
/* 16bpp */
SYS16B
,
/* 18bpp, 16:2 */
SYS16C
,
/* 18bpp, 2:16 */
SYS18
,
/* 18bpp */
SYS24
,
/* 24bpp */
RGB8
=
LDMT1R_MIFTYP_RGB8
,
/* 24bpp, 8:8:8 */
RGB9
=
LDMT1R_MIFTYP_RGB9
,
/* 18bpp, 9:9 */
RGB12A
=
LDMT1R_MIFTYP_RGB12A
,
/* 24bpp, 12:12 */
RGB12B
=
LDMT1R_MIFTYP_RGB12B
,
/* 12bpp */
RGB16
=
LDMT1R_MIFTYP_RGB16
,
/* 16bpp */
RGB18
=
LDMT1R_MIFTYP_RGB18
,
/* 18bpp */
RGB24
=
LDMT1R_MIFTYP_RGB24
,
/* 24bpp */
YUV422
=
LDMT1R_MIFTYP_YCBCR
,
/* 16bpp */
SYS8A
=
LDMT1R_IFM
|
LDMT1R_MIFTYP_SYS8A
,
/* 24bpp, 8:8:8 */
SYS8B
=
LDMT1R_IFM
|
LDMT1R_MIFTYP_SYS8B
,
/* 18bpp, 8:8:2 */
SYS8C
=
LDMT1R_IFM
|
LDMT1R_MIFTYP_SYS8C
,
/* 18bpp, 2:8:8 */
SYS8D
=
LDMT1R_IFM
|
LDMT1R_MIFTYP_SYS8D
,
/* 16bpp, 8:8 */
SYS9
=
LDMT1R_IFM
|
LDMT1R_MIFTYP_SYS9
,
/* 18bpp, 9:9 */
SYS12
=
LDMT1R_IFM
|
LDMT1R_MIFTYP_SYS12
,
/* 24bpp, 12:12 */
SYS16A
=
LDMT1R_IFM
|
LDMT1R_MIFTYP_SYS16A
,
/* 16bpp */
SYS16B
=
LDMT1R_IFM
|
LDMT1R_MIFTYP_SYS16B
,
/* 18bpp, 16:2 */
SYS16C
=
LDMT1R_IFM
|
LDMT1R_MIFTYP_SYS16C
,
/* 18bpp, 2:16 */
SYS18
=
LDMT1R_IFM
|
LDMT1R_MIFTYP_SYS18
,
/* 18bpp */
SYS24
=
LDMT1R_IFM
|
LDMT1R_MIFTYP_SYS24
,
/* 24bpp */
};
enum
{
LCDC_CHAN_DISABLED
=
0
,
...
...
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