staging: fbtft: add tearing signal detect

For st7789v IC, when we need continuous full screen refresh, it is best to
wait for the tearing effect line signal to arrive to avoid screen tearing.

Signed-off-by: Carlis <zhangxuezhi1@yulong.com>
Link: https://lore.kernel.org/r/1612706517-124617-1-git-send-email-zhangxuezhi3@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Carlis 2021-02-07 22:01:57 +08:00 committed by Greg Kroah-Hartman
parent 95897fdf1f
commit fa7d3e66f6

View File

@ -7,9 +7,13 @@
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/completion.h>
#include <linux/module.h> #include <linux/module.h>
#include <video/mipi_display.h> #include <video/mipi_display.h>
#include "fbtft.h" #include "fbtft.h"
@ -66,6 +70,62 @@ enum st7789v_command {
#define MADCTL_MX BIT(6) /* bitmask for column address order */ #define MADCTL_MX BIT(6) /* bitmask for column address order */
#define MADCTL_MY BIT(7) /* bitmask for page address order */ #define MADCTL_MY BIT(7) /* bitmask for page address order */
/* 60Hz for 16.6ms, configured as 2*16.6ms */
#define PANEL_TE_TIMEOUT_MS 33
static struct completion panel_te; /* completion for panel TE line */
static int irq_te; /* Linux IRQ for LCD TE line */
static irqreturn_t panel_te_handler(int irq, void *data)
{
complete(&panel_te);
return IRQ_HANDLED;
}
/*
* init_tearing_effect_line() - init tearing effect line.
* @par: FBTFT parameter object.
*
* Return: 0 on success, or a negative error code otherwise.
*/
static int init_tearing_effect_line(struct fbtft_par *par)
{
struct device *dev = par->info->device;
struct gpio_desc *te;
int rc, irq;
te = gpiod_get_optional(dev, "te", GPIOD_IN);
if (IS_ERR(te))
return dev_err_probe(dev, PTR_ERR(te), "Failed to request te GPIO\n");
/* if te is NULL, indicating no configuration, directly return success */
if (!te) {
irq_te = 0;
return 0;
}
irq = gpiod_to_irq(te);
/* GPIO is locked as an IRQ, we may drop the reference */
gpiod_put(te);
if (irq < 0)
return irq;
irq_te = irq;
init_completion(&panel_te);
/* The effective state is high and lasts no more than 1000 microseconds */
rc = devm_request_irq(dev, irq_te, panel_te_handler,
IRQF_TRIGGER_RISING, "TE_GPIO", par);
if (rc)
return dev_err_probe(dev, rc, "TE IRQ request failed.\n");
disable_irq_nosync(irq_te);
return 0;
}
/** /**
* init_display() - initialize the display controller * init_display() - initialize the display controller
* *
@ -82,6 +142,12 @@ enum st7789v_command {
*/ */
static int init_display(struct fbtft_par *par) static int init_display(struct fbtft_par *par)
{ {
int rc;
rc = init_tearing_effect_line(par);
if (rc)
return rc;
/* turn off sleep mode */ /* turn off sleep mode */
write_reg(par, MIPI_DCS_EXIT_SLEEP_MODE); write_reg(par, MIPI_DCS_EXIT_SLEEP_MODE);
mdelay(120); mdelay(120);
@ -137,6 +203,10 @@ static int init_display(struct fbtft_par *par)
*/ */
write_reg(par, PWCTRL1, 0xA4, 0xA1); write_reg(par, PWCTRL1, 0xA4, 0xA1);
/* TE line output is off by default when powering on */
if (irq_te)
write_reg(par, MIPI_DCS_SET_TEAR_ON, 0x00);
write_reg(par, MIPI_DCS_SET_DISPLAY_ON); write_reg(par, MIPI_DCS_SET_DISPLAY_ON);
if (HSD20_IPS) if (HSD20_IPS)
@ -145,6 +215,50 @@ static int init_display(struct fbtft_par *par)
return 0; return 0;
} }
/*
* write_vmem() - write data to display.
* @par: FBTFT parameter object.
* @offset: offset from screen_buffer.
* @len: the length of data to be writte.
*
* Return: 0 on success, or a negative error code otherwise.
*/
static int write_vmem(struct fbtft_par *par, size_t offset, size_t len)
{
struct device *dev = par->info->device;
int ret;
if (irq_te) {
enable_irq(irq_te);
reinit_completion(&panel_te);
ret = wait_for_completion_timeout(&panel_te,
msecs_to_jiffies(PANEL_TE_TIMEOUT_MS));
if (ret == 0)
dev_err(dev, "wait panel TE timeout\n");
disable_irq(irq_te);
}
switch (par->pdata->display.buswidth) {
case 8:
ret = fbtft_write_vmem16_bus8(par, offset, len);
break;
case 9:
ret = fbtft_write_vmem16_bus9(par, offset, len);
break;
case 16:
ret = fbtft_write_vmem16_bus16(par, offset, len);
break;
default:
dev_err(dev, "Unsupported buswidth %d\n",
par->pdata->display.buswidth);
ret = 0;
break;
}
return ret;
}
/** /**
* set_var() - apply LCD properties like rotation and BGR mode * set_var() - apply LCD properties like rotation and BGR mode
* *
@ -259,6 +373,7 @@ static struct fbtft_display display = {
.gamma = HSD20_IPS_GAMMA, .gamma = HSD20_IPS_GAMMA,
.fbtftops = { .fbtftops = {
.init_display = init_display, .init_display = init_display,
.write_vmem = write_vmem,
.set_var = set_var, .set_var = set_var,
.set_gamma = set_gamma, .set_gamma = set_gamma,
.blank = blank, .blank = blank,