Write tagged line

This commit is contained in:
Andrew D'Angelo 2023-06-09 15:04:58 -05:00
parent 8c566d8422
commit c0132fdba2

114
sharp.c
View File

@ -29,13 +29,13 @@
#include <drm/drm_probe_helper.h> #include <drm/drm_probe_helper.h>
#include <drm/drm_simple_kms_helper.h> #include <drm/drm_simple_kms_helper.h>
#define CMD_WRITE_LINE 0b10000000
#define CMD_CLEAR_SCREEN 0b00100000
#define GPIO_DISP 22 #define GPIO_DISP 22
#define GPIO_SCS 8 #define GPIO_SCS 8
#define GPIO_VCOM 23 #define GPIO_VCOM 23
#define CMD_WRITE_LINE 0b10000000
#define CMD_CLEAR_SCREEN 0b00100000
struct sharp_memory_panel { struct sharp_memory_panel {
struct drm_device drm; struct drm_device drm;
struct drm_simple_display_pipe pipe; struct drm_simple_display_pipe pipe;
@ -72,32 +72,22 @@ static void vcom_timer_callback(struct timer_list *t)
static int sharp_memory_spi_clear_screen(struct sharp_memory_panel *panel) static int sharp_memory_spi_clear_screen(struct sharp_memory_panel *panel)
{ {
struct spi_transfer tr[1] = {}; int rc;
int ret; unsigned char tx_buf[2];
u8 *command_buf; struct spi_transfer tr;
command_buf = kmalloc(2, GFP_KERNEL); // Create screen clear command SPI transfer
if (!command_buf) { tx_buf[0] = CMD_CLEAR_SCREEN;
return -ENOMEM; tx_buf[1] = 0;
} tr.tx_buf = &tx_buf;
tr.len = 2;
// Clear screen command and trailer
command_buf[0] = CMD_CLEAR_SCREEN;
command_buf[1] = 0;
tr[0].tx_buf = command_buf;
tr[0].len = 2;
ndelay(80); ndelay(80);
gpio_set_value(GPIO_SCS, 1); gpio_set_value(GPIO_SCS, 1);
ret = spi_sync_transfer(panel->spi, tr, 1); rc = spi_sync_transfer(panel->spi, &tr, 1);
gpio_set_value(GPIO_SCS, 0); gpio_set_value(GPIO_SCS, 0);
goto out_free; return rc;
out_free:
kfree(command_buf);
return ret;
} }
static inline u8 sharp_memory_reverse_byte(u8 b) static inline u8 sharp_memory_reverse_byte(u8 b)
@ -108,8 +98,8 @@ static inline u8 sharp_memory_reverse_byte(u8 b)
return b; return b;
} }
static int sharp_memory_spi_write_line(struct sharp_memory_panel *panel, static int sharp_memory_spi_write_tagged_line(struct sharp_memory_panel *panel,
size_t y, const void *line_data, size_t len) const void *line_data, size_t len)
{ {
void *tx_buf = NULL; void *tx_buf = NULL;
struct spi_transfer tr[3] = {}; struct spi_transfer tr[3] = {};
@ -126,11 +116,10 @@ static int sharp_memory_spi_write_line(struct sharp_memory_panel *panel,
return -ENOMEM; return -ENOMEM;
} }
// Write line at line Y command // Write line command
command_buf[0] = CMD_WRITE_LINE; command_buf[0] = 0b10000000;
command_buf[1] = sharp_memory_reverse_byte((u8)(y + 1)); // Indexed from 1
tr[0].tx_buf = command_buf; tr[0].tx_buf = command_buf;
tr[0].len = 2; tr[0].len = 1;
// Line data // Line data
tx_buf = kmemdup(line_data, len, GFP_KERNEL); tx_buf = kmemdup(line_data, len, GFP_KERNEL);
@ -139,7 +128,7 @@ static int sharp_memory_spi_write_line(struct sharp_memory_panel *panel,
// Trailer // Trailer
tr[2].tx_buf = trailer_buf; tr[2].tx_buf = trailer_buf;
tr[2].len = 2; tr[2].len = 1;
ndelay(80); ndelay(80);
gpio_set_value(GPIO_SCS, 1); gpio_set_value(GPIO_SCS, 1);
@ -156,35 +145,58 @@ out_free:
return ret; return ret;
} }
static void sharp_memory_gray8_to_mono_reversed(u8 *buf, size_t len) static size_t sharp_memory_gray8_to_mono_tagged(u8 *buf, int width, int height, int y0)
{ {
size_t i, j; int line, b8, b1;
unsigned char b; unsigned char d;
for (i = 0; i < len; i += 8) { int const tagged_line_len = 2 + width / 8;
b = 0;
for (j = 0; j < 8; j++) { // Iterate over lines from [0, height)
if (buf[i + j] & BIT(7)) { for (line = 0; line < height; line++) {
b |= 0b10000000 >> j;
// Iterate over chunks of 8 source grayscale bytes
// Each 8-byte source chunk will map to one destination mono byte
for (b8 = 0; b8 < width; b8 += 8) {
d = 0;
// Iterate over each of the 8 grayscale bytes in the chunk
// Build up the destination mono byte
for (b1 = 0; b1 < 8; b1++) {
if (buf[(line * width) + b8 + b1] & BIT(7)) {
d |= 0b10000000 >> b1;
} }
} }
buf[i / 8] = b;
// Without the line number and trailer tags, each destination
// mono line would have a length `width / 8`. However, we are
// inserting the line number at the beginning of the line and
// the zero-byte trailer at the end.
// So the destination mono line is at index
// `line * tagged_line_len = line * (2 + width / 8)`
// The destination mono byte is offset by 1 to make room for
// the line tag, written at the end of converting the current
// line.
buf[(line * tagged_line_len) + 1 + (b8 / 8)] = d;
} }
// Write the line number and trailer tags
buf[line * tagged_line_len] = sharp_memory_reverse_byte((u8)(y0 + 1)); // Indexed from 1
buf[(line * tagged_line_len) + tagged_line_len - 1] = 0;
y0++;
}
return height * tagged_line_len;
} }
// Use DMA to get grayscale representation, then convert to mono // Use DMA to get grayscale representation, then convert to mono
// Output is stored in `buf`, which must be at least W*H bytes // Output is stored in `buf`, which must be at least W*H bytes
static int sharp_memory_clip_mono(u8* buf, static int sharp_memory_clip_mono(size_t* result_len, u8* buf,
struct drm_framebuffer *fb, struct drm_rect const* clip) struct drm_framebuffer *fb, struct drm_rect const* clip)
{ {
int rc; int rc;
struct drm_gem_dma_object *dma_obj; struct drm_gem_dma_object *dma_obj;
size_t clip_len;
struct iosys_map dst, vmap; struct iosys_map dst, vmap;
// buf is the size of the whole screen, but only the clip region
// is copied from framebuffer
clip_len = (clip->y2 - clip->y1) * fb->width;
// Get GEM memory manager // Get GEM memory manager
dma_obj = drm_fb_dma_get_gem_obj(fb, 0); dma_obj = drm_fb_dma_get_gem_obj(fb, 0);
@ -204,7 +216,8 @@ static int sharp_memory_clip_mono(u8* buf,
drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE); drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE);
// Convert in-place from 8-bit grayscale to mono // Convert in-place from 8-bit grayscale to mono
sharp_memory_gray8_to_mono_reversed(buf, clip_len); *result_len = sharp_memory_gray8_to_mono_tagged(buf,
(clip->x2 - clip->x1), (clip->y2 - clip->y1), clip->y1);
// Success // Success
return 0; return 0;
@ -217,6 +230,7 @@ static int sharp_memory_fb_dirty(struct drm_framebuffer *fb,
struct drm_rect clip; struct drm_rect clip;
struct sharp_memory_panel *panel; struct sharp_memory_panel *panel;
int drm_idx; int drm_idx;
size_t buf_len;
u8 *line; u8 *line;
int y; int y;
@ -234,8 +248,8 @@ static int sharp_memory_fb_dirty(struct drm_framebuffer *fb,
return -ENODEV; return -ENODEV;
} }
// Get mono contents of `clip` // Get mono contents of `clip` with line number tags
rc = sharp_memory_clip_mono(panel->buf, fb, &clip); rc = sharp_memory_clip_mono(&buf_len, panel->buf, fb, &clip);
if (rc) { if (rc) {
goto out_exit; goto out_exit;
} }
@ -243,8 +257,8 @@ static int sharp_memory_fb_dirty(struct drm_framebuffer *fb,
// Write mono data to display // Write mono data to display
line = panel->buf; line = panel->buf;
for (y = clip.y1; y < clip.y2; y++) { for (y = clip.y1; y < clip.y2; y++) {
sharp_memory_spi_write_line(panel, y, line, fb->width / 8); sharp_memory_spi_write_tagged_line(panel, line, fb->width / 8 + 2);
line += (fb->width / 8); line += 2 + (fb->width / 8);
} }
// Success // Success