Skip to content

Commit eb876a6

Browse files
committed
fbtft:fbcon changes: no more software tearing, triple backbuffer switching in fbtft, ise of FBIOPAN_DISPLAY ioctl to flip fbtft buffers
1 parent 706a184 commit eb876a6

File tree

6 files changed

+148
-35
lines changed

6 files changed

+148
-35
lines changed

arch/arm/boot/dts/sun8i-v3s-funkey.dts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@
184184
spi-max-frequency = <50000000>;
185185
txbuflen = <115202>;
186186
spi_async_mode = "true";
187-
rotate = <0>;
187+
rotate = <0>;
188188
rotate_soft = <270>;
189189
fps = <100>;
190190
buswidth = <8>;

drivers/staging/fbtft/fb_st7789v.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
enum st7789v_command {
6262
TEOFF = 0x34,
6363
TEON = 0x35,
64+
STE = 0x44,
6465
PORCTRL = 0xB2,
6566
GCTRL = 0xB7,
6667
VCOMS = 0xBB,
@@ -95,6 +96,10 @@ enum st7789v_command {
9596
static int init_display(struct fbtft_par *par)
9697
{
9798
#ifndef SAEF_SETTINGS
99+
/* Software reset */
100+
write_reg(par, 0x01);
101+
mdelay(5);
102+
98103
/* turn off sleep mode */
99104
write_reg(par, 0x11);
100105
mdelay(120);
@@ -168,6 +173,10 @@ static int init_display(struct fbtft_par *par)
168173
/* Activate TE signal for Vsync only */
169174
write_reg(par, TEON, 0x00);
170175

176+
/* Set TE tearline */
177+
/*uint16_t tearline=10;
178+
write_reg(par, STE, (tearline>>8), (tearline&0xff) );*/
179+
171180
/* refresh rate */
172181
//write_reg(par, 0xC6,0x1F); //39Hz
173182
//write_reg(par, 0xC6,0x1A); //44Hz

drivers/staging/fbtft/fbtft-bus.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ int fbtft_start_new_screen_transfer_async(struct fbtft_par *par)
124124
lock = true;
125125

126126
/* Debug fps */
127-
//#define FPS_DEBUG
127+
#define FPS_DEBUG
128128
#ifdef FPS_DEBUG
129129
long fps;
130130
ktime_t ts_now = ktime_get();
@@ -146,9 +146,9 @@ int fbtft_start_new_screen_transfer_async(struct fbtft_par *par)
146146
"Display update%s: fps=%ld\n",
147147
par->pdata->te_irq_enabled?" (TE)":"",
148148
par->avg_fps / par->nb_fps_values);
149-
printk("Display update%s: fps=%ld\n",
149+
printk("Display update%s: fps=%ld, par->must_render=%d\n",
150150
par->pdata->te_irq_enabled?" (TE)":"",
151-
par->avg_fps / par->nb_fps_values);
151+
par->avg_fps / par->nb_fps_values, par->must_render);
152152
par->avg_fps = 0;
153153
par->nb_fps_values = 0;
154154
}

drivers/staging/fbtft/fbtft-core.c

Lines changed: 99 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,9 @@ static void fbtft_update_display(struct fbtft_par *par, unsigned int start_line,
429429
if (par->pdata->rotate == 90)
430430
par->fbtftops.set_addr_win(par, 80, start_line,
431431
320 - 1, end_line);
432+
else if (par->pdata->rotate == 180)
433+
par->fbtftops.set_addr_win(par, 0, 80,
434+
par->info->var.xres - 1, 320 - 1);
432435
else
433436
par->fbtftops.set_addr_win(par, 0, start_line,
434437
par->info->var.xres - 1, end_line);
@@ -575,13 +578,19 @@ void fbtft_post_process_screen(struct fbtft_par *par)
575578
screen_post_process = true;
576579
}
577580

581+
/* Get last memory buffer not written */
582+
if(par->must_render){
583+
par->vmem_ptr = par->vmem_back_buffers[par->vmem_prev_buf_idx];
584+
}
585+
else{
586+
par->vmem_ptr = par->info->screen_buffer;
587+
}
588+
//par->vmem_ptr = par->vmem_back_buffers[par->vmem_prev_buf_idx];
589+
//par->vmem_ptr = par->info->screen_buffer;
590+
578591
/* Post process */
579592
if (screen_post_process) {
580-
/* Change vmem ptr to send by SPI */
581-
par->vmem_ptr = par->vmem_post_process;
582-
583593
/* Copy buffer */
584-
585594
/*
586595
This should be handled using a double buffer (or
587596
triple depending on game fps vs screen fps) pointed
@@ -598,17 +607,22 @@ void fbtft_post_process_screen(struct fbtft_par *par)
598607
be noticed much and it takes up so little CPU that
599608
really, it's worth the compromise for now
600609
*/
610+
#if 1
601611
//printk("m\n");
602612
memcpy(par->vmem_post_process + par->write_line_start * par->info->fix.line_length,
603-
par->info->screen_buffer + par->write_line_start * par->info->fix.line_length,
613+
par->vmem_ptr + par->write_line_start * par->info->fix.line_length,
604614
(par->write_line_end-par->write_line_start + 1) * par->info->fix.line_length);
605615
//printk("n\n");
606616

617+
/* Change vmem ptr to send by SPI */
618+
par->vmem_ptr = par->vmem_post_process;
619+
#endif
620+
607621
/* Notifications */
608622
if (par->notification[0]) {
609623
x_notif = 0;
610624
y_notif = 0;
611-
basic_text_out16_bg((u16 *)par->vmem_post_process, par->info->var.xres, par->info->var.yres,
625+
basic_text_out16_bg((u16 *)par->vmem_ptr, par->info->var.xres, par->info->var.yres,
612626
x_notif, y_notif, RGB565(255, 255, 255), RGB565(0, 0, 0), par->notification);
613627

614628
if (y_notif < par->write_line_start)
@@ -619,19 +633,44 @@ void fbtft_post_process_screen(struct fbtft_par *par)
619633

620634
/* Low battery icon */
621635
if (par->low_battery) {
622-
draw_low_battery((u16 *)par->vmem_post_process, par->info->var.xres, par->info->var.yres);
636+
draw_low_battery((u16 *)par->vmem_ptr, par->info->var.xres, par->info->var.yres);
623637
}
624638

625639
/* Soft rotation */
626640
if (par->pdata->rotate_soft)
627-
fbtft_rotate_soft((u16*)par->vmem_post_process, par->info->var.yres, par->pdata->rotate_soft);
628-
} else
629-
par->vmem_ptr = par->info->screen_buffer;
641+
fbtft_rotate_soft((u16*)par->vmem_ptr, par->info->var.yres, par->pdata->rotate_soft);
642+
}
643+
}
644+
645+
/* Copy framebuffer memory in current back buffer, then
646+
change current back buffer */
647+
void fbtft_flip_backbuffer(struct fbtft_par *par)
648+
{
649+
//spin_lock(&par->dirty_lock);
650+
memcpy(par->vmem_back_buffers[par->vmem_cur_buf_idx],
651+
par->info->screen_buffer,
652+
par->vmem_size);
653+
par->vmem_prev_buf_idx = par->vmem_cur_buf_idx;
654+
par->vmem_cur_buf_idx = (par->vmem_cur_buf_idx+1)%FBTFT_VMEM_BUFS;
655+
par->must_render++;
656+
//spin_unlock(&par->dirty_lock);
657+
}
658+
659+
static void fbtft_first_io(struct fb_info *info){
660+
/*struct fbtft_par *par = info->par;
661+
printk("f\n");*/
630662
}
631663

632664
static void fbtft_deferred_io(struct fb_info *info, struct list_head *pagelist)
633665
{
666+
634667
struct fbtft_par *par = info->par;
668+
669+
/* This disables fbtft's defered io, useful in spi_async mode or
670+
if any other driver handles screens updates instead of fbtft */
671+
if (par->spi_async_mode)
672+
return VM_FAULT_LOCKED;
673+
635674
unsigned int dirty_lines_start, dirty_lines_end;
636675
struct page *page;
637676
unsigned long index;
@@ -772,20 +811,24 @@ static struct page *fb_deferred_io_page(struct fb_info *info, unsigned long offs
772811
return page;
773812
}
774813

775-
/* this is to find and return the vmalloc-ed fb pages */
814+
/* This is to find and return the vmalloc-ed fb pages */
776815
static int fb_deferred_io_fault(struct vm_fault *vmf)
777816
{
778817
unsigned long offset;
779818
struct page *page;
780819
struct fb_info *info = vmf->vma->vm_private_data;
781820

782821
offset = vmf->pgoff << PAGE_SHIFT;
783-
if (offset >= info->fix.smem_len)
822+
if (offset >= info->fix.smem_len){
823+
printk("fault\n");
784824
return VM_FAULT_SIGBUS;
825+
}
785826

786827
page = fb_deferred_io_page(info, offset);
787-
if (!page)
828+
if (!page){
829+
printk("no page\n");
788830
return VM_FAULT_SIGBUS;
831+
}
789832

790833
get_page(page);
791834

@@ -827,8 +870,9 @@ static int fb_deferred_io_mkwrite(struct vm_fault *vmf)
827870
mutex_lock(&fbdefio->lock);
828871

829872
/* first write in this cycle, notify the driver */
830-
if (fbdefio->first_io && list_empty(&fbdefio->pagelist))
873+
if (fbdefio->first_io && list_empty(&fbdefio->pagelist)){
831874
fbdefio->first_io(info);
875+
}
832876

833877
/*
834878
* We want the page to remain locked from ->page_mkwrite until
@@ -1008,6 +1052,7 @@ struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display,
10081052
struct fb_ops *fbops = NULL;
10091053
struct fb_deferred_io *fbdefio = NULL;
10101054
u8 *vmem = NULL;
1055+
u8 *vmem_back_buffers[FBTFT_VMEM_BUFS] = {NULL};
10111056
u8 *vmem_post_process = NULL;
10121057
void *txbuf = NULL;
10131058
void *buf = NULL;
@@ -1078,10 +1123,16 @@ struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display,
10781123

10791124
vmem_size = display->width * display->height * bpp / 8;
10801125
vmem = vzalloc(vmem_size);
1081-
if (!vmem)
1082-
goto alloc_fail;
1126+
for (i = 0; i < FBTFT_VMEM_BUFS; ++i)
1127+
{
1128+
vmem_back_buffers[i] = devm_kzalloc(dev, vmem_size, GFP_KERNEL);
1129+
if (!vmem_back_buffers[i])
1130+
goto alloc_fail;
1131+
}
10831132

1084-
vmem_post_process = kzalloc(vmem_size, GFP_DMA | GFP_KERNEL);
1133+
vmem_post_process = devm_kzalloc(dev, vmem_size, GFP_KERNEL);
1134+
//vmem_post_process = kzalloc(vmem_size, GFP_DMA | GFP_KERNEL);
1135+
//vmem_post_process = vzalloc(vmem_size);
10851136
if (!vmem_post_process)
10861137
goto alloc_fail;
10871138

@@ -1126,10 +1177,11 @@ struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display,
11261177

11271178
fbdefio->delay = HZ/fps;
11281179
fbdefio->deferred_io = fbtft_deferred_io;
1180+
fbdefio->first_io = fbtft_first_io;
11291181
fb_deferred_io_init(info);
11301182

1131-
// Overload
1132-
info->fbops->fb_mmap = fbtft_fb_deferred_io_mmap;
1183+
// Surcharge fb_mmap (after fb_deferred_io_init)
1184+
fbops->fb_mmap = fbtft_fb_deferred_io_mmap;
11331185

11341186
strncpy(info->fix.id, dev->driver->name, 16);
11351187
info->fix.type = FB_TYPE_PACKED_PIXELS;
@@ -1139,13 +1191,13 @@ struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display,
11391191
info->fix.ywrapstep = 0;
11401192
info->fix.line_length = width * bpp / 8;
11411193
info->fix.accel = FB_ACCEL_NONE;
1142-
info->fix.smem_len = vmem_size;
1194+
info->fix.smem_len = vmem_size*FBTFT_VMEM_BUFS;
11431195

11441196
info->var.rotate = pdata->rotate;
11451197
info->var.xres = width;
11461198
info->var.yres = height;
11471199
info->var.xres_virtual = info->var.xres;
1148-
info->var.yres_virtual = info->var.yres;
1200+
info->var.yres_virtual = info->var.yres*2; // So that SDL allows SDL_DOUBLEBUF
11491201
info->var.bits_per_pixel = bpp;
11501202
info->var.nonstd = 1;
11511203

@@ -1163,8 +1215,16 @@ struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display,
11631215

11641216
par = info->par;
11651217
par->info = info;
1218+
par->vmem_size = vmem_size;
1219+
for (i = 0; i < FBTFT_VMEM_BUFS; ++i)
1220+
{
1221+
par->vmem_back_buffers[i] = vmem_back_buffers[i];
1222+
}
11661223
par->vmem_post_process = vmem_post_process;
1167-
par->vmem_ptr = par->info->screen_buffer;
1224+
par->vmem_prev_buf_idx = 0;
1225+
par->vmem_cur_buf_idx = 0;
1226+
par->vmem_ptr = par->info->screen_buffer + (par->vmem_cur_buf_idx*par->vmem_size);
1227+
par->must_render = 0;
11681228
par->pdata = pdata;
11691229
pdata->par = par;
11701230
par->debug = display->debug;
@@ -1653,9 +1713,24 @@ static irqreturn_t irq_TE_handler(int irq_no, void *dev_id)
16531713
}
16541714
#endif //DEBUG_TE_IRQ_COUNT
16551715

1656-
if(pdata->par->ready_for_spi_async){
1657-
fbtft_start_new_screen_transfer_async(pdata->par);
1716+
if(!pdata->par->ready_for_spi_async)
1717+
return IRQ_HANDLED;
1718+
1719+
#if 0
1720+
if (pdata->par->must_render <= 0)
1721+
return IRQ_HANDLED;
1722+
/*static int prev_must_render = 0;
1723+
if (prev_must_render == pdata->par->must_render);
1724+
return IRQ_HANDLED;*/
1725+
1726+
pdata->par->must_render--;
1727+
if(pdata->par->must_render > 1024){
1728+
pdata->par->must_render=1;
16581729
}
1730+
prev_must_render = pdata->par->must_render;
1731+
#endif
1732+
1733+
fbtft_start_new_screen_transfer_async(pdata->par);
16591734

16601735
return IRQ_HANDLED;
16611736
}

drivers/staging/fbtft/fbtft-sysfs.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,25 @@ static ssize_t show_low_battery(struct device *device,
416416
static struct device_attribute low_battery_device_attr =
417417
__ATTR(low_battery, 0660, show_low_battery, store_low_battery);
418418

419+
static ssize_t store_switch_backbuf(struct device *device,
420+
struct device_attribute *attr,
421+
const char *buf, size_t count)
422+
{
423+
struct fb_info *fb_info = dev_get_drvdata(device);
424+
fbtft_flip_backbuffer(fb_info->par);
425+
426+
return count;
427+
}
428+
429+
static ssize_t show_switch_backbuf(struct device *device,
430+
struct device_attribute *attr, char *buf)
431+
{
432+
return 0;
433+
}
434+
435+
static struct device_attribute switch_backbuf_device_attr =
436+
__ATTR(switch_backbuf, 0660, show_switch_backbuf, store_switch_backbuf);
437+
419438
void fbtft_expand_debug_value(unsigned long *debug)
420439
{
421440
switch (*debug & 0x7) {
@@ -478,6 +497,7 @@ void fbtft_sysfs_init(struct fbtft_par *par)
478497
{
479498
device_create_file(par->info->dev, &debug_device_attr);
480499
device_create_file(par->info->dev, &low_battery_device_attr);
500+
device_create_file(par->info->dev, &switch_backbuf_device_attr);
481501
device_create_file(par->info->dev, &rotate_soft_device_attr);
482502
device_create_file(par->info->dev, &notification_device_attr);
483503
device_create_file(par->info->dev, &overlay_device_attrs[0]);
@@ -489,6 +509,7 @@ void fbtft_sysfs_exit(struct fbtft_par *par)
489509
{
490510
device_remove_file(par->info->dev, &debug_device_attr);
491511
device_remove_file(par->info->dev, &low_battery_device_attr);
512+
device_remove_file(par->info->dev, &switch_backbuf_device_attr);
492513
device_remove_file(par->info->dev, &rotate_soft_device_attr);
493514
device_remove_file(par->info->dev, &notification_device_attr);
494515
device_remove_file(par->info->dev, &overlay_device_attrs[0]);
Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,20 @@
2020
#include <linux/spi/spi.h>
2121
#include <linux/platform_device.h>
2222

23-
#define FBTFT_ONBOARD_BACKLIGHT 2
2423

25-
#define FBTFT_GPIO_NO_MATCH 0xFFFF
26-
#define FBTFT_GPIO_NAME_SIZE 32
24+
#define FBTFT_VMEM_BUFS 3
25+
26+
#define FBTFT_ONBOARD_BACKLIGHT 2
27+
#define FBTFT_GPIO_NO_MATCH 0xFFFF
28+
#define FBTFT_GPIO_NAME_SIZE 32
2729
#define FBTFT_MAX_INIT_SEQUENCE 512
2830
#define FBTFT_GAMMA_MAX_VALUES_TOTAL 128
29-
#define FBTFT_OVERLAY_NB_VALUES 4
31+
#define FBTFT_OVERLAY_NB_VALUES 4
3032

31-
#define FBTFT_NOTIF_MAX_SIZE 400
33+
#define FBTFT_NOTIF_MAX_SIZE 400
3234

33-
#define FBTFT_OF_INIT_CMD BIT(24)
34-
#define FBTFT_OF_INIT_DELAY BIT(25)
35+
#define FBTFT_OF_INIT_CMD BIT(24)
36+
#define FBTFT_OF_INIT_DELAY BIT(25)
3537

3638
/**
3739
* struct fbtft_gpio - Structure that holds one pinname to gpio mapping
@@ -224,6 +226,11 @@ struct fbtft_par {
224226
u8 *buf;
225227
u8 *vmem_ptr;
226228
u8 *vmem_post_process;
229+
u8 *vmem_back_buffers[FBTFT_VMEM_BUFS];
230+
u8 vmem_prev_buf_idx;
231+
u8 vmem_cur_buf_idx;
232+
int vmem_size;
233+
int must_render;
227234
u8 startbyte;
228235
struct fbtft_ops fbtftops;
229236
spinlock_t dirty_lock;
@@ -298,6 +305,7 @@ int fbtft_probe_common(struct fbtft_display *display, struct spi_device *sdev,
298305
int fbtft_remove_common(struct device *dev, struct fb_info *info);
299306
void fbtft_rotate_soft(u16 *mat, int size, int rotation);
300307
void fbtft_post_process_screen(struct fbtft_par *par);
308+
void fbtft_flip_backbuffer(struct fbtft_par *par);
301309

302310
/* fbtft-io.c */
303311
int fbtft_write_spi(struct fbtft_par *par, void *buf, size_t len);

0 commit comments

Comments
 (0)