Skip to content

Commit cc79971

Browse files
committed
fbtft: add TE IRQ to remove all tearing
Signed-off-by: Vincent-FK <vincent.buso@funkey-project.com>
1 parent 00903c8 commit cc79971

5 files changed

Lines changed: 120 additions & 27 deletions

File tree

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@
184184
buswidth = <8>;
185185
reset-gpios = <&pio 1 2 GPIO_ACTIVE_HIGH>; //PB2
186186
dc-gpios = <&pio 2 0 GPIO_ACTIVE_LOW>; //PC0 (MISO)
187+
te-irq = <&pio 1 1 GPIO_ACTIVE_LOW>; //PB1
187188
debug = <0>;
188189
};
189190
};

drivers/staging/fbtft/fb_st7789v.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@
5252
* out as well to avoid duplicate entries.
5353
*/
5454
enum st7789v_command {
55+
TEOFF = 0x34,
56+
TEON = 0x35,
5557
PORCTRL = 0xB2,
5658
GCTRL = 0xB7,
5759
VCOMS = 0xBB,
@@ -152,19 +154,23 @@ static int init_display(struct fbtft_par *par)
152154
/* Display Inversion of colors */
153155
write_reg(par, 0x21);
154156

157+
/* Activate TE signal for Vsync only */
158+
write_reg(par, TEON, 0x00);
159+
155160
/* refresh rate */
156161
//write_reg(par, 0xC6,0x1F); //39Hz
157162
//write_reg(par, 0xC6,0x1A); //44Hz
158-
//write_reg(par, 0xC6,0x17); //48Hz
163+
//write_reg(par, 0xC6,0x18); //46Hz
164+
write_reg(par, 0xC6,0x17); //48Hz
159165
//write_reg(par, 0xC6,0x16); //49Hz
160166
//write_reg(par, 0xC6,0x15); //50Hz
161167
//write_reg(par, 0xC6,0x14); //52Hz
162168
//write_reg(par, 0xC6,0x12); //55Hz
163169
//write_reg(par, 0xC6,0x10); //58Hz
164-
//write_reg(par, 0xC6,0x0F); //60H
170+
//write_reg(par, 0xC6,0x0F); //60Hz
165171
//write_reg(par, 0xC6,0x09); //60Hz
166172
//write_reg(par, 0xC6,0x03); //99Hz
167-
write_reg(par, 0xC6,0x02); //105Hz
173+
//write_reg(par, 0xC6,0x02); //105Hz -> good one when no TE signal
168174

169175
write_reg(par, MIPI_DCS_SET_DISPLAY_ON);
170176

drivers/staging/fbtft/fbtft-bus.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -117,13 +117,15 @@ static bool lock = false;
117117
int fbtft_start_new_screen_transfer_async(struct fbtft_par *par)
118118
{
119119
// printk("%s\n", __func__);
120+
if (par->pdata->te_irq && !par->ready_for_spi_async)
121+
return -1;
120122
if (lock)
121123
return -1;
122124
lock = true;
123125

124126
/* Debug fps */
125-
#define FPS_DEBUG 1
126-
#if FPS_DEBUG
127+
//#define FPS_DEBUG
128+
#ifdef FPS_DEBUG
127129
long fps;
128130
ktime_t ts_now = ktime_get();
129131

@@ -290,7 +292,8 @@ static void spi_complete_data_write(void *arg)
290292
/* Start sending cmd init data */
291293
par->odd_line = !par->odd_line;
292294
lock = false;
293-
fbtft_start_new_screen_transfer_async(par);
295+
if (!par->pdata->te_irq)
296+
fbtft_start_new_screen_transfer_async(par);
294297
} else {
295298
write_line_start += 2;
296299
write_line_end = write_line_start;
@@ -300,7 +303,8 @@ static void spi_complete_data_write(void *arg)
300303
}
301304
} else {
302305
lock = false;
303-
fbtft_start_new_screen_transfer_async(par);
306+
if (!par->pdata->te_irq)
307+
fbtft_start_new_screen_transfer_async(par);
304308
}
305309
}
306310

drivers/staging/fbtft/fbtft-core.c

Lines changed: 99 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include <video/mipi_display.h>
3838
#include <linux/hrtimer.h>
3939
#include <linux/list.h>
40+
#include <linux/interrupt.h>
4041

