Commit b0020d8a authored by Marko Kohtala's avatar Marko Kohtala Committed by Bartlomiej Zolnierkiewicz

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: default avatarMarko 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: default avatarBartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190618074111.9309-5-marko.kohtala@okoko.fi
parent dd978283
...@@ -150,10 +150,11 @@ static void ssd1307fb_update_display(struct ssd1307fb_par *par) ...@@ -150,10 +150,11 @@ static void ssd1307fb_update_display(struct ssd1307fb_par *par)
{ {
struct ssd1307fb_array *array; struct ssd1307fb_array *array;
u8 *vmem = par->info->screen_buffer; 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; int i, j, k;
array = ssd1307fb_alloc_array(par->width * par->height / 8, array = ssd1307fb_alloc_array(par->width * pages, SSD1307FB_DATA);
SSD1307FB_DATA);
if (!array) if (!array)
return; return;
...@@ -186,22 +187,24 @@ static void ssd1307fb_update_display(struct ssd1307fb_par *par) ...@@ -186,22 +187,24 @@ static void ssd1307fb_update_display(struct ssd1307fb_par *par)
* (5) A4 B4 C4 D4 E4 F4 G4 H4 * (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++) { for (j = 0; j < par->width; j++) {
int m = 8;
u32 array_idx = i * par->width + j; u32 array_idx = i * par->width + j;
array->data[array_idx] = 0; array->data[array_idx] = 0;
for (k = 0; k < 8; k++) { /* Last page may be partial */
u32 page_length = par->width * i; if (i + 1 == pages && par->height % 8)
u32 index = page_length + (par->width * k + j) / 8; m = par->height % 8;
u8 byte = *(vmem + index); for (k = 0; k < m; k++) {
u8 bit = byte & (1 << (j % 8)); u8 byte = vmem[(8 * i + k) * line_length +
bit = bit >> (j % 8); j / 8];
u8 bit = (byte >> (j % 8)) & 1;
array->data[array_idx] |= bit << k; 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); kfree(array);
} }
...@@ -437,7 +440,8 @@ static int ssd1307fb_init(struct ssd1307fb_par *par) ...@@ -437,7 +440,8 @@ static int ssd1307fb_init(struct ssd1307fb_par *par)
return ret; return ret;
ret = ssd1307fb_write_cmd(par->client, 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) if (ret < 0)
return ret; return ret;
...@@ -615,7 +619,7 @@ static int ssd1307fb_probe(struct i2c_client *client, ...@@ -615,7 +619,7 @@ static int ssd1307fb_probe(struct i2c_client *client,
par->dclk_div = par->device_info->default_dclk_div; par->dclk_div = par->device_info->default_dclk_div;
par->dclk_frq = par->device_info->default_dclk_frq; 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, vmem = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
get_order(vmem_size)); get_order(vmem_size));
...@@ -638,7 +642,7 @@ static int ssd1307fb_probe(struct i2c_client *client, ...@@ -638,7 +642,7 @@ static int ssd1307fb_probe(struct i2c_client *client,
info->fbops = &ssd1307fb_ops; info->fbops = &ssd1307fb_ops;
info->fix = ssd1307fb_fix; 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->fbdefio = ssd1307fb_defio;
info->var = ssd1307fb_var; info->var = ssd1307fb_var;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment