summaryrefslogtreecommitdiffstats
path: root/drivers/video/fbdev
diff options
context:
space:
mode:
authorMarko Kohtala <marko.kohtala@okoko.fi>2019-06-18 10:41:09 +0300
committerBartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>2019-07-23 17:18:19 +0200
commitb0020d8af991a904de57dbd9a7bc7a61982a6a8c (patch)
tree8644811d4e2be773dcb84185f3c84e0053be198b /drivers/video/fbdev
parentdd9782834dd9dde3624ff1acea8859f3d3e792d4 (diff)
downloadlinux-stable-b0020d8af991a904de57dbd9a7bc7a61982a6a8c.tar.gz
linux-stable-b0020d8af991a904de57dbd9a7bc7a61982a6a8c.tar.bz2
linux-stable-b0020d8af991a904de57dbd9a7bc7a61982a6a8c.zip
video: ssd1307fb: Handle width and height that are not multiple of 8
Some displays have dimensions that are not multiple of eight, for example height of 36, but the driver divided the dimensions by 8. Defining display to the next multiple of 8 is not good as then the display registers get configured to dimensions that do not match. This contradicts intructions by some display manufacturers. Use DIV_ROUND_UP to multiple of 8 when needed so correct values can be used. The ssd1307fb_update_display bit reordering receives a simplification in the process. Signed-off-by: Marko Kohtala <marko.kohtala@okoko.fi> Cc: Mark Rutland <mark.rutland@arm.com> Cc: Rob Herring <robh+dt@kernel.org> Cc: Daniel Vetter <daniel@ffwll.ch> Cc: David Airlie <airlied@linux.ie> Cc: Michal Vokáč <michal.vokac@ysoft.com> Signed-off-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com> Link: https://patchwork.freedesktop.org/patch/msgid/20190618074111.9309-5-marko.kohtala@okoko.fi
Diffstat (limited to 'drivers/video/fbdev')
-rw-r--r--drivers/video/fbdev/ssd1307fb.c30
1 files changed, 17 insertions, 13 deletions
diff --git a/drivers/video/fbdev/ssd1307fb.c b/drivers/video/fbdev/ssd1307fb.c
index 4f911480f2eb..8e0720444467 100644
--- a/drivers/video/fbdev/ssd1307fb.c
+++ b/drivers/video/fbdev/ssd1307fb.c
@@ -150,10 +150,11 @@ static void ssd1307fb_update_display(struct ssd1307fb_par *par)
{
struct ssd1307fb_array *array;
u8 *vmem = par->info->screen_buffer;
+ unsigned int line_length = par->info->fix.line_length;
+ unsigned int pages = DIV_ROUND_UP(par->height, 8);
int i, j, k;
- array = ssd1307fb_alloc_array(par->width * par->height / 8,
- SSD1307FB_DATA);
+ array = ssd1307fb_alloc_array(par->width * pages, SSD1307FB_DATA);
if (!array)
return;
@@ -186,22 +187,24 @@ static void ssd1307fb_update_display(struct ssd1307fb_par *par)
* (5) A4 B4 C4 D4 E4 F4 G4 H4
*/
- for (i = 0; i < (par->height / 8); i++) {
+ for (i = 0; i < pages; i++) {
for (j = 0; j < par->width; j++) {
+ int m = 8;
u32 array_idx = i * par->width + j;
array->data[array_idx] = 0;
- for (k = 0; k < 8; k++) {
- u32 page_length = par->width * i;
- u32 index = page_length + (par->width * k + j) / 8;
- u8 byte = *(vmem + index);
- u8 bit = byte & (1 << (j % 8));
- bit = bit >> (j % 8);
+ /* Last page may be partial */
+ if (i + 1 == pages && par->height % 8)
+ m = par->height % 8;
+ for (k = 0; k < m; k++) {
+ u8 byte = vmem[(8 * i + k) * line_length +
+ j / 8];
+ u8 bit = (byte >> (j % 8)) & 1;
array->data[array_idx] |= bit << k;
}
}
}
- ssd1307fb_write_array(par->client, array, par->width * par->height / 8);
+ ssd1307fb_write_array(par->client, array, par->width * pages);
kfree(array);
}
@@ -437,7 +440,8 @@ static int ssd1307fb_init(struct ssd1307fb_par *par)
return ret;
ret = ssd1307fb_write_cmd(par->client,
- par->page_offset + (par->height / 8) - 1);
+ par->page_offset +
+ DIV_ROUND_UP(par->height, 8) - 1);
if (ret < 0)
return ret;
@@ -615,7 +619,7 @@ static int ssd1307fb_probe(struct i2c_client *client,
par->dclk_div = par->device_info->default_dclk_div;
par->dclk_frq = par->device_info->default_dclk_frq;
- vmem_size = par->width * par->height / 8;
+ vmem_size = DIV_ROUND_UP(par->width, 8) * par->height;
vmem = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
get_order(vmem_size));
@@ -638,7 +642,7 @@ static int ssd1307fb_probe(struct i2c_client *client,
info->fbops = &ssd1307fb_ops;
info->fix = ssd1307fb_fix;
- info->fix.line_length = par->width / 8;
+ info->fix.line_length = DIV_ROUND_UP(par->width, 8);
info->fbdefio = ssd1307fb_defio;
info->var = ssd1307fb_var;