added linux patch for fbtft: 0024_TE_irq_no_more_tearing.patch

This commit is contained in:
vincent 2020-09-26 02:16:25 +02:00
parent 4c6e586bff
commit d95fba5154

View File

@ -0,0 +1,394 @@
From fc4a5c2f32f088e23d0078d2e1867ed6708b66f3 Mon Sep 17 00:00:00 2001
From: vincent <vbusoenseirb@gmail.com>
Date: Sat, 26 Sep 2020 02:11:52 +0200
Subject: [PATCH] fbtft with TE working
---
arch/arm/boot/dts/sun8i-v3s-funkey.dts | 1 +
drivers/staging/fbtft/fb_st7789v.c | 10 ++-
drivers/staging/fbtft/fbtft-bus.c | 22 ++++--
drivers/staging/fbtft/fbtft-core.c | 128 ++++++++++++++++++++++++++-------
drivers/staging/fbtft/fbtft.h | 3 +
5 files changed, 129 insertions(+), 35 deletions(-)
diff --git a/arch/arm/boot/dts/sun8i-v3s-funkey.dts b/arch/arm/boot/dts/sun8i-v3s-funkey.dts
index 20f9913..24e26b2 100644
--- a/arch/arm/boot/dts/sun8i-v3s-funkey.dts
+++ b/arch/arm/boot/dts/sun8i-v3s-funkey.dts
@@ -186,6 +186,7 @@
buswidth = <8>;
reset-gpios = <&pio 1 2 GPIO_ACTIVE_HIGH>; //PB2
dc-gpios = <&pio 2 0 GPIO_ACTIVE_LOW>; //PC0 (MISO)
+ te-irq = <&pio 1 1 GPIO_ACTIVE_LOW>; //PB1
debug = <0>;
};
};
diff --git a/drivers/staging/fbtft/fb_st7789v.c b/drivers/staging/fbtft/fb_st7789v.c
index e2c9078..f33f8e3 100755
--- a/drivers/staging/fbtft/fb_st7789v.c
+++ b/drivers/staging/fbtft/fb_st7789v.c
@@ -52,6 +52,8 @@
* out as well to avoid duplicate entries.
*/
enum st7789v_command {
+ TEOFF = 0x34,
+ TEON = 0x35,
PORCTRL = 0xB2,
GCTRL = 0xB7,
VCOMS = 0xBB,
@@ -153,10 +155,14 @@ static int init_display(struct fbtft_par *par)
/* Display Inversion of colors */
write_reg(par, 0x21);
+ /* Activate TE signal for Vsync only */
+ write_reg(par, TEON, 0x00);
+
/* refresh rate */
//write_reg(par, 0xC6,0x1F); //39Hz
//write_reg(par, 0xC6,0x1A); //44Hz
- //write_reg(par, 0xC6,0x17); //48Hz
+ //write_reg(par, 0xC6,0x18); //46Hz
+ write_reg(par, 0xC6,0x17); //48Hz
//write_reg(par, 0xC6,0x16); //49Hz
//write_reg(par, 0xC6,0x15); //50Hz
//write_reg(par, 0xC6,0x14); //52Hz
@@ -165,7 +171,7 @@ static int init_display(struct fbtft_par *par)
//write_reg(par, 0xC6,0x0F); //60Hz
//write_reg(par, 0xC6,0x09); //60Hz
//write_reg(par, 0xC6,0x03); //99Hz
- write_reg(par, 0xC6,0x02); //105Hz
+ //write_reg(par, 0xC6,0x02); //105Hz -> good one when no TE signal
write_reg(par, MIPI_DCS_SET_DISPLAY_ON);
diff --git a/drivers/staging/fbtft/fbtft-bus.c b/drivers/staging/fbtft/fbtft-bus.c
index ce865ed..801cdf4 100644
--- a/drivers/staging/fbtft/fbtft-bus.c
+++ b/drivers/staging/fbtft/fbtft-bus.c
@@ -124,6 +124,10 @@ void fbtft_write_reg8_bus9(struct fbtft_par *par, int len, ...)
int fbtft_start_new_screen_transfer_async(struct fbtft_par *par){
//printk("%s\n", __func__);
+ if(par->pdata->te_irq && !par->ready_for_spi_async){
+ return -1;
+ }
+
if(lock){
return -1;
}
@@ -135,8 +139,8 @@ int fbtft_start_new_screen_transfer_async(struct fbtft_par *par){
}*/
/* Debug fps */
-#define FPS_DEBUG 1
-#if FPS_DEBUG
+//#define FPS_DEBUG
+#ifdef FPS_DEBUG
long fps;
ktime_t ts_now = ktime_get();
@@ -153,13 +157,13 @@ int fbtft_start_new_screen_transfer_async(struct fbtft_par *par){
par->nb_fps_values++;
if(par->nb_fps_values == 200){
- fbtft_par_dbg(DEBUG_TIME_EACH_UPDATE, par,
- "Display update: fps=%ld\n", par->avg_fps/par->nb_fps_values);
+ /*fbtft_par_dbg(DEBUG_TIME_EACH_UPDATE, par,
+ "Display update: fps=%ld\n", par->avg_fps/par->nb_fps_values);*/
+ printk("Display update: fps=%ld\n", par->avg_fps/par->nb_fps_values);
par->avg_fps = 0;
par->nb_fps_values = 0;
}
}
-
#endif //FPS_DEBUG
/* Post process screen for doufle buf cpy, notifs, rotation soft... */
@@ -350,7 +354,9 @@ static void spi_complete_data_write(void *arg)
/* Start sending cmd init data */
par->odd_line = !par->odd_line;
lock = false;
- fbtft_start_new_screen_transfer_async(par);
+ if(!par->pdata->te_irq){
+ fbtft_start_new_screen_transfer_async(par);
+ }
}
else{
write_line_start += 2;
@@ -362,7 +368,9 @@ static void spi_complete_data_write(void *arg)
}
else{
lock = false;
- fbtft_start_new_screen_transfer_async(par);
+ if(!par->pdata->te_irq){
+ fbtft_start_new_screen_transfer_async(par);
+ }
}
}
diff --git a/drivers/staging/fbtft/fbtft-core.c b/drivers/staging/fbtft/fbtft-core.c
index bcfa8c4..b362bc0 100755
--- a/drivers/staging/fbtft/fbtft-core.c
+++ b/drivers/staging/fbtft/fbtft-core.c
@@ -37,6 +37,7 @@
#include <video/mipi_display.h>
#include <linux/hrtimer.h>
#include <linux/list.h>
+#include <linux/interrupt.h>
/* to support deferred IO */
#include <linux/rmap.h>
@@ -432,12 +433,16 @@ static void fbtft_update_display(struct fbtft_par *par, unsigned int start_line,
fbtft_par_dbg(DEBUG_UPDATE_DISPLAY, par, "%s(start_line=%u, end_line=%u)\n",
__func__, start_line, end_line);
- par->fbtftops.set_addr_win(par, 0, start_line,
- par->info->var.xres - 1, end_line);
- /*if (par->fbtftops.set_addr_win){
+
+ if(par->pdata->rotate == 90){
par->fbtftops.set_addr_win(par, 80, start_line,
- 320 - 1, end_line);
- }*/
+ 320 - 1, end_line);
+ }
+ else{
+ par->fbtftops.set_addr_win(par, 0, start_line,
+ par->info->var.xres - 1, end_line);
+ }
+
}
/* Send cmd to start transfer */
@@ -500,7 +505,7 @@ void fbtft_rotate_soft(u16 *mat, int size, int rotation){
mat[AT(i, j)] = mat[AT(N - 1 - j, i)];
mat[AT(N - 1 - j, i)] = mat[AT(N - 1 - i, N - 1 - j)];
mat[AT(N - 1 - i, N - 1 - j)] = mat[AT(j, N - 1 - i)];
- mat[AT(j, N - 1 - i)] = temp;
+ mat[AT(j, N - 1 - i)] = temp;
}
}
}
@@ -524,7 +529,7 @@ static void fbtft_mkdirty(struct fb_info *info, int y, int height)
struct fbtft_par *par = info->par;
struct fb_deferred_io *fbdefio = info->fbdefio;
- /* This disables fbtft's defered io, useful in spi_asyn mode or
+ /* This disables fbtft's defered io, useful in spi_async mode or
if any other driver handles screens updates instead of fbtft */
if (par->spi_async_mode){
return;
@@ -554,9 +559,12 @@ void fbtft_post_process_screen(struct fbtft_par *par){
bool screen_post_process = false;
/* bypass */
+//#define FORCE_POSTPROCESS
+#ifdef FORCE_POSTPROCESS
screen_post_process = true;
par->write_line_start = 0;
par->write_line_end = par->info->var.yres-1;
+#endif //FORCE_POSTPROCESS
/* If soft rotation, mark whole screen to update to avoid data non rotated */
if(par->pdata->rotate_soft)
@@ -594,6 +602,15 @@ void fbtft_post_process_screen(struct fbtft_par *par){
par->vmem_ptr = par->vmem_post_process;
/* Copy buffer */
+ /* This should be handled using a double buffer (or triple depending on game fps vs screen fps) */
+ /* pointed by par->info->screen_buffer. The buffer pointed (the one being written) should */
+ /* change using the FBIOPAN_DISPLAY ioctl called by SDL_Flip() (in FB_FlipHWSurface) */
+ /* This is a dirty but very efficient alternative for now: we make a quick memcpy of the */
+ /* screen_buffer in another one. It goes so fast that the "applicative" */
+ /* tearing that could happen if this function were to launch in the middle of a */
+ /* user space SDL_BlitSurface(sw_surface, NULL, hw_surface, NULL) call */
+ /* is so unbelievably rare that completey unnoticeable and it takes up so little CPU */
+ /* that really, it's worth the compromise for now */
memcpy(par->vmem_post_process + par->write_line_start * par->info->fix.line_length,
par->info->screen_buffer + par->write_line_start * par->info->fix.line_length,
(par->write_line_end-par->write_line_start+1) * par->info->fix.line_length);
@@ -623,6 +640,9 @@ void fbtft_post_process_screen(struct fbtft_par *par){
fbtft_rotate_soft((u16*)par->vmem_post_process, par->info->var.yres, par->pdata->rotate_soft);
}
}
+ else{
+ par->vmem_ptr = par->info->screen_buffer;
+ }
}
static void fbtft_deferred_io(struct fb_info *info, struct list_head *pagelist)
@@ -690,31 +710,19 @@ static void fbtft_deferred_io(struct fb_info *info, struct list_head *pagelist)
}
/* Copy buffer */
- if(dirty_lines_start!=0 || dirty_lines_end!=par->info->var.yres - 1){
+ /*if(dirty_lines_start!=0 || dirty_lines_end!=par->info->var.yres - 1){
printk("dirty_lines_start = %d, dirty_lines_end = %d\n", dirty_lines_start, dirty_lines_end);
- }
+ }*/
/*dirty_lines_start = 0;
dirty_lines_end = par->info->var.yres - 1;*/
par->write_line_start = dirty_lines_start;
par->write_line_end = dirty_lines_end;
- memcpy(par->vmem_post_process + dirty_lines_start * par->info->fix.line_length,
- par->info->screen_buffer + dirty_lines_start * par->info->fix.line_length,
- (dirty_lines_end-dirty_lines_start+1) * par->info->fix.line_length);
- par->vmem_ptr = par->vmem_post_process;
+ /* Post process screen for doufle buf cpy, notifs, rotation soft... */
+ fbtft_post_process_screen(par);
- /* Exit in SPI async mode, otherwise update screen now */
- if (par->spi_async_mode){
- fbtft_start_new_screen_transfer_async(par);
- return;
- }
- else{
- /* Post process screen for doufle buf cpy, notifs, rotation soft... */
- fbtft_post_process_screen(par);
-
- /* Screen upgrade */
- par->fbtftops.update_display(par, dirty_lines_start, dirty_lines_end);
- }
+ /* Screen upgrade */
+ par->fbtftops.update_display(par, dirty_lines_start, dirty_lines_end);
}
static void fbtft_fb_fillrect(struct fb_info *info,
@@ -1182,11 +1190,13 @@ struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display,
par->vmem_post_process = vmem_post_process;
par->vmem_ptr = par->info->screen_buffer;
par->pdata = pdata;
+ pdata->par = par;
par->debug = display->debug;
par->buf = buf;
spin_lock_init(&par->dirty_lock);
par->bgr = pdata->bgr;
par->spi_async_mode = pdata->spi_async_mode;
+ par->ready_for_spi_async = false;
par->interlacing = pdata->interlacing;
par->startbyte = pdata->startbyte;
par->init_sequence = init_sequence;
@@ -1648,10 +1658,40 @@ static u32 fbtft_of_value(struct device_node *node, const char *propname)
return val;
}
+
+static irqreturn_t irq_TE_handler(int irq_no, void *dev_id)
+{
+ struct fbtft_platform_data *pdata = (struct fbtft_platform_data *) dev_id;
+
+//#define DEBUG_TE_IRQ_COUNT
+#ifdef DEBUG_TE_IRQ_COUNT
+ static ktime_t prev_ts = 0;
+ static int te_count = 0;
+ static int nb_sec = 5;
+ te_count++;
+
+ ktime_t ts_now = ktime_get();
+ if(ktime_us_delta(ts_now, prev_ts) > nb_sec*1000000){
+ prev_ts = ts_now;
+ printk("TE irq: %d times/sec\n", te_count/nb_sec);
+ te_count = 0;
+ }
+#endif //DEBUG_TE_IRQ_COUNT
+
+ fbtft_start_new_screen_transfer_async(pdata->par);
+
+ return IRQ_HANDLED;
+}
+
+
+
static struct fbtft_platform_data *fbtft_probe_dt(struct device *dev)
{
struct device_node *node = dev->of_node;
struct fbtft_platform_data *pdata;
+ int gpio, irq_id, err;
+ enum of_gpio_flags of_flags;
+ char *te_irq_name;
if (!node) {
dev_err(dev, "Missing platform data or DT\n");
@@ -1685,6 +1725,37 @@ static struct fbtft_platform_data *fbtft_probe_dt(struct device *dev)
pdata->display.fbtftops.init_display = fbtft_init_display_dt;
pdata->display.fbtftops.request_gpios = fbtft_request_gpios_dt;
+ /* TE signal for Vsync */
+ pdata->te_irq = false;
+ te_irq_name = "te-irq";
+ if (of_find_property(node, te_irq_name, NULL)) {
+ gpio = of_get_named_gpio_flags(node, te_irq_name, 0, &of_flags);
+ if (gpio == -ENOENT || gpio == -EPROBE_DEFER || gpio < 0) {
+ dev_err(dev,
+ "failed to get '%s' from DT\n", te_irq_name);
+ }
+ else{
+ pr_info("%s: '%s' = GPIO%d\n", __func__, te_irq_name, gpio);
+
+ irq_id = gpio_to_irq(gpio);
+ if(irq_id < 0) {
+ dev_err(dev,"%s - Unable to request IRQ: %d\n", __func__, irq_id);
+ }
+ else{
+ pr_info("TE GPIO%d, IRQ id = %d\n", gpio, irq_id);
+
+ err = request_irq(irq_id, irq_TE_handler, IRQF_SHARED | IRQF_TRIGGER_RISING,
+ "TE", pdata);
+ if (err < 0) {
+ dev_err(dev,"ERROR initializing TE signal irq\n");
+ }
+ else{
+ pdata->te_irq = true;
+ }
+ }
+ }
+ }
+
return pdata;
}
#else
@@ -1817,7 +1888,12 @@ int fbtft_probe_common(struct fbtft_display *display,
/* Start constant Display update using spi async*/
par->write_line_start = 0;
par->write_line_end = par->info->var.yres - 1;
- fbtft_start_new_screen_transfer_async(par);
+ if(par->pdata->te_irq){
+ par->ready_for_spi_async = true;
+ }
+ else{
+ fbtft_start_new_screen_transfer_async(par);
+ }
}
return 0;
diff --git a/drivers/staging/fbtft/fbtft.h b/drivers/staging/fbtft/fbtft.h
index 64dec83..8a9daee 100644
--- a/drivers/staging/fbtft/fbtft.h
+++ b/drivers/staging/fbtft/fbtft.h
@@ -154,12 +154,14 @@ struct fbtft_platform_data {
unsigned long rotate_soft;
bool bgr;
bool spi_async_mode;
+ bool te_irq;
bool interlacing;
unsigned int fps;
int txbuflen;
u8 startbyte;
char *gamma;
void *extra;
+ struct fbtft_par *par;
};
/**
@@ -263,6 +265,7 @@ struct fbtft_par {
/* SPI async */
bool spi_async_mode;
+ bool ready_for_spi_async;
bool interlacing;
bool odd_line;
int cur_line;
--
1.9.1