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
f9b4a5ce
Commit
f9b4a5ce
authored
Mar 13, 2012
by
Florian Tobias Schandinat
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'for-next' of
git://linuxtv.org/pinchartl/fbdev
into fbdev-next
parents
afb0499b
af89956b
Changes
22
Show whitespace changes
Inline
Side-by-side
Showing
22 changed files
with
1594 additions
and
1490 deletions
+1594
-1490
arch/arm/mach-shmobile/board-ag5evm.c
arch/arm/mach-shmobile/board-ag5evm.c
+7
-17
arch/arm/mach-shmobile/board-ap4evb.c
arch/arm/mach-shmobile/board-ap4evb.c
+145
-145
arch/arm/mach-shmobile/board-bonito.c
arch/arm/mach-shmobile/board-bonito.c
+3
-3
arch/arm/mach-shmobile/board-mackerel.c
arch/arm/mach-shmobile/board-mackerel.c
+50
-56
arch/sh/boards/mach-ap325rxa/setup.c
arch/sh/boards/mach-ap325rxa/setup.c
+10
-12
arch/sh/boards/mach-ecovec24/setup.c
arch/sh/boards/mach-ecovec24/setup.c
+9
-11
arch/sh/boards/mach-kfr2r09/lcd_wqvga.c
arch/sh/boards/mach-kfr2r09/lcd_wqvga.c
+4
-6
arch/sh/boards/mach-kfr2r09/setup.c
arch/sh/boards/mach-kfr2r09/setup.c
+3
-5
arch/sh/boards/mach-migor/lcd_qvga.c
arch/sh/boards/mach-migor/lcd_qvga.c
+1
-2
arch/sh/boards/mach-migor/setup.c
arch/sh/boards/mach-migor/setup.c
+7
-9
arch/sh/boards/mach-se/7724/setup.c
arch/sh/boards/mach-se/7724/setup.c
+5
-7
arch/sh/include/mach-kfr2r09/mach/kfr2r09.h
arch/sh/include/mach-kfr2r09/mach/kfr2r09.h
+8
-8
arch/sh/include/mach-migor/mach/migor.h
arch/sh/include/mach-migor/mach/migor.h
+1
-1
drivers/video/Kconfig
drivers/video/Kconfig
+1
-0
drivers/video/sh_mipi_dsi.c
drivers/video/sh_mipi_dsi.c
+43
-54
drivers/video/sh_mobile_hdmi.c
drivers/video/sh_mobile_hdmi.c
+74
-223
drivers/video/sh_mobile_lcdcfb.c
drivers/video/sh_mobile_lcdcfb.c
+753
-545
drivers/video/sh_mobile_lcdcfb.h
drivers/video/sh_mobile_lcdcfb.h
+69
-15
drivers/video/sh_mobile_meram.c
drivers/video/sh_mobile_meram.c
+366
-324
include/video/sh_mobile_hdmi.h
include/video/sh_mobile_hdmi.h
+0
-2
include/video/sh_mobile_lcdc.h
include/video/sh_mobile_lcdc.h
+15
-20
include/video/sh_mobile_meram.h
include/video/sh_mobile_meram.h
+20
-25
No files found.
arch/arm/mach-shmobile/board-ag5evm.c
View file @
f9b4a5ce
...
...
@@ -229,16 +229,6 @@ static void lcd_backlight_reset(void)
gpio_set_value
(
GPIO_PORT235
,
1
);
}
static
void
lcd_on
(
void
*
board_data
,
struct
fb_info
*
info
)
{
lcd_backlight_on
();
}
static
void
lcd_off
(
void
*
board_data
)
{
lcd_backlight_reset
();
}
/* LCDC0 */
static
const
struct
fb_videomode
lcdc0_modes
[]
=
{
{
...
...
@@ -262,14 +252,14 @@ static struct sh_mobile_lcdc_info lcdc0_info = {
.
interface_type
=
RGB24
,
.
clock_divider
=
1
,
.
flags
=
LCDC_FLAGS_DWPOL
,
.
lcd_size_cfg
.
width
=
44
,
.
lcd_size_cfg
.
height
=
79
,
.
fourcc
=
V4L2_PIX_FMT_RGB565
,
.
lcd_cfg
=
lcdc0_modes
,
.
num_cfg
=
ARRAY_SIZE
(
lcdc0_modes
),
.
board_cfg
=
{
.
display_on
=
lcd_on
,
.
display_off
=
lcd_off
,
.
lcd_modes
=
lcdc0_modes
,
.
num_modes
=
ARRAY_SIZE
(
lcdc0_modes
),
.
panel_cfg
=
{
.
width
=
44
,
.
height
=
79
,
.
display_on
=
lcd_backlight_on
,
.
display_off
=
lcd_backlight_reset
,
},
}
};
...
...
arch/arm/mach-shmobile/board-ap4evb.c
View file @
f9b4a5ce
...
...
@@ -258,8 +258,14 @@ static struct sh_mobile_meram_info meram_info = {
static
struct
resource
meram_resources
[]
=
{
[
0
]
=
{
.
name
=
"MERAM
"
,
.
name
=
"regs
"
,
.
start
=
0xe8000000
,
.
end
=
0xe807ffff
,
.
flags
=
IORESOURCE_MEM
,
},
[
1
]
=
{
.
name
=
"meram"
,
.
start
=
0xe8080000
,
.
end
=
0xe81fffff
,
.
flags
=
IORESOURCE_MEM
,
},
...
...
@@ -437,82 +443,6 @@ static struct platform_device usb1_host_device = {
.
resource
=
usb1_host_resources
,
};
static
const
struct
fb_videomode
ap4evb_lcdc_modes
[]
=
{
{
#ifdef CONFIG_AP4EVB_QHD
.
name
=
"R63302(QHD)"
,
.
xres
=
544
,
.
yres
=
961
,
.
left_margin
=
72
,
.
right_margin
=
600
,
.
hsync_len
=
16
,
.
upper_margin
=
8
,
.
lower_margin
=
8
,
.
vsync_len
=
2
,
.
sync
=
FB_SYNC_VERT_HIGH_ACT
|
FB_SYNC_HOR_HIGH_ACT
,
#else
.
name
=
"WVGA Panel"
,
.
xres
=
800
,
.
yres
=
480
,
.
left_margin
=
220
,
.
right_margin
=
110
,
.
hsync_len
=
70
,
.
upper_margin
=
20
,
.
lower_margin
=
5
,
.
vsync_len
=
5
,
.
sync
=
0
,
#endif
},
};
static
struct
sh_mobile_meram_cfg
lcd_meram_cfg
=
{
.
icb
[
0
]
=
{
.
marker_icb
=
28
,
.
cache_icb
=
24
,
.
meram_offset
=
0x0
,
.
meram_size
=
0x40
,
},
.
icb
[
1
]
=
{
.
marker_icb
=
29
,
.
cache_icb
=
25
,
.
meram_offset
=
0x40
,
.
meram_size
=
0x40
,
},
};
static
struct
sh_mobile_lcdc_info
lcdc_info
=
{
.
meram_dev
=
&
meram_info
,
.
ch
[
0
]
=
{
.
chan
=
LCDC_CHAN_MAINLCD
,
.
fourcc
=
V4L2_PIX_FMT_RGB565
,
.
lcd_cfg
=
ap4evb_lcdc_modes
,
.
num_cfg
=
ARRAY_SIZE
(
ap4evb_lcdc_modes
),
.
meram_cfg
=
&
lcd_meram_cfg
,
}
};
static
struct
resource
lcdc_resources
[]
=
{
[
0
]
=
{
.
name
=
"LCDC"
,
.
start
=
0xfe940000
,
/* P4-only space */
.
end
=
0xfe943fff
,
.
flags
=
IORESOURCE_MEM
,
},
[
1
]
=
{
.
start
=
intcs_evt2irq
(
0x580
),
.
flags
=
IORESOURCE_IRQ
,
},
};
static
struct
platform_device
lcdc_device
=
{
.
name
=
"sh_mobile_lcdc_fb"
,
.
num_resources
=
ARRAY_SIZE
(
lcdc_resources
),
.
resource
=
lcdc_resources
,
.
dev
=
{
.
platform_data
=
&
lcdc_info
,
.
coherent_dma_mask
=
~
0
,
},
};
/*
* QHD display
*/
...
...
@@ -593,6 +523,8 @@ static struct resource mipidsi0_resources[] = {
},
};
static
struct
sh_mobile_lcdc_info
lcdc_info
;
static
struct
sh_mipi_dsi_info
mipidsi0_info
=
{
.
data_format
=
MIPI_RGB888
,
.
lcd_chan
=
&
lcdc_info
.
ch
[
0
],
...
...
@@ -619,6 +551,81 @@ static struct platform_device *qhd_devices[] __initdata = {
};
#endif
/* CONFIG_AP4EVB_QHD */
/* LCDC0 */
static
const
struct
fb_videomode
ap4evb_lcdc_modes
[]
=
{
{
#ifdef CONFIG_AP4EVB_QHD
.
name
=
"R63302(QHD)"
,
.
xres
=
544
,
.
yres
=
961
,
.
left_margin
=
72
,
.
right_margin
=
600
,
.
hsync_len
=
16
,
.
upper_margin
=
8
,
.
lower_margin
=
8
,
.
vsync_len
=
2
,
.
sync
=
FB_SYNC_VERT_HIGH_ACT
|
FB_SYNC_HOR_HIGH_ACT
,
#else
.
name
=
"WVGA Panel"
,
.
xres
=
800
,
.
yres
=
480
,
.
left_margin
=
220
,
.
right_margin
=
110
,
.
hsync_len
=
70
,
.
upper_margin
=
20
,
.
lower_margin
=
5
,
.
vsync_len
=
5
,
.
sync
=
0
,
#endif
},
};
static
const
struct
sh_mobile_meram_cfg
lcd_meram_cfg
=
{
.
icb
[
0
]
=
{
.
meram_size
=
0x40
,
},
.
icb
[
1
]
=
{
.
meram_size
=
0x40
,
},
};
static
struct
sh_mobile_lcdc_info
lcdc_info
=
{
.
meram_dev
=
&
meram_info
,
.
ch
[
0
]
=
{
.
chan
=
LCDC_CHAN_MAINLCD
,
.
fourcc
=
V4L2_PIX_FMT_RGB565
,
.
lcd_modes
=
ap4evb_lcdc_modes
,
.
num_modes
=
ARRAY_SIZE
(
ap4evb_lcdc_modes
),
.
meram_cfg
=
&
lcd_meram_cfg
,
#ifdef CONFIG_AP4EVB_QHD
.
tx_dev
=
&
mipidsi0_device
,
#endif
}
};
static
struct
resource
lcdc_resources
[]
=
{
[
0
]
=
{
.
name
=
"LCDC"
,
.
start
=
0xfe940000
,
/* P4-only space */
.
end
=
0xfe943fff
,
.
flags
=
IORESOURCE_MEM
,
},
[
1
]
=
{
.
start
=
intcs_evt2irq
(
0x580
),
.
flags
=
IORESOURCE_IRQ
,
},
};
static
struct
platform_device
lcdc_device
=
{
.
name
=
"sh_mobile_lcdc_fb"
,
.
num_resources
=
ARRAY_SIZE
(
lcdc_resources
),
.
resource
=
lcdc_resources
,
.
dev
=
{
.
platform_data
=
&
lcdc_info
,
.
coherent_dma_mask
=
~
0
,
},
};
/* FSI */
#define IRQ_FSI evt2irq(0x1840)
static
int
__fsi_set_rate
(
struct
clk
*
clk
,
long
rate
,
int
enable
)
...
...
@@ -798,65 +805,11 @@ static struct platform_device fsi_ak4643_device = {
},
};
static
struct
sh_mobile_meram_cfg
hdmi_meram_cfg
=
{
.
icb
[
0
]
=
{
.
marker_icb
=
30
,
.
cache_icb
=
26
,
.
meram_offset
=
0x80
,
.
meram_size
=
0x100
,
},
.
icb
[
1
]
=
{
.
marker_icb
=
31
,
.
cache_icb
=
27
,
.
meram_offset
=
0x180
,
.
meram_size
=
0x100
,
},
};
static
struct
sh_mobile_lcdc_info
sh_mobile_lcdc1_info
=
{
.
clock_source
=
LCDC_CLK_EXTERNAL
,
.
meram_dev
=
&
meram_info
,
.
ch
[
0
]
=
{
.
chan
=
LCDC_CHAN_MAINLCD
,
.
fourcc
=
V4L2_PIX_FMT_RGB565
,
.
interface_type
=
RGB24
,
.
clock_divider
=
1
,
.
flags
=
LCDC_FLAGS_DWPOL
,
.
meram_cfg
=
&
hdmi_meram_cfg
,
}
};
static
struct
resource
lcdc1_resources
[]
=
{
[
0
]
=
{
.
name
=
"LCDC1"
,
.
start
=
0xfe944000
,
.
end
=
0xfe947fff
,
.
flags
=
IORESOURCE_MEM
,
},
[
1
]
=
{
.
start
=
intcs_evt2irq
(
0x1780
),
.
flags
=
IORESOURCE_IRQ
,
},
};
static
struct
platform_device
lcdc1_device
=
{
.
name
=
"sh_mobile_lcdc_fb"
,
.
num_resources
=
ARRAY_SIZE
(
lcdc1_resources
),
.
resource
=
lcdc1_resources
,
.
id
=
1
,
.
dev
=
{
.
platform_data
=
&
sh_mobile_lcdc1_info
,
.
coherent_dma_mask
=
~
0
,
},
};
/* LCDC1 */
static
long
ap4evb_clk_optimize
(
unsigned
long
target
,
unsigned
long
*
best_freq
,
unsigned
long
*
parent_freq
);
static
struct
sh_mobile_hdmi_info
hdmi_info
=
{
.
lcd_chan
=
&
sh_mobile_lcdc1_info
.
ch
[
0
],
.
lcd_dev
=
&
lcdc1_device
.
dev
,
.
flags
=
HDMI_SND_SRC_SPDIF
,
.
clk_optimize_parent
=
ap4evb_clk_optimize
,
};
...
...
@@ -885,10 +838,6 @@ static struct platform_device hdmi_device = {
},
};
static
struct
platform_device
fsi_hdmi_device
=
{
.
name
=
"sh_fsi2_b_hdmi"
,
};
static
long
ap4evb_clk_optimize
(
unsigned
long
target
,
unsigned
long
*
best_freq
,
unsigned
long
*
parent_freq
)
{
...
...
@@ -908,6 +857,57 @@ static long ap4evb_clk_optimize(unsigned long target, unsigned long *best_freq,
return
error
;
}
static
const
struct
sh_mobile_meram_cfg
hdmi_meram_cfg
=
{
.
icb
[
0
]
=
{
.
meram_size
=
0x100
,
},
.
icb
[
1
]
=
{
.
meram_size
=
0x100
,
},
};
static
struct
sh_mobile_lcdc_info
sh_mobile_lcdc1_info
=
{
.
clock_source
=
LCDC_CLK_EXTERNAL
,
.
meram_dev
=
&
meram_info
,
.
ch
[
0
]
=
{
.
chan
=
LCDC_CHAN_MAINLCD
,
.
fourcc
=
V4L2_PIX_FMT_RGB565
,
.
interface_type
=
RGB24
,
.
clock_divider
=
1
,
.
flags
=
LCDC_FLAGS_DWPOL
,
.
meram_cfg
=
&
hdmi_meram_cfg
,
.
tx_dev
=
&
hdmi_device
,
}
};
static
struct
resource
lcdc1_resources
[]
=
{
[
0
]
=
{
.
name
=
"LCDC1"
,
.
start
=
0xfe944000
,
.
end
=
0xfe947fff
,
.
flags
=
IORESOURCE_MEM
,
},
[
1
]
=
{
.
start
=
intcs_evt2irq
(
0x1780
),
.
flags
=
IORESOURCE_IRQ
,
},
};
static
struct
platform_device
lcdc1_device
=
{
.
name
=
"sh_mobile_lcdc_fb"
,
.
num_resources
=
ARRAY_SIZE
(
lcdc1_resources
),
.
resource
=
lcdc1_resources
,
.
id
=
1
,
.
dev
=
{
.
platform_data
=
&
sh_mobile_lcdc1_info
,
.
coherent_dma_mask
=
~
0
,
},
};
static
struct
platform_device
fsi_hdmi_device
=
{
.
name
=
"sh_fsi2_b_hdmi"
,
};
static
struct
gpio_led
ap4evb_leds
[]
=
{
{
.
name
=
"led4"
,
...
...
@@ -1042,9 +1042,9 @@ static struct platform_device *ap4evb_devices[] __initdata = {
&
fsi_ak4643_device
,
&
fsi_hdmi_device
,
&
sh_mmcif_device
,
&
lcdc1_device
,
&
lcdc_device
,
&
hdmi_device
,
&
lcdc_device
,
&
lcdc1_device
,
&
ceu_device
,
&
ap4evb_camera
,
&
meram_device
,
...
...
@@ -1355,8 +1355,8 @@ static void __init ap4evb_init(void)
lcdc_info
.
ch
[
0
].
interface_type
=
RGB24
;
lcdc_info
.
ch
[
0
].
clock_divider
=
1
;
lcdc_info
.
ch
[
0
].
flags
=
LCDC_FLAGS_DWPOL
;
lcdc_info
.
ch
[
0
].
lcd_size_cfg
.
width
=
44
;
lcdc_info
.
ch
[
0
].
lcd_size
_cfg
.
height
=
79
;
lcdc_info
.
ch
[
0
].
panel_cfg
.
width
=
44
;
lcdc_info
.
ch
[
0
].
panel
_cfg
.
height
=
79
;
platform_add_devices
(
qhd_devices
,
ARRAY_SIZE
(
qhd_devices
));
...
...
@@ -1397,8 +1397,8 @@ static void __init ap4evb_init(void)
lcdc_info
.
ch
[
0
].
interface_type
=
RGB18
;
lcdc_info
.
ch
[
0
].
clock_divider
=
3
;
lcdc_info
.
ch
[
0
].
flags
=
0
;
lcdc_info
.
ch
[
0
].
lcd_size_cfg
.
width
=
152
;
lcdc_info
.
ch
[
0
].
lcd_size
_cfg
.
height
=
91
;
lcdc_info
.
ch
[
0
].
panel_cfg
.
width
=
152
;
lcdc_info
.
ch
[
0
].
panel
_cfg
.
height
=
91
;
/* enable TouchScreen */
irq_set_irq_type
(
IRQ7
,
IRQ_TYPE_LEVEL_LOW
);
...
...
arch/arm/mach-shmobile/board-bonito.c
View file @
f9b4a5ce
...
...
@@ -245,9 +245,9 @@ static struct sh_mobile_lcdc_info lcdc0_info = {
.
interface_type
=
RGB24
,
.
clock_divider
=
5
,
.
flags
=
0
,
.
lcd_
cfg
=
&
lcdc0_mode
,
.
num_
cfg
=
1
,
.
lcd_size
_cfg
=
{
.
lcd_
modes
=
&
lcdc0_mode
,
.
num_
modes
=
1
,
.
panel
_cfg
=
{
.
width
=
152
,
.
height
=
91
,
},
...
...
arch/arm/mach-shmobile/board-mackerel.c
View file @
f9b4a5ce
...
...
@@ -318,8 +318,14 @@ static struct sh_mobile_meram_info mackerel_meram_info = {
static
struct
resource
meram_resources
[]
=
{
[
0
]
=
{
.
name
=
"
MERAM
"
,
.
name
=
"
regs
"
,
.
start
=
0xe8000000
,
.
end
=
0xe807ffff
,
.
flags
=
IORESOURCE_MEM
,
},
[
1
]
=
{
.
name
=
"meram"
,
.
start
=
0xe8080000
,
.
end
=
0xe81fffff
,
.
flags
=
IORESOURCE_MEM
,
},
...
...
@@ -351,29 +357,23 @@ static struct fb_videomode mackerel_lcdc_modes[] = {
},
};
static
int
mackerel_set_brightness
(
void
*
board_data
,
int
brightness
)
static
int
mackerel_set_brightness
(
int
brightness
)
{
gpio_set_value
(
GPIO_PORT31
,
brightness
);
return
0
;
}
static
int
mackerel_get_brightness
(
void
*
board_data
)
static
int
mackerel_get_brightness
(
void
)
{
return
gpio_get_value
(
GPIO_PORT31
);
}
static
struct
sh_mobile_meram_cfg
lcd_meram_cfg
=
{
static
const
struct
sh_mobile_meram_cfg
lcd_meram_cfg
=
{
.
icb
[
0
]
=
{
.
marker_icb
=
28
,
.
cache_icb
=
24
,
.
meram_offset
=
0x0
,
.
meram_size
=
0x40
,
},
.
icb
[
1
]
=
{
.
marker_icb
=
29
,
.
cache_icb
=
25
,
.
meram_offset
=
0x40
,
.
meram_size
=
0x40
,
},
};
...
...
@@ -384,20 +384,20 @@ static struct sh_mobile_lcdc_info lcdc_info = {
.
ch
[
0
]
=
{
.
chan
=
LCDC_CHAN_MAINLCD
,
.
fourcc
=
V4L2_PIX_FMT_RGB565
,
.
lcd_
cfg
=
mackerel_lcdc_modes
,
.
num_
cfg
=
ARRAY_SIZE
(
mackerel_lcdc_modes
),
.
lcd_
modes
=
mackerel_lcdc_modes
,
.
num_
modes
=
ARRAY_SIZE
(
mackerel_lcdc_modes
),
.
interface_type
=
RGB24
,
.
clock_divider
=
3
,
.
flags
=
0
,
.
lcd_size_cfg
.
width
=
152
,
.
lcd_size_cfg
.
height
=
91
,
.
board_cfg
=
{
.
set_brightness
=
mackerel_set_brightness
,
.
get_brightness
=
mackerel_get_brightness
,
.
panel_cfg
=
{
.
width
=
152
,
.
height
=
91
,
},
.
bl_info
=
{
.
name
=
"sh_mobile_lcdc_bl"
,
.
max_brightness
=
1
,
.
set_brightness
=
mackerel_set_brightness
,
.
get_brightness
=
mackerel_get_brightness
,
},
.
meram_cfg
=
&
lcd_meram_cfg
,
}
...
...
@@ -426,21 +426,44 @@ static struct platform_device lcdc_device = {
},
};
static
struct
sh_mobile_meram_cfg
hdmi_meram_cfg
=
{
/* HDMI */
static
struct
sh_mobile_hdmi_info
hdmi_info
=
{
.
flags
=
HDMI_SND_SRC_SPDIF
,
};
static
struct
resource
hdmi_resources
[]
=
{
[
0
]
=
{
.
name
=
"HDMI"
,
.
start
=
0xe6be0000
,
.
end
=
0xe6be00ff
,
.
flags
=
IORESOURCE_MEM
,
},
[
1
]
=
{
/* There's also an HDMI interrupt on INTCS @ 0x18e0 */
.
start
=
evt2irq
(
0x17e0
),
.
flags
=
IORESOURCE_IRQ
,
},
};
static
struct
platform_device
hdmi_device
=
{
.
name
=
"sh-mobile-hdmi"
,
.
num_resources
=
ARRAY_SIZE
(
hdmi_resources
),
.
resource
=
hdmi_resources
,
.
id
=
-
1
,
.
dev
=
{
.
platform_data
=
&
hdmi_info
,
},
};
static
const
struct
sh_mobile_meram_cfg
hdmi_meram_cfg
=
{
.
icb
[
0
]
=
{
.
marker_icb
=
30
,
.
cache_icb
=
26
,
.
meram_offset
=
0x80
,
.
meram_size
=
0x100
,
},
.
icb
[
1
]
=
{
.
marker_icb
=
31
,
.
cache_icb
=
27
,
.
meram_offset
=
0x180
,
.
meram_size
=
0x100
,
},
};
/* HDMI */
static
struct
sh_mobile_lcdc_info
hdmi_lcdc_info
=
{
.
meram_dev
=
&
mackerel_meram_info
,
.
clock_source
=
LCDC_CLK_EXTERNAL
,
...
...
@@ -451,6 +474,7 @@ static struct sh_mobile_lcdc_info hdmi_lcdc_info = {
.
clock_divider
=
1
,
.
flags
=
LCDC_FLAGS_DWPOL
,
.
meram_cfg
=
&
hdmi_meram_cfg
,
.
tx_dev
=
&
hdmi_device
,
}
};
...
...
@@ -478,36 +502,6 @@ static struct platform_device hdmi_lcdc_device = {
},
};
static
struct
sh_mobile_hdmi_info
hdmi_info
=
{
.
lcd_chan
=
&
hdmi_lcdc_info
.
ch
[
0
],
.
lcd_dev
=
&
hdmi_lcdc_device
.
dev
,
.
flags
=
HDMI_SND_SRC_SPDIF
,
};
static
struct
resource
hdmi_resources
[]
=
{
[
0
]
=
{
.
name
=
"HDMI"
,
.
start
=
0xe6be0000
,
.
end
=
0xe6be00ff
,
.
flags
=
IORESOURCE_MEM
,
},
[
1
]
=
{
/* There's also an HDMI interrupt on INTCS @ 0x18e0 */
.
start
=
evt2irq
(
0x17e0
),
.
flags
=
IORESOURCE_IRQ
,
},
};
static
struct
platform_device
hdmi_device
=
{
.
name
=
"sh-mobile-hdmi"
,
.
num_resources
=
ARRAY_SIZE
(
hdmi_resources
),
.
resource
=
hdmi_resources
,
.
id
=
-
1
,
.
dev
=
{
.
platform_data
=
&
hdmi_info
,
},
};
static
struct
platform_device
fsi_hdmi_device
=
{
.
name
=
"sh_fsi2_b_hdmi"
,
};
...
...
@@ -1276,8 +1270,8 @@ static struct platform_device *mackerel_devices[] __initdata = {
&
sh_mmcif_device
,
&
ceu_device
,
&
mackerel_camera
,
&
hdmi_lcdc_device
,
&
hdmi_device
,
&
hdmi_lcdc_device
,
&
meram_device
,
};
...
...
arch/sh/boards/mach-ap325rxa/setup.c
View file @
f9b4a5ce
...
...
@@ -157,7 +157,7 @@ static struct platform_device nand_flash_device = {
#define PORT_DRVCRA 0xA405018A
#define PORT_DRVCRB 0xA405018C
static
int
ap320_wvga_set_brightness
(
void
*
board_data
,
int
brightness
)
static
int
ap320_wvga_set_brightness
(
int
brightness
)
{
if
(
brightness
)
{
gpio_set_value
(
GPIO_PTS3
,
0
);
...
...
@@ -170,12 +170,12 @@ static int ap320_wvga_set_brightness(void *board_data, int brightness)
return
0
;
}
static
int
ap320_wvga_get_brightness
(
void
*
board_data
)
static
int
ap320_wvga_get_brightness
(
void
)
{
return
gpio_get_value
(
GPIO_PTS3
);
}
static
void
ap320_wvga_power_on
(
void
*
board_data
,
struct
fb_info
*
info
)
static
void
ap320_wvga_power_on
(
void
)
{
msleep
(
100
);
...
...
@@ -183,7 +183,7 @@ static void ap320_wvga_power_on(void *board_data, struct fb_info *info)
__raw_writew
(
FPGA_LCDREG_VAL
,
FPGA_LCDREG
);
}
static
void
ap320_wvga_power_off
(
void
*
board_data
)
static
void
ap320_wvga_power_off
(
void
)
{
/* ASD AP-320/325 LCD OFF */
__raw_writew
(
0
,
FPGA_LCDREG
);
...
...
@@ -211,21 +211,19 @@ static struct sh_mobile_lcdc_info lcdc_info = {
.
fourcc
=
V4L2_PIX_FMT_RGB565
,
.
interface_type
=
RGB18
,
.
clock_divider
=
1
,
.
lcd_
cfg
=
ap325rxa_lcdc_modes
,
.
num_
cfg
=
ARRAY_SIZE
(
ap325rxa_lcdc_modes
),
.
lcd_size_cfg
=
{
/* 7.0 inch */
.
width
=
152
,
.
lcd_
modes
=
ap325rxa_lcdc_modes
,
.
num_
modes
=
ARRAY_SIZE
(
ap325rxa_lcdc_modes
),
.
panel_cfg
=
{
.
width
=
152
,
/* 7.0 inch */
.
height
=
91
,
},
.
board_cfg
=
{
.
display_on
=
ap320_wvga_power_on
,
.
display_off
=
ap320_wvga_power_off
,
.
set_brightness
=
ap320_wvga_set_brightness
,
.
get_brightness
=
ap320_wvga_get_brightness
,
},
.
bl_info
=
{
.
name
=
"sh_mobile_lcdc_bl"
,
.
max_brightness
=
1
,
.
set_brightness
=
ap320_wvga_set_brightness
,
.
get_brightness
=
ap320_wvga_get_brightness
,
},
}
};
...
...
arch/sh/boards/mach-ecovec24/setup.c
View file @
f9b4a5ce
...
...
@@ -310,14 +310,14 @@ static const struct fb_videomode ecovec_dvi_modes[] = {
},
};
static
int
ecovec24_set_brightness
(
void
*
board_data
,
int
brightness
)
static
int
ecovec24_set_brightness
(
int
brightness
)
{
gpio_set_value
(
GPIO_PTR1
,
brightness
);
return
0
;
}
static
int
ecovec24_get_brightness
(
void
*
board_data
)
static
int
ecovec24_get_brightness
(
void
)
{
return
gpio_get_value
(
GPIO_PTR1
);
}
...
...
@@ -327,17 +327,15 @@ static struct sh_mobile_lcdc_info lcdc_info = {
.
interface_type
=
RGB18
,
.
chan
=
LCDC_CHAN_MAINLCD
,
.
fourcc
=
V4L2_PIX_FMT_RGB565
,
.
lcd_size
_cfg
=
{
/* 7.0 inch */
.
panel
_cfg
=
{
/* 7.0 inch */
.
width
=
152
,
.
height
=
91
,
},
.
board_cfg
=
{
.
set_brightness
=
ecovec24_set_brightness
,
.
get_brightness
=
ecovec24_get_brightness
,
},
.
bl_info
=
{
.
name
=
"sh_mobile_lcdc_bl"
,
.
max_brightness
=
1
,
.
set_brightness
=
ecovec24_set_brightness
,
.
get_brightness
=
ecovec24_get_brightness
,
},
}
};
...
...
@@ -1116,8 +1114,8 @@ static int __init arch_setup(void)
/* DVI */
lcdc_info
.
clock_source
=
LCDC_CLK_EXTERNAL
;
lcdc_info
.
ch
[
0
].
clock_divider
=
1
;
lcdc_info
.
ch
[
0
].
lcd_
cfg
=
ecovec_dvi_modes
;
lcdc_info
.
ch
[
0
].
num_
cfg
=
ARRAY_SIZE
(
ecovec_dvi_modes
);
lcdc_info
.
ch
[
0
].
lcd_
modes
=
ecovec_dvi_modes
;
lcdc_info
.
ch
[
0
].
num_
modes
=
ARRAY_SIZE
(
ecovec_dvi_modes
);
gpio_set_value
(
GPIO_PTA2
,
1
);
gpio_set_value
(
GPIO_PTU1
,
1
);
...
...
@@ -1125,8 +1123,8 @@ static int __init arch_setup(void)
/* Panel */
lcdc_info
.
clock_source
=
LCDC_CLK_PERIPHERAL
;
lcdc_info
.
ch
[
0
].
clock_divider
=
2
;
lcdc_info
.
ch
[
0
].
lcd_
cfg
=
ecovec_lcd_modes
;
lcdc_info
.
ch
[
0
].
num_
cfg
=
ARRAY_SIZE
(
ecovec_lcd_modes
);
lcdc_info
.
ch
[
0
].
lcd_
modes
=
ecovec_lcd_modes
;
lcdc_info
.
ch
[
0
].
num_
modes
=
ARRAY_SIZE
(
ecovec_lcd_modes
);
gpio_set_value
(
GPIO_PTR1
,
1
);
...
...
arch/sh/boards/mach-kfr2r09/lcd_wqvga.c
View file @
f9b4a5ce
...
...
@@ -251,8 +251,7 @@ static void display_on(void *sohandle,
write_memory_start
(
sohandle
,
so
);
}
int
kfr2r09_lcd_setup
(
void
*
board_data
,
void
*
sohandle
,
struct
sh_mobile_lcdc_sys_bus_ops
*
so
)
int
kfr2r09_lcd_setup
(
void
*
sohandle
,
struct
sh_mobile_lcdc_sys_bus_ops
*
so
)
{
/* power on */
gpio_set_value
(
GPIO_PTF4
,
0
);
/* PROTECT/ -> L */
...
...
@@ -273,8 +272,7 @@ int kfr2r09_lcd_setup(void *board_data, void *sohandle,
return
0
;
}
void
kfr2r09_lcd_start
(
void
*
board_data
,
void
*
sohandle
,
struct
sh_mobile_lcdc_sys_bus_ops
*
so
)
void
kfr2r09_lcd_start
(
void
*
sohandle
,
struct
sh_mobile_lcdc_sys_bus_ops
*
so
)
{
write_memory_start
(
sohandle
,
so
);
}
...
...
@@ -327,12 +325,12 @@ static int kfr2r09_lcd_backlight(int on)
return
0
;
}
void
kfr2r09_lcd_on
(
void
*
board_data
,
struct
fb_info
*
info
)
void
kfr2r09_lcd_on
(
void
)
{
kfr2r09_lcd_backlight
(
1
);
}
void
kfr2r09_lcd_off
(
void
*
board_data
)
void
kfr2r09_lcd_off
(
void
)
{
kfr2r09_lcd_backlight
(
0
);
}
arch/sh/boards/mach-kfr2r09/setup.c
View file @
f9b4a5ce
...
...
@@ -148,13 +148,11 @@ static struct sh_mobile_lcdc_info kfr2r09_sh_lcdc_info = {
.
interface_type
=
SYS18
,
.
clock_divider
=
6
,
.
flags
=
LCDC_FLAGS_DWPOL
,
.
lcd_
cfg
=
kfr2r09_lcdc_modes
,
.
num_
cfg
=
ARRAY_SIZE
(
kfr2r09_lcdc_modes
),
.
lcd_size
_cfg
=
{
.
lcd_
modes
=
kfr2r09_lcdc_modes
,
.
num_
modes
=
ARRAY_SIZE
(
kfr2r09_lcdc_modes
),
.
panel
_cfg
=
{
.
width
=
35
,
.
height
=
58
,
},
.
board_cfg
=
{
.
setup_sys
=
kfr2r09_lcd_setup
,
.
start_transfer
=
kfr2r09_lcd_start
,
.
display_on
=
kfr2r09_lcd_on
,
...
...
arch/sh/boards/mach-migor/lcd_qvga.c
View file @
f9b4a5ce
...
...
@@ -113,8 +113,7 @@ static const unsigned short magic3_data[] = {
0x0010
,
0x16B0
,
0x0011
,
0x0111
,
0x0007
,
0x0061
,
};
int
migor_lcd_qvga_setup
(
void
*
board_data
,
void
*
sohandle
,
struct
sh_mobile_lcdc_sys_bus_ops
*
so
)
int
migor_lcd_qvga_setup
(
void
*
sohandle
,
struct
sh_mobile_lcdc_sys_bus_ops
*
so
)
{
unsigned
long
xres
=
320
;
unsigned
long
yres
=
240
;
...
...
arch/sh/boards/mach-migor/setup.c
View file @
f9b4a5ce
...
...
@@ -246,9 +246,9 @@ static struct sh_mobile_lcdc_info sh_mobile_lcdc_info = {
.
fourcc
=
V4L2_PIX_FMT_RGB565
,
.
interface_type
=
RGB16
,
.
clock_divider
=
2
,
.
lcd_
cfg
=
migor_lcd_modes
,
.
num_
cfg
=
ARRAY_SIZE
(
migor_lcd_modes
),
.
lcd_size
_cfg
=
{
/* 7.0 inch */
.
lcd_
modes
=
migor_lcd_modes
,
.
num_
modes
=
ARRAY_SIZE
(
migor_lcd_modes
),
.
panel
_cfg
=
{
/* 7.0 inch */
.
width
=
152
,
.
height
=
91
,
},
...
...
@@ -260,13 +260,11 @@ static struct sh_mobile_lcdc_info sh_mobile_lcdc_info = {
.
fourcc
=
V4L2_PIX_FMT_RGB565
,
.
interface_type
=
SYS16A
,
.
clock_divider
=
10
,
.
lcd_
cfg
=
migor_lcd_modes
,
.
num_
cfg
=
ARRAY_SIZE
(
migor_lcd_modes
),
.
lcd_size_cfg
=
{
/* 2.4 inch */
.
width
=
49
,
.
lcd_
modes
=
migor_lcd_modes
,
.
num_
modes
=
ARRAY_SIZE
(
migor_lcd_modes
),
.
panel_cfg
=
{
.
width
=
49
,
/* 2.4 inch */
.
height
=
37
,
},
.
board_cfg
=
{
.
setup_sys
=
migor_lcd_qvga_setup
,
},
.
sys_bus_cfg
=
{
...
...
arch/sh/boards/mach-se/7724/setup.c
View file @
f9b4a5ce
...
...
@@ -182,12 +182,10 @@ static struct sh_mobile_lcdc_info lcdc_info = {
.
chan
=
LCDC_CHAN_MAINLCD
,
.
fourcc
=
V4L2_PIX_FMT_RGB565
,
.
clock_divider
=
1
,
.
lcd_size
_cfg
=
{
/* 7.0 inch */
.
panel
_cfg
=
{
/* 7.0 inch */
.
width
=
152
,
.
height
=
91
,
},
.
board_cfg
=
{
},
}
};
...
...
@@ -888,12 +886,12 @@ static int __init devices_setup(void)
if
(
sw
&
SW41_B
)
{
/* 720p */
lcdc_info
.
ch
[
0
].
lcd_
cfg
=
lcdc_720p_modes
;
lcdc_info
.
ch
[
0
].
num_
cfg
=
ARRAY_SIZE
(
lcdc_720p_modes
);
lcdc_info
.
ch
[
0
].
lcd_
modes
=
lcdc_720p_modes
;
lcdc_info
.
ch
[
0
].
num_
modes
=
ARRAY_SIZE
(
lcdc_720p_modes
);
}
else
{
/* VGA */
lcdc_info
.
ch
[
0
].
lcd_
cfg
=
lcdc_vga_modes
;
lcdc_info
.
ch
[
0
].
num_
cfg
=
ARRAY_SIZE
(
lcdc_vga_modes
);
lcdc_info
.
ch
[
0
].
lcd_
modes
=
lcdc_vga_modes
;
lcdc_info
.
ch
[
0
].
num_
modes
=
ARRAY_SIZE
(
lcdc_vga_modes
);
}
if
(
sw
&
SW41_A
)
{
...
...
arch/sh/include/mach-kfr2r09/mach/kfr2r09.h
View file @
f9b4a5ce
...
...
@@ -4,21 +4,21 @@
#include <video/sh_mobile_lcdc.h>
#if defined(CONFIG_FB_SH_MOBILE_LCDC) || defined(CONFIG_FB_SH_MOBILE_LCDC_MODULE)
void
kfr2r09_lcd_on
(
void
*
board_data
,
struct
fb_info
*
info
);
void
kfr2r09_lcd_off
(
void
*
board_data
);
int
kfr2r09_lcd_setup
(
void
*
board_data
,
void
*
sys_ops_handle
,
void
kfr2r09_lcd_on
(
void
);
void
kfr2r09_lcd_off
(
void
);
int
kfr2r09_lcd_setup
(
void
*
sys_ops_handle
,
struct
sh_mobile_lcdc_sys_bus_ops
*
sys_ops
);
void
kfr2r09_lcd_start
(
void
*
board_data
,
void
*
sys_ops_handle
,
void
kfr2r09_lcd_start
(
void
*
sys_ops_handle
,
struct
sh_mobile_lcdc_sys_bus_ops
*
sys_ops
);
#else
static
void
kfr2r09_lcd_on
(
void
*
board_data
)
{}
static
void
kfr2r09_lcd_off
(
void
*
board_data
)
{}
static
int
kfr2r09_lcd_setup
(
void
*
board_data
,
void
*
sys_ops_handle
,
static
void
kfr2r09_lcd_on
(
void
)
{}
static
void
kfr2r09_lcd_off
(
void
)
{}
static
int
kfr2r09_lcd_setup
(
void
*
sys_ops_handle
,
struct
sh_mobile_lcdc_sys_bus_ops
*
sys_ops
)
{
return
-
ENODEV
;
}
static
void
kfr2r09_lcd_start
(
void
*
board_data
,
void
*
sys_ops_handle
,
static
void
kfr2r09_lcd_start
(
void
*
sys_ops_handle
,
struct
sh_mobile_lcdc_sys_bus_ops
*
sys_ops
)
{
}
...
...
arch/sh/include/mach-migor/mach/migor.h
View file @
f9b4a5ce
...
...
@@ -9,7 +9,7 @@
#include <video/sh_mobile_lcdc.h>
int
migor_lcd_qvga_setup
(
void
*
board_data
,
void
*
sys_ops_handle
,
int
migor_lcd_qvga_setup
(
void
*
sys_ops_handle
,
struct
sh_mobile_lcdc_sys_bus_ops
*
sys_ops
);
#endif
/* __ASM_SH_MIGOR_H */
drivers/video/Kconfig
View file @
f9b4a5ce
...
...
@@ -2016,6 +2016,7 @@ config FB_SH_MOBILE_HDMI
config FB_SH_MOBILE_MERAM
tristate "SuperH Mobile MERAM read ahead support for LCDC"
depends on FB_SH_MOBILE_LCDC
select GENERIC_ALLOCATOR
default y
---help---
Enable MERAM support for the SH-Mobile LCD controller.
...
...
drivers/video/sh_mipi_dsi.c
View file @
f9b4a5ce
...
...
@@ -24,6 +24,8 @@
#include <video/sh_mipi_dsi.h>
#include <video/sh_mobile_lcdc.h>
#include "sh_mobile_lcdcfb.h"
#define SYSCTRL 0x0000
#define SYSCONF 0x0004
#define TIMSET 0x0008
...
...
@@ -50,16 +52,16 @@
#define MAX_SH_MIPI_DSI 2
struct
sh_mipi
{
struct
sh_mobile_lcdc_entity
entity
;
void
__iomem
*
base
;
void
__iomem
*
linkbase
;
struct
clk
*
dsit_clk
;
struct
platform_device
*
pdev
;
void
*
next_board_data
;
void
(
*
next_display_on
)(
void
*
board_data
,
struct
fb_info
*
info
);
void
(
*
next_display_off
)(
void
*
board_data
);
};
#define to_sh_mipi(e) container_of(e, struct sh_mipi, entity)
static
struct
sh_mipi
*
mipi_dsi
[
MAX_SH_MIPI_DSI
];
/* Protect the above array */
...
...
@@ -120,7 +122,7 @@ static void sh_mipi_dsi_enable(struct sh_mipi *mipi, bool enable)
static
void
sh_mipi_shutdown
(
struct
platform_device
*
pdev
)
{
struct
sh_mipi
*
mipi
=
platform_get_drvdata
(
pdev
);
struct
sh_mipi
*
mipi
=
to_sh_mipi
(
platform_get_drvdata
(
pdev
)
);
sh_mipi_dsi_enable
(
mipi
,
false
);
}
...
...
@@ -145,77 +147,77 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi,
pctype
=
0
;
datatype
=
MIPI_DSI_PACKED_PIXEL_STREAM_24
;
pixfmt
=
MIPI_DCS_PIXEL_FMT_24BIT
;
linelength
=
ch
->
lcd_
cfg
[
0
].
xres
*
3
;
linelength
=
ch
->
lcd_
modes
[
0
].
xres
*
3
;
yuv
=
false
;
break
;
case
MIPI_RGB565
:
pctype
=
1
;
datatype
=
MIPI_DSI_PACKED_PIXEL_STREAM_16
;
pixfmt
=
MIPI_DCS_PIXEL_FMT_16BIT
;
linelength
=
ch
->
lcd_
cfg
[
0
].
xres
*
2
;
linelength
=
ch
->
lcd_
modes
[
0
].
xres
*
2
;
yuv
=
false
;
break
;
case
MIPI_RGB666_LP
:
pctype
=
2
;
datatype
=
MIPI_DSI_PIXEL_STREAM_3BYTE_18
;
pixfmt
=
MIPI_DCS_PIXEL_FMT_24BIT
;
linelength
=
ch
->
lcd_
cfg
[
0
].
xres
*
3
;
linelength
=
ch
->
lcd_
modes
[
0
].
xres
*
3
;
yuv
=
false
;
break
;
case
MIPI_RGB666
:
pctype
=
3
;
datatype
=
MIPI_DSI_PACKED_PIXEL_STREAM_18
;
pixfmt
=
MIPI_DCS_PIXEL_FMT_18BIT
;
linelength
=
(
ch
->
lcd_
cfg
[
0
].
xres
*
18
+
7
)
/
8
;
linelength
=
(
ch
->
lcd_
modes
[
0
].
xres
*
18
+
7
)
/
8
;
yuv
=
false
;
break
;
case
MIPI_BGR888
:
pctype
=
8
;
datatype
=
MIPI_DSI_PACKED_PIXEL_STREAM_24
;
pixfmt
=
MIPI_DCS_PIXEL_FMT_24BIT
;
linelength
=
ch
->
lcd_
cfg
[
0
].
xres
*
3
;
linelength
=
ch
->
lcd_
modes
[
0
].
xres
*
3
;
yuv
=
false
;
break
;
case
MIPI_BGR565
:
pctype
=
9
;
datatype
=
MIPI_DSI_PACKED_PIXEL_STREAM_16
;
pixfmt
=
MIPI_DCS_PIXEL_FMT_16BIT
;
linelength
=
ch
->
lcd_
cfg
[
0
].
xres
*
2
;
linelength
=
ch
->
lcd_
modes
[
0
].
xres
*
2
;
yuv
=
false
;
break
;
case
MIPI_BGR666_LP
:
pctype
=
0xa
;
datatype
=
MIPI_DSI_PIXEL_STREAM_3BYTE_18
;
pixfmt
=
MIPI_DCS_PIXEL_FMT_24BIT
;
linelength
=
ch
->
lcd_
cfg
[
0
].
xres
*
3
;
linelength
=
ch
->
lcd_
modes
[
0
].
xres
*
3
;
yuv
=
false
;
break
;
case
MIPI_BGR666
:
pctype
=
0xb
;
datatype
=
MIPI_DSI_PACKED_PIXEL_STREAM_18
;
pixfmt
=
MIPI_DCS_PIXEL_FMT_18BIT
;
linelength
=
(
ch
->
lcd_
cfg
[
0
].
xres
*
18
+
7
)
/
8
;
linelength
=
(
ch
->
lcd_
modes
[
0
].
xres
*
18
+
7
)
/
8
;
yuv
=
false
;
break
;
case
MIPI_YUYV
:
pctype
=
4
;
datatype
=
MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16
;
pixfmt
=
MIPI_DCS_PIXEL_FMT_16BIT
;
linelength
=
ch
->
lcd_
cfg
[
0
].
xres
*
2
;
linelength
=
ch
->
lcd_
modes
[
0
].
xres
*
2
;
yuv
=
true
;
break
;
case
MIPI_UYVY
:
pctype
=
5
;
datatype
=
MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16
;
pixfmt
=
MIPI_DCS_PIXEL_FMT_16BIT
;
linelength
=
ch
->
lcd_
cfg
[
0
].
xres
*
2
;
linelength
=
ch
->
lcd_
modes
[
0
].
xres
*
2
;
yuv
=
true
;
break
;
case
MIPI_YUV420_L
:
pctype
=
6
;
datatype
=
MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12
;
pixfmt
=
MIPI_DCS_PIXEL_FMT_12BIT
;
linelength
=
(
ch
->
lcd_
cfg
[
0
].
xres
*
12
+
7
)
/
8
;
linelength
=
(
ch
->
lcd_
modes
[
0
].
xres
*
12
+
7
)
/
8
;
yuv
=
true
;
break
;
case
MIPI_YUV420
:
...
...
@@ -223,7 +225,7 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi,
datatype
=
MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12
;
pixfmt
=
MIPI_DCS_PIXEL_FMT_12BIT
;
/* Length of U/V line */
linelength
=
(
ch
->
lcd_
cfg
[
0
].
xres
+
1
)
/
2
;
linelength
=
(
ch
->
lcd_
modes
[
0
].
xres
+
1
)
/
2
;
yuv
=
true
;
break
;
default:
...
...
@@ -292,7 +294,7 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi,
*/
iowrite32
(
0x00000006
,
mipi
->
linkbase
+
DTCTR
);
/* VSYNC width = 2 (<< 17) */
iowrite32
((
ch
->
lcd_
cfg
[
0
].
vsync_len
<<
pdata
->
vsynw_offset
)
|
iowrite32
((
ch
->
lcd_
modes
[
0
].
vsync_len
<<
pdata
->
vsynw_offset
)
|
(
pdata
->
clksrc
<<
16
)
|
(
pctype
<<
12
)
|
datatype
,
mipi
->
linkbase
+
VMCTR1
);
...
...
@@ -326,7 +328,7 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi,
top
=
linelength
<<
16
;
/* RGBLEN */
bottom
=
0x00000001
;
if
(
pdata
->
flags
&
SH_MIPI_DSI_HSABM
)
/* HSALEN */
bottom
=
(
pdata
->
lane
*
ch
->
lcd_
cfg
[
0
].
hsync_len
)
-
10
;
bottom
=
(
pdata
->
lane
*
ch
->
lcd_
modes
[
0
].
hsync_len
)
-
10
;
iowrite32
(
top
|
bottom
,
mipi
->
linkbase
+
VMLEN1
);
/*
...
...
@@ -346,18 +348,18 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi,
div
=
2
;
if
(
pdata
->
flags
&
SH_MIPI_DSI_HFPBM
)
{
/* HBPLEN */
top
=
ch
->
lcd_
cfg
[
0
].
hsync_len
+
ch
->
lcd_cfg
[
0
].
left_margin
;
top
=
ch
->
lcd_
modes
[
0
].
hsync_len
+
ch
->
lcd_modes
[
0
].
left_margin
;
top
=
((
pdata
->
lane
*
top
/
div
)
-
10
)
<<
16
;
}
if
(
pdata
->
flags
&
SH_MIPI_DSI_HBPBM
)
{
/* HFPLEN */
bottom
=
ch
->
lcd_
cfg
[
0
].
right_margin
;
bottom
=
ch
->
lcd_
modes
[
0
].
right_margin
;
bottom
=
(
pdata
->
lane
*
bottom
/
div
)
-
12
;
}
bpp
=
linelength
/
ch
->
lcd_
cfg
[
0
].
xres
;
/* byte / pixel */
bpp
=
linelength
/
ch
->
lcd_
modes
[
0
].
xres
;
/* byte / pixel */
if
((
pdata
->
lane
/
div
)
>
bpp
)
{
tmp
=
ch
->
lcd_
cfg
[
0
].
xres
/
bpp
;
/* output cycle */
tmp
=
ch
->
lcd_
cfg
[
0
].
xres
-
tmp
;
/* (input - output) cycle */
tmp
=
ch
->
lcd_
modes
[
0
].
xres
/
bpp
;
/* output cycle */
tmp
=
ch
->
lcd_
modes
[
0
].
xres
-
tmp
;
/* (input - output) cycle */
delay
=
(
pdata
->
lane
*
tmp
);
}
...
...
@@ -392,9 +394,9 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi,
return
0
;
}
static
void
mipi_display_on
(
void
*
arg
,
struct
fb_info
*
info
)
static
int
mipi_display_on
(
struct
sh_mobile_lcdc_entity
*
entity
)
{
struct
sh_mipi
*
mipi
=
arg
;
struct
sh_mipi
*
mipi
=
to_sh_mipi
(
entity
)
;
struct
sh_mipi_dsi_info
*
pdata
=
mipi
->
pdev
->
dev
.
platform_data
;
int
ret
;
...
...
@@ -410,25 +412,21 @@ static void mipi_display_on(void *arg, struct fb_info *info)
sh_mipi_dsi_enable
(
mipi
,
true
);
if
(
mipi
->
next_display_on
)
mipi
->
next_display_on
(
mipi
->
next_board_data
,
info
);
return
;
return
SH_MOBILE_LCDC_DISPLAY_CONNECTED
;
mipi_display_on_fail1:
pm_runtime_put_sync
(
&
mipi
->
pdev
->
dev
);
mipi_display_on_fail2:
pdata
->
set_dot_clock
(
mipi
->
pdev
,
mipi
->
base
,
0
);
return
ret
;
}
static
void
mipi_display_off
(
void
*
arg
)
static
void
mipi_display_off
(
struct
sh_mobile_lcdc_entity
*
entity
)
{
struct
sh_mipi
*
mipi
=
arg
;
struct
sh_mipi
*
mipi
=
to_sh_mipi
(
entity
)
;
struct
sh_mipi_dsi_info
*
pdata
=
mipi
->
pdev
->
dev
.
platform_data
;
if
(
mipi
->
next_display_off
)
mipi
->
next_display_off
(
mipi
->
next_board_data
);
sh_mipi_dsi_enable
(
mipi
,
false
);
pdata
->
set_dot_clock
(
mipi
->
pdev
,
mipi
->
base
,
0
);
...
...
@@ -436,6 +434,11 @@ static void mipi_display_off(void *arg)
pm_runtime_put_sync
(
&
mipi
->
pdev
->
dev
);
}
static
const
struct
sh_mobile_lcdc_entity_ops
mipi_ops
=
{
.
display_on
=
mipi_display_on
,
.
display_off
=
mipi_display_off
,
};
static
int
__init
sh_mipi_probe
(
struct
platform_device
*
pdev
)
{
struct
sh_mipi
*
mipi
;
...
...
@@ -467,6 +470,9 @@ static int __init sh_mipi_probe(struct platform_device *pdev)
goto
ealloc
;
}
mipi
->
entity
.
owner
=
THIS_MODULE
;
mipi
->
entity
.
ops
=
&
mipi_ops
;
if
(
!
request_mem_region
(
res
->
start
,
resource_size
(
res
),
pdev
->
name
))
{
dev_err
(
&
pdev
->
dev
,
"MIPI register region already claimed
\n
"
);
ret
=
-
EBUSY
;
...
...
@@ -521,18 +527,7 @@ static int __init sh_mipi_probe(struct platform_device *pdev)
pm_runtime_resume
(
&
pdev
->
dev
);
mutex_unlock
(
&
array_lock
);
platform_set_drvdata
(
pdev
,
mipi
);
/* Save original LCDC callbacks */
mipi
->
next_board_data
=
pdata
->
lcd_chan
->
board_cfg
.
board_data
;
mipi
->
next_display_on
=
pdata
->
lcd_chan
->
board_cfg
.
display_on
;
mipi
->
next_display_off
=
pdata
->
lcd_chan
->
board_cfg
.
display_off
;
/* Set up LCDC callbacks */
pdata
->
lcd_chan
->
board_cfg
.
board_data
=
mipi
;
pdata
->
lcd_chan
->
board_cfg
.
display_on
=
mipi_display_on
;
pdata
->
lcd_chan
->
board_cfg
.
display_off
=
mipi_display_off
;
pdata
->
lcd_chan
->
board_cfg
.
owner
=
THIS_MODULE
;
platform_set_drvdata
(
pdev
,
&
mipi
->
entity
);
return
0
;
...
...
@@ -558,10 +553,9 @@ static int __init sh_mipi_probe(struct platform_device *pdev)
static
int
__exit
sh_mipi_remove
(
struct
platform_device
*
pdev
)
{
struct
sh_mipi_dsi_info
*
pdata
=
pdev
->
dev
.
platform_data
;
struct
resource
*
res
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
0
);
struct
resource
*
res2
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
1
);
struct
sh_mipi
*
mipi
=
platform_get_drvdata
(
pdev
);
struct
sh_mipi
*
mipi
=
to_sh_mipi
(
platform_get_drvdata
(
pdev
)
);
int
i
,
ret
;
mutex_lock
(
&
array_lock
);
...
...
@@ -581,11 +575,6 @@ static int __exit sh_mipi_remove(struct platform_device *pdev)
if
(
ret
<
0
)
return
ret
;
pdata
->
lcd_chan
->
board_cfg
.
owner
=
NULL
;
pdata
->
lcd_chan
->
board_cfg
.
display_on
=
NULL
;
pdata
->
lcd_chan
->
board_cfg
.
display_off
=
NULL
;
pdata
->
lcd_chan
->
board_cfg
.
board_data
=
NULL
;
pm_runtime_disable
(
&
pdev
->
dev
);
clk_disable
(
mipi
->
dsit_clk
);
clk_put
(
mipi
->
dsit_clk
);
...
...
drivers/video/sh_mobile_hdmi.c
View file @
f9b4a5ce
...
...
@@ -208,6 +208,8 @@ enum hotplug_state {
};
struct
sh_hdmi
{
struct
sh_mobile_lcdc_entity
entity
;
void
__iomem
*
base
;
enum
hotplug_state
hp_state
;
/* hot-plug status */
u8
preprogrammed_vic
;
/* use a pre-programmed VIC or
...
...
@@ -217,14 +219,13 @@ struct sh_hdmi {
u8
edid_blocks
;
struct
clk
*
hdmi_clk
;
struct
device
*
dev
;
struct
fb_info
*
info
;
struct
mutex
mutex
;
/* Protect the info pointer */
struct
delayed_work
edid_work
;
struct
fb_v
ar_screeninfo
var
;
struct
fb_v
ideomode
mode
;
struct
fb_monspecs
monspec
;
struct
notifier_block
notifier
;
};
#define entity_to_sh_hdmi(e) container_of(e, struct sh_hdmi, entity)
static
void
hdmi_write
(
struct
sh_hdmi
*
hdmi
,
u8
data
,
u8
reg
)
{
iowrite8
(
data
,
hdmi
->
base
+
reg
);
...
...
@@ -290,24 +291,24 @@ static struct snd_soc_codec_driver soc_codec_dev_sh_hdmi = {
/* External video parameter settings */
static
void
sh_hdmi_external_video_param
(
struct
sh_hdmi
*
hdmi
)
{
struct
fb_v
ar_screeninfo
*
var
=
&
hdmi
->
var
;
struct
fb_v
ideomode
*
mode
=
&
hdmi
->
mode
;
u16
htotal
,
hblank
,
hdelay
,
vtotal
,
vblank
,
vdelay
,
voffset
;
u8
sync
=
0
;
htotal
=
var
->
xres
+
var
->
right_margin
+
var
->
left_margin
+
var
->
hsync_len
;
hdelay
=
var
->
hsync_len
+
var
->
left_margin
;
hblank
=
var
->
right_margin
+
hdelay
;
htotal
=
mode
->
xres
+
mode
->
right_margin
+
mode
->
left_margin
+
mode
->
hsync_len
;
hdelay
=
mode
->
hsync_len
+
mode
->
left_margin
;
hblank
=
mode
->
right_margin
+
hdelay
;
/*
* Vertical timing looks a bit different in Figure 18,
* but let's try the same first by setting offset = 0
*/
vtotal
=
var
->
yres
+
var
->
upper_margin
+
var
->
lower_margin
+
var
->
vsync_len
;
vdelay
=
var
->
vsync_len
+
var
->
upper_margin
;
vblank
=
var
->
lower_margin
+
vdelay
;
voffset
=
min
(
var
->
upper_margin
/
2
,
6U
);
vtotal
=
mode
->
yres
+
mode
->
upper_margin
+
mode
->
lower_margin
+
mode
->
vsync_len
;
vdelay
=
mode
->
vsync_len
+
mode
->
upper_margin
;
vblank
=
mode
->
lower_margin
+
vdelay
;
voffset
=
min
(
mode
->
upper_margin
/
2
,
6U
);
/*
* [3]: VSYNC polarity: Positive
...
...
@@ -315,14 +316,14 @@ static void sh_hdmi_external_video_param(struct sh_hdmi *hdmi)
* [1]: Interlace/Progressive: Progressive
* [0]: External video settings enable: used.
*/
if
(
var
->
sync
&
FB_SYNC_HOR_HIGH_ACT
)
if
(
mode
->
sync
&
FB_SYNC_HOR_HIGH_ACT
)
sync
|=
4
;
if
(
var
->
sync
&
FB_SYNC_VERT_HIGH_ACT
)
if
(
mode
->
sync
&
FB_SYNC_VERT_HIGH_ACT
)
sync
|=
8
;
dev_dbg
(
hdmi
->
dev
,
"H: %u, %u, %u, %u; V: %u, %u, %u, %u; sync 0x%x
\n
"
,
htotal
,
hblank
,
hdelay
,
var
->
hsync_len
,
vtotal
,
vblank
,
vdelay
,
var
->
vsync_len
,
sync
);
htotal
,
hblank
,
hdelay
,
mode
->
hsync_len
,
vtotal
,
vblank
,
vdelay
,
mode
->
vsync_len
,
sync
);
hdmi_write
(
hdmi
,
sync
|
(
voffset
<<
4
),
HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS
);
...
...
@@ -335,8 +336,8 @@ static void sh_hdmi_external_video_param(struct sh_hdmi *hdmi)
hdmi_write
(
hdmi
,
hdelay
,
HDMI_EXTERNAL_H_DELAY_7_0
);
hdmi_write
(
hdmi
,
hdelay
>>
8
,
HDMI_EXTERNAL_H_DELAY_9_8
);
hdmi_write
(
hdmi
,
var
->
hsync_len
,
HDMI_EXTERNAL_H_DURATION_7_0
);
hdmi_write
(
hdmi
,
var
->
hsync_len
>>
8
,
HDMI_EXTERNAL_H_DURATION_9_8
);
hdmi_write
(
hdmi
,
mode
->
hsync_len
,
HDMI_EXTERNAL_H_DURATION_7_0
);
hdmi_write
(
hdmi
,
mode
->
hsync_len
>>
8
,
HDMI_EXTERNAL_H_DURATION_9_8
);
hdmi_write
(
hdmi
,
vtotal
,
HDMI_EXTERNAL_V_TOTAL_7_0
);
hdmi_write
(
hdmi
,
vtotal
>>
8
,
HDMI_EXTERNAL_V_TOTAL_9_8
);
...
...
@@ -345,7 +346,7 @@ static void sh_hdmi_external_video_param(struct sh_hdmi *hdmi)
hdmi_write
(
hdmi
,
vdelay
,
HDMI_EXTERNAL_V_DELAY
);
hdmi_write
(
hdmi
,
var
->
vsync_len
,
HDMI_EXTERNAL_V_DURATION
);
hdmi_write
(
hdmi
,
mode
->
vsync_len
,
HDMI_EXTERNAL_V_DURATION
);
/* Set bit 0 of HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS here for external mode */
if
(
!
hdmi
->
preprogrammed_vic
)
...
...
@@ -472,7 +473,7 @@ static void sh_hdmi_audio_config(struct sh_hdmi *hdmi)
*/
static
void
sh_hdmi_phy_config
(
struct
sh_hdmi
*
hdmi
)
{
if
(
hdmi
->
var
.
pixclock
<
10000
)
{
if
(
hdmi
->
mode
.
pixclock
<
10000
)
{
/* for 1080p8bit 148MHz */
hdmi_write
(
hdmi
,
0x1d
,
HDMI_SLIPHDMIT_PARAM_SETTINGS_1
);
hdmi_write
(
hdmi
,
0x00
,
HDMI_SLIPHDMIT_PARAM_SETTINGS_2
);
...
...
@@ -483,7 +484,7 @@ static void sh_hdmi_phy_config(struct sh_hdmi *hdmi)
hdmi_write
(
hdmi
,
0x0e
,
HDMI_SLIPHDMIT_PARAM_SETTINGS_8
);
hdmi_write
(
hdmi
,
0x25
,
HDMI_SLIPHDMIT_PARAM_SETTINGS_9
);
hdmi_write
(
hdmi
,
0x04
,
HDMI_SLIPHDMIT_PARAM_SETTINGS_10
);
}
else
if
(
hdmi
->
var
.
pixclock
<
30000
)
{
}
else
if
(
hdmi
->
mode
.
pixclock
<
30000
)
{
/* 720p, 8bit, 74.25MHz. Might need to be adjusted for other formats */
/*
* [1:0] Speed_A
...
...
@@ -732,14 +733,12 @@ static unsigned long sh_hdmi_rate_error(struct sh_hdmi *hdmi,
static
int
sh_hdmi_read_edid
(
struct
sh_hdmi
*
hdmi
,
unsigned
long
*
hdmi_rate
,
unsigned
long
*
parent_rate
)
{
struct
fb_var_screeninfo
tmpvar
;
struct
fb_var_screeninfo
*
var
=
&
tmpvar
;
struct
sh_mobile_lcdc_chan
*
ch
=
hdmi
->
entity
.
lcdc
;
const
struct
fb_videomode
*
mode
,
*
found
=
NULL
;
struct
fb_info
*
info
=
hdmi
->
info
;
struct
fb_modelist
*
modelist
=
NULL
;
unsigned
int
f_width
=
0
,
f_height
=
0
,
f_refresh
=
0
;
unsigned
long
found_rate_error
=
ULONG_MAX
;
/* silly compiler... */
bool
scanning
=
false
,
preferred_bad
=
false
;
bool
use_edid_mode
=
false
;
u8
edid
[
128
];
char
*
forced
;
int
i
;
...
...
@@ -854,12 +853,9 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate,
}
/* Check if supported: sufficient fb memory, supported clock-rate */
fb_videomode_to_var
(
var
,
mode
);
var
->
bits_per_pixel
=
info
->
var
.
bits_per_pixel
;
if
(
info
&&
info
->
fbops
->
fb_check_var
&&
info
->
fbops
->
fb_check_var
(
var
,
info
))
{
if
(
ch
&&
ch
->
notify
&&
ch
->
notify
(
ch
,
SH_MOBILE_LCDC_EVENT_DISPLAY_MODE
,
mode
,
NULL
))
{
scanning
=
true
;
preferred_bad
=
true
;
continue
;
...
...
@@ -867,28 +863,19 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate,
found
=
mode
;
found_rate_error
=
rate_error
;
use_edid_mode
=
true
;
}
hdmi
->
var
.
width
=
hdmi
->
monspec
.
max_x
*
10
;
hdmi
->
var
.
height
=
hdmi
->
monspec
.
max_y
*
10
;
/*
* TODO 1: if no
->info is present, postpone running the config until
*
after ->info first gets register
ed.
* TODO 1: if no
default mode is present, postpone running the config
*
until after the LCDC channel is initializ
ed.
* TODO 2: consider registering the HDMI platform device from the LCDC
* driver
, and passing ->info with HDMI platform data
.
* driver.
*/
if
(
info
&&
!
found
)
{
modelist
=
info
->
modelist
.
next
&&
!
list_empty
(
&
info
->
modelist
)
?
list_entry
(
info
->
modelist
.
next
,
struct
fb_modelist
,
list
)
:
NULL
;
if
(
modelist
)
{
found
=
&
modelist
->
mode
;
found_rate_error
=
sh_hdmi_rate_error
(
hdmi
,
found
,
hdmi_rate
,
parent_rate
);
}
if
(
!
found
&&
hdmi
->
entity
.
def_mode
.
xres
!=
0
)
{
found
=
&
hdmi
->
entity
.
def_mode
;
found_rate_error
=
sh_hdmi_rate_error
(
hdmi
,
found
,
hdmi_rate
,
parent_rate
);
}
/* No cookie today */
...
...
@@ -912,12 +899,13 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate,
else
hdmi
->
preprogrammed_vic
=
0
;
dev_dbg
(
hdmi
->
dev
,
"Using %s %s mode %ux%u@%uHz (%luHz), clock error %luHz
\n
"
,
modelist
?
"default"
:
"EDID"
,
hdmi
->
preprogrammed_vic
?
"VIC"
:
"external"
,
found
->
xres
,
found
->
yres
,
found
->
refresh
,
PICOS2KHZ
(
found
->
pixclock
)
*
1000
,
found_rate_error
);
dev_dbg
(
hdmi
->
dev
,
"Using %s %s mode %ux%u@%uHz (%luHz), "
"clock error %luHz
\n
"
,
use_edid_mode
?
"EDID"
:
"default"
,
hdmi
->
preprogrammed_vic
?
"VIC"
:
"external"
,
found
->
xres
,
found
->
yres
,
found
->
refresh
,
PICOS2KHZ
(
found
->
pixclock
)
*
1000
,
found_rate_error
);
fb_videomode_to_var
(
&
hdmi
->
var
,
found
)
;
hdmi
->
mode
=
*
found
;
sh_hdmi_external_video_param
(
hdmi
);
return
0
;
...
...
@@ -998,22 +986,12 @@ static irqreturn_t sh_hdmi_hotplug(int irq, void *dev_id)
return
IRQ_HANDLED
;
}
/* locking: called with info->lock held, or before register_framebuffer() */
static
void
sh_hdmi_display_on
(
void
*
arg
,
struct
fb_info
*
info
)
static
int
sh_hdmi_display_on
(
struct
sh_mobile_lcdc_entity
*
entity
)
{
/*
* info is guaranteed to be valid, when we are called, because our
* FB_EVENT_FB_UNBIND notify is also called with info->lock held
*/
struct
sh_hdmi
*
hdmi
=
arg
;
struct
sh_mobile_hdmi_info
*
pdata
=
hdmi
->
dev
->
platform_data
;
struct
sh_mobile_lcdc_chan
*
ch
=
info
->
par
;
struct
sh_hdmi
*
hdmi
=
entity_to_sh_hdmi
(
entity
);
dev_dbg
(
hdmi
->
dev
,
"%s(%p): state %x
\n
"
,
__func__
,
pdata
->
lcd_dev
,
info
->
state
);
/* No need to lock */
hdmi
->
info
=
info
;
dev_dbg
(
hdmi
->
dev
,
"%s(%p): state %x
\n
"
,
__func__
,
hdmi
,
hdmi
->
hp_state
);
/*
* hp_state can be set to
...
...
@@ -1021,56 +999,30 @@ static void sh_hdmi_display_on(void *arg, struct fb_info *info)
* HDMI_HOTPLUG_CONNECTED: on monitor plug-in
* HDMI_HOTPLUG_EDID_DONE: on EDID read completion
*/
switch
(
hdmi
->
hp_state
)
{
case
HDMI_HOTPLUG_EDID_DONE
:
if
(
hdmi
->
hp_state
==
HDMI_HOTPLUG_EDID_DONE
)
{
/* PS mode d->e. All functions are active */
hdmi_write
(
hdmi
,
0x80
,
HDMI_SYSTEM_CTRL
);
dev_dbg
(
hdmi
->
dev
,
"HDMI running
\n
"
);
break
;
case
HDMI_HOTPLUG_DISCONNECTED
:
info
->
state
=
FBINFO_STATE_SUSPENDED
;
default:
hdmi
->
var
=
ch
->
display_var
;
}
return
hdmi
->
hp_state
==
HDMI_HOTPLUG_DISCONNECTED
?
SH_MOBILE_LCDC_DISPLAY_DISCONNECTED
:
SH_MOBILE_LCDC_DISPLAY_CONNECTED
;
}
/* locking: called with info->lock held */
static
void
sh_hdmi_display_off
(
void
*
arg
)
static
void
sh_hdmi_display_off
(
struct
sh_mobile_lcdc_entity
*
entity
)
{
struct
sh_hdmi
*
hdmi
=
arg
;
struct
sh_mobile_hdmi_info
*
pdata
=
hdmi
->
dev
->
platform_data
;
struct
sh_hdmi
*
hdmi
=
entity_to_sh_hdmi
(
entity
);
dev_dbg
(
hdmi
->
dev
,
"%s(%p)
\n
"
,
__func__
,
pdata
->
lcd_dev
);
dev_dbg
(
hdmi
->
dev
,
"%s(%p)
\n
"
,
__func__
,
hdmi
);
/* PS mode e->a */
hdmi_write
(
hdmi
,
0x10
,
HDMI_SYSTEM_CTRL
);
}
static
bool
sh_hdmi_must_reconfigure
(
struct
sh_hdmi
*
hdmi
)
{
struct
fb_info
*
info
=
hdmi
->
info
;
struct
sh_mobile_lcdc_chan
*
ch
=
info
->
par
;
struct
fb_var_screeninfo
*
new_var
=
&
hdmi
->
var
,
*
old_var
=
&
ch
->
display_var
;
struct
fb_videomode
mode1
,
mode2
;
fb_var_to_videomode
(
&
mode1
,
old_var
);
fb_var_to_videomode
(
&
mode2
,
new_var
);
dev_dbg
(
info
->
dev
,
"Old %ux%u, new %ux%u
\n
"
,
mode1
.
xres
,
mode1
.
yres
,
mode2
.
xres
,
mode2
.
yres
);
if
(
fb_mode_is_equal
(
&
mode1
,
&
mode2
))
{
/* It can be a different monitor with an equal video-mode */
old_var
->
width
=
new_var
->
width
;
old_var
->
height
=
new_var
->
height
;
return
false
;
}
dev_dbg
(
info
->
dev
,
"Switching %u -> %u lines
\n
"
,
mode1
.
yres
,
mode2
.
yres
);
*
old_var
=
*
new_var
;
return
true
;
}
static
const
struct
sh_mobile_lcdc_entity_ops
sh_hdmi_ops
=
{
.
display_on
=
sh_hdmi_display_on
,
.
display_off
=
sh_hdmi_display_off
,
};
/**
* sh_hdmi_clk_configure() - set HDMI clock frequency and enable the clock
...
...
@@ -1111,20 +1063,11 @@ static long sh_hdmi_clk_configure(struct sh_hdmi *hdmi, unsigned long hdmi_rate,
static
void
sh_hdmi_edid_work_fn
(
struct
work_struct
*
work
)
{
struct
sh_hdmi
*
hdmi
=
container_of
(
work
,
struct
sh_hdmi
,
edid_work
.
work
);
struct
fb_info
*
info
;
struct
sh_mobile_hdmi_info
*
pdata
=
hdmi
->
dev
->
platform_data
;
struct
sh_mobile_lcdc_chan
*
ch
;
struct
sh_mobile_lcdc_chan
*
ch
=
hdmi
->
entity
.
lcdc
;
int
ret
;
dev_dbg
(
hdmi
->
dev
,
"%s(%p): begin, hotplug status %d
\n
"
,
__func__
,
pdata
->
lcd_dev
,
hdmi
->
hp_state
);
if
(
!
pdata
->
lcd_dev
)
return
;
mutex_lock
(
&
hdmi
->
mutex
);
info
=
hdmi
->
info
;
dev_dbg
(
hdmi
->
dev
,
"%s(%p): begin, hotplug status %d
\n
"
,
__func__
,
hdmi
,
hdmi
->
hp_state
);
if
(
hdmi
->
hp_state
==
HDMI_HOTPLUG_CONNECTED
)
{
unsigned
long
parent_rate
=
0
,
hdmi_rate
;
...
...
@@ -1145,103 +1088,32 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work)
/* Switched to another (d) power-save mode */
msleep
(
10
);
if
(
!
info
)
goto
out
;
ch
=
info
->
par
;
if
(
lock_fb_info
(
info
))
{
console_lock
();
/* HDMI plug in */
if
(
!
sh_hdmi_must_reconfigure
(
hdmi
)
&&
info
->
state
==
FBINFO_STATE_RUNNING
)
{
/*
* First activation with the default monitor - just turn
* on, if we run a resume here, the logo disappears
*/
info
->
var
.
width
=
hdmi
->
var
.
width
;
info
->
var
.
height
=
hdmi
->
var
.
height
;
sh_hdmi_display_on
(
hdmi
,
info
);
}
else
{
/* New monitor or have to wake up */
fb_set_suspend
(
info
,
0
);
}
console_unlock
();
unlock_fb_info
(
info
);
}
if
(
ch
&&
ch
->
notify
)
ch
->
notify
(
ch
,
SH_MOBILE_LCDC_EVENT_DISPLAY_CONNECT
,
&
hdmi
->
mode
,
&
hdmi
->
monspec
);
}
else
{
ret
=
0
;
if
(
!
info
)
goto
out
;
hdmi
->
monspec
.
modedb_len
=
0
;
fb_destroy_modedb
(
hdmi
->
monspec
.
modedb
);
hdmi
->
monspec
.
modedb
=
NULL
;
if
(
lock_fb_info
(
info
))
{
console_lock
();
if
(
ch
&&
ch
->
notify
)
ch
->
notify
(
ch
,
SH_MOBILE_LCDC_EVENT_DISPLAY_DISCONNECT
,
NULL
,
NULL
);
/* HDMI disconnect */
fb_set_suspend
(
info
,
1
);
console_unlock
();
unlock_fb_info
(
info
);
}
ret
=
0
;
}
out:
if
(
ret
<
0
&&
ret
!=
-
EAGAIN
)
hdmi
->
hp_state
=
HDMI_HOTPLUG_DISCONNECTED
;
mutex_unlock
(
&
hdmi
->
mutex
);
dev_dbg
(
hdmi
->
dev
,
"%s(%p): end
\n
"
,
__func__
,
pdata
->
lcd_dev
);
}
static
int
sh_hdmi_notify
(
struct
notifier_block
*
nb
,
unsigned
long
action
,
void
*
data
)
{
struct
fb_event
*
event
=
data
;
struct
fb_info
*
info
=
event
->
info
;
struct
sh_mobile_lcdc_chan
*
ch
=
info
->
par
;
struct
sh_mobile_lcdc_board_cfg
*
board_cfg
=
&
ch
->
cfg
.
board_cfg
;
struct
sh_hdmi
*
hdmi
=
board_cfg
->
board_data
;
if
(
!
hdmi
||
nb
!=
&
hdmi
->
notifier
||
hdmi
->
info
!=
info
)
return
NOTIFY_DONE
;
switch
(
action
)
{
case
FB_EVENT_FB_REGISTERED
:
/* Unneeded, activation taken care by sh_hdmi_display_on() */
break
;
case
FB_EVENT_FB_UNREGISTERED
:
/*
* We are called from unregister_framebuffer() with the
* info->lock held. This is bad for us, because we can race with
* the scheduled work, which has to call fb_set_suspend(), which
* takes info->lock internally, so, sh_hdmi_edid_work_fn()
* cannot take and hold info->lock for the whole function
* duration. Using an additional lock creates a classical AB-BA
* lock up. Therefore, we have to release the info->lock
* temporarily, synchronise with the work queue and re-acquire
* the info->lock.
*/
unlock_fb_info
(
info
);
mutex_lock
(
&
hdmi
->
mutex
);
hdmi
->
info
=
NULL
;
mutex_unlock
(
&
hdmi
->
mutex
);
lock_fb_info
(
info
);
return
NOTIFY_OK
;
}
return
NOTIFY_DONE
;
dev_dbg
(
hdmi
->
dev
,
"%s(%p): end
\n
"
,
__func__
,
hdmi
);
}
static
int
__init
sh_hdmi_probe
(
struct
platform_device
*
pdev
)
{
struct
sh_mobile_hdmi_info
*
pdata
=
pdev
->
dev
.
platform_data
;
struct
resource
*
res
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
0
);
struct
sh_mobile_lcdc_board_cfg
*
board_cfg
;
int
irq
=
platform_get_irq
(
pdev
,
0
),
ret
;
struct
sh_hdmi
*
hdmi
;
long
rate
;
...
...
@@ -1255,9 +1127,9 @@ static int __init sh_hdmi_probe(struct platform_device *pdev)
return
-
ENOMEM
;
}
mutex_init
(
&
hdmi
->
mutex
);
hdmi
->
dev
=
&
pdev
->
dev
;
hdmi
->
entity
.
owner
=
THIS_MODULE
;
hdmi
->
entity
.
ops
=
&
sh_hdmi_ops
;
hdmi
->
hdmi_clk
=
clk_get
(
&
pdev
->
dev
,
"ick"
);
if
(
IS_ERR
(
hdmi
->
hdmi_clk
))
{
...
...
@@ -1297,14 +1169,7 @@ static int __init sh_hdmi_probe(struct platform_device *pdev)
goto
emap
;
}
platform_set_drvdata
(
pdev
,
hdmi
);
/* Set up LCDC callbacks */
board_cfg
=
&
pdata
->
lcd_chan
->
board_cfg
;
board_cfg
->
owner
=
THIS_MODULE
;
board_cfg
->
board_data
=
hdmi
;
board_cfg
->
display_on
=
sh_hdmi_display_on
;
board_cfg
->
display_off
=
sh_hdmi_display_off
;
platform_set_drvdata
(
pdev
,
&
hdmi
->
entity
);
INIT_DELAYED_WORK
(
&
hdmi
->
edid_work
,
sh_hdmi_edid_work_fn
);
...
...
@@ -1329,9 +1194,6 @@ static int __init sh_hdmi_probe(struct platform_device *pdev)
goto
ecodec
;
}
hdmi
->
notifier
.
notifier_call
=
sh_hdmi_notify
;
fb_register_client
(
&
hdmi
->
notifier
);
return
0
;
ecodec:
...
...
@@ -1347,7 +1209,6 @@ static int __init sh_hdmi_probe(struct platform_device *pdev)
erate:
clk_put
(
hdmi
->
hdmi_clk
);
egetclk:
mutex_destroy
(
&
hdmi
->
mutex
);
kfree
(
hdmi
);
return
ret
;
...
...
@@ -1355,21 +1216,12 @@ static int __init sh_hdmi_probe(struct platform_device *pdev)
static
int
__exit
sh_hdmi_remove
(
struct
platform_device
*
pdev
)
{
struct
sh_mobile_hdmi_info
*
pdata
=
pdev
->
dev
.
platform_data
;
struct
sh_hdmi
*
hdmi
=
platform_get_drvdata
(
pdev
);
struct
sh_hdmi
*
hdmi
=
entity_to_sh_hdmi
(
platform_get_drvdata
(
pdev
));
struct
resource
*
res
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
0
);
struct
sh_mobile_lcdc_board_cfg
*
board_cfg
=
&
pdata
->
lcd_chan
->
board_cfg
;
int
irq
=
platform_get_irq
(
pdev
,
0
);
snd_soc_unregister_codec
(
&
pdev
->
dev
);
fb_unregister_client
(
&
hdmi
->
notifier
);
board_cfg
->
display_on
=
NULL
;
board_cfg
->
display_off
=
NULL
;
board_cfg
->
board_data
=
NULL
;
board_cfg
->
owner
=
NULL
;
/* No new work will be scheduled, wait for running ISR */
free_irq
(
irq
,
hdmi
);
/* Wait for already scheduled work */
...
...
@@ -1380,7 +1232,6 @@ static int __exit sh_hdmi_remove(struct platform_device *pdev)
clk_put
(
hdmi
->
hdmi_clk
);
iounmap
(
hdmi
->
base
);
release_mem_region
(
res
->
start
,
resource_size
(
res
));
mutex_destroy
(
&
hdmi
->
mutex
);
kfree
(
hdmi
);
return
0
;
...
...
drivers/video/sh_mobile_lcdcfb.c
View file @
f9b4a5ce
...
...
@@ -8,26 +8,27 @@
* for more details.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/atomic.h>
#include <linux/backlight.h>
#include <linux/clk.h>
#include <linux/pm_runtime.h>
#include <linux/platform_device.h>
#include <linux/console.h>
#include <linux/dma-mapping.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/videodev2.h>
#include <linux/vmalloc.h>
#include <linux/ioctl.h>
#include <linux/slab.h>
#include <linux/console.h>
#include <linux/backlight.h>
#include <linux/gpio.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/videodev2.h>
#include <linux/vmalloc.h>
#include <video/sh_mobile_lcdc.h>
#include <video/sh_mobile_meram.h>
#include <linux/atomic.h>
#include "sh_mobile_lcdcfb.h"
...
...
@@ -37,6 +38,24 @@
#define MAX_XRES 1920
#define MAX_YRES 1080
struct
sh_mobile_lcdc_priv
{
void
__iomem
*
base
;
int
irq
;
atomic_t
hw_usecnt
;
struct
device
*
dev
;
struct
clk
*
dot_clk
;
unsigned
long
lddckr
;
struct
sh_mobile_lcdc_chan
ch
[
2
];
struct
notifier_block
notifier
;
int
started
;
int
forced_fourcc
;
/* 2 channel LCDC must share fourcc setting */
struct
sh_mobile_meram_info
*
meram_dev
;
};
/* -----------------------------------------------------------------------------
* Registers access
*/
static
unsigned
long
lcdc_offs_mainlcd
[
NR_CH_REGS
]
=
{
[
LDDCKPAT1R
]
=
0x400
,
[
LDDCKPAT2R
]
=
0x404
,
...
...
@@ -75,38 +94,6 @@ static unsigned long lcdc_offs_sublcd[NR_CH_REGS] = {
[
LDPMR
]
=
0x63c
,
};
static
const
struct
fb_videomode
default_720p
=
{
.
name
=
"HDMI 720p"
,
.
xres
=
1280
,
.
yres
=
720
,
.
left_margin
=
220
,
.
right_margin
=
110
,
.
hsync_len
=
40
,
.
upper_margin
=
20
,
.
lower_margin
=
5
,
.
vsync_len
=
5
,
.
pixclock
=
13468
,
.
refresh
=
60
,
.
sync
=
FB_SYNC_VERT_HIGH_ACT
|
FB_SYNC_HOR_HIGH_ACT
,
};
struct
sh_mobile_lcdc_priv
{
void
__iomem
*
base
;
int
irq
;
atomic_t
hw_usecnt
;
struct
device
*
dev
;
struct
clk
*
dot_clk
;
unsigned
long
lddckr
;
struct
sh_mobile_lcdc_chan
ch
[
2
];
struct
notifier_block
notifier
;
int
started
;
int
forced_fourcc
;
/* 2 channel LCDC must share fourcc setting */
struct
sh_mobile_meram_info
*
meram_dev
;
};
static
bool
banked
(
int
reg_nr
)
{
switch
(
reg_nr
)
{
...
...
@@ -127,6 +114,11 @@ static bool banked(int reg_nr)
return
false
;
}
static
int
lcdc_chan_is_sublcd
(
struct
sh_mobile_lcdc_chan
*
chan
)
{
return
chan
->
cfg
->
chan
==
LCDC_CHAN_SUBLCD
;
}
static
void
lcdc_write_chan
(
struct
sh_mobile_lcdc_chan
*
chan
,
int
reg_nr
,
unsigned
long
data
)
{
...
...
@@ -169,11 +161,72 @@ static void lcdc_wait_bit(struct sh_mobile_lcdc_priv *priv,
cpu_relax
();
}
static
int
lcdc_chan_is_sublcd
(
struct
sh_mobile_lcdc_chan
*
chan
)
/* -----------------------------------------------------------------------------
* Clock management
*/
static
void
sh_mobile_lcdc_clk_on
(
struct
sh_mobile_lcdc_priv
*
priv
)
{
if
(
atomic_inc_and_test
(
&
priv
->
hw_usecnt
))
{
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
)
{
return
chan
->
cfg
.
chan
==
LCDC_CHAN_SUBLCD
;
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
);
}
}
static
int
sh_mobile_lcdc_setup_clocks
(
struct
sh_mobile_lcdc_priv
*
priv
,
int
clock_source
)
{
struct
clk
*
clk
;
char
*
str
;
switch
(
clock_source
)
{
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
;
}
if
(
str
==
NULL
)
return
0
;
clk
=
clk_get
(
priv
->
dev
,
str
);
if
(
IS_ERR
(
clk
))
{
dev_err
(
priv
->
dev
,
"cannot get dot clock %s
\n
"
,
str
);
return
PTR_ERR
(
clk
);
}
priv
->
dot_clk
=
clk
;
return
0
;
}
/* -----------------------------------------------------------------------------
* Display, panel and deferred I/O
*/
static
void
lcdc_sys_write_index
(
void
*
handle
,
unsigned
long
data
)
{
struct
sh_mobile_lcdc_chan
*
ch
=
handle
;
...
...
@@ -216,74 +269,11 @@ struct sh_mobile_lcdc_sys_bus_ops sh_mobile_lcdc_sys_bus_ops = {
lcdc_sys_read_data
,
};
static
int
sh_mobile_format_fourcc
(
const
struct
fb_var_screeninfo
*
var
)
{
if
(
var
->
grayscale
>
1
)
return
var
->
grayscale
;
switch
(
var
->
bits_per_pixel
)
{
case
16
:
return
V4L2_PIX_FMT_RGB565
;
case
24
:
return
V4L2_PIX_FMT_BGR24
;
case
32
:
return
V4L2_PIX_FMT_BGR32
;
default:
return
0
;
}
}
static
int
sh_mobile_format_is_fourcc
(
const
struct
fb_var_screeninfo
*
var
)
{
return
var
->
grayscale
>
1
;
}
static
bool
sh_mobile_format_is_yuv
(
const
struct
fb_var_screeninfo
*
var
)
{
if
(
var
->
grayscale
<=
1
)
return
false
;
switch
(
var
->
grayscale
)
{
case
V4L2_PIX_FMT_NV12
:
case
V4L2_PIX_FMT_NV21
:
case
V4L2_PIX_FMT_NV16
:
case
V4L2_PIX_FMT_NV61
:
case
V4L2_PIX_FMT_NV24
:
case
V4L2_PIX_FMT_NV42
:
return
true
;
default:
return
false
;
}
}
static
void
sh_mobile_lcdc_clk_on
(
struct
sh_mobile_lcdc_priv
*
priv
)
{
if
(
atomic_inc_and_test
(
&
priv
->
hw_usecnt
))
{
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
);
}
}
static
int
sh_mobile_lcdc_sginit
(
struct
fb_info
*
info
,
struct
list_head
*
pagelist
)
{
struct
sh_mobile_lcdc_chan
*
ch
=
info
->
par
;
unsigned
int
nr_pages_max
=
info
->
fix
.
smem_len
>>
PAGE_SHIFT
;
unsigned
int
nr_pages_max
=
ch
->
fb_size
>>
PAGE_SHIFT
;
struct
page
*
page
;
int
nr_pages
=
0
;
...
...
@@ -299,7 +289,7 @@ static void sh_mobile_lcdc_deferred_io(struct fb_info *info,
struct
list_head
*
pagelist
)
{
struct
sh_mobile_lcdc_chan
*
ch
=
info
->
par
;
struct
sh_mobile_lcdc_board_cfg
*
bcfg
=
&
ch
->
cfg
.
board
_cfg
;
const
struct
sh_mobile_lcdc_panel_cfg
*
panel
=
&
ch
->
cfg
->
panel
_cfg
;
/* enable clocks before accessing hardware */
sh_mobile_lcdc_clk_on
(
ch
->
lcdc
);
...
...
@@ -323,16 +313,15 @@ static void sh_mobile_lcdc_deferred_io(struct fb_info *info,
unsigned
int
nr_pages
=
sh_mobile_lcdc_sginit
(
info
,
pagelist
);
/* trigger panel update */
dma_map_sg
(
info
->
dev
,
ch
->
sglist
,
nr_pages
,
DMA_TO_DEVICE
);
if
(
bcfg
->
start_transfer
)
bcfg
->
start_transfer
(
bcfg
->
board_data
,
ch
,
&
sh_mobile_lcdc_sys_bus_ops
);
dma_map_sg
(
ch
->
lcdc
->
dev
,
ch
->
sglist
,
nr_pages
,
DMA_TO_DEVICE
);
if
(
panel
->
start_transfer
)
panel
->
start_transfer
(
ch
,
&
sh_mobile_lcdc_sys_bus_ops
);
lcdc_write_chan
(
ch
,
LDSM2R
,
LDSM2R_OSTRG
);
dma_unmap_sg
(
info
->
dev
,
ch
->
sglist
,
nr_pages
,
DMA_TO_DEVICE
);
dma_unmap_sg
(
ch
->
lcdc
->
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
);
if
(
panel
->
start_transfer
)
panel
->
start_transfer
(
ch
,
&
sh_mobile_lcdc_sys_bus_ops
);
lcdc_write_chan
(
ch
,
LDSM2R
,
LDSM2R_OSTRG
);
}
}
...
...
@@ -345,6 +334,217 @@ static void sh_mobile_lcdc_deferred_io_touch(struct fb_info *info)
schedule_delayed_work
(
&
info
->
deferred_work
,
fbdefio
->
delay
);
}
static
void
sh_mobile_lcdc_display_on
(
struct
sh_mobile_lcdc_chan
*
ch
)
{
const
struct
sh_mobile_lcdc_panel_cfg
*
panel
=
&
ch
->
cfg
->
panel_cfg
;
if
(
ch
->
tx_dev
)
{
int
ret
;
ret
=
ch
->
tx_dev
->
ops
->
display_on
(
ch
->
tx_dev
);
if
(
ret
<
0
)
return
;
if
(
ret
==
SH_MOBILE_LCDC_DISPLAY_DISCONNECTED
)
ch
->
info
->
state
=
FBINFO_STATE_SUSPENDED
;
}
/* HDMI must be enabled before LCDC configuration */
if
(
panel
->
display_on
)
panel
->
display_on
();
}
static
void
sh_mobile_lcdc_display_off
(
struct
sh_mobile_lcdc_chan
*
ch
)
{
const
struct
sh_mobile_lcdc_panel_cfg
*
panel
=
&
ch
->
cfg
->
panel_cfg
;
if
(
panel
->
display_off
)
panel
->
display_off
();
if
(
ch
->
tx_dev
)
ch
->
tx_dev
->
ops
->
display_off
(
ch
->
tx_dev
);
}
static
bool
sh_mobile_lcdc_must_reconfigure
(
struct
sh_mobile_lcdc_chan
*
ch
,
const
struct
fb_videomode
*
new_mode
)
{
dev_dbg
(
ch
->
info
->
dev
,
"Old %ux%u, new %ux%u
\n
"
,
ch
->
display
.
mode
.
xres
,
ch
->
display
.
mode
.
yres
,
new_mode
->
xres
,
new_mode
->
yres
);
/* It can be a different monitor with an equal video-mode */
if
(
fb_mode_is_equal
(
&
ch
->
display
.
mode
,
new_mode
))
return
false
;
dev_dbg
(
ch
->
info
->
dev
,
"Switching %u -> %u lines
\n
"
,
ch
->
display
.
mode
.
yres
,
new_mode
->
yres
);
ch
->
display
.
mode
=
*
new_mode
;
return
true
;
}
static
int
sh_mobile_check_var
(
struct
fb_var_screeninfo
*
var
,
struct
fb_info
*
info
);
static
int
sh_mobile_lcdc_display_notify
(
struct
sh_mobile_lcdc_chan
*
ch
,
enum
sh_mobile_lcdc_entity_event
event
,
const
struct
fb_videomode
*
mode
,
const
struct
fb_monspecs
*
monspec
)
{
struct
fb_info
*
info
=
ch
->
info
;
struct
fb_var_screeninfo
var
;
int
ret
=
0
;
switch
(
event
)
{
case
SH_MOBILE_LCDC_EVENT_DISPLAY_CONNECT
:
/* HDMI plug in */
if
(
lock_fb_info
(
info
))
{
console_lock
();
ch
->
display
.
width
=
monspec
->
max_x
*
10
;
ch
->
display
.
height
=
monspec
->
max_y
*
10
;
if
(
!
sh_mobile_lcdc_must_reconfigure
(
ch
,
mode
)
&&
info
->
state
==
FBINFO_STATE_RUNNING
)
{
/* First activation with the default monitor.
* Just turn on, if we run a resume here, the
* logo disappears.
*/
info
->
var
.
width
=
monspec
->
max_x
*
10
;
info
->
var
.
height
=
monspec
->
max_y
*
10
;
sh_mobile_lcdc_display_on
(
ch
);
}
else
{
/* New monitor or have to wake up */
fb_set_suspend
(
info
,
0
);
}
console_unlock
();
unlock_fb_info
(
info
);
}
break
;
case
SH_MOBILE_LCDC_EVENT_DISPLAY_DISCONNECT
:
/* HDMI disconnect */
if
(
lock_fb_info
(
info
))
{
console_lock
();
fb_set_suspend
(
info
,
1
);
console_unlock
();
unlock_fb_info
(
info
);
}
break
;
case
SH_MOBILE_LCDC_EVENT_DISPLAY_MODE
:
/* Validate a proposed new mode */
fb_videomode_to_var
(
&
var
,
mode
);
var
.
bits_per_pixel
=
info
->
var
.
bits_per_pixel
;
var
.
grayscale
=
info
->
var
.
grayscale
;
ret
=
sh_mobile_check_var
(
&
var
,
info
);
break
;
}
return
ret
;
}
/* -----------------------------------------------------------------------------
* Format helpers
*/
struct
sh_mobile_lcdc_format_info
{
u32
fourcc
;
unsigned
int
bpp
;
bool
yuv
;
u32
lddfr
;
};
static
const
struct
sh_mobile_lcdc_format_info
sh_mobile_format_infos
[]
=
{
{
.
fourcc
=
V4L2_PIX_FMT_RGB565
,
.
bpp
=
16
,
.
yuv
=
false
,
.
lddfr
=
LDDFR_PKF_RGB16
,
},
{
.
fourcc
=
V4L2_PIX_FMT_BGR24
,
.
bpp
=
24
,
.
yuv
=
false
,
.
lddfr
=
LDDFR_PKF_RGB24
,
},
{
.
fourcc
=
V4L2_PIX_FMT_BGR32
,
.
bpp
=
32
,
.
yuv
=
false
,
.
lddfr
=
LDDFR_PKF_ARGB32
,
},
{
.
fourcc
=
V4L2_PIX_FMT_NV12
,
.
bpp
=
12
,
.
yuv
=
true
,
.
lddfr
=
LDDFR_CC
|
LDDFR_YF_420
,
},
{
.
fourcc
=
V4L2_PIX_FMT_NV21
,
.
bpp
=
12
,
.
yuv
=
true
,
.
lddfr
=
LDDFR_CC
|
LDDFR_YF_420
,
},
{
.
fourcc
=
V4L2_PIX_FMT_NV16
,
.
bpp
=
16
,
.
yuv
=
true
,
.
lddfr
=
LDDFR_CC
|
LDDFR_YF_422
,
},
{
.
fourcc
=
V4L2_PIX_FMT_NV61
,
.
bpp
=
16
,
.
yuv
=
true
,
.
lddfr
=
LDDFR_CC
|
LDDFR_YF_422
,
},
{
.
fourcc
=
V4L2_PIX_FMT_NV24
,
.
bpp
=
24
,
.
yuv
=
true
,
.
lddfr
=
LDDFR_CC
|
LDDFR_YF_444
,
},
{
.
fourcc
=
V4L2_PIX_FMT_NV42
,
.
bpp
=
24
,
.
yuv
=
true
,
.
lddfr
=
LDDFR_CC
|
LDDFR_YF_444
,
},
};
static
const
struct
sh_mobile_lcdc_format_info
*
sh_mobile_format_info
(
u32
fourcc
)
{
unsigned
int
i
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
sh_mobile_format_infos
);
++
i
)
{
if
(
sh_mobile_format_infos
[
i
].
fourcc
==
fourcc
)
return
&
sh_mobile_format_infos
[
i
];
}
return
NULL
;
}
static
int
sh_mobile_format_fourcc
(
const
struct
fb_var_screeninfo
*
var
)
{
if
(
var
->
grayscale
>
1
)
return
var
->
grayscale
;
switch
(
var
->
bits_per_pixel
)
{
case
16
:
return
V4L2_PIX_FMT_RGB565
;
case
24
:
return
V4L2_PIX_FMT_BGR24
;
case
32
:
return
V4L2_PIX_FMT_BGR32
;
default:
return
0
;
}
}
static
int
sh_mobile_format_is_fourcc
(
const
struct
fb_var_screeninfo
*
var
)
{
return
var
->
grayscale
>
1
;
}
/* -----------------------------------------------------------------------------
* Start, stop and IRQ
*/
static
irqreturn_t
sh_mobile_lcdc_irq
(
int
irq
,
void
*
data
)
{
struct
sh_mobile_lcdc_priv
*
priv
=
data
;
...
...
@@ -385,6 +585,26 @@ static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data)
return
IRQ_HANDLED
;
}
static
int
sh_mobile_wait_for_vsync
(
struct
sh_mobile_lcdc_chan
*
ch
)
{
unsigned
long
ldintr
;
int
ret
;
/* Enable VSync End interrupt and be careful not to acknowledge any
* pending interrupt.
*/
ldintr
=
lcdc_read
(
ch
->
lcdc
,
_LDINTR
);
ldintr
|=
LDINTR_VEE
|
LDINTR_STATUS_MASK
;
lcdc_write
(
ch
->
lcdc
,
_LDINTR
,
ldintr
);
ret
=
wait_for_completion_interruptible_timeout
(
&
ch
->
vsync_completion
,
msecs_to_jiffies
(
100
));
if
(
!
ret
)
return
-
ETIMEDOUT
;
return
0
;
}
static
void
sh_mobile_lcdc_start_stop
(
struct
sh_mobile_lcdc_priv
*
priv
,
int
start
)
{
...
...
@@ -416,53 +636,52 @@ static void sh_mobile_lcdc_start_stop(struct sh_mobile_lcdc_priv *priv,
static
void
sh_mobile_lcdc_geometry
(
struct
sh_mobile_lcdc_chan
*
ch
)
{
struct
fb_var_screeninfo
*
var
=
&
ch
->
info
->
var
,
*
display_var
=
&
ch
->
display_var
;
const
struct
fb_var_screeninfo
*
var
=
&
ch
->
info
->
var
;
const
struct
fb_videomode
*
mode
=
&
ch
->
display
.
mode
;
unsigned
long
h_total
,
hsync_pos
,
display_h_total
;
u32
tmp
;
tmp
=
ch
->
ldmt1r_value
;
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
;
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 */
lcdc_write_chan
(
ch
,
LDMT2R
,
ch
->
cfg
.
sys_bus_cfg
.
ldmt2r
);
lcdc_write_chan
(
ch
,
LDMT3R
,
ch
->
cfg
.
sys_bus_cfg
.
ldmt3r
);
lcdc_write_chan
(
ch
,
LDMT2R
,
ch
->
cfg
->
sys_bus_cfg
.
ldmt2r
);
lcdc_write_chan
(
ch
,
LDMT3R
,
ch
->
cfg
->
sys_bus_cfg
.
ldmt3r
);
/* horizontal configuration */
h_total
=
display_var
->
xres
+
display_var
->
hsync_len
+
display_var
->
left_margin
+
display_var
->
right_margin
;
h_total
=
mode
->
xres
+
mode
->
hsync_len
+
mode
->
left_margin
+
mode
->
right_margin
;
tmp
=
h_total
/
8
;
/* HTCN */
tmp
|=
(
min
(
display_var
->
xres
,
var
->
xres
)
/
8
)
<<
16
;
/* HDCN */
tmp
|=
(
min
(
mode
->
xres
,
ch
->
xres
)
/
8
)
<<
16
;
/* HDCN */
lcdc_write_chan
(
ch
,
LDHCNR
,
tmp
);
hsync_pos
=
display_var
->
xres
+
display_var
->
right_margin
;
hsync_pos
=
mode
->
xres
+
mode
->
right_margin
;
tmp
=
hsync_pos
/
8
;
/* HSYNP */
tmp
|=
(
display_var
->
hsync_len
/
8
)
<<
16
;
/* HSYNW */
tmp
|=
(
mode
->
hsync_len
/
8
)
<<
16
;
/* HSYNW */
lcdc_write_chan
(
ch
,
LDHSYNR
,
tmp
);
/* vertical configuration */
tmp
=
display_var
->
yres
+
display_var
->
vsync_len
+
display_var
->
upper_margin
+
display_var
->
lower_margin
;
/* VTLN */
tmp
|=
min
(
display_var
->
yres
,
var
->
yres
)
<<
16
;
/* VDLN */
tmp
=
mode
->
yres
+
mode
->
vsync_len
+
mode
->
upper_margin
+
mode
->
lower_margin
;
/* VTLN */
tmp
|=
min
(
mode
->
yres
,
ch
->
yres
)
<<
16
;
/* VDLN */
lcdc_write_chan
(
ch
,
LDVLNR
,
tmp
);
tmp
=
display_var
->
yres
+
display_var
->
lower_margin
;
/* VSYNP */
tmp
|=
display_var
->
vsync_len
<<
16
;
/* VSYNW */
tmp
=
mode
->
yres
+
mode
->
lower_margin
;
/* VSYNP */
tmp
|=
mode
->
vsync_len
<<
16
;
/* VSYNW */
lcdc_write_chan
(
ch
,
LDVSYNR
,
tmp
);
/* Adjust horizontal synchronisation for HDMI */
display_h_total
=
display_var
->
xres
+
display_var
->
hsync_len
+
display_var
->
left_margin
+
display_var
->
right_margin
;
tmp
=
((
display_var
->
xres
&
7
)
<<
24
)
|
((
display_h_total
&
7
)
<<
16
)
|
((
display_var
->
hsync_len
&
7
)
<<
8
)
|
(
hsync_pos
&
7
);
display_h_total
=
mode
->
xres
+
mode
->
hsync_len
+
mode
->
left_margin
+
mode
->
right_margin
;
tmp
=
((
mode
->
xres
&
7
)
<<
24
)
|
((
display_h_total
&
7
)
<<
16
)
|
((
mode
->
hsync_len
&
7
)
<<
8
)
|
(
hsync_pos
&
7
);
lcdc_write_chan
(
ch
,
LDHAJR
,
tmp
);
}
...
...
@@ -498,7 +717,7 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
/* Power supply */
lcdc_write_chan
(
ch
,
LDPMR
,
0
);
m
=
ch
->
cfg
.
clock_divider
;
m
=
ch
->
cfg
->
clock_divider
;
if
(
!
m
)
continue
;
...
...
@@ -525,32 +744,10 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
sh_mobile_lcdc_geometry
(
ch
);
switch
(
sh_mobile_format_fourcc
(
&
ch
->
info
->
var
))
{
case
V4L2_PIX_FMT_RGB565
:
tmp
=
LDDFR_PKF_RGB16
;
break
;
case
V4L2_PIX_FMT_BGR24
:
tmp
=
LDDFR_PKF_RGB24
;
break
;
case
V4L2_PIX_FMT_BGR32
:
tmp
=
LDDFR_PKF_ARGB32
;
break
;
case
V4L2_PIX_FMT_NV12
:
case
V4L2_PIX_FMT_NV21
:
tmp
=
LDDFR_CC
|
LDDFR_YF_420
;
break
;
case
V4L2_PIX_FMT_NV16
:
case
V4L2_PIX_FMT_NV61
:
tmp
=
LDDFR_CC
|
LDDFR_YF_422
;
break
;
case
V4L2_PIX_FMT_NV24
:
case
V4L2_PIX_FMT_NV42
:
tmp
=
LDDFR_CC
|
LDDFR_YF_444
;
break
;
}
tmp
=
ch
->
format
->
lddfr
;
if
(
sh_mobile_format_is_yuv
(
&
ch
->
info
->
var
)
)
{
switch
(
ch
->
info
->
var
.
colorspace
)
{
if
(
ch
->
format
->
yuv
)
{
switch
(
ch
->
colorspace
)
{
case
V4L2_COLORSPACE_REC709
:
tmp
|=
LDDFR_CF1
;
break
;
...
...
@@ -563,7 +760,7 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
lcdc_write_chan
(
ch
,
LDDFR
,
tmp
);
lcdc_write_chan
(
ch
,
LDMLSR
,
ch
->
pitch
);
lcdc_write_chan
(
ch
,
LDSA1R
,
ch
->
base_addr_y
);
if
(
sh_mobile_format_is_yuv
(
&
ch
->
info
->
var
)
)
if
(
ch
->
format
->
yuv
)
lcdc_write_chan
(
ch
,
LDSA2R
,
ch
->
base_addr_c
);
/* When using deferred I/O mode, configure the LCDC for one-shot
...
...
@@ -571,7 +768,7 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
* continuous read mode.
*/
if
(
ch
->
ldmt1r_value
&
LDMT1R_IFM
&&
ch
->
cfg
.
sys_bus_cfg
.
deferred_io_msec
)
{
ch
->
cfg
->
sys_bus_cfg
.
deferred_io_msec
)
{
lcdc_write_chan
(
ch
,
LDSM1R
,
LDSM1R_OS
);
lcdc_write
(
priv
,
_LDINTR
,
LDINTR_FE
);
}
else
{
...
...
@@ -580,7 +777,7 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
}
/* Word and long word swap. */
switch
(
sh_mobile_format_fourcc
(
&
priv
->
ch
[
0
].
info
->
var
)
)
{
switch
(
priv
->
ch
[
0
].
format
->
fourcc
)
{
case
V4L2_PIX_FMT_RGB565
:
case
V4L2_PIX_FMT_NV21
:
case
V4L2_PIX_FMT_NV61
:
...
...
@@ -609,7 +806,6 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
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
;
...
...
@@ -626,15 +822,15 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
lcdc_wait_bit
(
priv
,
_LDCNT2R
,
LDCNT2R_BR
,
0
);
for
(
k
=
0
;
k
<
ARRAY_SIZE
(
priv
->
ch
);
k
++
)
{
c
h
=
&
priv
->
ch
[
k
]
;
c
onst
struct
sh_mobile_lcdc_panel_cfg
*
panel
;
ch
=
&
priv
->
ch
[
k
];
if
(
!
ch
->
enabled
)
continue
;
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
);
panel
=
&
ch
->
cfg
->
panel_cfg
;
if
(
panel
->
setup_sys
)
{
ret
=
panel
->
setup_sys
(
ch
,
&
sh_mobile_lcdc_sys_bus_ops
);
if
(
ret
)
return
ret
;
}
...
...
@@ -642,33 +838,30 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
/* 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
;
void
*
meram
;
ch
=
&
priv
->
ch
[
k
];
if
(
!
ch
->
enabled
)
continue
;
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
;
ch
->
base_addr_y
=
ch
->
dma_handle
;
ch
->
base_addr_c
=
ch
->
base_addr_y
+
ch
->
xres
*
ch
->
yres_virtual
;
/* Enable MERAM if possible. */
cfg
=
ch
->
cfg
.
meram_cfg
;
if
(
mdev
==
NULL
||
mdev
->
ops
==
NULL
||
cfg
==
NULL
)
if
(
mdev
==
NULL
||
mdev
->
ops
==
NULL
||
ch
->
cfg
->
meram_
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
,
c
fg
);
ch
->
meram
_enabled
=
0
;
if
(
ch
->
meram
)
{
mdev
->
ops
->
meram_unregister
(
mdev
,
c
h
->
meram
);
ch
->
meram
=
NULL
;
}
switch
(
sh_mobile_format_fourcc
(
&
ch
->
info
->
var
)
)
{
switch
(
ch
->
format
->
fourcc
)
{
case
V4L2_PIX_FMT_NV12
:
case
V4L2_PIX_FMT_NV21
:
case
V4L2_PIX_FMT_NV16
:
...
...
@@ -687,13 +880,15 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
break
;
}
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
,
meram
=
mdev
->
ops
->
meram_register
(
mdev
,
ch
->
cfg
->
meram_cfg
,
ch
->
pitch
,
ch
->
yres
,
pixelformat
,
&
ch
->
pitch
);
if
(
!
ret
)
ch
->
meram_enabled
=
1
;
if
(
!
IS_ERR
(
meram
))
{
mdev
->
ops
->
meram_update
(
mdev
,
meram
,
ch
->
base_addr_y
,
ch
->
base_addr_c
,
&
ch
->
base_addr_y
,
&
ch
->
base_addr_c
);
ch
->
meram
=
meram
;
}
}
/* Start the LCDC. */
...
...
@@ -707,7 +902,7 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
if
(
!
ch
->
enabled
)
continue
;
tmp
=
ch
->
cfg
.
sys_bus_cfg
.
deferred_io_msec
;
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
);
...
...
@@ -715,11 +910,7 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
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
);
module_put
(
board_cfg
->
owner
);
}
sh_mobile_lcdc_display_on
(
ch
);
if
(
ch
->
bl
)
{
ch
->
bl
->
props
.
power
=
FB_BLANK_UNBLANK
;
...
...
@@ -733,7 +924,6 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
static
void
sh_mobile_lcdc_stop
(
struct
sh_mobile_lcdc_priv
*
priv
)
{
struct
sh_mobile_lcdc_chan
*
ch
;
struct
sh_mobile_lcdc_board_cfg
*
board_cfg
;
int
k
;
/* clean up deferred io and ask board code to disable panel */
...
...
@@ -760,20 +950,14 @@ static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv)
backlight_update_status
(
ch
->
bl
);
}
board_cfg
=
&
ch
->
cfg
.
board_cfg
;
if
(
board_cfg
->
display_off
&&
try_module_get
(
board_cfg
->
owner
))
{
board_cfg
->
display_off
(
board_cfg
->
board_data
);
module_put
(
board_cfg
->
owner
);
}
sh_mobile_lcdc_display_off
(
ch
);
/* disable the meram */
if
(
ch
->
meram_enabled
)
{
struct
sh_mobile_meram_cfg
*
cfg
;
if
(
ch
->
meram
)
{
struct
sh_mobile_meram_info
*
mdev
;
cfg
=
ch
->
cfg
.
meram_cfg
;
mdev
=
priv
->
meram_dev
;
mdev
->
ops
->
meram_unregister
(
mdev
,
c
fg
);
ch
->
meram
_enabled
=
0
;
mdev
->
ops
->
meram_unregister
(
mdev
,
c
h
->
meram
);
ch
->
meram
=
0
;
}
}
...
...
@@ -790,86 +974,9 @@ static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv)
sh_mobile_lcdc_clk_off
(
priv
);
}
static
int
sh_mobile_lcdc_check_interface
(
struct
sh_mobile_lcdc_chan
*
ch
)
{
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
(
!
(
interface_type
&
LDMT1R_IFM
))
return
-
EINVAL
;
interface_type
&=
~
LDMT1R_IFM
;
}
ch
->
ldmt1r_value
=
interface_type
;
return
0
;
}
static
int
sh_mobile_lcdc_setup_clocks
(
struct
platform_device
*
pdev
,
int
clock_source
,
struct
sh_mobile_lcdc_priv
*
priv
)
{
char
*
str
;
switch
(
clock_source
)
{
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
;
}
if
(
str
)
{
priv
->
dot_clk
=
clk_get
(
&
pdev
->
dev
,
str
);
if
(
IS_ERR
(
priv
->
dot_clk
))
{
dev_err
(
&
pdev
->
dev
,
"cannot get dot clock %s
\n
"
,
str
);
return
PTR_ERR
(
priv
->
dot_clk
);
}
}
/* Runtime PM support involves two step for this driver:
* 1) Enable Runtime PM
* 2) Force Runtime PM Resume since hardware is accessed from probe()
/* -----------------------------------------------------------------------------
* Frame buffer operations
*/
priv
->
dev
=
&
pdev
->
dev
;
pm_runtime_enable
(
priv
->
dev
);
pm_runtime_resume
(
priv
->
dev
);
return
0
;
}
static
int
sh_mobile_lcdc_setcolreg
(
u_int
regno
,
u_int
red
,
u_int
green
,
u_int
blue
,
...
...
@@ -936,14 +1043,12 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var,
unsigned
long
new_pan_offset
;
unsigned
long
base_addr_y
,
base_addr_c
;
unsigned
long
c_offset
;
bool
yuv
=
sh_mobile_format_is_yuv
(
&
info
->
var
);
if
(
!
yuv
)
new_pan_offset
=
var
->
yoffset
*
info
->
fix
.
line_lengt
h
+
var
->
xoffset
*
(
info
->
var
.
bits_per_pixel
/
8
);
if
(
!
ch
->
format
->
yuv
)
new_pan_offset
=
var
->
yoffset
*
ch
->
pitc
h
+
var
->
xoffset
*
(
ch
->
format
->
bpp
/
8
);
else
new_pan_offset
=
var
->
yoffset
*
info
->
fix
.
line_length
+
var
->
xoffset
;
new_pan_offset
=
var
->
yoffset
*
ch
->
pitch
+
var
->
xoffset
;
if
(
new_pan_offset
==
ch
->
pan_offset
)
return
0
;
/* No change, do nothing */
...
...
@@ -952,39 +1057,33 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var,
/* Set the source address for the next refresh */
base_addr_y
=
ch
->
dma_handle
+
new_pan_offset
;
if
(
yuv
)
{
if
(
ch
->
format
->
yuv
)
{
/* Set y offset */
c_offset
=
var
->
yoffset
*
info
->
fix
.
line_length
*
(
info
->
var
.
bits_per_pixel
-
8
)
/
8
;
base_addr_c
=
ch
->
dma_handle
+
info
->
var
.
xres
*
info
->
var
.
yres_virtual
c_offset
=
var
->
yoffset
*
ch
->
pitch
*
(
ch
->
format
->
bpp
-
8
)
/
8
;
base_addr_c
=
ch
->
dma_handle
+
ch
->
xres
*
ch
->
yres_virtual
+
c_offset
;
/* Set x offset */
if
(
sh_mobile_format_fourcc
(
&
info
->
var
)
==
V4L2_PIX_FMT_NV24
)
if
(
ch
->
format
->
fourcc
==
V4L2_PIX_FMT_NV24
)
base_addr_c
+=
2
*
var
->
xoffset
;
else
base_addr_c
+=
var
->
xoffset
;
}
if
(
ch
->
meram_enabled
)
{
struct
sh_mobile_meram_cfg
*
cfg
;
if
(
ch
->
meram
)
{
struct
sh_mobile_meram_info
*
mdev
;
int
ret
;
cfg
=
ch
->
cfg
.
meram_cfg
;
mdev
=
priv
->
meram_dev
;
ret
=
mdev
->
ops
->
meram_update
(
mdev
,
cfg
,
mdev
->
ops
->
meram_update
(
mdev
,
ch
->
meram
,
base_addr_y
,
base_addr_c
,
&
base_addr_y
,
&
base_addr_c
);
if
(
ret
)
return
ret
;
}
ch
->
base_addr_y
=
base_addr_y
;
ch
->
base_addr_c
=
base_addr_c
;
lcdc_write_chan_mirror
(
ch
,
LDSA1R
,
base_addr_y
);
if
(
yuv
)
if
(
ch
->
format
->
yuv
)
lcdc_write_chan_mirror
(
ch
,
LDSA2R
,
base_addr_c
);
if
(
lcdc_chan_is_sublcd
(
ch
))
...
...
@@ -999,27 +1098,6 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var,
return
0
;
}
static
int
sh_mobile_wait_for_vsync
(
struct
fb_info
*
info
)
{
struct
sh_mobile_lcdc_chan
*
ch
=
info
->
par
;
unsigned
long
ldintr
;
int
ret
;
/* Enable VSync End interrupt and be careful not to acknowledge any
* pending interrupt.
*/
ldintr
=
lcdc_read
(
ch
->
lcdc
,
_LDINTR
);
ldintr
|=
LDINTR_VEE
|
LDINTR_STATUS_MASK
;
lcdc_write
(
ch
->
lcdc
,
_LDINTR
,
ldintr
);
ret
=
wait_for_completion_interruptible_timeout
(
&
ch
->
vsync_completion
,
msecs_to_jiffies
(
100
));
if
(
!
ret
)
return
-
ETIMEDOUT
;
return
0
;
}
static
int
sh_mobile_ioctl
(
struct
fb_info
*
info
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
...
...
@@ -1027,7 +1105,7 @@ static int sh_mobile_ioctl(struct fb_info *info, unsigned int cmd,
switch
(
cmd
)
{
case
FBIO_WAITFORVSYNC
:
retval
=
sh_mobile_wait_for_vsync
(
info
);
retval
=
sh_mobile_wait_for_vsync
(
info
->
par
);
break
;
default:
...
...
@@ -1040,7 +1118,8 @@ static int sh_mobile_ioctl(struct fb_info *info, unsigned int cmd,
static
void
sh_mobile_fb_reconfig
(
struct
fb_info
*
info
)
{
struct
sh_mobile_lcdc_chan
*
ch
=
info
->
par
;
struct
fb_videomode
mode1
,
mode2
;
struct
fb_var_screeninfo
var
;
struct
fb_videomode
mode
;
struct
fb_event
event
;
int
evnt
=
FB_EVENT_MODE_CHANGE_ALL
;
...
...
@@ -1048,14 +1127,19 @@ static void sh_mobile_fb_reconfig(struct fb_info *info)
/* More framebuffer users are active */
return
;
fb_var_to_videomode
(
&
mode1
,
&
ch
->
display_var
);
fb_var_to_videomode
(
&
mode2
,
&
info
->
var
);
fb_var_to_videomode
(
&
mode
,
&
info
->
var
);
if
(
fb_mode_is_equal
(
&
mode1
,
&
mode2
))
if
(
fb_mode_is_equal
(
&
ch
->
display
.
mode
,
&
mode
))
return
;
/* Display has been re-plugged, framebuffer is free now, reconfigure */
if
(
fb_set_var
(
info
,
&
ch
->
display_var
)
<
0
)
var
=
info
->
var
;
fb_videomode_to_var
(
&
var
,
&
ch
->
display
.
mode
);
var
.
width
=
ch
->
display
.
width
;
var
.
height
=
ch
->
display
.
height
;
var
.
activate
=
FB_ACTIVATE_NOW
;
if
(
fb_set_var
(
info
,
&
var
)
<
0
)
/* Couldn't reconfigure, hopefully, can continue as before */
return
;
...
...
@@ -1065,7 +1149,7 @@ static void sh_mobile_fb_reconfig(struct fb_info *info)
* user event, we have to call the chain ourselves.
*/
event
.
info
=
info
;
event
.
data
=
&
mode1
;
event
.
data
=
&
ch
->
display
.
mode
;
fb_notifier_call_chain
(
evnt
,
&
event
);
}
...
...
@@ -1124,8 +1208,8 @@ static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *in
* distance between two modes is defined as the size of the
* non-overlapping parts of the two rectangles.
*/
for
(
i
=
0
;
i
<
ch
->
cfg
.
num_cfg
;
++
i
)
{
const
struct
fb_videomode
*
mode
=
&
ch
->
cfg
.
lcd_cfg
[
i
];
for
(
i
=
0
;
i
<
ch
->
cfg
->
num_modes
;
++
i
)
{
const
struct
fb_videomode
*
mode
=
&
ch
->
cfg
->
lcd_modes
[
i
];
unsigned
int
dist
;
/* We can only round up. */
...
...
@@ -1144,7 +1228,7 @@ static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *in
}
/* If no available mode can be used, return an error. */
if
(
ch
->
cfg
.
num_cfg
!=
0
)
{
if
(
ch
->
cfg
->
num_modes
!=
0
)
{
if
(
best_dist
==
(
unsigned
int
)
-
1
)
return
-
EINVAL
;
...
...
@@ -1156,37 +1240,22 @@ static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *in
* resolution.
*/
if
(
var
->
xres_virtual
<
var
->
xres
)
var
->
xres_virtual
=
var
->
xres
;
if
(
var
->
yres_virtual
<
var
->
yres
)
var
->
yres_virtual
=
var
->
yres
;
if
(
sh_mobile_format_is_fourcc
(
var
))
{
switch
(
var
->
grayscale
)
{
case
V4L2_PIX_FMT_NV12
:
case
V4L2_PIX_FMT_NV21
:
var
->
bits_per_pixel
=
12
;
break
;
case
V4L2_PIX_FMT_RGB565
:
case
V4L2_PIX_FMT_NV16
:
case
V4L2_PIX_FMT_NV61
:
var
->
bits_per_pixel
=
16
;
break
;
case
V4L2_PIX_FMT_BGR24
:
case
V4L2_PIX_FMT_NV24
:
case
V4L2_PIX_FMT_NV42
:
var
->
bits_per_pixel
=
24
;
break
;
case
V4L2_PIX_FMT_BGR32
:
var
->
bits_per_pixel
=
32
;
break
;
default:
var
->
xres_virtual
=
var
->
xres
;
if
(
var
->
yres_virtual
<
var
->
yres
)
var
->
yres_virtual
=
var
->
yres
;
if
(
sh_mobile_format_is_fourcc
(
var
))
{
const
struct
sh_mobile_lcdc_format_info
*
format
;
format
=
sh_mobile_format_info
(
var
->
grayscale
);
if
(
format
==
NULL
)
return
-
EINVAL
;
}
var
->
bits_per_pixel
=
format
->
bpp
;
/* Default to RGB and JPEG color-spaces for RGB and YUV formats
* respectively.
*/
if
(
!
sh_mobile_format_is_yuv
(
var
)
)
if
(
!
format
->
yuv
)
var
->
colorspace
=
V4L2_COLORSPACE_SRGB
;
else
if
(
var
->
colorspace
!=
V4L2_COLORSPACE_REC709
)
var
->
colorspace
=
V4L2_COLORSPACE_JPEG
;
...
...
@@ -1246,22 +1315,28 @@ static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *in
static
int
sh_mobile_set_par
(
struct
fb_info
*
info
)
{
struct
sh_mobile_lcdc_chan
*
ch
=
info
->
par
;
u32
line_length
=
info
->
fix
.
line_length
;
int
ret
;
sh_mobile_lcdc_stop
(
ch
->
lcdc
);
if
(
sh_mobile_format_is_yuv
(
&
info
->
var
))
info
->
fix
.
line_length
=
info
->
var
.
xres
;
ch
->
format
=
sh_mobile_format_info
(
sh_mobile_format_fourcc
(
&
info
->
var
));
ch
->
colorspace
=
info
->
var
.
colorspace
;
ch
->
xres
=
info
->
var
.
xres
;
ch
->
xres_virtual
=
info
->
var
.
xres_virtual
;
ch
->
yres
=
info
->
var
.
yres
;
ch
->
yres_virtual
=
info
->
var
.
yres_virtual
;
if
(
ch
->
format
->
yuv
)
ch
->
pitch
=
info
->
var
.
xres
;
else
info
->
fix
.
line_length
=
info
->
var
.
xres
*
info
->
var
.
bits_per_pixel
/
8
;
ch
->
pitch
=
info
->
var
.
xres
*
ch
->
format
->
bpp
/
8
;
ret
=
sh_mobile_lcdc_start
(
ch
->
lcdc
);
if
(
ret
<
0
)
{
if
(
ret
<
0
)
dev_err
(
info
->
dev
,
"%s: unable to restart LCDC
\n
"
,
__func__
);
info
->
fix
.
line_length
=
line_length
;
}
info
->
fix
.
line_length
=
ch
->
pitch
;
if
(
sh_mobile_format_is_fourcc
(
&
info
->
var
))
{
info
->
fix
.
type
=
FB_TYPE_FOURCC
;
...
...
@@ -1290,8 +1365,8 @@ static int sh_mobile_lcdc_blank(int blank, struct fb_info *info)
/* blank the screen? */
if
(
blank
>
FB_BLANK_UNBLANK
&&
ch
->
blank_status
==
FB_BLANK_UNBLANK
)
{
struct
fb_fillrect
rect
=
{
.
width
=
info
->
var
.
xres
,
.
height
=
info
->
var
.
yres
,
.
width
=
ch
->
xres
,
.
height
=
ch
->
yres
,
};
sh_mobile_lcdc_fillrect
(
info
,
&
rect
);
}
...
...
@@ -1307,8 +1382,8 @@ static int sh_mobile_lcdc_blank(int blank, struct fb_info *info)
* mode will reenable the clocks and update the screen in time,
* so it does not need this. */
if
(
!
info
->
fbdefio
)
{
sh_mobile_wait_for_vsync
(
info
);
sh_mobile_wait_for_vsync
(
info
);
sh_mobile_wait_for_vsync
(
ch
);
sh_mobile_wait_for_vsync
(
ch
);
}
sh_mobile_lcdc_clk_off
(
p
);
}
...
...
@@ -1334,25 +1409,161 @@ static struct fb_ops sh_mobile_lcdc_ops = {
.
fb_set_par
=
sh_mobile_set_par
,
};
static
void
sh_mobile_lcdc_channel_fb_unregister
(
struct
sh_mobile_lcdc_chan
*
ch
)
{
if
(
ch
->
info
&&
ch
->
info
->
dev
)
unregister_framebuffer
(
ch
->
info
);
}
static
int
__devinit
sh_mobile_lcdc_channel_fb_register
(
struct
sh_mobile_lcdc_chan
*
ch
)
{
struct
fb_info
*
info
=
ch
->
info
;
int
ret
;
if
(
info
->
fbdefio
)
{
ch
->
sglist
=
vmalloc
(
sizeof
(
struct
scatterlist
)
*
ch
->
fb_size
>>
PAGE_SHIFT
);
if
(
!
ch
->
sglist
)
{
dev_err
(
ch
->
lcdc
->
dev
,
"cannot allocate sglist
\n
"
);
return
-
ENOMEM
;
}
}
info
->
bl_dev
=
ch
->
bl
;
ret
=
register_framebuffer
(
info
);
if
(
ret
<
0
)
return
ret
;
dev_info
(
ch
->
lcdc
->
dev
,
"registered %s/%s as %dx%d %dbpp.
\n
"
,
dev_name
(
ch
->
lcdc
->
dev
),
(
ch
->
cfg
->
chan
==
LCDC_CHAN_MAINLCD
)
?
"mainlcd"
:
"sublcd"
,
info
->
var
.
xres
,
info
->
var
.
yres
,
info
->
var
.
bits_per_pixel
);
/* deferred io mode: disable clock to save power */
if
(
info
->
fbdefio
||
info
->
state
==
FBINFO_STATE_SUSPENDED
)
sh_mobile_lcdc_clk_off
(
ch
->
lcdc
);
return
ret
;
}
static
void
sh_mobile_lcdc_channel_fb_cleanup
(
struct
sh_mobile_lcdc_chan
*
ch
)
{
struct
fb_info
*
info
=
ch
->
info
;
if
(
!
info
||
!
info
->
device
)
return
;
if
(
ch
->
sglist
)
vfree
(
ch
->
sglist
);
fb_dealloc_cmap
(
&
info
->
cmap
);
framebuffer_release
(
info
);
}
static
int
__devinit
sh_mobile_lcdc_channel_fb_init
(
struct
sh_mobile_lcdc_chan
*
ch
,
const
struct
fb_videomode
*
mode
,
unsigned
int
num_modes
)
{
struct
sh_mobile_lcdc_priv
*
priv
=
ch
->
lcdc
;
struct
fb_var_screeninfo
*
var
;
struct
fb_info
*
info
;
int
ret
;
/* Allocate and initialize the frame buffer device. Create the modes
* list and allocate the color map.
*/
info
=
framebuffer_alloc
(
0
,
priv
->
dev
);
if
(
info
==
NULL
)
{
dev_err
(
priv
->
dev
,
"unable to allocate fb_info
\n
"
);
return
-
ENOMEM
;
}
ch
->
info
=
info
;
info
->
flags
=
FBINFO_FLAG_DEFAULT
;
info
->
fbops
=
&
sh_mobile_lcdc_ops
;
info
->
device
=
priv
->
dev
;
info
->
screen_base
=
ch
->
fb_mem
;
info
->
pseudo_palette
=
&
ch
->
pseudo_palette
;
info
->
par
=
ch
;
fb_videomode_to_modelist
(
mode
,
num_modes
,
&
info
->
modelist
);
ret
=
fb_alloc_cmap
(
&
info
->
cmap
,
PALETTE_NR
,
0
);
if
(
ret
<
0
)
{
dev_err
(
priv
->
dev
,
"unable to allocate cmap
\n
"
);
return
ret
;
}
/* Initialize fixed screen information. Restrict pan to 2 lines steps
* for NV12 and NV21.
*/
info
->
fix
=
sh_mobile_lcdc_fix
;
info
->
fix
.
smem_start
=
ch
->
dma_handle
;
info
->
fix
.
smem_len
=
ch
->
fb_size
;
info
->
fix
.
line_length
=
ch
->
pitch
;
if
(
ch
->
format
->
yuv
)
info
->
fix
.
visual
=
FB_VISUAL_FOURCC
;
else
info
->
fix
.
visual
=
FB_VISUAL_TRUECOLOR
;
if
(
ch
->
format
->
fourcc
==
V4L2_PIX_FMT_NV12
||
ch
->
format
->
fourcc
==
V4L2_PIX_FMT_NV21
)
info
->
fix
.
ypanstep
=
2
;
/* Initialize variable screen information using the first mode as
* default. The default Y virtual resolution is twice the panel size to
* allow for double-buffering.
*/
var
=
&
info
->
var
;
fb_videomode_to_var
(
var
,
mode
);
var
->
width
=
ch
->
cfg
->
panel_cfg
.
width
;
var
->
height
=
ch
->
cfg
->
panel_cfg
.
height
;
var
->
yres_virtual
=
var
->
yres
*
2
;
var
->
activate
=
FB_ACTIVATE_NOW
;
/* Use the legacy API by default for RGB formats, and the FOURCC API
* for YUV formats.
*/
if
(
!
ch
->
format
->
yuv
)
var
->
bits_per_pixel
=
ch
->
format
->
bpp
;
else
var
->
grayscale
=
ch
->
format
->
fourcc
;
ret
=
sh_mobile_check_var
(
var
,
info
);
if
(
ret
)
return
ret
;
return
0
;
}
/* -----------------------------------------------------------------------------
* Backlight
*/
static
int
sh_mobile_lcdc_update_bl
(
struct
backlight_device
*
bdev
)
{
struct
sh_mobile_lcdc_chan
*
ch
=
bl_get_data
(
bdev
);
struct
sh_mobile_lcdc_board_cfg
*
cfg
=
&
ch
->
cfg
.
board_cfg
;
int
brightness
=
bdev
->
props
.
brightness
;
if
(
bdev
->
props
.
power
!=
FB_BLANK_UNBLANK
||
bdev
->
props
.
state
&
(
BL_CORE_SUSPENDED
|
BL_CORE_FBBLANK
))
brightness
=
0
;
return
c
fg
->
set_brightness
(
cfg
->
board_data
,
brightness
);
return
c
h
->
cfg
->
bl_info
.
set_brightness
(
brightness
);
}
static
int
sh_mobile_lcdc_get_brightness
(
struct
backlight_device
*
bdev
)
{
struct
sh_mobile_lcdc_chan
*
ch
=
bl_get_data
(
bdev
);
struct
sh_mobile_lcdc_board_cfg
*
cfg
=
&
ch
->
cfg
.
board_cfg
;
return
c
fg
->
get_brightness
(
cfg
->
board_data
);
return
c
h
->
cfg
->
bl_info
.
get_brightness
(
);
}
static
int
sh_mobile_lcdc_check_fb
(
struct
backlight_device
*
bdev
,
...
...
@@ -1373,7 +1584,7 @@ static struct backlight_device *sh_mobile_lcdc_bl_probe(struct device *parent,
{
struct
backlight_device
*
bl
;
bl
=
backlight_device_register
(
ch
->
cfg
.
bl_info
.
name
,
parent
,
ch
,
bl
=
backlight_device_register
(
ch
->
cfg
->
bl_info
.
name
,
parent
,
ch
,
&
sh_mobile_lcdc_bl_ops
,
NULL
);
if
(
IS_ERR
(
bl
))
{
dev_err
(
parent
,
"unable to register backlight device: %ld
\n
"
,
...
...
@@ -1381,7 +1592,7 @@ static struct backlight_device *sh_mobile_lcdc_bl_probe(struct device *parent,
return
NULL
;
}
bl
->
props
.
max_brightness
=
ch
->
cfg
.
bl_info
.
max_brightness
;
bl
->
props
.
max_brightness
=
ch
->
cfg
->
bl_info
.
max_brightness
;
bl
->
props
.
brightness
=
bl
->
props
.
max_brightness
;
backlight_update_status
(
bl
);
...
...
@@ -1393,6 +1604,10 @@ static void sh_mobile_lcdc_bl_remove(struct backlight_device *bdev)
backlight_device_unregister
(
bdev
);
}
/* -----------------------------------------------------------------------------
* Power management
*/
static
int
sh_mobile_lcdc_suspend
(
struct
device
*
dev
)
{
struct
platform_device
*
pdev
=
to_platform_device
(
dev
);
...
...
@@ -1436,6 +1651,10 @@ static const struct dev_pm_ops sh_mobile_lcdc_dev_pm_ops = {
.
runtime_resume
=
sh_mobile_lcdc_runtime_resume
,
};
/* -----------------------------------------------------------------------------
* Framebuffer notifier
*/
/* locking: called with info->lock held */
static
int
sh_mobile_lcdc_notify
(
struct
notifier_block
*
nb
,
unsigned
long
action
,
void
*
data
)
...
...
@@ -1443,7 +1662,6 @@ static int sh_mobile_lcdc_notify(struct notifier_block *nb,
struct
fb_event
*
event
=
data
;
struct
fb_info
*
info
=
event
->
info
;
struct
sh_mobile_lcdc_chan
*
ch
=
info
->
par
;
struct
sh_mobile_lcdc_board_cfg
*
board_cfg
=
&
ch
->
cfg
.
board_cfg
;
if
(
&
ch
->
lcdc
->
notifier
!=
nb
)
return
NOTIFY_DONE
;
...
...
@@ -1453,10 +1671,7 @@ static int sh_mobile_lcdc_notify(struct notifier_block *nb,
switch
(
action
)
{
case
FB_EVENT_SUSPEND
:
if
(
board_cfg
->
display_off
&&
try_module_get
(
board_cfg
->
owner
))
{
board_cfg
->
display_off
(
board_cfg
->
board_data
);
module_put
(
board_cfg
->
owner
);
}
sh_mobile_lcdc_display_off
(
ch
);
sh_mobile_lcdc_stop
(
ch
->
lcdc
);
break
;
case
FB_EVENT_RESUME
:
...
...
@@ -1464,47 +1679,60 @@ static int sh_mobile_lcdc_notify(struct notifier_block *nb,
sh_mobile_fb_reconfig
(
info
);
mutex_unlock
(
&
ch
->
open_lock
);
/* HDMI must be enabled before LCDC configuration */
if
(
board_cfg
->
display_on
&&
try_module_get
(
board_cfg
->
owner
))
{
board_cfg
->
display_on
(
board_cfg
->
board_data
,
info
);
module_put
(
board_cfg
->
owner
);
}
sh_mobile_lcdc_display_on
(
ch
);
sh_mobile_lcdc_start
(
ch
->
lcdc
);
}
return
NOTIFY_OK
;
}
/* -----------------------------------------------------------------------------
* Probe/remove and driver init/exit
*/
static
const
struct
fb_videomode
default_720p
__devinitconst
=
{
.
name
=
"HDMI 720p"
,
.
xres
=
1280
,
.
yres
=
720
,
.
left_margin
=
220
,
.
right_margin
=
110
,
.
hsync_len
=
40
,
.
upper_margin
=
20
,
.
lower_margin
=
5
,
.
vsync_len
=
5
,
.
pixclock
=
13468
,
.
refresh
=
60
,
.
sync
=
FB_SYNC_VERT_HIGH_ACT
|
FB_SYNC_HOR_HIGH_ACT
,
};
static
int
sh_mobile_lcdc_remove
(
struct
platform_device
*
pdev
)
{
struct
sh_mobile_lcdc_priv
*
priv
=
platform_get_drvdata
(
pdev
);
struct
fb_info
*
info
;
int
i
;
fb_unregister_client
(
&
priv
->
notifier
);
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
priv
->
ch
);
i
++
)
if
(
priv
->
ch
[
i
].
info
&&
priv
->
ch
[
i
].
info
->
dev
)
unregister_framebuffer
(
priv
->
ch
[
i
].
info
);
sh_mobile_lcdc_channel_fb_unregister
(
&
priv
->
ch
[
i
]);
sh_mobile_lcdc_stop
(
priv
);
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
priv
->
ch
);
i
++
)
{
info
=
priv
->
ch
[
i
].
info
;
struct
sh_mobile_lcdc_chan
*
ch
=
&
priv
->
ch
[
i
]
;
if
(
!
info
||
!
info
->
device
)
continue
;
if
(
ch
->
tx_dev
)
{
ch
->
tx_dev
->
lcdc
=
NULL
;
module_put
(
ch
->
cfg
->
tx_dev
->
dev
.
driver
->
owner
);
}
if
(
priv
->
ch
[
i
].
sglist
)
vfree
(
priv
->
ch
[
i
].
sglist
);
sh_mobile_lcdc_channel_fb_cleanup
(
ch
);
if
(
info
->
screen_base
)
dma_free_coherent
(
&
pdev
->
dev
,
info
->
fix
.
smem_len
,
info
->
screen_base
,
priv
->
ch
[
i
].
dma_handle
);
fb_dealloc_cmap
(
&
info
->
cmap
);
framebuffer_release
(
info
);
if
(
ch
->
fb_mem
)
dma_free_coherent
(
&
pdev
->
dev
,
ch
->
fb_size
,
ch
->
fb_mem
,
ch
->
dma_handle
);
}
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
priv
->
ch
);
i
++
)
{
...
...
@@ -1512,11 +1740,10 @@ static int sh_mobile_lcdc_remove(struct platform_device *pdev)
sh_mobile_lcdc_bl_remove
(
priv
->
ch
[
i
].
bl
);
}
if
(
priv
->
dot_clk
)
if
(
priv
->
dot_clk
)
{
pm_runtime_disable
(
&
pdev
->
dev
);
clk_put
(
priv
->
dot_clk
);
if
(
priv
->
dev
)
pm_runtime_disable
(
priv
->
dev
);
}
if
(
priv
->
base
)
iounmap
(
priv
->
base
);
...
...
@@ -1527,49 +1754,82 @@ static int sh_mobile_lcdc_remove(struct platform_device *pdev)
return
0
;
}
static
int
__devinit
sh_mobile_lcdc_channel_init
(
struct
sh_mobile_lcdc_chan
*
ch
,
struct
device
*
dev
)
static
int
__devinit
sh_mobile_lcdc_check_interface
(
struct
sh_mobile_lcdc_chan
*
ch
)
{
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
(
!
(
interface_type
&
LDMT1R_IFM
))
return
-
EINVAL
;
interface_type
&=
~
LDMT1R_IFM
;
}
ch
->
ldmt1r_value
=
interface_type
;
return
0
;
}
static
int
__devinit
sh_mobile_lcdc_channel_init
(
struct
sh_mobile_lcdc_priv
*
priv
,
struct
sh_mobile_lcdc_chan
*
ch
)
{
struct
sh_mobile_lcdc_chan_cfg
*
cfg
=
&
ch
->
cfg
;
const
struct
sh_mobile_lcdc_format_info
*
format
;
const
struct
sh_mobile_lcdc_chan_cfg
*
cfg
=
ch
->
cfg
;
const
struct
fb_videomode
*
max_mode
;
const
struct
fb_videomode
*
mode
;
struct
fb_var_screeninfo
*
var
;
struct
fb_info
*
info
;
unsigned
int
num_modes
;
unsigned
int
max_size
;
int
num_cfg
;
void
*
buf
;
int
ret
;
int
i
;
unsigned
int
i
;
mutex_init
(
&
ch
->
open_lock
);
ch
->
notify
=
sh_mobile_lcdc_display_notify
;
/*
Allocate the frame buffer device
. */
ch
->
info
=
framebuffer_alloc
(
0
,
dev
);
if
(
!
ch
->
info
)
{
dev_err
(
dev
,
"unable to allocate fb_info
\n
"
);
return
-
E
NOMEM
;
/*
Validate the format
. */
format
=
sh_mobile_format_info
(
cfg
->
fourcc
);
if
(
format
==
NULL
)
{
dev_err
(
priv
->
dev
,
"Invalid FOURCC %08x.
\n
"
,
cfg
->
fourcc
);
return
-
E
INVAL
;
}
info
=
ch
->
info
;
info
->
fbops
=
&
sh_mobile_lcdc_ops
;
info
->
par
=
ch
;
info
->
pseudo_palette
=
&
ch
->
pseudo_palette
;
info
->
flags
=
FBINFO_FLAG_DEFAULT
;
/* Iterate through the modes to validate them and find the highest
* resolution.
*/
max_mode
=
NULL
;
max_size
=
0
;
for
(
i
=
0
,
mode
=
cfg
->
lcd_
cfg
;
i
<
cfg
->
num_cfg
;
i
++
,
mode
++
)
{
for
(
i
=
0
,
mode
=
cfg
->
lcd_
modes
;
i
<
cfg
->
num_modes
;
i
++
,
mode
++
)
{
unsigned
int
size
=
mode
->
yres
*
mode
->
xres
;
/* NV12/NV21 buffers must have even number of lines */
if
((
cfg
->
fourcc
==
V4L2_PIX_FMT_NV12
||
cfg
->
fourcc
==
V4L2_PIX_FMT_NV21
)
&&
(
mode
->
yres
&
0x1
))
{
dev_err
(
dev
,
"yres must be multiple of 2 for YCbCr420
"
"mode.
\n
"
);
dev_err
(
priv
->
dev
,
"yres must be multiple of 2 for
"
"
YCbCr420
mode.
\n
"
);
return
-
EINVAL
;
}
...
...
@@ -1582,93 +1842,59 @@ static int __devinit sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch,
if
(
!
max_size
)
max_size
=
MAX_XRES
*
MAX_YRES
;
else
dev_dbg
(
dev
,
"Found largest videomode %ux%u
\n
"
,
dev_dbg
(
priv
->
dev
,
"Found largest videomode %ux%u
\n
"
,
max_mode
->
xres
,
max_mode
->
yres
);
/* Create the mode list. */
if
(
cfg
->
lcd_cfg
==
NULL
)
{
if
(
cfg
->
lcd_modes
==
NULL
)
{
mode
=
&
default_720p
;
num_
cfg
=
1
;
num_
modes
=
1
;
}
else
{
mode
=
cfg
->
lcd_
cfg
;
num_
cfg
=
cfg
->
num_cfg
;
mode
=
cfg
->
lcd_
modes
;
num_
modes
=
cfg
->
num_modes
;
}
fb_videomode_to_modelist
(
mode
,
num_cfg
,
&
info
->
modelist
);
/* Use the first mode as default. */
ch
->
format
=
format
;
ch
->
xres
=
mode
->
xres
;
ch
->
xres_virtual
=
mode
->
xres
;
ch
->
yres
=
mode
->
yres
;
ch
->
yres_virtual
=
mode
->
yres
*
2
;
/* Initialize variable screen information using the first mode as
* default. The default Y virtual resolution is twice the panel size to
* allow for double-buffering.
*/
var
=
&
info
->
var
;
fb_videomode_to_var
(
var
,
mode
);
var
->
width
=
cfg
->
lcd_size_cfg
.
width
;
var
->
height
=
cfg
->
lcd_size_cfg
.
height
;
var
->
yres_virtual
=
var
->
yres
*
2
;
var
->
activate
=
FB_ACTIVATE_NOW
;
switch
(
cfg
->
fourcc
)
{
case
V4L2_PIX_FMT_RGB565
:
var
->
bits_per_pixel
=
16
;
break
;
case
V4L2_PIX_FMT_BGR24
:
var
->
bits_per_pixel
=
24
;
break
;
case
V4L2_PIX_FMT_BGR32
:
var
->
bits_per_pixel
=
32
;
break
;
default:
var
->
grayscale
=
cfg
->
fourcc
;
break
;
if
(
!
format
->
yuv
)
{
ch
->
colorspace
=
V4L2_COLORSPACE_SRGB
;
ch
->
pitch
=
ch
->
xres
*
format
->
bpp
/
8
;
}
else
{
ch
->
colorspace
=
V4L2_COLORSPACE_REC709
;
ch
->
pitch
=
ch
->
xres
;
}
/* Make sure the memory size check won't fail. smem_len is initialized
* later based on var.
*/
info
->
fix
.
smem_len
=
UINT_MAX
;
ret
=
sh_mobile_check_var
(
var
,
info
);
if
(
ret
)
return
ret
;
max_size
=
max_size
*
var
->
bits_per_pixel
/
8
*
2
;
ch
->
display
.
width
=
cfg
->
panel_cfg
.
width
;
ch
->
display
.
height
=
cfg
->
panel_cfg
.
height
;
ch
->
display
.
mode
=
*
mode
;
/* Allocate frame buffer memory and color map. */
buf
=
dma_alloc_coherent
(
dev
,
max_size
,
&
ch
->
dma_handle
,
GFP_KERNEL
);
if
(
!
buf
)
{
dev_err
(
dev
,
"unable to allocate buffer
\n
"
);
/* Allocate frame buffer memory. */
ch
->
fb_size
=
max_size
*
format
->
bpp
/
8
*
2
;
ch
->
fb_mem
=
dma_alloc_coherent
(
priv
->
dev
,
ch
->
fb_size
,
&
ch
->
dma_handle
,
GFP_KERNEL
);
if
(
ch
->
fb_mem
==
NULL
)
{
dev_err
(
priv
->
dev
,
"unable to allocate buffer
\n
"
);
return
-
ENOMEM
;
}
ret
=
fb_alloc_cmap
(
&
info
->
cmap
,
PALETTE_NR
,
0
);
if
(
ret
<
0
)
{
dev_err
(
dev
,
"unable to allocate cmap
\n
"
);
dma_free_coherent
(
dev
,
max_size
,
buf
,
ch
->
dma_handle
);
return
ret
;
/* Initialize the transmitter device if present. */
if
(
cfg
->
tx_dev
)
{
if
(
!
cfg
->
tx_dev
->
dev
.
driver
||
!
try_module_get
(
cfg
->
tx_dev
->
dev
.
driver
->
owner
))
{
dev_warn
(
priv
->
dev
,
"unable to get transmitter device
\n
"
);
return
-
EINVAL
;
}
/* Initialize fixed screen information. Restrict pan to 2 lines steps
* for NV12 and NV21.
*/
info
->
fix
=
sh_mobile_lcdc_fix
;
info
->
fix
.
smem_start
=
ch
->
dma_handle
;
info
->
fix
.
smem_len
=
max_size
;
if
(
cfg
->
fourcc
==
V4L2_PIX_FMT_NV12
||
cfg
->
fourcc
==
V4L2_PIX_FMT_NV21
)
info
->
fix
.
ypanstep
=
2
;
if
(
sh_mobile_format_is_yuv
(
var
))
{
info
->
fix
.
line_length
=
var
->
xres
;
info
->
fix
.
visual
=
FB_VISUAL_FOURCC
;
}
else
{
info
->
fix
.
line_length
=
var
->
xres
*
var
->
bits_per_pixel
/
8
;
info
->
fix
.
visual
=
FB_VISUAL_TRUECOLOR
;
ch
->
tx_dev
=
platform_get_drvdata
(
cfg
->
tx_dev
);
ch
->
tx_dev
->
lcdc
=
ch
;
ch
->
tx_dev
->
def_mode
=
*
mode
;
}
info
->
screen_base
=
buf
;
info
->
device
=
dev
;
ch
->
display_var
=
*
var
;
return
0
;
return
sh_mobile_lcdc_channel_fb_init
(
ch
,
mode
,
num_modes
);
}
static
int
__devinit
sh_mobile_lcdc_probe
(
struct
platform_device
*
pdev
)
...
...
@@ -1698,6 +1924,8 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
return
-
ENOMEM
;
}
priv
->
dev
=
&
pdev
->
dev
;
priv
->
meram_dev
=
pdata
->
meram_dev
;
platform_set_drvdata
(
pdev
,
priv
);
error
=
request_irq
(
i
,
sh_mobile_lcdc_irq
,
0
,
...
...
@@ -1714,7 +1942,7 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
struct
sh_mobile_lcdc_chan
*
ch
=
priv
->
ch
+
num_channels
;
ch
->
lcdc
=
priv
;
memcpy
(
&
ch
->
cfg
,
&
pdata
->
ch
[
i
],
sizeof
(
pdata
->
ch
[
i
]))
;
ch
->
cfg
=
&
pdata
->
ch
[
i
]
;
error
=
sh_mobile_lcdc_check_interface
(
ch
);
if
(
error
)
{
...
...
@@ -1726,7 +1954,7 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
ch
->
pan_offset
=
0
;
/* probe the backlight is there is one defined */
if
(
ch
->
cfg
.
bl_info
.
max_brightness
)
if
(
ch
->
cfg
->
bl_info
.
max_brightness
)
ch
->
bl
=
sh_mobile_lcdc_bl_probe
(
&
pdev
->
dev
,
ch
);
switch
(
pdata
->
ch
[
i
].
chan
)
{
...
...
@@ -1757,18 +1985,19 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
if
(
!
priv
->
base
)
goto
err1
;
error
=
sh_mobile_lcdc_setup_clocks
(
p
dev
,
pdata
->
clock_source
,
priv
);
error
=
sh_mobile_lcdc_setup_clocks
(
p
riv
,
pdata
->
clock_source
);
if
(
error
)
{
dev_err
(
&
pdev
->
dev
,
"unable to setup clocks
\n
"
);
goto
err1
;
}
priv
->
meram_dev
=
pdata
->
meram_dev
;
/* Enable runtime PM. */
pm_runtime_enable
(
&
pdev
->
dev
);
for
(
i
=
0
;
i
<
num_channels
;
i
++
)
{
struct
sh_mobile_lcdc_chan
*
ch
=
priv
->
ch
+
i
;
error
=
sh_mobile_lcdc_channel_init
(
ch
,
&
pdev
->
dev
);
error
=
sh_mobile_lcdc_channel_init
(
priv
,
ch
);
if
(
error
)
goto
err1
;
}
...
...
@@ -1781,31 +2010,10 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
for
(
i
=
0
;
i
<
num_channels
;
i
++
)
{
struct
sh_mobile_lcdc_chan
*
ch
=
priv
->
ch
+
i
;
struct
fb_info
*
info
=
ch
->
info
;
if
(
info
->
fbdefio
)
{
ch
->
sglist
=
vmalloc
(
sizeof
(
struct
scatterlist
)
*
info
->
fix
.
smem_len
>>
PAGE_SHIFT
);
if
(
!
ch
->
sglist
)
{
dev_err
(
&
pdev
->
dev
,
"cannot allocate sglist
\n
"
);
goto
err1
;
}
}
info
->
bl_dev
=
ch
->
bl
;
error
=
register_framebuffer
(
info
);
if
(
error
<
0
)
error
=
sh_mobile_lcdc_channel_fb_register
(
ch
);
if
(
error
)
goto
err1
;
dev_info
(
info
->
dev
,
"registered %s/%s as %dx%d %dbpp.
\n
"
,
pdev
->
name
,
(
ch
->
cfg
.
chan
==
LCDC_CHAN_MAINLCD
)
?
"mainlcd"
:
"sublcd"
,
info
->
var
.
xres
,
info
->
var
.
yres
,
info
->
var
.
bits_per_pixel
);
/* deferred io mode: disable clock to save power */
if
(
info
->
fbdefio
||
info
->
state
==
FBINFO_STATE_SUSPENDED
)
sh_mobile_lcdc_clk_off
(
priv
);
}
/* Failure ignored */
...
...
drivers/video/sh_mobile_lcdcfb.h
View file @
f9b4a5ce
...
...
@@ -14,9 +14,35 @@ enum { LDDCKPAT1R, LDDCKPAT2R, LDMT1R, LDMT2R, LDMT3R, LDDFR, LDSM1R,
#define PALETTE_NR 16
struct
sh_mobile_lcdc_priv
;
struct
fb_info
;
struct
backlight_device
;
struct
fb_info
;
struct
module
;
struct
sh_mobile_lcdc_chan
;
struct
sh_mobile_lcdc_entity
;
struct
sh_mobile_lcdc_format_info
;
struct
sh_mobile_lcdc_priv
;
#define SH_MOBILE_LCDC_DISPLAY_DISCONNECTED 0
#define SH_MOBILE_LCDC_DISPLAY_CONNECTED 1
struct
sh_mobile_lcdc_entity_ops
{
/* Display */
int
(
*
display_on
)(
struct
sh_mobile_lcdc_entity
*
entity
);
void
(
*
display_off
)(
struct
sh_mobile_lcdc_entity
*
entity
);
};
enum
sh_mobile_lcdc_entity_event
{
SH_MOBILE_LCDC_EVENT_DISPLAY_CONNECT
,
SH_MOBILE_LCDC_EVENT_DISPLAY_DISCONNECT
,
SH_MOBILE_LCDC_EVENT_DISPLAY_MODE
,
};
struct
sh_mobile_lcdc_entity
{
struct
module
*
owner
;
const
struct
sh_mobile_lcdc_entity_ops
*
ops
;
struct
sh_mobile_lcdc_chan
*
lcdc
;
struct
fb_videomode
def_mode
;
};
/*
* struct sh_mobile_lcdc_chan - LCDC display channel
...
...
@@ -27,29 +53,57 @@ struct backlight_device;
*/
struct
sh_mobile_lcdc_chan
{
struct
sh_mobile_lcdc_priv
*
lcdc
;
struct
sh_mobile_lcdc_entity
*
tx_dev
;
const
struct
sh_mobile_lcdc_chan_cfg
*
cfg
;
unsigned
long
*
reg_offs
;
unsigned
long
ldmt1r_value
;
unsigned
long
enabled
;
/* ME and SE in LDCNT2R */
struct
sh_mobile_lcdc_chan_cfg
cfg
;
u32
pseudo_palette
[
PALETTE_NR
];
struct
fb_info
*
info
;
struct
backlight_device
*
bl
;
void
*
meram
;
struct
mutex
open_lock
;
/* protects the use counter */
int
use_count
;
void
*
fb_mem
;
unsigned
long
fb_size
;
dma_addr_t
dma_handle
;
struct
fb_deferred_io
defio
;
struct
scatterlist
*
sglist
;
unsigned
long
frame_end
;
unsigned
long
pan_offset
;
unsigned
long
frame_end
;
wait_queue_head_t
frame_end_wait
;
struct
completion
vsync_completion
;
struct
fb_var_screeninfo
display_var
;
int
use_count
;
int
blank_status
;
struct
mutex
open_lock
;
/* protects the use counter */
int
meram_enabled
;
const
struct
sh_mobile_lcdc_format_info
*
format
;
u32
colorspace
;
unsigned
int
xres
;
unsigned
int
xres_virtual
;
unsigned
int
yres
;
unsigned
int
yres_virtual
;
unsigned
int
pitch
;
unsigned
long
base_addr_y
;
unsigned
long
base_addr_c
;
unsigned
int
pitch
;
int
(
*
notify
)(
struct
sh_mobile_lcdc_chan
*
ch
,
enum
sh_mobile_lcdc_entity_event
event
,
const
struct
fb_videomode
*
mode
,
const
struct
fb_monspecs
*
monspec
);
/* Backlight */
struct
backlight_device
*
bl
;
/* FB */
struct
fb_info
*
info
;
u32
pseudo_palette
[
PALETTE_NR
];
struct
{
unsigned
int
width
;
unsigned
int
height
;
struct
fb_videomode
mode
;
}
display
;
struct
fb_deferred_io
defio
;
struct
scatterlist
*
sglist
;
int
blank_status
;
};
#endif
drivers/video/sh_mobile_meram.c
View file @
f9b4a5ce
...
...
@@ -9,16 +9,22 @@
* for more details.
*/
#include <linux/device.h>
#include <linux/err.h>
#include <linux/genalloc.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/
platform_
device.h>
#include <linux/pm_runtime.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <video/sh_mobile_meram.h>
/* meram registers */
/* -----------------------------------------------------------------------------
* MERAM registers
*/
#define MEVCR1 0x4
#define MEVCR1_RST (1 << 31)
#define MEVCR1_WD (1 << 30)
...
...
@@ -81,16 +87,14 @@
((yszm1) << MExxBSIZE_YSZM1_SHIFT) | \
((xszm1) << MExxBSIZE_XSZM1_SHIFT))
#define SH_MOBILE_MERAM_ICB_NUM 32
static
unsigned
long
common_regs
[]
=
{
static
const
unsigned
long
common_regs
[]
=
{
MEVCR1
,
MEQSEL1
,
MEQSEL2
,
};
#define
CMN
_REGS_SIZE ARRAY_SIZE(common_regs)
#define
MERAM
_REGS_SIZE ARRAY_SIZE(common_regs)
static
unsigned
long
icb_regs
[]
=
{
static
const
unsigned
long
icb_regs
[]
=
{
MExxCTL
,
MExxBSIZE
,
MExxMNCF
,
...
...
@@ -100,216 +104,269 @@ static unsigned long icb_regs[] = {
};
#define ICB_REGS_SIZE ARRAY_SIZE(icb_regs)
/*
* sh_mobile_meram_icb - MERAM ICB information
* @regs: Registers cache
* @index: ICB index
* @offset: MERAM block offset
* @size: MERAM block size in KiB
* @cache_unit: Bytes to cache per ICB
* @pixelformat: Video pixel format of the data stored in the ICB
* @current_reg: Which of Start Address Register A (0) or B (1) is in use
*/
struct
sh_mobile_meram_icb
{
unsigned
long
regs
[
ICB_REGS_SIZE
];
unsigned
int
index
;
unsigned
long
offset
;
unsigned
int
size
;
unsigned
int
cache_unit
;
unsigned
int
pixelformat
;
unsigned
int
current_reg
;
};
#define MERAM_ICB_NUM 32
struct
sh_mobile_meram_fb_plane
{
struct
sh_mobile_meram_icb
*
marker
;
struct
sh_mobile_meram_icb
*
cache
;
};
struct
sh_mobile_meram_fb_cache
{
unsigned
int
nplanes
;
struct
sh_mobile_meram_fb_plane
planes
[
2
];
};
/*
* sh_mobile_meram_priv - MERAM device
* @base: Registers base address
* @meram: MERAM physical address
* @regs: Registers cache
* @lock: Protects used_icb and icbs
* @used_icb: Bitmask of used ICBs
* @icbs: ICBs
* @pool: Allocation pool to manage the MERAM
*/
struct
sh_mobile_meram_priv
{
void
__iomem
*
base
;
unsigned
long
meram
;
unsigned
long
regs
[
MERAM_REGS_SIZE
];
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
];
struct
sh_mobile_meram_icb
icbs
[
MERAM_ICB_NUM
];
struct
gen_pool
*
pool
;
};
/* settings */
#define MERAM_GRANULARITY 1024
#define MERAM_SEC_LINE 15
#define MERAM_LINE_WIDTH 2048
/*
*
MERAM/ICB access function
s
/*
-----------------------------------------------------------------------------
*
Registers acces
s
*/
#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
)
static
inline
void
meram_write_icb
(
void
__iomem
*
base
,
unsigned
int
idx
,
unsigned
int
off
,
unsigned
long
val
)
{
iowrite32
(
val
,
MERAM_ICB_OFFSET
(
base
,
idx
,
off
));
}
static
inline
unsigned
long
meram_read_icb
(
void
__iomem
*
base
,
int
idx
,
int
off
)
static
inline
unsigned
long
meram_read_icb
(
void
__iomem
*
base
,
unsigned
int
idx
,
unsigned
int
off
)
{
return
ioread32
(
MERAM_ICB_OFFSET
(
base
,
idx
,
off
));
}
static
inline
void
meram_write_reg
(
void
__iomem
*
base
,
int
off
,
static
inline
void
meram_write_reg
(
void
__iomem
*
base
,
unsigned
int
off
,
unsigned
long
val
)
{
iowrite32
(
val
,
base
+
off
);
}
static
inline
unsigned
long
meram_read_reg
(
void
__iomem
*
base
,
int
off
)
static
inline
unsigned
long
meram_read_reg
(
void
__iomem
*
base
,
unsigned
int
off
)
{
return
ioread32
(
base
+
off
);
}
/*
* register ICB
*/
#define MERAM_CACHE_START(p) ((p) >> 16)
#define MERAM_CACHE_END(p) ((p) & 0xffff)
#define MERAM_CACHE_SET(o, s) ((((o) & 0xffff) << 16) | \
(((o) + (s) - 1) & 0xffff))
/*
* check if there's no overlaps in MERAM allocation.
/* -----------------------------------------------------------------------------
* Allocation
*/
static
inline
int
meram_check_overlap
(
struct
sh_mobile_meram_priv
*
priv
,
struct
sh_mobile_meram_icb
*
new
)
/* Allocate ICBs and MERAM for a plane. */
static
int
__meram_alloc
(
struct
sh_mobile_meram_priv
*
priv
,
struct
sh_mobile_meram_fb_plane
*
plane
,
size_t
size
)
{
int
i
;
int
used_start
,
used_end
,
meram_start
,
meram_end
;
unsigned
long
mem
;
unsigned
long
idx
;
/* valid ICB? */
if
(
new
->
marker_icb
&
~
0x1f
||
new
->
cache_icb
&
~
0x1f
)
return
1
;
idx
=
find_first_zero_bit
(
&
priv
->
used_icb
,
28
);
if
(
idx
==
28
)
return
-
ENOMEM
;
plane
->
cache
=
&
priv
->
icbs
[
idx
];
if
(
test_bit
(
new
->
marker_icb
,
&
priv
->
used_icb
)
||
test_bit
(
new
->
cache_icb
,
&
priv
->
used_icb
))
return
1
;
idx
=
find_next_zero_bit
(
&
priv
->
used_icb
,
32
,
28
);
if
(
idx
==
32
)
return
-
ENOMEM
;
plane
->
marker
=
&
priv
->
icbs
[
idx
];
for
(
i
=
0
;
i
<
priv
->
used_meram_cache_regions
;
i
++
)
{
used_start
=
MERAM_CACHE_START
(
priv
->
used_meram_cache
[
i
]);
used_end
=
MERAM_CACHE_END
(
priv
->
used_meram_cache
[
i
]);
meram_start
=
new
->
meram_offset
;
meram_end
=
new
->
meram_offset
+
new
->
meram_size
;
mem
=
gen_pool_alloc
(
priv
->
pool
,
size
*
1024
);
if
(
mem
==
0
)
return
-
ENOMEM
;
if
((
meram_start
>=
used_start
&&
meram_start
<
used_end
)
||
(
meram_end
>
used_start
&&
meram_end
<
used_end
))
return
1
;
}
__set_bit
(
plane
->
marker
->
index
,
&
priv
->
used_icb
);
__set_bit
(
plane
->
cache
->
index
,
&
priv
->
used_icb
);
plane
->
marker
->
offset
=
mem
-
priv
->
meram
;
plane
->
marker
->
size
=
size
;
return
0
;
}
/*
* mark the specified ICB as used
*/
/* Free ICBs and MERAM for a plane. */
static
void
__meram_free
(
struct
sh_mobile_meram_priv
*
priv
,
struct
sh_mobile_meram_fb_plane
*
plane
)
{
gen_pool_free
(
priv
->
pool
,
priv
->
meram
+
plane
->
marker
->
offset
,
plane
->
marker
->
size
*
1024
);
static
inline
void
meram_mark
(
struct
sh_mobile_meram_priv
*
priv
,
struct
sh_mobile_meram_icb
*
new
)
__clear_bit
(
plane
->
marker
->
index
,
&
priv
->
used_icb
);
__clear_bit
(
plane
->
cache
->
index
,
&
priv
->
used_icb
);
}
/* Is this a YCbCr(NV12, NV16 or NV24) colorspace? */
static
int
is_nvcolor
(
int
cspace
)
{
int
n
;
if
(
cspace
==
SH_MOBILE_MERAM_PF_NV
||
cspace
==
SH_MOBILE_MERAM_PF_NV24
)
return
1
;
return
0
;
}
if
(
new
->
marker_icb
<
0
||
new
->
cache_icb
<
0
)
return
;
/* Allocate memory for the ICBs and mark them as used. */
static
struct
sh_mobile_meram_fb_cache
*
meram_alloc
(
struct
sh_mobile_meram_priv
*
priv
,
const
struct
sh_mobile_meram_cfg
*
cfg
,
int
pixelformat
)
{
struct
sh_mobile_meram_fb_cache
*
cache
;
unsigned
int
nplanes
=
is_nvcolor
(
pixelformat
)
?
2
:
1
;
int
ret
;
__set_bit
(
new
->
marker_icb
,
&
priv
->
used_icb
);
__set_bit
(
new
->
cache_icb
,
&
priv
->
used_icb
);
if
(
cfg
->
icb
[
0
].
meram_size
==
0
)
return
ERR_PTR
(
-
EINVAL
);
n
=
priv
->
used_meram_cache_regions
;
if
(
nplanes
==
2
&&
cfg
->
icb
[
1
].
meram_size
==
0
)
return
ERR_PTR
(
-
EINVAL
);
priv
->
used_meram_cache
[
n
]
=
MERAM_CACHE_SET
(
new
->
meram_offset
,
new
->
meram_size
);
cache
=
kzalloc
(
sizeof
(
*
cache
),
GFP_KERNEL
);
if
(
cache
==
NULL
)
return
ERR_PTR
(
-
ENOMEM
);
priv
->
used_meram_cache_regions
++
;
}
cache
->
nplanes
=
nplanes
;
/*
* unmark the specified ICB as used
*/
ret
=
__meram_alloc
(
priv
,
&
cache
->
planes
[
0
],
cfg
->
icb
[
0
].
meram_size
);
if
(
ret
<
0
)
goto
error
;
static
inline
void
meram_unmark
(
struct
sh_mobile_meram_priv
*
priv
,
struct
sh_mobile_meram_icb
*
icb
)
{
int
i
;
unsigned
long
pattern
;
if
(
icb
->
marker_icb
<
0
||
icb
->
cache_icb
<
0
)
return
;
__clear_bit
(
icb
->
marker_icb
,
&
priv
->
used_icb
);
__clear_bit
(
icb
->
cache_icb
,
&
priv
->
used_icb
);
pattern
=
MERAM_CACHE_SET
(
icb
->
meram_offset
,
icb
->
meram_size
);
for
(
i
=
0
;
i
<
priv
->
used_meram_cache_regions
;
i
++
)
{
if
(
priv
->
used_meram_cache
[
i
]
==
pattern
)
{
while
(
i
<
priv
->
used_meram_cache_regions
-
1
)
{
priv
->
used_meram_cache
[
i
]
=
priv
->
used_meram_cache
[
i
+
1
]
;
i
++
;
}
priv
->
used_meram_cache
[
i
]
=
0
;
priv
->
used_meram_cache_regions
--
;
break
;
}
cache
->
planes
[
0
].
marker
->
current_reg
=
1
;
cache
->
planes
[
0
].
marker
->
pixelformat
=
pixelformat
;
if
(
cache
->
nplanes
==
1
)
return
cache
;
ret
=
__meram_alloc
(
priv
,
&
cache
->
planes
[
1
],
cfg
->
icb
[
1
].
meram_size
);
if
(
ret
<
0
)
{
__meram_free
(
priv
,
&
cache
->
planes
[
0
]);
goto
error
;
}
return
cache
;
error:
kfree
(
cache
);
return
ERR_PTR
(
-
ENOMEM
);
}
/*
* is this a YCbCr(NV12, NV16 or NV24) colorspace
*/
static
inline
int
is_nvcolor
(
int
cspace
)
/* Unmark the specified ICB as used. */
static
void
meram_free
(
struct
sh_mobile_meram_priv
*
priv
,
struct
sh_mobile_meram_fb_cache
*
cache
)
{
if
(
cspace
==
SH_MOBILE_MERAM_PF_NV
||
cspace
==
SH_MOBILE_MERAM_PF_NV24
)
return
1
;
return
0
;
__meram_free
(
priv
,
&
cache
->
planes
[
0
]);
if
(
cache
->
nplanes
==
2
)
__meram_free
(
priv
,
&
cache
->
planes
[
1
]);
kfree
(
cache
);
}
/*
* set the next address to fetch
*/
static
inline
void
meram_set_next_addr
(
struct
sh_mobile_meram_priv
*
priv
,
struct
sh_mobile_meram_cfg
*
cfg
,
/* Set the next address to fetch. */
static
void
meram_set_next_addr
(
struct
sh_mobile_meram_priv
*
priv
,
struct
sh_mobile_meram_fb_cache
*
cache
,
unsigned
long
base_addr_y
,
unsigned
long
base_addr_c
)
{
struct
sh_mobile_meram_icb
*
icb
=
cache
->
planes
[
0
].
marker
;
unsigned
long
target
;
target
=
(
cfg
->
current_reg
)
?
MExxSARA
:
MExxSARB
;
cfg
->
current_reg
^=
1
;
icb
->
current_reg
^=
1
;
target
=
icb
->
current_reg
?
MExxSARB
:
MExxSARA
;
/* set the next address to fetch */
meram_write_icb
(
priv
->
base
,
c
fg
->
icb
[
0
].
cache_icb
,
target
,
meram_write_icb
(
priv
->
base
,
c
ache
->
planes
[
0
].
cache
->
index
,
target
,
base_addr_y
);
meram_write_icb
(
priv
->
base
,
cfg
->
icb
[
0
].
marker_icb
,
target
,
base_addr_y
+
cfg
->
icb
[
0
].
cache_unit
);
if
(
is_nvcolor
(
cfg
->
pixelformat
))
{
meram_write_icb
(
priv
->
base
,
cfg
->
icb
[
1
].
cache_icb
,
target
,
base_addr_c
);
meram_write_icb
(
priv
->
base
,
cfg
->
icb
[
1
].
marker_icb
,
target
,
base_addr_c
+
cfg
->
icb
[
1
].
cache_unit
);
meram_write_icb
(
priv
->
base
,
cache
->
planes
[
0
].
marker
->
index
,
target
,
base_addr_y
+
cache
->
planes
[
0
].
marker
->
cache_unit
);
if
(
cache
->
nplanes
==
2
)
{
meram_write_icb
(
priv
->
base
,
cache
->
planes
[
1
].
cache
->
index
,
target
,
base_addr_c
);
meram_write_icb
(
priv
->
base
,
cache
->
planes
[
1
].
marker
->
index
,
target
,
base_addr_c
+
cache
->
planes
[
1
].
marker
->
cache_unit
);
}
}
/*
* get the next ICB address
*/
static
inline
void
meram_get_next_icb_addr
(
struct
sh_mobile_meram_info
*
pdata
,
struct
sh_mobile_meram_cfg
*
cfg
,
unsigned
long
*
icb_addr_y
,
unsigned
long
*
icb_addr_c
)
/* Get the next ICB address. */
static
void
meram_get_next_icb_addr
(
struct
sh_mobile_meram_info
*
pdata
,
struct
sh_mobile_meram_fb_cache
*
cache
,
unsigned
long
*
icb_addr_y
,
unsigned
long
*
icb_addr_c
)
{
struct
sh_mobile_meram_icb
*
icb
=
cache
->
planes
[
0
].
marker
;
unsigned
long
icb_offset
;
if
(
pdata
->
addr_mode
==
SH_MOBILE_MERAM_MODE0
)
icb_offset
=
0x80000000
|
(
cfg
->
current_reg
<<
29
);
icb_offset
=
0x80000000
|
(
icb
->
current_reg
<<
29
);
else
icb_offset
=
0xc0000000
|
(
cfg
->
current_reg
<<
23
);
icb_offset
=
0xc0000000
|
(
icb
->
current_reg
<<
23
);
*
icb_addr_y
=
icb_offset
|
(
cfg
->
icb
[
0
].
marker_icb
<<
24
);
if
(
is_nvcolor
(
cfg
->
pixelformat
))
*
icb_addr_c
=
icb_offset
|
(
cfg
->
icb
[
1
].
marker_icb
<<
24
);
*
icb_addr_y
=
icb_offset
|
(
cache
->
planes
[
0
].
marker
->
index
<<
24
);
if
(
cache
->
nplanes
==
2
)
*
icb_addr_c
=
icb_offset
|
(
cache
->
planes
[
1
].
marker
->
index
<<
24
);
}
#define MERAM_CALC_BYTECOUNT(x, y) \
(((x) * (y) + (MERAM_LINE_WIDTH - 1)) & ~(MERAM_LINE_WIDTH - 1))
/*
* initialize MERAM
*/
/* Initialize MERAM. */
static
int
meram_init
(
struct
sh_mobile_meram_priv
*
priv
,
struct
sh_mobile_meram_icb
*
icb
,
int
xres
,
int
yres
,
int
*
out_pitch
)
struct
sh_mobile_meram_fb_plane
*
plane
,
unsigned
int
xres
,
unsigned
int
yres
,
unsigned
int
*
out_pitch
)
{
struct
sh_mobile_meram_icb
*
marker
=
plane
->
marker
;
unsigned
long
total_byte_count
=
MERAM_CALC_BYTECOUNT
(
xres
,
yres
);
unsigned
long
bnm
;
int
lcdc_pitch
,
xpitch
,
line_cnt
;
int
save_lines
;
unsigned
int
lcdc_pitch
;
unsigned
int
xpitch
;
unsigned
int
line_cnt
;
unsigned
int
save_lines
;
/* adjust pitch to 1024, 2048, 4096 or 8192 */
lcdc_pitch
=
(
xres
-
1
)
|
1023
;
...
...
@@ -322,13 +379,13 @@ static int meram_init(struct sh_mobile_meram_priv *priv,
lcdc_pitch
=
xpitch
=
MERAM_LINE_WIDTH
;
line_cnt
=
total_byte_count
>>
11
;
*
out_pitch
=
xres
;
save_lines
=
(
icb
->
meram_size
/
16
/
MERAM_SEC_LINE
)
;
save_lines
=
plane
->
marker
->
size
/
16
/
MERAM_SEC_LINE
;
save_lines
*=
MERAM_SEC_LINE
;
}
else
{
xpitch
=
xres
;
line_cnt
=
yres
;
*
out_pitch
=
lcdc_pitch
;
save_lines
=
icb
->
meram_
size
/
(
lcdc_pitch
>>
10
)
/
2
;
save_lines
=
plane
->
marker
->
size
/
(
lcdc_pitch
>>
10
)
/
2
;
save_lines
&=
0xff
;
}
bnm
=
(
save_lines
-
1
)
<<
16
;
...
...
@@ -336,19 +393,20 @@ static int meram_init(struct sh_mobile_meram_priv *priv,
/* TODO: we better to check if we have enough MERAM buffer size */
/* set up ICB */
meram_write_icb
(
priv
->
base
,
icb
->
cache_icb
,
MExxBSIZE
,
meram_write_icb
(
priv
->
base
,
plane
->
cache
->
index
,
MExxBSIZE
,
MERAM_MExxBSIZE_VAL
(
0x0
,
line_cnt
-
1
,
xpitch
-
1
));
meram_write_icb
(
priv
->
base
,
icb
->
marker_icb
,
MExxBSIZE
,
meram_write_icb
(
priv
->
base
,
plane
->
marker
->
index
,
MExxBSIZE
,
MERAM_MExxBSIZE_VAL
(
0xf
,
line_cnt
-
1
,
xpitch
-
1
));
meram_write_icb
(
priv
->
base
,
icb
->
cache_icb
,
MExxMNCF
,
bnm
);
meram_write_icb
(
priv
->
base
,
icb
->
marker_icb
,
MExxMNCF
,
bnm
);
meram_write_icb
(
priv
->
base
,
plane
->
cache
->
index
,
MExxMNCF
,
bnm
);
meram_write_icb
(
priv
->
base
,
plane
->
marker
->
index
,
MExxMNCF
,
bnm
);
meram_write_icb
(
priv
->
base
,
icb
->
cache_icb
,
MExxSBSIZE
,
xpitch
);
meram_write_icb
(
priv
->
base
,
icb
->
marker_icb
,
MExxSBSIZE
,
xpitch
);
meram_write_icb
(
priv
->
base
,
plane
->
cache
->
index
,
MExxSBSIZE
,
xpitch
);
meram_write_icb
(
priv
->
base
,
plane
->
marker
->
index
,
MExxSBSIZE
,
xpitch
);
/* save a cache unit size */
icb
->
cache_unit
=
xres
*
save_lines
;
plane
->
cache
->
cache_unit
=
xres
*
save_lines
;
plane
->
marker
->
cache_unit
=
xres
*
save_lines
;
/*
* Set MERAM for framebuffer
...
...
@@ -356,13 +414,13 @@ static int meram_init(struct sh_mobile_meram_priv *priv,
* 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
(
icb
->
marker_icb
,
icb
->
meram_offset
)
|
MExxCTL_WD1
|
MExxCTL_WD0
|
MExxCTL_WS
|
MExxCTL_CM
|
meram_write_icb
(
priv
->
base
,
plane
->
cache
->
index
,
MExxCTL
,
MERAM_MExxCTL_VAL
(
plane
->
marker
->
index
,
marker
->
offset
)
|
MExxCTL_WD1
|
MExxCTL_WD0
|
MExxCTL_WS
|
MExxCTL_CM
|
MExxCTL_MD_FB
);
meram_write_icb
(
priv
->
base
,
icb
->
marker_icb
,
MExxCTL
,
MERAM_MExxCTL_VAL
(
icb
->
cache_icb
,
icb
->
meram_
offset
+
icb
->
meram_
size
/
2
)
|
meram_write_icb
(
priv
->
base
,
plane
->
marker
->
index
,
MExxCTL
,
MERAM_MExxCTL_VAL
(
plane
->
cache
->
index
,
marker
->
offset
+
plane
->
marker
->
size
/
2
)
|
MExxCTL_WD1
|
MExxCTL_WD0
|
MExxCTL_WS
|
MExxCTL_CM
|
MExxCTL_MD_FB
);
...
...
@@ -370,239 +428,175 @@ static int meram_init(struct sh_mobile_meram_priv *priv,
}
static
void
meram_deinit
(
struct
sh_mobile_meram_priv
*
priv
,
struct
sh_mobile_meram_icb
*
icb
)
struct
sh_mobile_meram_fb_plane
*
plane
)
{
/* disable ICB */
meram_write_icb
(
priv
->
base
,
icb
->
cache_icb
,
MExxCTL
,
meram_write_icb
(
priv
->
base
,
plane
->
cache
->
index
,
MExxCTL
,
MExxCTL_WBF
|
MExxCTL_WF
|
MExxCTL_RF
);
meram_write_icb
(
priv
->
base
,
icb
->
marker_icb
,
MExxCTL
,
meram_write_icb
(
priv
->
base
,
plane
->
marker
->
index
,
MExxCTL
,
MExxCTL_WBF
|
MExxCTL_WF
|
MExxCTL_RF
);
icb
->
cache_unit
=
0
;
plane
->
cache
->
cache_unit
=
0
;
plane
->
marker
->
cache_unit
=
0
;
}
/*
*
register the ICB
/*
-----------------------------------------------------------------------------
*
Registration/unregistration
*/
static
int
sh_mobile_meram_register
(
struct
sh_mobile_meram_info
*
pdata
,
struct
sh_mobile_meram_cfg
*
cfg
,
int
xres
,
int
yres
,
int
pixelformat
,
unsigned
long
base_addr_y
,
unsigned
long
base_addr_c
,
unsigned
long
*
icb_addr_y
,
unsigned
long
*
icb_addr_c
,
int
*
pitch
)
static
void
*
sh_mobile_meram_register
(
struct
sh_mobile_meram_info
*
pdata
,
const
struct
sh_mobile_meram_cfg
*
cfg
,
unsigned
int
xres
,
unsigned
int
yres
,
unsigned
int
pixelformat
,
unsigned
int
*
pitch
)
{
struct
platform_device
*
pdev
;
struct
sh_mobile_meram_priv
*
priv
;
int
n
,
out_pitch
;
int
error
=
0
;
if
(
!
pdata
||
!
pdata
->
priv
||
!
pdata
->
pdev
||
!
cfg
)
return
-
EINVAL
;
struct
sh_mobile_meram_fb_cache
*
cache
;
struct
sh_mobile_meram_priv
*
priv
=
pdata
->
priv
;
struct
platform_device
*
pdev
=
pdata
->
pdev
;
unsigned
int
out_pitch
;
if
(
pixelformat
!=
SH_MOBILE_MERAM_PF_NV
&&
pixelformat
!=
SH_MOBILE_MERAM_PF_NV24
&&
pixelformat
!=
SH_MOBILE_MERAM_PF_RGB
)
return
-
EINVAL
;
return
ERR_PTR
(
-
EINVAL
)
;
priv
=
pdata
->
priv
;
pdev
=
pdata
->
pdev
;
dev_dbg
(
&
pdev
->
dev
,
"registering %dx%d (%s) (y=%08lx, c=%08lx)"
,
xres
,
yres
,
(
!
pixelformat
)
?
"yuv"
:
"rgb"
,
base_addr_y
,
base_addr_c
);
dev_dbg
(
&
pdev
->
dev
,
"registering %dx%d (%s)"
,
xres
,
yres
,
!
pixelformat
?
"yuv"
:
"rgb"
);
/* we can't handle wider than 8192px */
if
(
xres
>
8192
)
{
dev_err
(
&
pdev
->
dev
,
"width exceeding the limit (> 8192)."
);
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
;
return
ERR_PTR
(
-
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
;
}
/* make sure that there's no overlaps */
if
(
meram_check_overlap
(
priv
,
&
cfg
->
icb
[
0
]))
{
dev_err
(
&
pdev
->
dev
,
"conflicting config detected."
);
error
=
-
EINVAL
;
goto
err
;
}
n
=
1
;
/* do the same if we have the second ICB set */
if
(
cfg
->
icb
[
1
].
marker_icb
>=
0
&&
cfg
->
icb
[
1
].
cache_icb
>=
0
)
{
if
(
meram_check_overlap
(
priv
,
&
cfg
->
icb
[
1
]))
{
dev_err
(
&
pdev
->
dev
,
"conflicting config detected."
);
error
=
-
EINVAL
;
goto
err
;
}
n
=
2
;
}
if
(
is_nvcolor
(
pixelformat
)
&&
n
!=
2
)
{
dev_err
(
&
pdev
->
dev
,
"requires two ICB sets for planar Y/C."
);
error
=
-
EINVAL
;
/* We now register the ICBs and allocate the MERAM regions. */
cache
=
meram_alloc
(
priv
,
cfg
,
pixelformat
);
if
(
IS_ERR
(
cache
))
{
dev_err
(
&
pdev
->
dev
,
"MERAM allocation failed (%ld)."
,
PTR_ERR
(
cache
));
goto
err
;
}
/* we now register the ICB */
cfg
->
pixelformat
=
pixelformat
;
meram_mark
(
priv
,
&
cfg
->
icb
[
0
]);
if
(
is_nvcolor
(
pixelformat
))
meram_mark
(
priv
,
&
cfg
->
icb
[
1
]);
/* initialize MERAM */
meram_init
(
priv
,
&
c
fg
->
icb
[
0
],
xres
,
yres
,
&
out_pitch
);
meram_init
(
priv
,
&
c
ache
->
planes
[
0
],
xres
,
yres
,
&
out_pitch
);
*
pitch
=
out_pitch
;
if
(
pixelformat
==
SH_MOBILE_MERAM_PF_NV
)
meram_init
(
priv
,
&
c
fg
->
icb
[
1
],
xres
,
(
yres
+
1
)
/
2
,
meram_init
(
priv
,
&
c
ache
->
planes
[
1
],
xres
,
(
yres
+
1
)
/
2
,
&
out_pitch
);
else
if
(
pixelformat
==
SH_MOBILE_MERAM_PF_NV24
)
meram_init
(
priv
,
&
c
fg
->
icb
[
1
],
2
*
xres
,
(
yres
+
1
)
/
2
,
meram_init
(
priv
,
&
c
ache
->
planes
[
1
],
2
*
xres
,
(
yres
+
1
)
/
2
,
&
out_pitch
);
cfg
->
current_reg
=
1
;
meram_set_next_addr
(
priv
,
cfg
,
base_addr_y
,
base_addr_c
);
meram_get_next_icb_addr
(
pdata
,
cfg
,
icb_addr_y
,
icb_addr_c
);
dev_dbg
(
&
pdev
->
dev
,
"registered - can access via y=%08lx, c=%08lx"
,
*
icb_addr_y
,
*
icb_addr_c
);
err:
mutex_unlock
(
&
priv
->
lock
);
return
error
;
return
cache
;
}
static
int
sh_mobile_meram_unregister
(
struct
sh_mobile_meram_info
*
pdata
,
struct
sh_mobile_meram_cfg
*
cfg
)
static
void
sh_mobile_meram_unregister
(
struct
sh_mobile_meram_info
*
pdata
,
void
*
data
)
{
struct
sh_mobile_meram_priv
*
priv
;
if
(
!
pdata
||
!
pdata
->
priv
||
!
cfg
)
return
-
EINVAL
;
priv
=
pdata
->
priv
;
struct
sh_mobile_meram_fb_cache
*
cache
=
data
;
struct
sh_mobile_meram_priv
*
priv
=
pdata
->
priv
;
mutex_lock
(
&
priv
->
lock
);
/* deinit & unmark */
if
(
is_nvcolor
(
cfg
->
pixelformat
))
{
meram_deinit
(
priv
,
&
cfg
->
icb
[
1
]);
meram_unmark
(
priv
,
&
cfg
->
icb
[
1
]);
}
meram_deinit
(
priv
,
&
cfg
->
icb
[
0
]);
meram_unmark
(
priv
,
&
cfg
->
icb
[
0
]);
/* deinit & free */
meram_deinit
(
priv
,
&
cache
->
planes
[
0
]);
if
(
cache
->
nplanes
==
2
)
meram_deinit
(
priv
,
&
cache
->
planes
[
1
]);
m
utex_unlock
(
&
priv
->
lock
);
m
eram_free
(
priv
,
cache
);
return
0
;
mutex_unlock
(
&
priv
->
lock
)
;
}
static
int
sh_mobile_meram_update
(
struct
sh_mobile_meram_info
*
pdata
,
struct
sh_mobile_meram_cfg
*
cfg
,
unsigned
long
base_addr_y
,
unsigned
long
base_addr_c
,
unsigned
long
*
icb_addr_y
,
unsigned
long
*
icb_addr_c
)
static
void
sh_mobile_meram_update
(
struct
sh_mobile_meram_info
*
pdata
,
void
*
data
,
unsigned
long
base_addr_y
,
unsigned
long
base_addr_c
,
unsigned
long
*
icb_addr_y
,
unsigned
long
*
icb_addr_c
)
{
struct
sh_mobile_meram_priv
*
priv
;
if
(
!
pdata
||
!
pdata
->
priv
||
!
cfg
)
return
-
EINVAL
;
priv
=
pdata
->
priv
;
struct
sh_mobile_meram_fb_cache
*
cache
=
data
;
struct
sh_mobile_meram_priv
*
priv
=
pdata
->
priv
;
mutex_lock
(
&
priv
->
lock
);
meram_set_next_addr
(
priv
,
c
fg
,
base_addr_y
,
base_addr_c
);
meram_get_next_icb_addr
(
pdata
,
c
fg
,
icb_addr_y
,
icb_addr_c
);
meram_set_next_addr
(
priv
,
c
ache
,
base_addr_y
,
base_addr_c
);
meram_get_next_icb_addr
(
pdata
,
c
ache
,
icb_addr_y
,
icb_addr_c
);
mutex_unlock
(
&
priv
->
lock
);
return
0
;
}
static
int
sh_mobile_meram_runtime_suspend
(
struct
device
*
dev
)
static
struct
sh_mobile_meram_ops
sh_mobile_meram_ops
=
{
.
module
=
THIS_MODULE
,
.
meram_register
=
sh_mobile_meram_register
,
.
meram_unregister
=
sh_mobile_meram_unregister
,
.
meram_update
=
sh_mobile_meram_update
,
};
/* -----------------------------------------------------------------------------
* Power management
*/
static
int
sh_mobile_meram_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
;
unsigned
int
i
,
j
;
for
(
k
=
0
;
k
<
CMN_REGS_SIZE
;
k
++
)
priv
->
cmn_saved_regs
[
k
]
=
meram_read_reg
(
priv
->
base
,
common_regs
[
k
]);
for
(
i
=
0
;
i
<
MERAM_REGS_SIZE
;
i
++
)
priv
->
regs
[
i
]
=
meram_read_reg
(
priv
->
base
,
common_regs
[
i
]);
for
(
j
=
0
;
j
<
32
;
j
++
)
{
if
(
!
test_bit
(
j
,
&
priv
->
used_icb
))
for
(
i
=
0
;
i
<
32
;
i
++
)
{
if
(
!
test_bit
(
i
,
&
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
]);
for
(
j
=
0
;
j
<
ICB_REGS_SIZE
;
j
++
)
{
priv
->
icb
s
[
i
].
regs
[
j
]
=
meram_read_icb
(
priv
->
base
,
i
,
icb_regs
[
j
]);
/* Reset ICB on resume */
if
(
icb_regs
[
k
]
==
MExxCTL
)
priv
->
icb
_saved_regs
[
j
*
ICB_REGS_SIZE
+
k
]
|=
if
(
icb_regs
[
j
]
==
MExxCTL
)
priv
->
icb
s
[
i
].
regs
[
j
]
|=
MExxCTL_WBF
|
MExxCTL_WF
|
MExxCTL_RF
;
}
}
return
0
;
}
static
int
sh_mobile_meram_r
untime_r
esume
(
struct
device
*
dev
)
static
int
sh_mobile_meram_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
;
unsigned
int
i
,
j
;
for
(
j
=
0
;
j
<
32
;
j
++
)
{
if
(
!
test_bit
(
j
,
&
priv
->
used_icb
))
for
(
i
=
0
;
i
<
32
;
i
++
)
{
if
(
!
test_bit
(
i
,
&
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
(
j
=
0
;
j
<
ICB_REGS_SIZE
;
j
++
)
meram_write_icb
(
priv
->
base
,
i
,
icb_regs
[
j
],
priv
->
icbs
[
i
].
regs
[
j
]);
}
for
(
k
=
0
;
k
<
CMN_REGS_SIZE
;
k
++
)
meram_write_reg
(
priv
->
base
,
common_regs
[
k
],
priv
->
cmn_saved_regs
[
k
]);
for
(
i
=
0
;
i
<
MERAM_REGS_SIZE
;
i
++
)
meram_write_reg
(
priv
->
base
,
common_regs
[
i
],
priv
->
regs
[
i
]);
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
,
.
meram_unregister
=
sh_mobile_meram_unregister
,
.
meram_update
=
sh_mobile_meram_update
,
};
static
UNIVERSAL_DEV_PM_OPS
(
sh_mobile_meram_dev_pm_ops
,
sh_mobile_meram_suspend
,
sh_mobile_meram_resume
,
NULL
);
/*
*
initialize MERAM
/*
-----------------------------------------------------------------------------
*
Probe/remove and driver init/exit
*/
static
int
sh_mobile_meram_remove
(
struct
platform_device
*
pdev
);
static
int
__devinit
sh_mobile_meram_probe
(
struct
platform_device
*
pdev
)
{
struct
sh_mobile_meram_priv
*
priv
;
struct
sh_mobile_meram_info
*
pdata
=
pdev
->
dev
.
platform_data
;
struct
resource
*
res
;
struct
resource
*
regs
;
struct
resource
*
meram
;
unsigned
int
i
;
int
error
;
if
(
!
pdata
)
{
...
...
@@ -610,8 +604,9 @@ static int __devinit sh_mobile_meram_probe(struct platform_device *pdev)
return
-
EINVAL
;
}
res
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
0
);
if
(
!
res
)
{
regs
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
0
);
meram
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
1
);
if
(
regs
==
NULL
||
meram
==
NULL
)
{
dev_err
(
&
pdev
->
dev
,
"cannot get platform resources
\n
"
);
return
-
ENOENT
;
}
...
...
@@ -622,32 +617,74 @@ static int __devinit sh_mobile_meram_probe(struct platform_device *pdev)
return
-
ENOMEM
;
}
platform_set_drvdata
(
pdev
,
priv
);
/* initialize private data */
/* Initialize private data. */
mutex_init
(
&
priv
->
lock
);
priv
->
base
=
ioremap_nocache
(
res
->
start
,
resource_size
(
res
));
priv
->
used_icb
=
pdata
->
reserved_icbs
;
for
(
i
=
0
;
i
<
MERAM_ICB_NUM
;
++
i
)
priv
->
icbs
[
i
].
index
=
i
;
pdata
->
ops
=
&
sh_mobile_meram_ops
;
pdata
->
priv
=
priv
;
pdata
->
pdev
=
pdev
;
/* Request memory regions and remap the registers. */
if
(
!
request_mem_region
(
regs
->
start
,
resource_size
(
regs
),
pdev
->
name
))
{
dev_err
(
&
pdev
->
dev
,
"MERAM registers region already claimed
\n
"
);
error
=
-
EBUSY
;
goto
err_req_regs
;
}
if
(
!
request_mem_region
(
meram
->
start
,
resource_size
(
meram
),
pdev
->
name
))
{
dev_err
(
&
pdev
->
dev
,
"MERAM memory region already claimed
\n
"
);
error
=
-
EBUSY
;
goto
err_req_meram
;
}
priv
->
base
=
ioremap_nocache
(
regs
->
start
,
resource_size
(
regs
));
if
(
!
priv
->
base
)
{
dev_err
(
&
pdev
->
dev
,
"ioremap failed
\n
"
);
error
=
-
EFAULT
;
goto
err
;
goto
err
_ioremap
;
}
pdata
->
ops
=
&
sh_mobile_meram_ops
;
pdata
->
priv
=
priv
;
pdata
->
pdev
=
pdev
;
priv
->
meram
=
meram
->
start
;
/* Create and initialize the MERAM memory pool. */
priv
->
pool
=
gen_pool_create
(
ilog2
(
MERAM_GRANULARITY
),
-
1
);
if
(
priv
->
pool
==
NULL
)
{
error
=
-
ENOMEM
;
goto
err_genpool
;
}
error
=
gen_pool_add
(
priv
->
pool
,
meram
->
start
,
resource_size
(
meram
),
-
1
);
if
(
error
<
0
)
goto
err_genpool
;
/* initialize ICB addressing mode */
if
(
pdata
->
addr_mode
==
SH_MOBILE_MERAM_MODE1
)
meram_write_reg
(
priv
->
base
,
MEVCR1
,
MEVCR1_AMD1
);
platform_set_drvdata
(
pdev
,
priv
);
pm_runtime_enable
(
&
pdev
->
dev
);
dev_info
(
&
pdev
->
dev
,
"sh_mobile_meram initialized."
);
return
0
;
err:
sh_mobile_meram_remove
(
pdev
);
err_genpool:
if
(
priv
->
pool
)
gen_pool_destroy
(
priv
->
pool
);
iounmap
(
priv
->
base
);
err_ioremap:
release_mem_region
(
meram
->
start
,
resource_size
(
meram
));
err_req_meram:
release_mem_region
(
regs
->
start
,
resource_size
(
regs
));
err_req_regs:
mutex_destroy
(
&
priv
->
lock
);
kfree
(
priv
);
return
error
;
}
...
...
@@ -656,11 +693,16 @@ static int __devinit sh_mobile_meram_probe(struct platform_device *pdev)
static
int
sh_mobile_meram_remove
(
struct
platform_device
*
pdev
)
{
struct
sh_mobile_meram_priv
*
priv
=
platform_get_drvdata
(
pdev
);
struct
resource
*
regs
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
0
);
struct
resource
*
meram
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
1
);
pm_runtime_disable
(
&
pdev
->
dev
);
if
(
priv
->
base
)
gen_pool_destroy
(
priv
->
pool
);
iounmap
(
priv
->
base
);
release_mem_region
(
meram
->
start
,
resource_size
(
meram
));
release_mem_region
(
regs
->
start
,
resource_size
(
regs
));
mutex_destroy
(
&
priv
->
lock
);
...
...
include/video/sh_mobile_hdmi.h
View file @
f9b4a5ce
...
...
@@ -31,8 +31,6 @@ struct clk;
#define HDMI_SND_SRC_HBR (3 << 0)
struct
sh_mobile_hdmi_info
{
struct
sh_mobile_lcdc_chan_cfg
*
lcd_chan
;
struct
device
*
lcd_dev
;
unsigned
int
flags
;
long
(
*
clk_optimize_parent
)(
unsigned
long
target
,
unsigned
long
*
best_freq
,
unsigned
long
*
parent_freq
);
...
...
include/video/sh_mobile_lcdc.h
View file @
f9b4a5ce
...
...
@@ -147,29 +147,23 @@ struct sh_mobile_lcdc_sys_bus_ops {
unsigned
long
(
*
read_data
)(
void
*
handle
);
};
struct
module
;
struct
sh_mobile_lcdc_board_cfg
{
struct
module
*
owner
;
void
*
board_data
;
int
(
*
setup_sys
)(
void
*
board_data
,
void
*
sys_ops_handle
,
struct
sh_mobile_lcdc_panel_cfg
{
unsigned
long
width
;
/* Panel width in mm */
unsigned
long
height
;
/* Panel height in mm */
int
(
*
setup_sys
)(
void
*
sys_ops_handle
,
struct
sh_mobile_lcdc_sys_bus_ops
*
sys_ops
);
void
(
*
start_transfer
)(
void
*
board_data
,
void
*
sys_ops_handle
,
void
(
*
start_transfer
)(
void
*
sys_ops_handle
,
struct
sh_mobile_lcdc_sys_bus_ops
*
sys_ops
);
void
(
*
display_on
)(
void
*
board_data
,
struct
fb_info
*
info
);
void
(
*
display_off
)(
void
*
board_data
);
int
(
*
set_brightness
)(
void
*
board_data
,
int
brightness
);
int
(
*
get_brightness
)(
void
*
board_data
);
};
struct
sh_mobile_lcdc_lcd_size_cfg
{
/* width and height of panel in mm */
unsigned
long
width
;
unsigned
long
height
;
void
(
*
display_on
)(
void
);
void
(
*
display_off
)(
void
);
};
/* backlight info */
struct
sh_mobile_lcdc_bl_info
{
const
char
*
name
;
int
max_brightness
;
int
(
*
set_brightness
)(
int
brightness
);
int
(
*
get_brightness
)(
void
);
};
struct
sh_mobile_lcdc_chan_cfg
{
...
...
@@ -179,13 +173,14 @@ struct sh_mobile_lcdc_chan_cfg {
int
interface_type
;
/* selects RGBn or SYSn I/F, see above */
int
clock_divider
;
unsigned
long
flags
;
/* LCDC_FLAGS_... */
const
struct
fb_videomode
*
lcd_cfg
;
int
num_cfg
;
struct
sh_mobile_lcdc_lcd_size_cfg
lcd_size_cfg
;
struct
sh_mobile_lcdc_board_cfg
board_cfg
;
const
struct
fb_videomode
*
lcd_modes
;
int
num_modes
;
struct
sh_mobile_lcdc_panel_cfg
panel_cfg
;
struct
sh_mobile_lcdc_bl_info
bl_info
;
struct
sh_mobile_lcdc_sys_bus_cfg
sys_bus_cfg
;
/* only for SYSn I/F */
struct
sh_mobile_meram_cfg
*
meram_cfg
;
const
struct
sh_mobile_meram_cfg
*
meram_cfg
;
struct
platform_device
*
tx_dev
;
/* HDMI/DSI transmitter device */
};
struct
sh_mobile_lcdc_info
{
...
...
include/video/sh_mobile_meram.h
View file @
f9b4a5ce
...
...
@@ -17,48 +17,43 @@ enum {
struct
sh_mobile_meram_priv
;
struct
sh_mobile_meram_ops
;
/*
* struct sh_mobile_meram_info - MERAM platform data
* @reserved_icbs: Bitmask of reserved ICBs (for instance used through UIO)
*/
struct
sh_mobile_meram_info
{
int
addr_mode
;
u32
reserved_icbs
;
struct
sh_mobile_meram_ops
*
ops
;
struct
sh_mobile_meram_priv
*
priv
;
struct
platform_device
*
pdev
;
};
/* icb config */
struct
sh_mobile_meram_icb
{
int
marker_icb
;
/* ICB # for Marker ICB */
int
cache_icb
;
/* ICB # for Cache ICB */
int
meram_offset
;
/* MERAM Buffer Offset to use */
int
meram_size
;
/* MERAM Buffer Size to use */
int
cache_unit
;
/* bytes to cache per ICB */
struct
sh_mobile_meram_icb_cfg
{
unsigned
int
meram_size
;
/* MERAM Buffer Size to use */
};
struct
sh_mobile_meram_cfg
{
struct
sh_mobile_meram_icb
icb
[
2
];
int
pixelformat
;
int
current_reg
;
struct
sh_mobile_meram_icb_cfg
icb
[
2
];
};
struct
module
;
struct
sh_mobile_meram_ops
{
struct
module
*
module
;
/* register usage of meram */
int
(
*
meram_register
)(
struct
sh_mobile_meram_info
*
meram_dev
,
struct
sh_mobile_meram_cfg
*
cfg
,
int
xres
,
int
yres
,
int
pixelformat
,
unsigned
long
base_addr_y
,
unsigned
long
base_addr_c
,
unsigned
long
*
icb_addr_y
,
unsigned
long
*
icb_addr_c
,
int
*
pitch
);
void
*
(
*
meram_register
)(
struct
sh_mobile_meram_info
*
meram_dev
,
const
struct
sh_mobile_meram_cfg
*
cfg
,
unsigned
int
xres
,
unsigned
int
yres
,
unsigned
int
pixelformat
,
unsigned
int
*
pitch
);
/* unregister usage of meram */
int
(
*
meram_unregister
)(
struct
sh_mobile_meram_info
*
meram_dev
,
struct
sh_mobile_meram_cfg
*
cfg
);
void
(
*
meram_unregister
)(
struct
sh_mobile_meram_info
*
meram_dev
,
void
*
data
);
/* update meram settings */
int
(
*
meram_update
)(
struct
sh_mobile_meram_info
*
meram_dev
,
struct
sh_mobile_meram_cfg
*
cfg
,
void
(
*
meram_update
)(
struct
sh_mobile_meram_info
*
meram_dev
,
void
*
data
,
unsigned
long
base_addr_y
,
unsigned
long
base_addr_c
,
unsigned
long
*
icb_addr_y
,
...
...
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