[PATCH 0/4] Runtime mode setting

143 views
Skip to first unread message

Jari Helaakoski

unread,
Jan 6, 2013, 5:04:18 PM1/6/13
to linux...@googlegroups.com, Jari Helaakoski
This patchset improves Hans De Goede's EDID patch by allowing user to set new mode at runtime.
Example: echo D:1280x720p-60 > /sys/devices/platform/disp/graphics/fb0/mode
But precondition is that EDID support must be activated like before.
modprobe example: options disp screen0_output_mode=EDID:1280x720p60

It also has two cleanup patches.

To further improve disp we need to reduce usage of disp modules own definitions.
Ie. It would be good to replace __disp_video_timing struct with fb_videomode.

Jari Helaakoski (4):
video:sunxi:disp:Dynamic mode switching
video:sunxi:disp:Use BSP_disp_get_videomode elsewhere. And fix bug
with double buffering, which caused performance problems.
video:sunxi:disp:Remove struct __disp_tcon_timing_t
video:sunxi:disp:Make Fb_Init export cleaner

drivers/video/sunxi/disp/bsp_display.h | 5 +-
drivers/video/sunxi/disp/de_lcdc.c | 14 ++---
drivers/video/sunxi/disp/dev_disp.c | 1 -
drivers/video/sunxi/disp/dev_disp.h | 6 ++
drivers/video/sunxi/disp/dev_fb.c | 93 ++++++++++++++++-------------
drivers/video/sunxi/disp/dev_fb.h | 1 -
drivers/video/sunxi/disp/disp_hdmi.c | 78 ++++++++++++++++++++++++
drivers/video/sunxi/disp/disp_lcd.c | 83 ++++++++++++++++++-------
drivers/video/sunxi/disp/ebios_lcdc_tve.h | 2 +-
drivers/video/sunxi/hdmi/dev_hdmi.c | 3 +-
drivers/video/sunxi/hdmi/dev_hdmi.h | 1 -
drivers/video/sunxi/hdmi/drv_hdmi.c | 22 +++++++
drivers/video/sunxi/lcd/dev_lcd.c | 3 +-
drivers/video/sunxi/lcd/dev_lcd.h | 2 -
include/video/sunxi_disp_ioctl.h | 15 +----
15 files changed, 237 insertions(+), 92 deletions(-)

--
1.7.10.4

Jari Helaakoski

unread,
Jan 6, 2013, 5:04:19 PM1/6/13
to linux...@googlegroups.com, Jari Helaakoski
This patch improves Hans De Goede's EDID patch by allowing user to set new mode at runtime.
Example: echo D:1280x720p-60 > /sys/devices/platform/disp/graphics/fb0/mode
But precondition is that EDID support must be activated like before.
Ie. by using following modprobe configuration:
options disp screen0_output_mode=EDID:1280x720p60

Signed-off-by: Jari Helaakoski <tek...@gmail.com>
---
drivers/video/sunxi/disp/bsp_display.h | 4 ++
drivers/video/sunxi/disp/dev_fb.c | 29 +++++++++++-
drivers/video/sunxi/disp/disp_hdmi.c | 78 ++++++++++++++++++++++++++++++++
drivers/video/sunxi/disp/disp_lcd.c | 73 ++++++++++++++++++++++++++++++
drivers/video/sunxi/hdmi/drv_hdmi.c | 22 +++++++++
include/video/sunxi_disp_ioctl.h | 1 +
6 files changed, 206 insertions(+), 1 deletion(-)

