mirror of
https://github.com/FunKey-Project/FunKey-OS.git
synced 2025-12-12 15:48:51 +01:00
added linux patch for fbtft: 0024_TE_irq_no_more_tearing.patch
This commit is contained in:
parent
4c6e586bff
commit
d95fba5154
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user