From e119f271350c7eb5da50908196f05704feda011a Mon Sep 17 00:00:00 2001 From: root Date: Sun, 27 Dec 2015 20:15:45 +0000 Subject: first working version --- master/eink-auto-update | 418 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 418 insertions(+) create mode 100644 master/eink-auto-update (limited to 'master/eink-auto-update') diff --git a/master/eink-auto-update b/master/eink-auto-update new file mode 100644 index 0000000..de9f574 --- /dev/null +++ b/master/eink-auto-update @@ -0,0 +1,418 @@ +diff --git a/drivers/video/mxc/mxc_epdc_fb.c b/drivers/video/mxc/mxc_epdc_fb.c +index 39de51d..511c980 100644 +--- a/drivers/video/mxc/mxc_epdc_fb.c ++++ b/drivers/video/mxc/mxc_epdc_fb.c +@@ -47,6 +47,9 @@ + #include + #include + #include ++#include ++#include ++ + #include + #include + #include +@@ -140,10 +143,17 @@ uint32_t aa_time_stamp[2]; + + #define NUM_SCREENS_MIN 2 + ++#if 0 + #define EPDC_V1_NUM_LUTS 16 + #define EPDC_V1_MAX_NUM_UPDATES 20 + #define EPDC_V2_NUM_LUTS 64 + #define EPDC_V2_MAX_NUM_UPDATES 64 ++#else ++#define EPDC_V1_NUM_LUTS 16 ++#define EPDC_V1_MAX_NUM_UPDATES 2 ++#define EPDC_V2_NUM_LUTS 64 ++#define EPDC_V2_MAX_NUM_UPDATES 6 ++#endif + #define EPDC_MAX_NUM_BUFFERS 2 + #define INVALID_LUT (-1) + #define DRY_RUN_NO_LUT 100 +@@ -187,6 +197,9 @@ static int vcom_nominal; + + static unsigned long default_bpp = 16; + ++static int *_line_ranges; // temporary buffer for calculating which line ranges needs to be updated ++static u16 *_blocksCRC16; // CRC16 checksum of every 16x8 pixel block ++ + struct update_marker_data { + struct list_head full_list; + struct list_head upd_list; +@@ -4775,6 +4788,29 @@ static int mxc_epdc_fb_ioctl(struct fb_info *info, unsigned int cmd, + return ret; + } + ++// calculates CRC16 of 8x8 pixel block ++static u16 calcBlockCRC16(struct mxc_epdc_fb_data *fb_data, u16 x, u16 y) ++{ ++ int bpp = fb_data->epdc_fb_var.bits_per_pixel / 8; ++ int src_stride = fb_data->epdc_fb_var.xres_virtual * bpp; ++ unsigned char *src_ptr; ++ u16 res; ++ ++ src_ptr = fb_data->info.screen_base + fb_data->fb_offset + y * src_stride + x * bpp; ++ ++ res = crc16(0, src_ptr, 8 * bpp); src_ptr += src_stride; ++ res = crc16(res, src_ptr, 8 * bpp); src_ptr += src_stride; ++ res = crc16(res, src_ptr, 8 * bpp); src_ptr += src_stride; ++ res = crc16(res, src_ptr, 8 * bpp); src_ptr += src_stride; ++ res = crc16(res, src_ptr, 8 * bpp); src_ptr += src_stride; ++ res = crc16(res, src_ptr, 8 * bpp); src_ptr += src_stride; ++ res = crc16(res, src_ptr, 8 * bpp); src_ptr += src_stride; ++ res = crc16(res, src_ptr, 8 * bpp); ++ ++ return res; ++} ++ ++#if 0 + static void mxc_epdc_fb_update_pages(struct mxc_epdc_fb_data *fb_data, + u16 y1, u16 y2) + { +@@ -4793,7 +4829,141 @@ static void mxc_epdc_fb_update_pages(struct mxc_epdc_fb_data *fb_data, + + mxc_epdc_fb_send_update(&update, &fb_data->info); + } ++#else ++ ++ ++static void refresh_whole_screen(struct mxc_epdc_fb_data *fb_data) ++{ ++ struct mxcfb_update_data update; ++ int x, y; ++ u16 *crcFB; ++ ++ GALLEN_DBGLOCAL_BEGIN(); ++ ++ /* Do full screen update */ ++ update.update_region.left = 0; ++ update.update_region.width = fb_data->epdc_fb_var.xres; ++ update.update_region.top = 0; ++ update.update_region.height = fb_data->epdc_fb_var.yres; ++ update.waveform_mode = WAVEFORM_MODE_AUTO; ++ update.update_mode = UPDATE_MODE_FULL; ++ update.update_marker = 0; ++ update.temp = TEMP_USE_AMBIENT; ++ update.flags = 0; ++ ++ // update crc checksums ++ crcFB = _blocksCRC16; ++ for (y = 0; y < fb_data->epdc_fb_var.yres; y += 8) ++ { ++ for (x = 0; x < fb_data->epdc_fb_var.xres; x += 8) ++ { ++ *crcFB++ = calcBlockCRC16(fb_data, x, y); ++ } ++ } ++ ++ // refresh screen ++ mxc_epdc_fb_send_update(&update, &fb_data->info); ++ ++ GALLEN_DBGLOCAL_END(); ++} + ++ ++static void mxc_epdc_fb_update_pages(struct mxc_epdc_fb_data *fb_data, ++ u16 y1, u16 y2) ++{ ++ struct mxcfb_update_data update; ++ int x, y, first_x; ++ int low_y; ++ int high_y; ++ u16 crc; ++ u16 *crcFB; ++ bool change; ++ ++ /* Do partial screen update */ ++ update.update_region.left = 0; ++ update.update_region.width = fb_data->epdc_fb_var.xres; ++ update.update_region.top = y1; ++ update.update_region.height = y2 - y1 + 1; ++ update.waveform_mode = WAVEFORM_MODE_AUTO; ++ update.update_mode = UPDATE_MODE_PARTIAL; ++ update.update_marker = 0; ++ update.temp = TEMP_USE_AMBIENT; ++ update.flags = 0; ++ ++ low_y = y2; ++ high_y = y1; ++ first_x = -1; ++ for (x = 0; x < fb_data->epdc_fb_var.xres; x += 8) ++ { ++ change = false; ++ for (y = y1; y < y2; y += 8) ++ { ++ crc = calcBlockCRC16(fb_data, x, y); ++ crcFB = &_blocksCRC16[(y/8) * (fb_data->native_width/8) + x/8]; ++ ++ if (*crcFB != crc) ++ { ++ *crcFB = crc; ++ change = true; ++ ++ if (yhigh_y) high_y=y; ++ } ++ } ++ ++ if (change) ++ { ++ if (first_x < 0) first_x = x; ++ } ++ else ++ { ++ // flush previous blocks ++ if (first_x >= 0) ++ { ++ high_y += 8; ++ if (high_y > y2) high_y=y2; ++ update.update_region.left = first_x; ++ update.update_region.width = x - first_x; ++ update.update_region.top = low_y; ++ update.update_region.height = high_y - low_y; ++ mxc_epdc_fb_send_update(&update, &fb_data->info); ++ ++ first_x = -1; ++ low_y = y2; ++ high_y = y1; ++ } ++ } ++ } ++ ++ // flush last blocks ++ if (first_x >= 0) ++ { ++ high_y += 8; ++ if (high_y > y2) high_y=y2; ++ update.update_region.left = first_x; ++ update.update_region.width = fb_data->epdc_fb_var.xres - first_x; ++ update.update_region.top = low_y; ++ update.update_region.height = high_y - low_y; ++ mxc_epdc_fb_send_update(&update, &fb_data->info); ++ } ++ ++} ++#endif ++ ++// compare two line ranges (y1/y2) ++static int line_ranges_cmp(const void *a, const void *b) ++{ ++ const int *ia = (const int*)a; ++ const int *ib = (const int*)b; ++ ++ // increasing y1 ++ if (ia[0] != ib[0]) return ia[0] - ib[0]; ++ ++ // but decreasing y2 ++ return ib[1] - ia[1]; ++} ++ ++#if 0 + /* this is called back from the deferred io workqueue */ + static void mxc_epdc_fb_deferred_io(struct fb_info *info, + struct list_head *pagelist) +@@ -4802,6 +4972,7 @@ static void mxc_epdc_fb_deferred_io(struct fb_info *info, + struct page *page; + unsigned long beg, end; + int y1, y2, miny, maxy; ++ int number_of_changed_lines; + + GALLEN_DBGLOCAL_BEGIN(); + +@@ -4828,6 +4999,153 @@ static void mxc_epdc_fb_deferred_io(struct fb_info *info, + + GALLEN_DBGLOCAL_END(); + } ++#else ++/* this is called back from the deferred io workqueue */ ++static void mxc_epdc_fb_deferred_io(struct fb_info *info, ++ struct list_head *pagelist) ++{ ++ struct mxc_epdc_fb_data *fb_data = (struct mxc_epdc_fb_data *)info; ++ struct page *page; ++ unsigned long beg, end; ++ int i, y1, y2, last_y1, last_y2; ++ int no_ranges; ++ int number_of_changed_lines; ++ ++ GALLEN_DBGLOCAL_BEGIN(); ++ ++ if (fb_data->auto_mode != AUTO_UPDATE_MODE_AUTOMATIC_MODE) { ++ return; ++ } ++ ++ // collect y1/y2 ranges to update ++ no_ranges = 0; ++ last_y1 = -1; last_y2 = -1; ++ list_for_each_entry(page, pagelist, lru) ++ { ++ beg = page->index << PAGE_SHIFT; ++ end = beg + PAGE_SIZE - 1; ++ y1 = beg / info->fix.line_length; ++ y2 = end / info->fix.line_length; ++ ++ ++ // align lines to 8 ++ y1 &= ~0x7; ++ if (((y2 + 1) & 0x7) != 0) ++ { ++ y2++; y2 &= ~0x7; y2 += 7; ++ } ++ ++ ++ ++ if (y2 >= fb_data->epdc_fb_var.yres) ++ { ++ y2 = fb_data->epdc_fb_var.yres - 1; ++ } ++ ++ ++ if (y1 != last_y1 || y2 != last_y2) ++ { ++ if (no_ranges > fb_data->native_height) ++ { ++ // too many ranges (temp array size is too short) ++ // update whole screen ++ mxc_epdc_fb_update_pages(fb_data, 0, fb_data->epdc_fb_var.yres - 1); ++ return; ++ } ++ else ++ { ++ _line_ranges[no_ranges*2 + 0] = last_y1 = y1; ++ _line_ranges[no_ranges*2 + 1] = last_y2 = y2; ++ no_ranges++; ++ } ++ } ++ } ++ ++ // sort y1/y2 ranges - increasing y1 but decresing y2 ++ if (no_ranges > 1) ++ { ++ sort(_line_ranges, no_ranges, sizeof(int)*2, line_ranges_cmp, NULL); ++ } ++ ++ ++ // calculate number of changed lines ++ number_of_changed_lines = 0; ++ for (i = 0; i < no_ranges; i++) ++ { ++ y1 = _line_ranges[i*2 + 0]; ++ y2 = _line_ranges[i*2 + 1]; ++ ++ if (i == 0) ++ { ++ last_y1 = y1; ++ last_y2 = y2; ++ } ++ ++ if (y1 > last_y2 + 1) ++ { ++ number_of_changed_lines += (last_y2 - last_y1 + 1); ++ ++ last_y1 = y1; ++ last_y2 = y2; ++ } ++ else ++ { ++ if (y2 > last_y2) ++ { ++ last_y2 = y2; ++ } ++ } ++ } ++ if (no_ranges > 0) ++ { ++ number_of_changed_lines += (last_y2 - last_y1 + 1); ++ } ++ ++#if 0 ++ // if too many lines were changed - refresh whole screen ++ if (number_of_changed_lines > (fb_data->native_height *3) / 4) { ++ refresh_whole_screen(fb_data); ++ return; ++ } ++#endif ++ ++ // merge & update ranges ++ for (i = 0; i < no_ranges; i++) ++ { ++ y1 = _line_ranges[i*2 + 0]; ++ y2 = _line_ranges[i*2 + 1]; ++ ++ if (i == 0) ++ { ++ last_y1 = y1; ++ last_y2 = y2; ++ } ++ ++ if (y1 > last_y2 + 1) ++ { ++ // flush previous range ++ mxc_epdc_fb_update_pages(fb_data, last_y1, last_y2); ++ ++ last_y1 = y1; ++ last_y2 = y2; ++ } ++ else ++ { ++ if (y2 > last_y2) { ++ last_y2 = y2; ++ } ++ } ++ } ++ ++ // flush last range ++ if (no_ranges > 0) ++ { ++ mxc_epdc_fb_update_pages(fb_data, last_y1, last_y2); ++ } ++ ++ GALLEN_DBGLOCAL_END(); ++} ++#endif + + void mxc_epdc_fb_flush_updates(struct mxc_epdc_fb_data *fb_data) + { +@@ -5033,7 +5351,7 @@ static struct fb_ops mxc_epdc_fb_ops = { + }; + + static struct fb_deferred_io mxc_epdc_fb_defio = { +- .delay = HZ, ++ .delay = HZ / 10, + .deferred_io = mxc_epdc_fb_deferred_io, + }; + +@@ -7070,6 +7388,18 @@ int __devinit mxc_epdc_fb_probe(struct platform_device *pdev) + + info->fbdefio = &mxc_epdc_fb_defio; + #ifdef CONFIG_FB_MXC_EINK_AUTO_UPDATE_MODE ++ // allocate memory for update algorithms ++ _line_ranges = kmalloc(sizeof(int)*2*fb_data->native_height, GFP_KERNEL); ++ if (!_line_ranges) ++ { ++ dev_err(&pdev->dev, "cannot allocate memory for _line_ranges array\n"); ++ } ++ _blocksCRC16 = kzalloc(sizeof(u16)*(fb_data->native_width/8)*(fb_data->native_height/8), GFP_KERNEL); ++ if (!_line_ranges) ++ { ++ dev_err(&pdev->dev, "cannot allocate memory for _blocksCRC16 array\n"); ++ } ++ + fb_deferred_io_init(info); + #endif + +@@ -7415,6 +7745,13 @@ static int mxc_epdc_fb_remove(struct platform_device *pdev) + } + #ifdef CONFIG_FB_MXC_EINK_AUTO_UPDATE_MODE + fb_deferred_io_cleanup(&fb_data->info); ++ ++ // free memory for update algorithms ++ if (_line_ranges) ++ { ++ kfree(_line_ranges); _line_ranges = 0; ++ kfree(_blocksCRC16); _blocksCRC16 = 0; ++ } + #endif + + dma_free_writecombine(&pdev->dev, fb_data->map_size, fb_data->info.screen_base, -- cgit v1.2.3