From: Carlis <zhangxuez...@yulong.com>

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 <zhangxuez...@yulong.com>
---
v15: change ret value return logic in write_vmem.
v14: change to define TE completion and TE irq only in st7789v.
v13: change TE completion to par data struct member and add a new
     function to deal te gpio request, add new write_vmem function.
v12: change dev_err to dev_err_probe and add space in comments start, and
     delete te_mutex, change te wait logic.
v11: remove devm_gpio_put and change a dev_err to dev_info.
v10: additional notes.
v9: change pr_* to dev_*.
v8: delete a log line.
v7: return error value when request fail.
v6: add te gpio request fail deal logic.
v5: fix log print.
v4: modify some code style and change te irq set function name.
v3: modify author and signed-off-by name.
v2: add release te gpio after irq request fail.
---
 drivers/staging/fbtft/fb_st7789v.c | 115 +++++++++++++++++++++++++++++++++++++
 1 file changed, 115 insertions(+)

diff --git a/drivers/staging/fbtft/fb_st7789v.c 
b/drivers/staging/fbtft/fb_st7789v.c
index 3a280cc..abe9395 100644
--- a/drivers/staging/fbtft/fb_st7789v.c
+++ b/drivers/staging/fbtft/fb_st7789v.c
@@ -7,9 +7,13 @@
 
 #include <linux/bitops.h>
 #include <linux/delay.h>
+#include <linux/gpio/consumer.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
 #include <linux/module.h>
+
 #include <video/mipi_display.h>
 
 #include "fbtft.h"
@@ -66,6 +70,62 @@ enum st7789v_command {
 #define MADCTL_MX BIT(6) /* bitmask for column 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
  *
@@ -82,6 +142,12 @@ enum st7789v_command {
  */
 static int init_display(struct fbtft_par *par)
 {
+       int rc;
+
+       rc = init_tearing_effect_line(par);
+       if (rc)
+               return rc;
+
        /* turn off sleep mode */
        write_reg(par, MIPI_DCS_EXIT_SLEEP_MODE);
        mdelay(120);
@@ -137,6 +203,10 @@ static int init_display(struct fbtft_par *par)
         */
        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);
 
        if (HSD20_IPS)
@@ -145,6 +215,50 @@ static int init_display(struct fbtft_par *par)
        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
  *
@@ -259,6 +373,7 @@ static int blank(struct fbtft_par *par, bool on)
        .gamma = HSD20_IPS_GAMMA,
        .fbtftops = {
                .init_display = init_display,
+               .write_vmem = write_vmem,
                .set_var = set_var,
                .set_gamma = set_gamma,
                .blank = blank,
-- 
1.9.1

_______________________________________________
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

Reply via email to