4142
/* to support deferred IO */
4243
#include <linux/rmap.h>
@@ -425,7 +426,11 @@ static void fbtft_update_display(struct fbtft_par *par, unsigned int start_line,
425426

426427
fbtft_par_dbg(DEBUG_UPDATE_DISPLAY, par, "%s(start_line=%u, end_line=%u)\n",
427428
__func__, start_line, end_line);
428-
par->fbtftops.set_addr_win(par, 0, start_line,
429+
if (par->pdata->rotate == 90)
430+
par->fbtftops.set_addr_win(par, 80, start_line,
431+
320 - 1, end_line);
432+
else
433+
par->fbtftops.set_addr_win(par, 0, start_line,
429434
par->info->var.xres - 1, end_line);
430435
}
431436

@@ -510,7 +515,7 @@ static void fbtft_mkdirty(struct fb_info *info, int y, int height)
510515
struct fbtft_par *par = info->par;
511516
struct fb_deferred_io *fbdefio = info->fbdefio;
512517

513-
/* This disables fbtft's defered io, useful in spi_asyn mode or
518+
/* This disables fbtft's defered io, useful in spi_async mode or
514519
if any other driver handles screens updates instead of fbtft */
515520
if (par->spi_async_mode)
516521
return;
@@ -540,9 +545,12 @@ void fbtft_post_process_screen(struct fbtft_par *par)
540545
bool screen_post_process = false;
541546

542547
/* bypass */
548+
//#define FORCE_POSTPROCESS
549+
#ifdef FORCE_POSTPROCESS
543550
screen_post_process = true;
544551
par->write_line_start = 0;
545552
par->write_line_end = par->info->var.yres - 1;
553+
#endif //FORCE_POSTPROCESS
546554

547555
/* If soft rotation, mark whole screen to update to avoid data
548556
non rotated */
@@ -573,6 +581,22 @@ void fbtft_post_process_screen(struct fbtft_par *par)
573581
par->vmem_ptr = par->vmem_post_process;
574582

575583
/* Copy buffer */
584+
585+
/* This should be handled using a double buffer (or
586+
triple depending on game fps vs screen fps) pointed
587+
by par->info->screen_buffer. The buffer pointed
588+
(the one being written) should change using the
589+
FBIOPAN_DISPLAY ioctl called by SDL_Flip() (in
590+
FB_FlipHWSurface). This is a dirty but very
591+
efficient alternative for now: we make a quick
592+
memcpy of the screen_buffer in another one. It goes
593+
so fast that the "applicative" tearing that could
594+
happen if this function were to launch in the
595+
middle of a user space SDL_BlitSurface(sw_surface,
596+
NULL, hw_surface, NULL) call is so unbelievably
597+
rare that completey unnoticeable and it takes up so
598+
little CPU that really, it's worth the compromise
599+
for now */
576600
memcpy(par->vmem_post_process + par->write_line_start * par->info->fix.line_length,
577601
par->info->screen_buffer + par->write_line_start * par->info->fix.line_length,
578602
(par->write_line_end-par->write_line_start + 1) * par->info->fix.line_length);
@@ -598,7 +622,8 @@ void fbtft_post_process_screen(struct fbtft_par *par)
598622
/* Soft rotation */
599623
if (par->pdata->rotate_soft)
600624
fbtft_rotate_soft((u16*)par->vmem_post_process, par->info->var.yres, par->pdata->rotate_soft);
601-
}
625+
} else
626+
par->vmem_ptr = par->info->screen_buffer;
602627
}
603628

604629
static void fbtft_deferred_io(struct fb_info *info, struct list_head *pagelist)
@@ -666,26 +691,14 @@ static void fbtft_deferred_io(struct fb_info *info, struct list_head *pagelist)
666691
}
667692

668693
/* Copy buffer */
669-
if (dirty_lines_start!=0 || dirty_lines_end!=par->info->var.yres - 1)
670-
printk("dirty_lines_start = %d, dirty_lines_end = %d\n", dirty_lines_start, dirty_lines_end);
671694
par->write_line_start = dirty_lines_start;
672695
par->write_line_end = dirty_lines_end;
673-
memcpy(par->vmem_post_process + dirty_lines_start * par->info->fix.line_length,
674-
par->info->screen_buffer + dirty_lines_start * par->info->fix.line_length,
675-
(dirty_lines_end-dirty_lines_start + 1) * par->info->fix.line_length);
676-
par->vmem_ptr = par->vmem_post_process;
677696

678-
/* Exit in SPI async mode, otherwise update screen now */
679-
if (par->spi_async_mode) {
680-
fbtft_start_new_screen_transfer_async(par);
681-
return;
682-
} else {
683-
/* Post process screen for doufle buf cpy, notifs, rotation soft... */
684-
fbtft_post_process_screen(par);
697+
/* Post process screen for doufle buf cpy, notifs, rotation soft... */
698+
fbtft_post_process_screen(par);
685699

686-
/* Screen upgrade */
687-
par->fbtftops.update_display(par, dirty_lines_start, dirty_lines_end);
688-
}
700+
/* Screen upgrade */
701+
par->fbtftops.update_display(par, dirty_lines_start, dirty_lines_end);
689702
}
690703

691704
static void fbtft_fb_fillrect(struct fb_info *info,
@@ -1150,11 +1163,13 @@ struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display,
11501163
par->vmem_post_process = vmem_post_process;
11511164
par->vmem_ptr = par->info->screen_buffer;
11521165
par->pdata = pdata;
1166+
pdata->par = par;
11531167
par->debug = display->debug;
11541168
par->buf = buf;
11551169
spin_lock_init(&par->dirty_lock);
11561170
par->bgr = pdata->bgr;
11571171
par->spi_async_mode = pdata->spi_async_mode;
1172+
par->ready_for_spi_async = false;
11581173
par->interlacing = pdata->interlacing;
11591174
par->startbyte = pdata->startbyte;
11601175
par->init_sequence = init_sequence;
@@ -1615,10 +1630,40 @@ static u32 fbtft_of_value(struct device_node *node, const char *propname)
16151630
return val;
16161631
}
16171632

