From 66c09308856048a242083279c8c428f962313d32 Mon Sep 17 00:00:00 2001 From: Martijn Versteegh Date: Wed, 29 Nov 2017 00:00:02 +0100 Subject: [PATCH 1/3] fbtft: Add a sysfs parameter to set the vertical scrolling position on a window. Add a sysfs param scroll_pos which sets the scanline where the display starts for 'rolling scrolling'. This needs support from the specific display driver as well. When supported it can be used to implement smooth vertical (when the display is in portrait mode) hor horizontal (when the display is used in landscape mode) scrolling by strategically changing the start scanline of the display and erasing/redrawing only the wrapping part. This way you never need to redraw what's already there, preventing slow full screen redraws over spi. --- drivers/staging/fbtft/fbtft-core.c | 3 +++ drivers/staging/fbtft/fbtft-sysfs.c | 39 +++++++++++++++++++++++++++++ drivers/staging/fbtft/fbtft.h | 2 ++ 3 files changed, 44 insertions(+) diff --git a/drivers/staging/fbtft/fbtft-core.c b/drivers/staging/fbtft/fbtft-core.c index 587f68aa466c2e..38b3313e9f7c57 100644 --- a/drivers/staging/fbtft/fbtft-core.c +++ b/drivers/staging/fbtft/fbtft-core.c @@ -623,6 +623,9 @@ static void fbtft_merge_fbtftops(struct fbtft_ops *dst, struct fbtft_ops *src) dst->set_var = src->set_var; if (src->set_gamma) dst->set_gamma = src->set_gamma; + if (src->set_scroll) + dst->set_scroll = src->set_scroll; + } /** diff --git a/drivers/staging/fbtft/fbtft-sysfs.c b/drivers/staging/fbtft/fbtft-sysfs.c index 8d8bd12b90a1d3..ddcdfe1723f0b2 100644 --- a/drivers/staging/fbtft/fbtft-sysfs.c +++ b/drivers/staging/fbtft/fbtft-sysfs.c @@ -204,9 +204,46 @@ static ssize_t show_debug(struct device *device, static struct device_attribute debug_device_attr = \ __ATTR(debug, 0660, show_debug, store_debug); + + +static ssize_t store_scroll(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + struct fbtft_par *par = fb_info->par; + int ret; + + ret = kstrtoul(buf, 10, &par->scroll_pos); + + if (ret) + return ret; + + if (par->fbtftops.set_scroll) + par->fbtftops.set_scroll(par); + + + return count; +} + +static ssize_t show_scroll(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + struct fbtft_par *par = fb_info->par; + + return snprintf(buf, PAGE_SIZE, "%lu\n", par->scroll_pos); +} + +static struct device_attribute scroll_pos_device_attr = \ + __ATTR(scroll_pos, 0660, show_scroll, store_scroll); + + void fbtft_sysfs_init(struct fbtft_par *par) { device_create_file(par->info->dev, &debug_device_attr); + if (par->fbtftops.set_scroll) + device_create_file(par->info->dev, &scroll_pos_device_attr); if (par->gamma.curves && par->fbtftops.set_gamma) device_create_file(par->info->dev, &gamma_device_attrs[0]); } @@ -214,6 +251,8 @@ void fbtft_sysfs_init(struct fbtft_par *par) void fbtft_sysfs_exit(struct fbtft_par *par) { device_remove_file(par->info->dev, &debug_device_attr); + if (par->fbtftops.set_scroll) + device_remove_file(par->info->dev, &scroll_pos_device_attr); if (par->gamma.curves && par->fbtftops.set_gamma) device_remove_file(par->info->dev, &gamma_device_attrs[0]); } diff --git a/drivers/staging/fbtft/fbtft.h b/drivers/staging/fbtft/fbtft.h index 89c4b5b76ce69d..0c935c23118542 100644 --- a/drivers/staging/fbtft/fbtft.h +++ b/drivers/staging/fbtft/fbtft.h @@ -93,6 +93,7 @@ struct fbtft_ops { int (*set_var)(struct fbtft_par *par); int (*set_gamma)(struct fbtft_par *par, unsigned long *curves); + void (*set_scroll)(struct fbtft_par *par); }; /** @@ -240,6 +241,7 @@ struct fbtft_par { bool first_update_done; ktime_t update_time; bool bgr; + unsigned long scroll_pos; void *extra; }; From 4a6fd8d6d2af879f8bfe179485cd9a52d336786a Mon Sep 17 00:00:00 2001 From: Martijn Versteegh Date: Wed, 29 Nov 2017 00:05:37 +0100 Subject: [PATCH 2/3] fbtft: Implement the scroll_pos sysfs param for the HX8357D fbtft driver. --- drivers/staging/fbtft/fb_hx8357d.c | 11 +++++++++++ drivers/staging/fbtft/fb_hx8357d.h | 3 +++ 2 files changed, 14 insertions(+) diff --git a/drivers/staging/fbtft/fb_hx8357d.c b/drivers/staging/fbtft/fb_hx8357d.c index 32e6efe1d0a79c..f5e9278ed61b31 100644 --- a/drivers/staging/fbtft/fb_hx8357d.c +++ b/drivers/staging/fbtft/fb_hx8357d.c @@ -127,6 +127,9 @@ static int init_display(struct fbtft_par *par) /* tear line */ write_reg(par, MIPI_DCS_SET_TEAR_SCANLINE, 0x00, 0x02); + /* set scrolling are to whole screen*/ + write_reg(par, HX8357D_VSCRDEF, 0x00, 0x00, 0x1, 0xE0, 0x00, 0x00); + /* Exit Sleep */ write_reg(par, MIPI_DCS_EXIT_SLEEP_MODE); msleep(150); @@ -182,9 +185,16 @@ static int set_var(struct fbtft_par *par) /* Memory Access Control */ write_reg(par, MIPI_DCS_SET_ADDRESS_MODE, val); + write_reg(par, HX8357D_VSCRADD, ((par->scroll_pos) >> 8) & 0xFF, (par->scroll_pos) & 0xFF); + return 0; } +static void set_scroll(struct fbtft_par *par) +{ + write_reg(par, HX8357D_VSCRADD, ((par->scroll_pos) >> 8) & 0xFF, (par->scroll_pos) & 0xFF); +} + static struct fbtft_display display = { .regwidth = 8, .width = WIDTH, @@ -195,6 +205,7 @@ static struct fbtft_display display = { .init_display = init_display, .set_addr_win = set_addr_win, .set_var = set_var, + .set_scroll = set_scroll, }, }; diff --git a/drivers/staging/fbtft/fb_hx8357d.h b/drivers/staging/fbtft/fb_hx8357d.h index e281921d4a975a..20888eec219dd8 100644 --- a/drivers/staging/fbtft/fb_hx8357d.h +++ b/drivers/staging/fbtft/fb_hx8357d.h @@ -22,6 +22,9 @@ #define HX8357_TFTWIDTH 320 #define HX8357_TFTHEIGHT 480 +#define HX8357D_VSCRDEF 0x33 +#define HX8357D_VSCRADD 0x37 + #define HX8357_SETOSC 0xB0 #define HX8357_SETPWR1 0xB1 #define HX8357B_SETDISPLAY 0xB2 From d57f30000a45204df77a4a6e3695176a843dc053 Mon Sep 17 00:00:00 2001 From: Martijn Versteegh Date: Wed, 29 Nov 2017 11:16:50 +0100 Subject: [PATCH 3/3] Don't write to tft registers from sysfs store handler. Writing to registers of the device directly from the sysfs store handler leads to race conditions with updating the screen. Just set the variable and update the scroll pos from the next update_display call. This means the scrolling might not actually happen until you draw something to the screen. But as scrolling without drawing a new scanline is not very useful anyway this is a minor annoyance. --- drivers/staging/fbtft/fbtft-core.c | 5 +++++ drivers/staging/fbtft/fbtft-sysfs.c | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/staging/fbtft/fbtft-core.c b/drivers/staging/fbtft/fbtft-core.c index 38b3313e9f7c57..86c07355c49640 100644 --- a/drivers/staging/fbtft/fbtft-core.c +++ b/drivers/staging/fbtft/fbtft-core.c @@ -358,6 +358,11 @@ static void fbtft_update_display(struct fbtft_par *par, unsigned int start_line, } } + if (par->fbtftops.set_scroll) + { + par->fbtftops.set_scroll(par); + } + /* Sanity checks */ if (start_line > end_line) { dev_warn(par->info->device, diff --git a/drivers/staging/fbtft/fbtft-sysfs.c b/drivers/staging/fbtft/fbtft-sysfs.c index ddcdfe1723f0b2..89e8b80abfb0aa 100644 --- a/drivers/staging/fbtft/fbtft-sysfs.c +++ b/drivers/staging/fbtft/fbtft-sysfs.c @@ -219,8 +219,8 @@ static ssize_t store_scroll(struct device *device, if (ret) return ret; - if (par->fbtftops.set_scroll) - par->fbtftops.set_scroll(par); +// if (par->fbtftops.set_scroll) +// par->fbtftops.set_scroll(par); return count;