Write tagged line
This commit is contained in:
parent
8c566d8422
commit
c0132fdba2
114
sharp.c
114
sharp.c
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user