1633+
1634+
static irqreturn_t irq_TE_handler(int irq_no, void *dev_id)
1635+
{
1636+
struct fbtft_platform_data *pdata = (struct fbtft_platform_data *) dev_id;
1637+
1638+
//#define DEBUG_TE_IRQ_COUNT
1639+
#ifdef DEBUG_TE_IRQ_COUNT
1640+
static ktime_t prev_ts = 0;
1641+
static int te_count = 0;
1642+
static int nb_sec = 5;
1643+
te_count++;
1644+
1645+
ktime_t ts_now = ktime_get();
1646+
if(ktime_us_delta(ts_now, prev_ts) > nb_sec*1000000){
1647+
prev_ts = ts_now;
1648+
printk("TE irq: %d times/sec\n", te_count/nb_sec);
1649+
te_count = 0;
1650+
}
1651+
#endif //DEBUG_TE_IRQ_COUNT
1652+
1653+
fbtft_start_new_screen_transfer_async(pdata->par);
1654+
1655+
return IRQ_HANDLED;
1656+
}
1657+
1658+
1659+
16181660
static struct fbtft_platform_data *fbtft_probe_dt(struct device *dev)
16191661
{
16201662
struct device_node *node = dev->of_node;
16211663
struct fbtft_platform_data *pdata;
1664+
int gpio, irq_id, err;
1665+
enum of_gpio_flags of_flags;
1666+
char *te_irq_name;
16221667

16231668
if (!node) {
16241669
dev_err(dev, "Missing platform data or DT\n");
@@ -1652,6 +1697,37 @@ static struct fbtft_platform_data *fbtft_probe_dt(struct device *dev)
16521697
pdata->display.fbtftops.init_display = fbtft_init_display_dt;
16531698
pdata->display.fbtftops.request_gpios = fbtft_request_gpios_dt;
16541699

1700+
/* TE signal for Vsync */
1701+
pdata->te_irq = false;
1702+
te_irq_name = "te-irq";
1703+
if (of_find_property(node, te_irq_name, NULL)) {
1704+
gpio = of_get_named_gpio_flags(node, te_irq_name, 0, &of_flags);
1705+
if (gpio == -ENOENT || gpio == -EPROBE_DEFER || gpio < 0) {
1706+
dev_err(dev,
1707+
"failed to get '%s' from DT\n", te_irq_name);
1708+
}
1709+
else{
1710+
pr_info("%s: '%s' = GPIO%d\n", __func__, te_irq_name, gpio);
1711+
1712+
irq_id = gpio_to_irq(gpio);
1713+
if(irq_id < 0) {
1714+
dev_err(dev,"%s - Unable to request IRQ: %d\n", __func__, irq_id);
1715+
}
1716+
else{
1717+
pr_info("TE GPIO%d, IRQ id = %d\n", gpio, irq_id);
1718+
1719+
err = request_irq(irq_id, irq_TE_handler, IRQF_SHARED | IRQF_TRIGGER_RISING,
1720+
"TE", pdata);
1721+
if (err < 0) {
1722+
dev_err(dev,"ERROR initializing TE signal irq\n");
1723+
}
1724+
else{
1725+
pdata->te_irq = true;
1726+
}
1727+
}
1728+
}
1729+
}
1730+
16551731
return pdata;
16561732
}
16571733
#else
@@ -1783,7 +1859,10 @@ int fbtft_probe_common(struct fbtft_display *display,
17831859
/* Start constant Display update using spi async */
17841860
par->write_line_start = 0;
17851861
par->write_line_end = par->info->var.yres - 1;
1786-
fbtft_start_new_screen_transfer_async(par);
1862+
if (par->pdata->te_irq)
1863+
par->ready_for_spi_async = true;
1864+
else
1865+
fbtft_start_new_screen_transfer_async(par);
17871866
}
17881867
return 0;
17891868

drivers/staging/fbtft/fbtft.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,12 +154,14 @@ struct fbtft_platform_data {
154154
unsigned long rotate_soft;
155155
bool bgr;
156156
bool spi_async_mode;
157+
bool te_irq;
157158
bool interlacing;
158159
unsigned int fps;
159160
int txbuflen;
160161
u8 startbyte;
161162
char *gamma;
162163
void *extra;
164+
struct fbtft_par *par;
163165
};
164166

165167
/**
@@ -263,6 +265,7 @@ struct fbtft_par {
263265

264266
/* SPI async */
265267
bool spi_async_mode;
268+
bool ready_for_spi_async;
266269
bool interlacing;
267270
bool odd_line;
268271
int cur_line;

0 commit comments

Comments
 (0)