From: "carlis.zhang_cp" zhangxuezhi1@yulong.com
For st7789v ic,add tearing signal detect to avoid screen tearing
Signed-off-by: carlis.zhang_cp zhangxuezhi1@yulong.com --- drivers/staging/fbtft/fb_st7789v.c | 133 ++++++++++++++++++++++++++++++++++++- drivers/staging/fbtft/fbtft.h | 1 + 2 files changed, 133 insertions(+), 1 deletion(-)
diff --git a/drivers/staging/fbtft/fb_st7789v.c b/drivers/staging/fbtft/fb_st7789v.c index 3a280cc..c687b58 100644 --- a/drivers/staging/fbtft/fb_st7789v.c +++ b/drivers/staging/fbtft/fb_st7789v.c @@ -9,9 +9,12 @@ #include <linux/delay.h> #include <linux/init.h> #include <linux/kernel.h> +#include <linux/mutex.h> +#include <linux/interrupt.h> +#include <linux/completion.h> #include <linux/module.h> #include <video/mipi_display.h> - +#include <linux/gpio/consumer.h> #include "fbtft.h"
#define DRVNAME "fb_st7789v" @@ -66,6 +69,38 @@ enum st7789v_command { #define MADCTL_MX BIT(6) /* bitmask for column address order */ #define MADCTL_MY BIT(7) /* bitmask for page address order */
+#define SPI_PANEL_TE_TIMEOUT 400 +static struct mutex te_mutex;/*mutex for tearing line*/ +static struct completion spi_panel_te; + +static irqreturn_t spi_panel_te_handler(int irq, void *data) +{ + complete(&spi_panel_te); + return IRQ_HANDLED; +} + +static void enable_spi_panel_te_irq(struct fbtft_par *par, bool enable) +{ + static int te_irq_count; + + if (!par->gpio.te) { + pr_err("%s:%d,SPI panel TE GPIO not configured\n", + __func__, __LINE__); + return; + } + + mutex_lock(&te_mutex); + + if (enable) { + if (++te_irq_count == 1) + enable_irq(gpiod_to_irq(par->gpio.te)); + } else { + if (--te_irq_count == 0) + disable_irq(gpiod_to_irq(par->gpio.te)); + } + mutex_unlock(&te_mutex); +} + /** * init_display() - initialize the display controller * @@ -82,6 +117,28 @@ enum st7789v_command { */ static int init_display(struct fbtft_par *par) { + int rc; + struct device *dev = par->info->device; + + par->gpio.te = devm_gpiod_get_index_optional(dev, "te", 0, GPIOD_IN); + if (par->gpio.te) { + init_completion(&spi_panel_te); + mutex_init(&te_mutex); + rc = devm_request_irq(dev, + gpiod_to_irq(par->gpio.te), + spi_panel_te_handler, IRQF_TRIGGER_RISING, + "TE_GPIO", par); + if (rc) { + pr_err("TE request_irq failed.\n"); + par->gpio.te = NULL; + } else { + disable_irq_nosync(gpiod_to_irq(par->gpio.te)); + pr_err("TE request_irq completion.\n"); + } + } else { + pr_err("%s:%d, TE gpio not specified\n", + __func__, __LINE__); + } /* turn off sleep mode */ write_reg(par, MIPI_DCS_EXIT_SLEEP_MODE); mdelay(120); @@ -137,6 +194,9 @@ static int init_display(struct fbtft_par *par) */ write_reg(par, PWCTRL1, 0xA4, 0xA1);
+ /*Tearing Effect Line On*/ + if (par->gpio.te) + write_reg(par, 0x35, 0x00); write_reg(par, MIPI_DCS_SET_DISPLAY_ON);
if (HSD20_IPS) @@ -145,6 +205,76 @@ static int init_display(struct fbtft_par *par) return 0; }
+/***************************************************************************** + * + * int (*write_vmem)(struct fbtft_par *par); + * + *****************************************************************************/ + +/* 16 bit pixel over 8-bit databus */ +int st7789v_write_vmem16_bus8(struct fbtft_par *par, size_t offset, size_t len) +{ + u16 *vmem16; + __be16 *txbuf16 = par->txbuf.buf; + size_t remain; + size_t to_copy; + size_t tx_array_size; + int i; + int rc, ret = 0; + size_t startbyte_size = 0; + + fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "st7789v ---%s(offset=%zu, len=%zu)\n", + __func__, offset, len); + + remain = len / 2; + vmem16 = (u16 *)(par->info->screen_buffer + offset); + + if (par->gpio.dc) + gpiod_set_value(par->gpio.dc, 1); + + /* non buffered write */ + if (!par->txbuf.buf) + return par->fbtftops.write(par, vmem16, len); + + /* buffered write */ + tx_array_size = par->txbuf.len / 2; + + if (par->startbyte) { + txbuf16 = par->txbuf.buf + 1; + tx_array_size -= 2; + *(u8 *)(par->txbuf.buf) = par->startbyte | 0x2; + startbyte_size = 1; + } + + while (remain) { + to_copy = min(tx_array_size, remain); + dev_dbg(par->info->device, " to_copy=%zu, remain=%zu\n", + to_copy, remain - to_copy); + + for (i = 0; i < to_copy; i++) + txbuf16[i] = cpu_to_be16(vmem16[i]); + + vmem16 = vmem16 + to_copy; + if (par->gpio.te) { + enable_spi_panel_te_irq(par, true); + reinit_completion(&spi_panel_te); + rc = wait_for_completion_timeout(&spi_panel_te, + msecs_to_jiffies(SPI_PANEL_TE_TIMEOUT)); + if (rc == 0) + pr_err("wait panel TE time out\n"); + } + ret = par->fbtftops.write(par, par->txbuf.buf, + startbyte_size + to_copy * 2); + if (par->gpio.te) + enable_spi_panel_te_irq(par, false); + if (ret < 0) + return ret; + remain -= to_copy; + } + + return ret; +} + /** * set_var() - apply LCD properties like rotation and BGR mode * @@ -259,6 +389,7 @@ static int blank(struct fbtft_par *par, bool on) .gamma = HSD20_IPS_GAMMA, .fbtftops = { .init_display = init_display, + .write_vmem = st7789v_write_vmem16_bus8, .set_var = set_var, .set_gamma = set_gamma, .blank = blank, diff --git a/drivers/staging/fbtft/fbtft.h b/drivers/staging/fbtft/fbtft.h index 76f8c09..93bac05 100644 --- a/drivers/staging/fbtft/fbtft.h +++ b/drivers/staging/fbtft/fbtft.h @@ -212,6 +212,7 @@ struct fbtft_par { struct gpio_desc *wr; struct gpio_desc *latch; struct gpio_desc *cs; + struct gpio_desc *te; struct gpio_desc *db[16]; struct gpio_desc *led[16]; struct gpio_desc *aux[16];
On Sun, Jan 24, 2021 at 11:35:37PM +0800, Carlis wrote:
It quite confused me that enable actually disables. I always feel like it's clearer to write these as two separate functions.
This is always checked in the caller. And it's when it's NULL that means it's deliberate so don't print a message.
devm_gpiod_get_index_optional() can return NULL or error pointers. If it returns NULL then don't print an error message. NULL reports are deliberate.
par->gpio.te = devm_gpiod_get_index_optional(dev, "te", 0, GPIOD_IN); if (IS_ERR(par->gpio.te)) { pr_err("%s:%d, TE gpio not specified\n", __func__, __LINE__); return PTR_ERR(par->gpio.te); }
if (par->gpio.te) {
Why is this printing an error message if devm_request_irq() succeeds?
Delete one of these "rc" or "rec" variables.
Line break is whacky.
Shouldn't this be "return len;" or something?
regards, dan carpenter
On Tue, 26 Jan 2021 10:54:41 +0300 Dan Carpenter dan.carpenter@oracle.com wrote:
OK,i will fix in patch v4
regards, zhangxuezhi
dri-devel@lists.freedesktop.org