diff --git a/drivers/video/sunxi/disp/bsp_display.h b/drivers/video/sunxi/disp/bsp_display.h
index a46f3ad..09c02fd 100644
--- a/drivers/video/sunxi/disp/bsp_display.h
+++ b/drivers/video/sunxi/disp/bsp_display.h
@@ -77,6 +77,7 @@ typedef struct {

void (*tve_interrup) (__u32 sel);
__s32(*hdmi_set_mode) (__disp_tv_mode_t mode);
+ __s32(*hdmi_set_videomode) (const struct __disp_video_timing *mode);
__s32(*hdmi_wait_edid) (void);
__s32(*Hdmi_open) (void);
__s32(*Hdmi_close) (void);
@@ -235,6 +236,7 @@ extern __s32 LCD_PWM_EN(__u32 sel, __bool b_en);
extern __s32 LCD_BL_EN(__u32 sel, __bool b_en);
extern __s32 BSP_disp_lcd_user_defined_func(__u32 sel, __u32 para1, __u32 para2,
__u32 para3);
+extern __s32 BSP_disp_get_videomode(__u32 sel, struct fb_videomode *videomode);
extern __s32 BSP_disp_get_timing(__u32 sel, __disp_tcon_timing_t *tt);
extern __u32 BSP_disp_get_cur_line(__u32 sel);
#ifdef CONFIG_ARCH_SUN5I
@@ -257,6 +259,8 @@ extern __s32 BSP_disp_tv_get_dac_source(__u32 sel, __u32 index);
extern __s32 BSP_disp_hdmi_open(__u32 sel);
extern __s32 BSP_disp_hdmi_close(__u32 sel);
extern __s32 BSP_disp_hdmi_set_mode(__u32 sel, __disp_tv_mode_t mode);
+extern __s32 BSP_disp_set_videomode(__u32 sel,
+ const struct fb_videomode *mode);
extern __s32 BSP_disp_hdmi_get_mode(__u32 sel);
extern __s32 BSP_disp_hdmi_check_support_mode(__u32 sel, __u8 mode);
extern __s32 BSP_disp_hdmi_get_hpd_status(__u32 sel);
diff --git a/drivers/video/sunxi/disp/dev_fb.c b/drivers/video/sunxi/disp/dev_fb.c
index 4104b12..d0e65c9 100644
--- a/drivers/video/sunxi/disp/dev_fb.c
+++ b/drivers/video/sunxi/disp/dev_fb.c
@@ -1037,9 +1037,20 @@ static int Fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
static int Fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{
__disp_pixel_fmt_t fmt;
+ int dummy, sel;
__inf("Fb_check_var: %dx%d %dbits\n", var->xres, var->yres,
var->bits_per_pixel);

+ for (sel = 0; sel < 2; sel++) {
+ if (g_fbi.disp_init.output_type[sel] != DISP_OUTPUT_TYPE_HDMI)
+ continue;
+
+ /* Check that pll is found */
+ if (disp_get_pll_freq(PICOS2KHZ(var->pixclock) *
+ 1000, &dummy, &dummy))
+ return -EINVAL;
+ }
+
switch (var->bits_per_pixel) {
case 16:
if (var->transp.length == 1 && var->transp.offset == 15)
@@ -1089,11 +1100,26 @@ static int Fb_set_par(struct fb_info *info)
(g_fbi.fb_mode[info->node] != FB_MODE_SCREEN0))) {
struct fb_var_screeninfo *var = &info->var;
struct fb_fix_screeninfo *fix = &info->fix;
+ bool mode_changed = false;
__s32 layer_hdl = g_fbi.layer_hdl[info->node][sel];
__disp_layer_info_t layer_para;
__u32 buffer_num = 1;
__u32 y_offset = 0;

+
+ if (g_fbi.disp_init.output_type[sel] ==
+ DISP_OUTPUT_TYPE_HDMI) {
+ struct fb_videomode new_mode;
+ struct fb_videomode old_mode;
+ fb_var_to_videomode(&new_mode, var);
+ BSP_disp_get_videomode(sel, &old_mode);
+ if (!fb_mode_is_equal(&new_mode, &old_mode)) {
+ mode_changed = (BSP_disp_set_videomode(
+ sel, &new_mode) == 0);
+
+ }
+ }
+
if (g_fbi.fb_mode[info->node] ==
FB_MODE_DUAL_SAME_SCREEN_TB)
buffer_num = 2;
@@ -1109,7 +1135,8 @@ static int Fb_set_par(struct fb_info *info)
layer_para.src_win.y = var->yoffset + y_offset;
layer_para.src_win.width = var->xres;
layer_para.src_win.height = var->yres / buffer_num;
- if (layer_para.mode != DISP_LAYER_WORK_MODE_SCALER) {
+ if (layer_para.mode != DISP_LAYER_WORK_MODE_SCALER ||
+ mode_changed) {
layer_para.scn_win.width =
layer_para.src_win.width;
layer_para.scn_win.height =
diff --git a/drivers/video/sunxi/disp/disp_hdmi.c b/drivers/video/sunxi/disp/disp_hdmi.c
index 9a84ac7..fa833be 100644
--- a/drivers/video/sunxi/disp/disp_hdmi.c
+++ b/drivers/video/sunxi/disp/disp_hdmi.c
@@ -191,6 +191,83 @@ __s32 BSP_disp_hdmi_set_mode(__u32 sel, __disp_tv_mode_t mode)
return DIS_SUCCESS;
}

+void videomode_to_video_timing(struct __disp_video_timing *video_timing,
+ const struct fb_videomode *mode)
+{
+ memset(video_timing, 0, sizeof(struct __disp_video_timing));
+ video_timing->VIC = 511;
+ video_timing->PCLK = (PICOS2KHZ(mode->pixclock) * 1000);
+ video_timing->AVI_PR = 0;
+ video_timing->INPUTX = mode->xres;
+ video_timing->INPUTY = mode->yres;
+ video_timing->HT = mode->xres + mode->left_margin +
+ mode->right_margin + mode->hsync_len;
+ video_timing->HBP = mode->left_margin + mode->hsync_len;
+ video_timing->HFP = mode->right_margin;
+ video_timing->HPSW = mode->hsync_len;
+ video_timing->VT = mode->yres + mode->upper_margin +
+ mode->lower_margin + mode->vsync_len;
+ video_timing->VBP = mode->upper_margin + mode->vsync_len;
+ video_timing->VFP = mode->lower_margin;
+ video_timing->VPSW = mode->vsync_len;
+ if (mode->vmode & FB_VMODE_INTERLACED)
+ video_timing->I = true;
+
+ if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
+ video_timing->HSYNC = true;
+
+ if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
+ video_timing->VSYNC = true;
+
+}
+
+__s32 BSP_disp_set_videomode(__u32 sel, const struct fb_videomode *mode)
+{
+ struct __disp_video_timing *old_video_timing =
+ kzalloc(sizeof(struct __disp_video_timing), 0);
+ struct __disp_video_timing *new_video_timing =
+ kzalloc(sizeof(struct __disp_video_timing), 0);
+ __disp_tv_mode_t hdmi_mode = gdisp.screen[sel].hdmi_mode;
+
+ if (!gdisp.init_para.hdmi_set_videomode)
+ return DIS_FAIL;
+
+ if (gdisp.init_para.hdmi_get_video_timing(hdmi_mode,
+ old_video_timing) != 0)
+ return DIS_FAIL;
+
+ videomode_to_video_timing(new_video_timing, mode);
+
+ if (gdisp.init_para.hdmi_set_videomode(new_video_timing) != 0)
+ return DIS_FAIL;
+
+ if (disp_clk_cfg(sel, DISP_OUTPUT_TYPE_HDMI, hdmi_mode) != 0)
+ goto failure;
+
+ if (DE_BE_set_display_size(sel, new_video_timing->INPUTX,
+ new_video_timing->INPUTY) != 0)
+ goto failure;
+
+ if (TCON1_set_hdmi_mode(sel, hdmi_mode) != 0)
+ goto failure;
+
+ gdisp.screen[sel].b_out_interlace = new_video_timing->I;
+
+ kfree(old_video_timing);
+ kfree(new_video_timing);
+ return DIS_SUCCESS;
+
+failure:
+ gdisp.init_para.hdmi_set_videomode(old_video_timing);
+ disp_clk_cfg(sel, DISP_OUTPUT_TYPE_HDMI, hdmi_mode);
+ DE_BE_set_display_size(sel, old_video_timing->INPUTX,
+ old_video_timing->INPUTY);
+ TCON1_set_hdmi_mode(sel, hdmi_mode);
+ kfree(old_video_timing);
+ kfree(new_video_timing);
+ return DIS_FAIL;
+}
+
__s32 BSP_disp_hdmi_get_mode(__u32 sel)
{
return gdisp.screen[sel].hdmi_mode;
@@ -253,6 +330,7 @@ __s32 BSP_disp_set_hdmi_func(__disp_hdmi_func *func)
gdisp.init_para.Hdmi_open = func->Hdmi_open;
gdisp.init_para.Hdmi_close = func->Hdmi_close;
gdisp.init_para.hdmi_set_mode = func->hdmi_set_mode;
+ gdisp.init_para.hdmi_set_videomode = func->hdmi_set_videomode;
gdisp.init_para.hdmi_mode_support = func->hdmi_mode_support;
gdisp.init_para.hdmi_get_video_timing = func->hdmi_get_video_timing;
gdisp.init_para.hdmi_get_HPD_status = func->hdmi_get_HPD_status;
diff --git a/drivers/video/sunxi/disp/disp_lcd.c b/drivers/video/sunxi/disp/disp_lcd.c
index 7fa6e52..cb4128e 100644
--- a/drivers/video/sunxi/disp/disp_lcd.c
+++ b/drivers/video/sunxi/disp/disp_lcd.c
@@ -1816,6 +1816,79 @@ void LCD_set_panel_funs(__lcd_panel_fun_t *lcd0_cfg,
}
EXPORT_SYMBOL(LCD_set_panel_funs);

+__s32 BSP_disp_get_videomode(__u32 sel, struct fb_videomode *videomode)
+{
+ __disp_tcon_timing_t tt;
+ bool interlaced, hsync, vsync = false;
+ u32 pixclock, hfreq, htotal, vtotal;
+ memset(videomode, 0, sizeof(struct fb_videomode));
+
+ if (BSP_disp_get_timing(sel, &tt) != 0)
+ return DIS_FAIL;
+
+ if (gdisp.screen[sel].status & LCD_ON) {
+ interlaced = false;
+ } else if ((gdisp.screen[sel].status & TV_ON)) {
+ interlaced = Disp_get_screen_scan_mode(
+ gdisp.screen[sel].tv_mode);
+ } else if (gdisp.screen[sel].status & HDMI_ON) {
+ struct __disp_video_timing video_timing;
+ __disp_tv_mode_t hdmi_mode = gdisp.screen[sel].hdmi_mode;
+ if (gdisp.init_para.hdmi_get_video_timing(
+ hdmi_mode, &video_timing) != 0)
+ return DIS_FAIL;
+
+ interlaced = video_timing.I;
+ hsync = video_timing.HSYNC;
+ vsync = video_timing.VSYNC;
+ } else if (gdisp.screen[sel].status & VGA_ON) {
+ interlaced = Disp_get_screen_scan_mode(
+ gdisp.screen[sel].vga_mode);
+ } else {
+ DE_INF("get videomode fail because device is not output !\n");
+ return DIS_FAIL;
+ }
+
+ videomode->xres = BSP_disp_get_screen_width(sel);
+ videomode->yres = BSP_disp_get_screen_height(sel);
+ videomode->pixclock = KHZ2PICOS(tt.pixel_clk);
+ videomode->left_margin = tt.hor_back_porch;
+ videomode->right_margin = tt.hor_front_porch;
+ videomode->upper_margin = tt.ver_back_porch;
+ videomode->lower_margin = tt.ver_front_porch;
+ videomode->hsync_len = tt.hor_sync_time;
+ videomode->vsync_len = tt.ver_sync_time;
+
+
+ if (interlaced)
+ videomode->vmode = FB_VMODE_INTERLACED;
+
+ if (vsync)
+ videomode->sync = FB_SYNC_VERT_HIGH_ACT;
+
+ if (hsync)
+ videomode->sync |= FB_SYNC_HOR_HIGH_ACT;
+
+ if (!videomode->pixclock)
+ return DIS_SUCCESS;
+
+ pixclock = PICOS2KHZ(videomode->pixclock) * 1000;
+
+ htotal = videomode->xres + videomode->right_margin +
+ videomode->hsync_len + videomode->left_margin;
+ vtotal = videomode->yres + videomode->lower_margin +
+ videomode->vsync_len + videomode->upper_margin;
+
+ if (videomode->vmode & FB_VMODE_INTERLACED)
+ vtotal /= 2;
+ if (videomode->vmode & FB_VMODE_DOUBLE)
+ vtotal *= 2;
+
+ hfreq = pixclock/htotal;
+ videomode->refresh = hfreq/vtotal;
+ return DIS_SUCCESS;
+}
+
__s32 BSP_disp_get_timing(__u32 sel, __disp_tcon_timing_t *tt)
{
memset(tt, 0, sizeof(__disp_tcon_timing_t));
diff --git a/drivers/video/sunxi/hdmi/drv_hdmi.c b/drivers/video/sunxi/hdmi/drv_hdmi.c
index e867377..7eb0987 100644
--- a/drivers/video/sunxi/hdmi/drv_hdmi.c
+++ b/drivers/video/sunxi/hdmi/drv_hdmi.c
@@ -163,6 +163,27 @@ __s32 Hdmi_set_display_mode(__disp_tv_mode_t mode)
return 0;
}

+__s32 Hdmi_set_display_videomode(const struct __disp_video_timing *mode)
+{
+ __inf("[Hdmi_set_display_videomode]\n");
+
+ if (video_mode != HDMI_EDID)
+ return -1;
+
+ if (memcmp(mode, &video_timing[video_timing_edid],
+ sizeof(struct __disp_video_timing)) != 0) {
+
+ if (hdmi_state >= HDMI_State_Video_config)
+ hdmi_state = HDMI_State_Video_config;
+
+ memcpy(&video_timing[video_timing_edid], mode,
+ sizeof(struct __disp_video_timing));
+
+ }
+
+ return 0;
+}
+
__s32 Hdmi_Audio_Enable(__u8 mode, __u8 channel)
{
__inf("[Hdmi_Audio_Enable],ch:%d\n", channel);
@@ -316,6 +337,7 @@ __s32 Hdmi_init(void)
disp_func.Hdmi_open = Hdmi_open;
disp_func.Hdmi_close = Hdmi_close;
disp_func.hdmi_set_mode = Hdmi_set_display_mode;
+ disp_func.hdmi_set_videomode = Hdmi_set_display_videomode;
disp_func.hdmi_mode_support = Hdmi_mode_support;
disp_func.hdmi_get_video_timing = hdmi_get_video_timing;
disp_func.hdmi_get_HPD_status = Hdmi_get_HPD_status;
diff --git a/include/video/sunxi_disp_ioctl.h b/include/video/sunxi_disp_ioctl.h
index 53a3d0f..1220bf9 100644
--- a/include/video/sunxi_disp_ioctl.h
+++ b/include/video/sunxi_disp_ioctl.h
@@ -452,6 +452,7 @@ typedef struct {
__s32(*Hdmi_open) (void);
__s32(*Hdmi_close) (void);
__s32(*hdmi_set_mode) (__disp_tv_mode_t mode);
+ __s32(*hdmi_set_videomode) (const struct __disp_video_timing *mode);
__s32(*hdmi_mode_support) (__disp_tv_mode_t mode);
__s32(*hdmi_get_video_timing) (__disp_tv_mode_t mode,
struct __disp_video_timing *video_timing);
--
1.7.10.4

Jari Helaakoski

unread,
Jan 6, 2013, 5:04:20 PM1/6/13
to linux...@googlegroups.com, Jari Helaakoski
Double buffering must be always on, or it can cause performance problems in gles applications.


Signed-off-by: Jari Helaakoski <tek...@gmail.com>
---
drivers/video/sunxi/disp/dev_fb.c | 60 ++++++++++++++-----------------------
1 file changed, 22 insertions(+), 38 deletions(-)

diff --git a/drivers/video/sunxi/disp/dev_fb.c b/drivers/video/sunxi/disp/dev_fb.c
index d0e65c9..af1f6fc 100644
--- a/drivers/video/sunxi/disp/dev_fb.c
+++ b/drivers/video/sunxi/disp/dev_fb.c
@@ -1112,6 +1112,8 @@ static int Fb_set_par(struct fb_info *info)
struct fb_videomode new_mode;
struct fb_videomode old_mode;
fb_var_to_videomode(&new_mode, var);
+ var->yres_virtual = new_mode.yres *
+ g_fbi.fb_para[sel].buffer_num;
BSP_disp_get_videomode(sel, &old_mode);
if (!fb_mode_is_equal(&new_mode, &old_mode)) {
mode_changed = (BSP_disp_set_videomode(
@@ -1425,21 +1427,12 @@ __s32 Display_Fb_Request(__u32 fb_id, __disp_fb_create_para_t * fb_para)
((sel == fb_para->primary_screen_id) &&
(fb_para->fb_mode ==
FB_MODE_DUAL_DIFF_SCREEN_SAME_CONTENTS))) {
- __disp_tcon_timing_t tt;
-
- if (BSP_disp_get_timing(sel, &tt) >= 0) {
- info->var.pixclock =
- 1000000000 / tt.pixel_clk;
- info->var.left_margin =
- tt.hor_back_porch;
- info->var.right_margin =
- tt.hor_front_porch;
- info->var.upper_margin =
- tt.ver_back_porch;
- info->var.lower_margin =
- tt.ver_front_porch;
- info->var.hsync_len = tt.hor_sync_time;
- info->var.vsync_len = tt.ver_sync_time;
+
+ struct fb_videomode mode;
+ if (BSP_disp_get_videomode(sel, &mode) == 0) {
+ fb_videomode_to_var(&info->var, &mode);
+ info->var.yres_virtual =
+ mode.yres * fb_para->buffer_num;
}
}

@@ -1570,33 +1563,24 @@ __s32 Display_set_fb_timing(__u32 sel)
__u8 fb_id = 0;

for (fb_id = 0; fb_id < SUNXI_MAX_FB; fb_id++) {
+ __disp_fb_create_para_t *fb_para = &g_fbi.fb_para[fb_id];
+ __fb_mode_t fb_mode = g_fbi.fb_mode[fb_id];
+ struct fb_var_screeninfo *var = &g_fbi.fbinfo[sel]->var;
if (g_fbi.fb_enable[fb_id]) {
if (((sel == 0) &&
- (g_fbi.fb_mode[fb_id] == FB_MODE_SCREEN0 ||
- g_fbi.fb_mode[fb_id] ==
- FB_MODE_DUAL_SAME_SCREEN_TB)) ||
+ (fb_mode == FB_MODE_SCREEN0 ||
+ fb_mode == FB_MODE_DUAL_SAME_SCREEN_TB)) ||
((sel == 1) &&
- (g_fbi.fb_mode[fb_id] == FB_MODE_SCREEN1)) ||
- ((sel == g_fbi.fb_para[fb_id].primary_screen_id) &&
- (g_fbi.fb_mode[fb_id] ==
+ (fb_mode == FB_MODE_SCREEN1)) ||
+ ((sel == fb_para->primary_screen_id) &&
+ (fb_mode ==
FB_MODE_DUAL_DIFF_SCREEN_SAME_CONTENTS))) {
- __disp_tcon_timing_t tt;
-
- if (BSP_disp_get_timing(sel, &tt) >= 0) {
- g_fbi.fbinfo[fb_id]->var.pixclock =
- 1000000000 / tt.pixel_clk;
- g_fbi.fbinfo[fb_id]->var.left_margin =
- tt.hor_back_porch;
- g_fbi.fbinfo[fb_id]->var.right_margin =
- tt.hor_front_porch;
- g_fbi.fbinfo[fb_id]->var.upper_margin =
- tt.ver_back_porch;
- g_fbi.fbinfo[fb_id]->var.lower_margin =
- tt.ver_front_porch;
- g_fbi.fbinfo[fb_id]->var.hsync_len =
- tt.hor_sync_time;
- g_fbi.fbinfo[fb_id]->var.vsync_len =
- tt.ver_sync_time;
+
+ struct fb_videomode mode;
+ if (BSP_disp_get_videomode(sel, &mode) == 0) {
+ fb_videomode_to_var(var, &mode);
+ var->yres_virtual = mode.yres *
+ fb_para->buffer_num;
}
}
}
--
1.7.10.4

Jari Helaakoski

unread,
Jan 6, 2013, 5:04:21 PM1/6/13
to linux...@googlegroups.com, Jari Helaakoski
Cleanup.

Signed-off-by: Jari Helaakoski <tek...@gmail.com>
---
drivers/video/sunxi/disp/bsp_display.h | 1 -
drivers/video/sunxi/disp/de_lcdc.c | 14 +++---
drivers/video/sunxi/disp/disp_lcd.c | 74 ++++++++---------------------
drivers/video/sunxi/disp/ebios_lcdc_tve.h | 2 +-
include/video/sunxi_disp_ioctl.h | 14 ------
5 files changed, 29 insertions(+), 76 deletions(-)

diff --git a/drivers/video/sunxi/disp/bsp_display.h b/drivers/video/sunxi/disp/bsp_display.h
index 09c02fd..09127d3 100644
--- a/drivers/video/sunxi/disp/bsp_display.h
+++ b/drivers/video/sunxi/disp/bsp_display.h
@@ -237,7 +237,6 @@ extern __s32 LCD_BL_EN(__u32 sel, __bool b_en);
extern __s32 BSP_disp_lcd_user_defined_func(__u32 sel, __u32 para1, __u32 para2,
__u32 para3);
extern __s32 BSP_disp_get_videomode(__u32 sel, struct fb_videomode *videomode);
-extern __s32 BSP_disp_get_timing(__u32 sel, __disp_tcon_timing_t *tt);
extern __u32 BSP_disp_get_cur_line(__u32 sel);
#ifdef CONFIG_ARCH_SUN5I
extern __s32 BSP_disp_close_lcd_backlight(__u32 sel);
diff --git a/drivers/video/sunxi/disp/de_lcdc.c b/drivers/video/sunxi/disp/de_lcdc.c
index 1db9829..100a2d8 100644
--- a/drivers/video/sunxi/disp/de_lcdc.c
+++ b/drivers/video/sunxi/disp/de_lcdc.c
@@ -181,7 +181,7 @@ __s32 LCDC_clear_int(__u32 sel, __u32 irqsrc)
return 0;
}

-__s32 LCDC_get_timing(__u32 sel, __u32 index, __disp_tcon_timing_t *tt)
+__s32 LCDC_get_timing(__u32 sel, __u32 index, struct fb_videomode *videomode)
{
__u32 reg0, reg1, reg2, reg3;
__u32 x, y, ht, hbp, vt, vbp, hspw, vspw;
@@ -207,17 +207,17 @@ __s32 LCDC_get_timing(__u32 sel, __u32 index, __disp_tcon_timing_t *tt)
vspw = (reg3 >> 0) & 0x3ff;

/* left margin */
- tt->hor_back_porch = (hbp + 1) - (hspw + 1);
+ videomode->left_margin = (hbp + 1) - (hspw + 1);
/* right margin */
- tt->hor_front_porch = (ht + 1) - (x + 1) - (hbp + 1);
+ videomode->right_margin = (ht + 1) - (x + 1) - (hbp + 1);
/* upper margin */
- tt->ver_back_porch = (vbp + 1) - (vspw + 1);
+ videomode->upper_margin = (vbp + 1) - (vspw + 1);
/* lower margin */
- tt->ver_front_porch = (vt / 2) - (y + 1) - (vbp + 1);
+ videomode->lower_margin = (vt / 2) - (y + 1) - (vbp + 1);
/* hsync_len */
- tt->hor_sync_time = (hspw + 1);
+ videomode->hsync_len = (hspw + 1);
/* vsync_len */
- tt->ver_sync_time = (vspw + 1);
+ videomode->vsync_len = (vspw + 1);

return 0;
}
diff --git a/drivers/video/sunxi/disp/disp_lcd.c b/drivers/video/sunxi/disp/disp_lcd.c
index cb4128e..312f783 100644
--- a/drivers/video/sunxi/disp/disp_lcd.c
+++ b/drivers/video/sunxi/disp/disp_lcd.c
@@ -1818,19 +1818,23 @@ EXPORT_SYMBOL(LCD_set_panel_funs);

__s32 BSP_disp_get_videomode(__u32 sel, struct fb_videomode *videomode)
{
- __disp_tcon_timing_t tt;
- bool interlaced, hsync, vsync = false;
+ bool interlaced = false, hsync = false, vsync = false;
u32 pixclock, hfreq, htotal, vtotal;
memset(videomode, 0, sizeof(struct fb_videomode));

- if (BSP_disp_get_timing(sel, &tt) != 0)
- return DIS_FAIL;
-
if (gdisp.screen[sel].status & LCD_ON) {
+ LCDC_get_timing(sel, 0, videomode);
+ videomode->pixclock = KHZ2PICOS(
+ gpanel_info[sel].lcd_dclk_freq * 1000);
interlaced = false;
} else if ((gdisp.screen[sel].status & TV_ON)) {
- interlaced = Disp_get_screen_scan_mode(
- gdisp.screen[sel].tv_mode);
+ __disp_tv_mode_t tv_mode = gdisp.screen[sel].tv_mode;
+ LCDC_get_timing(sel, 1, videomode);
+ videomode->pixclock = KHZ2PICOS(
+ (clk_tab.tv_clk_tab[tv_mode].tve_clk /
+ clk_tab.tv_clk_tab[tv_mode].pre_scale) / 1000);
+
+ interlaced = Disp_get_screen_scan_mode(tv_mode);
} else if (gdisp.screen[sel].status & HDMI_ON) {
struct __disp_video_timing video_timing;
__disp_tv_mode_t hdmi_mode = gdisp.screen[sel].hdmi_mode;
@@ -1838,12 +1842,20 @@ __s32 BSP_disp_get_videomode(__u32 sel, struct fb_videomode *videomode)
hdmi_mode, &video_timing) != 0)
return DIS_FAIL;

+ LCDC_get_timing(sel, 1, videomode);
+ videomode->pixclock = KHZ2PICOS(video_timing.PCLK / 1000);
interlaced = video_timing.I;
hsync = video_timing.HSYNC;
vsync = video_timing.VSYNC;
} else if (gdisp.screen[sel].status & VGA_ON) {
- interlaced = Disp_get_screen_scan_mode(
- gdisp.screen[sel].vga_mode);
+ __disp_vga_mode_t vga_mode = gdisp.screen[sel].vga_mode;
+
+ LCDC_get_timing(sel, 1, videomode);
+
+ videomode->pixclock = KHZ2PICOS(
+ (clk_tab.vga_clk_tab[vga_mode].tve_clk /
+ clk_tab.vga_clk_tab[vga_mode].pre_scale) / 1000);
+ interlaced = Disp_get_screen_scan_mode(vga_mode);
} else {
DE_INF("get videomode fail because device is not output !\n");
return DIS_FAIL;
@@ -1851,14 +1863,6 @@ __s32 BSP_disp_get_videomode(__u32 sel, struct fb_videomode *videomode)

videomode->xres = BSP_disp_get_screen_width(sel);
videomode->yres = BSP_disp_get_screen_height(sel);
- videomode->pixclock = KHZ2PICOS(tt.pixel_clk);
- videomode->left_margin = tt.hor_back_porch;
- videomode->right_margin = tt.hor_front_porch;
- videomode->upper_margin = tt.ver_back_porch;
- videomode->lower_margin = tt.ver_front_porch;
- videomode->hsync_len = tt.hor_sync_time;
- videomode->vsync_len = tt.ver_sync_time;
-

if (interlaced)
videomode->vmode = FB_VMODE_INTERLACED;
@@ -1889,42 +1893,6 @@ __s32 BSP_disp_get_videomode(__u32 sel, struct fb_videomode *videomode)
return DIS_SUCCESS;
}

-__s32 BSP_disp_get_timing(__u32 sel, __disp_tcon_timing_t *tt)
-{
- memset(tt, 0, sizeof(__disp_tcon_timing_t));
-
- if (gdisp.screen[sel].status & LCD_ON) {
- LCDC_get_timing(sel, 0, tt);
- tt->pixel_clk = gpanel_info[sel].lcd_dclk_freq * 1000;
- } else if ((gdisp.screen[sel].status & TV_ON)) {
- __disp_tv_mode_t mode = gdisp.screen[sel].tv_mode;
- LCDC_get_timing(sel, 1, tt);
- tt->pixel_clk =
- (clk_tab.tv_clk_tab[mode].tve_clk /
- clk_tab.tv_clk_tab[mode].pre_scale) / 1000;
- } else if (gdisp.screen[sel].status & HDMI_ON) {
- struct __disp_video_timing video_timing;
- __disp_tv_mode_t hdmi_mode = gdisp.screen[sel].hdmi_mode;
-
- LCDC_get_timing(sel, 1, tt);
- if (gdisp.init_para.hdmi_get_video_timing(
- hdmi_mode, &video_timing) == 0)
- tt->pixel_clk = video_timing.PCLK / 1000;
- } else if (gdisp.screen[sel].status & VGA_ON) {
- __disp_vga_mode_t mode = gdisp.screen[sel].vga_mode;
-
- LCDC_get_timing(sel, 1, tt);
- tt->pixel_clk =
- (clk_tab.vga_clk_tab[mode].tve_clk /
- clk_tab.vga_clk_tab[mode].pre_scale) / 1000;
- } else {
- DE_INF("get timing fail because device is not output !\n");
- return -1;
- }
-
- return 0;
-}
-
__u32 BSP_disp_get_cur_line(__u32 sel)
{
__u32 line = 0;
diff --git a/drivers/video/sunxi/disp/ebios_lcdc_tve.h b/drivers/video/sunxi/disp/ebios_lcdc_tve.h
index 5a69422..4dfe17c 100644
--- a/drivers/video/sunxi/disp/ebios_lcdc_tve.h
+++ b/drivers/video/sunxi/disp/ebios_lcdc_tve.h
@@ -131,7 +131,7 @@ void LCDC_open(__u32 sel);
void LCDC_close(__u32 sel);
__s32 LCDC_set_int_line(__u32 sel, __u32 tcon_index, __u32 num);
__s32 LCDC_clear_int(__u32 sel, __u32 irqsrc);
-__s32 LCDC_get_timing(__u32 sel, __u32 index, __disp_tcon_timing_t *tt);
+__s32 LCDC_get_timing(__u32 sel, __u32 index, struct fb_videomode *videomode);
__s32 LCDC_enable_int(__u32 sel, __u32 irqsrc);
__s32 LCDC_disable_int(__u32 sel, __u32 irqsrc);
__u32 LCDC_query_int(__u32 sel);
diff --git a/include/video/sunxi_disp_ioctl.h b/include/video/sunxi_disp_ioctl.h
index 1220bf9..b4d1151 100644
--- a/include/video/sunxi_disp_ioctl.h
+++ b/include/video/sunxi_disp_ioctl.h
@@ -544,20 +544,6 @@ typedef struct {
} __panel_para_t;

typedef struct {
- __u32 pixel_clk; /* khz */
- __u32 hor_pixels;
- __u32 ver_pixels;
- __u32 hor_total_time;
- __u32 hor_front_porch;
- __u32 hor_sync_time;
- __u32 hor_back_porch;
- __u32 ver_total_time;
- __u32 ver_front_porch;
- __u32 ver_sync_time;
- __u32 ver_back_porch;
-} __disp_tcon_timing_t;
-
-typedef struct {
__u32 base_lcdc0;
__u32 base_lcdc1;
__u32 base_pioc;
--
1.7.10.4

Jari Helaakoski

unread,
Jan 6, 2013, 5:04:22 PM1/6/13
to linux...@googlegroups.com, Jari Helaakoski
Cleanup


Signed-off-by: Jari Helaakoski <tek...@gmail.com>
---
drivers/video/sunxi/disp/dev_disp.c | 1 -
drivers/video/sunxi/disp/dev_disp.h | 6 ++++++
drivers/video/sunxi/disp/dev_fb.c | 4 ++--
drivers/video/sunxi/disp/dev_fb.h | 1 -
drivers/video/sunxi/hdmi/dev_hdmi.c | 3 ++-
drivers/video/sunxi/hdmi/dev_hdmi.h | 1 -
drivers/video/sunxi/lcd/dev_lcd.c | 3 ++-
drivers/video/sunxi/lcd/dev_lcd.h | 2 --
8 files changed, 12 insertions(+), 9 deletions(-)

diff --git a/drivers/video/sunxi/disp/dev_disp.c b/drivers/video/sunxi/disp/dev_disp.c
index 6478193..cbc4fa4 100644
--- a/drivers/video/sunxi/disp/dev_disp.c
+++ b/drivers/video/sunxi/disp/dev_disp.c
@@ -298,7 +298,6 @@ __s32 DRV_DISP_Init(void)

return 0;
}
-EXPORT_SYMBOL(DRV_DISP_Init);

__s32 DRV_DISP_Exit(void)
{
diff --git a/drivers/video/sunxi/disp/dev_disp.h b/drivers/video/sunxi/disp/dev_disp.h
index 3027a9c..681b3df 100644
--- a/drivers/video/sunxi/disp/dev_disp.h
+++ b/drivers/video/sunxi/disp/dev_disp.h
@@ -43,6 +43,11 @@ struct alloc_struct_t {
struct alloc_struct_t *next;
};

+enum {
+ SUNXI_LCD,
+ SUNXI_HDMI
+};
+
int disp_open(struct inode *inode, struct file *file);
int disp_release(struct inode *inode, struct file *file);
ssize_t disp_read(struct file *file, char __user *buf, size_t count,
@@ -64,6 +69,7 @@ extern __s32 DRV_DISP_Exit(void);
extern __disp_drv_t g_disp_drv;

extern void hdmi_edid_received(unsigned char *edid, int block);
+extern __s32 Fb_Init(__u32 from);
extern __s32 DRV_lcd_open(__u32 sel);
extern __s32 DRV_lcd_close(__u32 sel);

diff --git a/drivers/video/sunxi/disp/dev_fb.c b/drivers/video/sunxi/disp/dev_fb.c
index af1f6fc..1cf9284 100644
--- a/drivers/video/sunxi/disp/dev_fb.c
+++ b/drivers/video/sunxi/disp/dev_fb.c
@@ -1753,10 +1753,10 @@ __s32 Fb_Init(__u32 from)

__inf("Fb_Init: %d %d\n", from, need_open_hdmi);

- if (need_open_hdmi == 1 && from == 0)
+ if (need_open_hdmi == 1 && from == SUNXI_LCD)
/* it is called from lcd driver, but hdmi need to be opened */
return 0;
- else if (need_open_hdmi == 0 && from == 1)
+ else if (need_open_hdmi == 0 && from == SUNXI_HDMI)
/* it is called from hdmi driver, but hdmi need not be opened */
return 0;

diff --git a/drivers/video/sunxi/disp/dev_fb.h b/drivers/video/sunxi/disp/dev_fb.h
index 92a7faab..1b668e2 100644
--- a/drivers/video/sunxi/disp/dev_fb.h
+++ b/drivers/video/sunxi/disp/dev_fb.h
@@ -76,7 +76,6 @@ __s32 Display_Fb_get_para(__u32 fb_id, __disp_fb_create_para_t *fb_para);

__s32 Display_get_disp_init_para(__disp_init_t *init_para);

-__s32 Fb_Init(__u32 from);
__s32 Fb_Exit(void);

#endif /* __DEV_FB_H__ */
diff --git a/drivers/video/sunxi/hdmi/dev_hdmi.c b/drivers/video/sunxi/hdmi/dev_hdmi.c
index d3088a5..ef35377 100644
--- a/drivers/video/sunxi/hdmi/dev_hdmi.c
+++ b/drivers/video/sunxi/hdmi/dev_hdmi.c
@@ -19,6 +19,7 @@

#include "dev_hdmi.h"
#include "drv_hdmi_i.h"
+#include "../disp/dev_disp.h"

static struct cdev *my_cdev;
static dev_t devid;
@@ -59,7 +60,7 @@ static int __devinit hdmi_probe(struct platform_device *pdev)
ghdmi.base_hdmi = 0xf1c16000;

Hdmi_init();
- Fb_Init(1);
+ Fb_Init(SUNXI_HDMI);

return 0;
}
diff --git a/drivers/video/sunxi/hdmi/dev_hdmi.h b/drivers/video/sunxi/hdmi/dev_hdmi.h
index e4d0aad..83016c9 100644
--- a/drivers/video/sunxi/hdmi/dev_hdmi.h
+++ b/drivers/video/sunxi/hdmi/dev_hdmi.h
@@ -33,7 +33,6 @@ long hdmi_ioctl(struct file *file, unsigned int cmd, unsigned long arg);

extern __s32 Hdmi_init(void);
extern __s32 Hdmi_exit(void);
-extern __s32 Fb_Init(__u32 from);

typedef struct {
__bool bopen;
diff --git a/drivers/video/sunxi/lcd/dev_lcd.c b/drivers/video/sunxi/lcd/dev_lcd.c
index 364e657..e885c89 100644
--- a/drivers/video/sunxi/lcd/dev_lcd.c
+++ b/drivers/video/sunxi/lcd/dev_lcd.c
@@ -21,6 +21,7 @@
#include "lcd_panel_cfg.h"

#include "../disp/disp_lcd.h"
+#include "../disp/dev_disp.h"

static struct cdev *my_cdev;
static dev_t devid;
@@ -85,7 +86,7 @@ lcd_init(void)
LCD_get_panel_funs_1(&lcd1_cfg);
LCD_set_panel_funs(&lcd0_cfg, &lcd1_cfg);

- Fb_Init(0);
+ Fb_Init(SUNXI_LCD);

return 0;
}
diff --git a/drivers/video/sunxi/lcd/dev_lcd.h b/drivers/video/sunxi/lcd/dev_lcd.h
index 0520400..b2a6430 100644
--- a/drivers/video/sunxi/lcd/dev_lcd.h
+++ b/drivers/video/sunxi/lcd/dev_lcd.h
@@ -52,8 +52,6 @@

extern void LCD_get_panel_funs_0(__lcd_panel_fun_t *fun);
extern void LCD_get_panel_funs_1(__lcd_panel_fun_t *fun);
-extern __s32 Fb_Init(__u32 from);
-extern __s32 DRV_DISP_Init(void);

#define __inf(msg, ...) pr_debug("[DISP] " msg, ##__VA_ARGS__)
#define __wrn(msg, ...) pr_warn("[DISP] " msg, ##__VA_ARGS__)
--
1.7.10.4

Jari Helaakoski

unread,
Jan 6, 2013, 5:11:50 PM1/6/13
to linux...@googlegroups.com


2013/1/7 Jari Helaakoski <tek...@gmail.com>

This patchset improves Hans De Goede's EDID patch by allowing user to set new mode at runtime.
Example: echo D:1280x720p-60 > /sys/devices/platform/disp/graphics/fb0/mode
But precondition is that EDID support must be activated like before.
modprobe example: options disp screen0_output_mode=EDID:1280x720p60

It also has two cleanup patches.

To further improve disp we need to reduce usage of disp modules own definitions.
Ie. It would be good to replace __disp_video_timing struct with fb_videomode.

Patchset was tested with mini-x with HDMI output and a13_mid with LCD output.
-Jari

Hans de Goede

unread,
Jan 7, 2013, 5:08:52 AM1/7/13
to linux...@googlegroups.com, Jari Helaakoski
Hi,

I've given this a quick review (mind you I've not tested it) and it looks good,
so ack from me.

Regards,

Hans

Jari Helaakoski

unread,
Jan 7, 2013, 1:56:31 PM1/7/13
to linux...@googlegroups.com, Jari Helaakoski
This patch improves Hans De Goede's EDID patch by allowing user to set new mode at runtime.
Example: echo D:1280x720p-60 > /sys/devices/platform/disp/graphics/fb0/mode
But precondition is that EDID support must be activated like before.
Ie. by using following modprobe configuration:
options disp screen0_output_mode=EDID:1280x720p60

Signed-off-by: Jari Helaakoski <tek...@gmail.com>
---
drivers/video/sunxi/disp/bsp_display.h | 4 ++
drivers/video/sunxi/disp/dev_fb.c | 29 +++++++++++-
drivers/video/sunxi/disp/disp_hdmi.c | 81 ++++++++++++++++++++++++++++++++
drivers/video/sunxi/disp/disp_lcd.c | 73 ++++++++++++++++++++++++++++
drivers/video/sunxi/hdmi/drv_hdmi.c | 22 +++++++++
include/video/sunxi_disp_ioctl.h | 1 +
6 files changed, 209 insertions(+), 1 deletion(-)
index 9a84ac7..763218e 100644
--- a/drivers/video/sunxi/disp/disp_hdmi.c
+++ b/drivers/video/sunxi/disp/disp_hdmi.c
@@ -191,6 +191,86 @@ __s32 BSP_disp_hdmi_set_mode(__u32 sel, __disp_tv_mode_t mode)
+ kzalloc(sizeof(struct __disp_video_timing), GFP_KERNEL);
+ struct __disp_video_timing *new_video_timing =
+ kzalloc(sizeof(struct __disp_video_timing), GFP_KERNEL);
+ __disp_tv_mode_t hdmi_mode = gdisp.screen[sel].hdmi_mode;
+
+ if (!old_video_timing && !new_video_timing)
@@ -253,6 +333,7 @@ __s32 BSP_disp_set_hdmi_func(__disp_hdmi_func *func)

Alejandro Mery

unread,
Jan 8, 2013, 12:29:28 PM1/8/13
to linux...@googlegroups.com
awesome! applied on both stage branches for further testing

cheers,
Alejandro Mery

Siarhei Siamashka

unread,
Jan 10, 2013, 6:08:36 AM1/10/13
to linux...@googlegroups.com
On Mon, 7 Jan 2013 00:04:20 +0200
Jari Helaakoski <tek...@gmail.com> wrote:

> Double buffering must be always on, or it can cause performance problems in gles applications.
>
> Signed-off-by: Jari Helaakoski <tek...@gmail.com>

Does double buffering actually work? I just could not convince the mali
blob to render to into two UMP wrapped buffers, switching between them
for even and odd frames.

And I somehow doubt that double buffering can be fully functional
without also doing something to the UMP buffers initially wrapped here:
https://github.com/linux-sunxi/linux-sunxi/blob/sunxi-v3.4.24-r0/drivers/video/sunxi/disp/disp_ump.c#L51

Dynamic mode switching is great. Just a bit of clarification about
double buffering would be very much appeciated.
Best regards,
Siarhei Siamashka

Jari Helaakoski

unread,
Jan 10, 2013, 6:19:49 AM1/10/13
to linux...@googlegroups.com


2013/1/10 Siarhei Siamashka <siarhei....@gmail.com>

On Mon,  7 Jan 2013 00:04:20 +0200
Jari Helaakoski <tek...@gmail.com> wrote:

> Double buffering must be always on, or it can cause performance problems in gles applications.
>
> Signed-off-by: Jari Helaakoski <tek...@gmail.com>

Does double buffering actually work? I just could not convince the mali
blob to render to into two UMP wrapped buffers, switching between them
for even and odd frames.
If you reduce virtual yres to yres, then only every other frame is drawn. (tried with xbmc and framebuffer)
Yesterday I also tried es2_gears. I noticed that mouse cursor flickers when it is moved top of application. Otherwise it doesn't flicker.

So it could be that X11 doublebuffering has some work left.

-Jari

Reply all
Reply to author
Forward
0 new messages