diff options
Diffstat (limited to 'target/linux/xburst/patches-2.6.37/440-metronome.patch')
-rw-r--r-- | target/linux/xburst/patches-2.6.37/440-metronome.patch | 1213 |
1 files changed, 0 insertions, 1213 deletions
diff --git a/target/linux/xburst/patches-2.6.37/440-metronome.patch b/target/linux/xburst/patches-2.6.37/440-metronome.patch deleted file mode 100644 index eb6d660cbc..0000000000 --- a/target/linux/xburst/patches-2.6.37/440-metronome.patch +++ /dev/null @@ -1,1213 +0,0 @@ -From 057f6f13cff319e9f2fff39736371e95ff5ac47b Mon Sep 17 00:00:00 2001 -From: Lars-Peter Clausen <lars@metafoo.de> -Date: Wed, 12 May 2010 14:24:46 +0200 -Subject: [PATCH 1/5] metronome patches - ---- - drivers/video/metronomefb.c | 788 +++++++++++++++++++++++++++++++++++++------ - include/video/metronomefb.h | 33 ++- - 2 files changed, 710 insertions(+), 111 deletions(-) - ---- a/drivers/video/metronomefb.c -+++ b/drivers/video/metronomefb.c -@@ -18,11 +18,13 @@ - * is provided as am200epd.c - * - */ -+ - #include <linux/module.h> - #include <linux/kernel.h> - #include <linux/errno.h> - #include <linux/string.h> - #include <linux/mm.h> -+#include <linux/slab.h> - #include <linux/vmalloc.h> - #include <linux/delay.h> - #include <linux/interrupt.h> -@@ -34,16 +36,25 @@ - #include <linux/dma-mapping.h> - #include <linux/uaccess.h> - #include <linux/irq.h> -+#include <linux/ctype.h> - - #include <video/metronomefb.h> - - #include <asm/unaligned.h> - --/* Display specific information */ --#define DPY_W 832 --#define DPY_H 622 -+/* -+ * 12 is ok to avoid refreshing whole screen while small elements are changed, -+ * while forcing full refresh if largish dialog boxes or menus are -+ * shown/dismissed. -+ */ -+#define DEFAULT_MANUAL_REFRESH_THRESHOLD 12 -+ -+#define WF_MODE_INIT 0 /* Initialization */ -+#define WF_MODE_MU 1 /* Monochrome update */ -+#define WF_MODE_GU 2 /* Grayscale update */ -+#define WF_MODE_GC 3 /* Grayscale clearing */ - --static int user_wfm_size; -+static int temp = 25; - - /* frame differs from image. frame includes non-visible pixels */ - struct epd_frame { -@@ -53,7 +64,7 @@ struct epd_frame { - int wfm_size; - }; - --static struct epd_frame epd_frame_table[] = { -+static const struct epd_frame epd_frame_table[] = { - { - .fw = 832, - .fh = 622, -@@ -97,24 +108,40 @@ static struct epd_frame epd_frame_table[ - }, - .wfm_size = 46770, - }, -+ { -+ .fw = 800, -+ .fh = 600, -+ .config = { -+ 15 /* sdlew */ -+ | 2 << 8 /* sdosz */ -+ | 0 << 11 /* sdor */ -+ | 0 << 12 /* sdces */ -+ | 0 << 15, /* sdcer */ -+ 42 /* gdspl */ -+ | 1 << 8 /* gdr1 */ -+ | 1 << 9 /* sdshr */ -+ | 0 << 15, /* gdspp */ -+ 18 /* gdspw */ -+ | 0 << 15, /* dispc */ -+ 599 /* vdlc */ -+ | 0 << 11 /* dsi */ -+ | 0 << 12, /* dsic */ -+ }, -+ .wfm_size = 46901, -+ }, - }; - --static struct fb_fix_screeninfo metronomefb_fix __devinitdata = { -+static const struct fb_fix_screeninfo metronomefb_fix __devinitconst = { - .id = "metronomefb", - .type = FB_TYPE_PACKED_PIXELS, - .visual = FB_VISUAL_STATIC_PSEUDOCOLOR, - .xpanstep = 0, - .ypanstep = 0, - .ywrapstep = 0, -- .line_length = DPY_W, - .accel = FB_ACCEL_NONE, - }; - --static struct fb_var_screeninfo metronomefb_var __devinitdata = { -- .xres = DPY_W, -- .yres = DPY_H, -- .xres_virtual = DPY_W, -- .yres_virtual = DPY_H, -+static const struct fb_var_screeninfo metronomefb_var __devinitconst = { - .bits_per_pixel = 8, - .grayscale = 1, - .nonstd = 1, -@@ -167,7 +194,7 @@ static u16 calc_img_cksum(u16 *start, in - } - - /* here we decode the incoming waveform file and populate metromem */ --static int __devinit load_waveform(u8 *mem, size_t size, int m, int t, -+static int load_waveform(u8 *mem, size_t size, int m, int t, - struct metronomefb_par *par) - { - int tta; -@@ -181,16 +208,12 @@ static int __devinit load_waveform(u8 *m - int mem_idx = 0; - struct waveform_hdr *wfm_hdr; - u8 *metromem = par->metromem_wfm; -- struct device *dev = par->info->dev; -+ struct device *dev = &par->pdev->dev; -+ u8 mc, trc; -+ u16 *p; -+ u16 img_cksum; - -- if (user_wfm_size) -- epd_frame_table[par->dt].wfm_size = user_wfm_size; -- -- if (size != epd_frame_table[par->dt].wfm_size) { -- dev_err(dev, "Error: unexpected size %Zd != %d\n", size, -- epd_frame_table[par->dt].wfm_size); -- return -EINVAL; -- } -+ dev_dbg(dev, "Loading waveforms, mode %d, temperature %d\n", m, t); - - wfm_hdr = (struct waveform_hdr *) mem; - -@@ -208,8 +231,9 @@ static int __devinit load_waveform(u8 *m - wfm_hdr->wfm_cs); - return -EINVAL; - } -- wfm_hdr->mc += 1; -- wfm_hdr->trc += 1; -+ mc = wfm_hdr->mc + 1; -+ trc = wfm_hdr->trc + 1; -+ - for (i = 0; i < 5; i++) { - if (*(wfm_hdr->stuff2a + i) != 0) { - dev_err(dev, "Error: unexpected value in padding\n"); -@@ -221,10 +245,10 @@ static int __devinit load_waveform(u8 *m - the waveform. presumably selecting the right one for the - desired temperature. it works out the offset of the first - v that exceeds the specified temperature */ -- if ((sizeof(*wfm_hdr) + wfm_hdr->trc) > size) -+ if ((sizeof(*wfm_hdr) + trc) > size) - return -EINVAL; - -- for (i = sizeof(*wfm_hdr); i <= sizeof(*wfm_hdr) + wfm_hdr->trc; i++) { -+ for (i = sizeof(*wfm_hdr); i <= sizeof(*wfm_hdr) + trc; i++) { - if (mem[i] > t) { - trn = i - sizeof(*wfm_hdr) - 1; - break; -@@ -232,7 +256,7 @@ static int __devinit load_waveform(u8 *m - } - - /* check temperature range table checksum */ -- cksum_idx = sizeof(*wfm_hdr) + wfm_hdr->trc + 1; -+ cksum_idx = sizeof(*wfm_hdr) + trc + 1; - if (cksum_idx > size) - return -EINVAL; - cksum = calc_cksum(sizeof(*wfm_hdr), cksum_idx, mem); -@@ -294,6 +318,7 @@ static int __devinit load_waveform(u8 *m - cksum_idx = wfm_idx; - if (cksum_idx > size) - return -EINVAL; -+ dev_dbg(dev, "mem_idx = %u\n", mem_idx); - cksum = calc_cksum(owfm_idx, cksum_idx, mem); - if (cksum != mem[cksum_idx]) { - dev_err(dev, "Error: bad waveform data cksum" -@@ -302,16 +327,47 @@ static int __devinit load_waveform(u8 *m - } - par->frame_count = (mem_idx/64); - -+ p = (u16 *)par->metromem_wfm; -+ img_cksum = calc_img_cksum(p, 16384 / 2); -+ p[16384 / 2] = __cpu_to_le16(img_cksum); -+ -+ par->current_wf_mode = m; -+ par->current_wf_temp = t; -+ - return 0; - } - -+static int check_err(struct metronomefb_par *par) -+{ -+ int res; -+ -+ res = par->board->get_err(par); -+ dev_dbg(&par->pdev->dev, "ERR = %d\n", res); -+ return res; -+} -+ -+static inline int wait_for_rdy(struct metronomefb_par *par) -+{ -+ int res = 0; -+ -+ if (!par->board->get_rdy(par)) -+ res = par->board->met_wait_event_intr(par); -+ -+ return res; -+} -+ - static int metronome_display_cmd(struct metronomefb_par *par) - { - int i; - u16 cs; - u16 opcode; -- static u8 borderval; -+ int res; - -+ res = wait_for_rdy(par); -+ if (res) -+ return res; -+ -+ dev_dbg(&par->pdev->dev, "%s: ENTER\n", __func__); - /* setup display command - we can't immediately set the opcode since the controller - will try parse the command before we've set it all up -@@ -324,8 +380,9 @@ static int metronome_display_cmd(struct - - /* set the args ( 2 bytes ) for display */ - i = 0; -- par->metromem_cmd->args[i] = 1 << 3 /* border update */ -- | ((borderval++ % 4) & 0x0F) << 4 -+ par->metromem_cmd->args[i] = 0 << 3 /* border update */ -+ | (3 << 4) -+// | ((borderval++ % 4) & 0x0F) << 4 - | (par->frame_count - 1) << 8; - cs += par->metromem_cmd->args[i++]; - -@@ -335,21 +392,25 @@ static int metronome_display_cmd(struct - par->metromem_cmd->csum = cs; - par->metromem_cmd->opcode = opcode; /* display cmd */ - -- return par->board->met_wait_event_intr(par); -+ return 0; -+ - } - - static int __devinit metronome_powerup_cmd(struct metronomefb_par *par) - { - int i; - u16 cs; -+ int res; - -+ dev_dbg(&par->pdev->dev, "%s: ENTER\n", __func__); - /* setup power up command */ - par->metromem_cmd->opcode = 0x1234; /* pwr up pseudo cmd */ - cs = par->metromem_cmd->opcode; - - /* set pwr1,2,3 to 1024 */ - for (i = 0; i < 3; i++) { -- par->metromem_cmd->args[i] = 1024; -+// par->metromem_cmd->args[i] = 1024; -+ par->metromem_cmd->args[i] = 100; - cs += par->metromem_cmd->args[i]; - } - -@@ -364,7 +425,9 @@ static int __devinit metronome_powerup_c - msleep(1); - par->board->set_stdby(par, 1); - -- return par->board->met_wait_event(par); -+ res = par->board->met_wait_event(par); -+ dev_dbg(&par->pdev->dev, "%s: EXIT: %d\n", __func__, res); -+ return res; - } - - static int __devinit metronome_config_cmd(struct metronomefb_par *par) -@@ -373,8 +436,9 @@ static int __devinit metronome_config_cm - we can't immediately set the opcode since the controller - will try parse the command before we've set it all up */ - -- memcpy(par->metromem_cmd->args, epd_frame_table[par->dt].config, -- sizeof(epd_frame_table[par->dt].config)); -+ dev_dbg(&par->pdev->dev, "%s: ENTER\n", __func__); -+ memcpy(par->metromem_cmd->args, par->epd_frame->config, -+ sizeof(par->epd_frame->config)); - /* the rest are 0 */ - memset((u8 *) (par->metromem_cmd->args + 4), 0, (32-4)*2); - -@@ -395,11 +459,12 @@ static int __devinit metronome_init_cmd( - will try parse the command before we've set it all up - so we just set cs here and set the opcode at the end */ - -+ dev_dbg(&par->pdev->dev, "%s: ENTER\n", __func__); - cs = 0xCC20; - - /* set the args ( 2 bytes ) for init */ - i = 0; -- par->metromem_cmd->args[i] = 0; -+ par->metromem_cmd->args[i] = 0x0007; - cs += par->metromem_cmd->args[i++]; - - /* the rest are 0 */ -@@ -411,76 +476,268 @@ static int __devinit metronome_init_cmd( - return par->board->met_wait_event(par); - } - --static int __devinit metronome_init_regs(struct metronomefb_par *par) -+static int metronome_bootup(struct metronomefb_par *par) - { - int res; - -- res = par->board->setup_io(par); -- if (res) -- return res; -- - res = metronome_powerup_cmd(par); -- if (res) -- return res; -+ if (res) { -+ dev_err(&par->pdev->dev, "metronomefb: POWERUP cmd failed\n"); -+ goto finish; -+ } - -+ check_err(par); - res = metronome_config_cmd(par); -- if (res) -- return res; -+ if (res) { -+ dev_err(&par->pdev->dev, "metronomefb: CONFIG cmd failed\n"); -+ goto finish; -+ } -+ check_err(par); - - res = metronome_init_cmd(par); -+ if (res) -+ dev_err(&par->pdev->dev, "metronomefb: INIT cmd failed\n"); -+ check_err(par); -+ -+finish: -+ return res; -+} -+ -+static int __devinit metronome_init_regs(struct metronomefb_par *par) -+{ -+ int res; -+ -+ if (par->board->power_ctl) -+ par->board->power_ctl(par, METRONOME_POWER_ON); -+ -+ res = metronome_bootup(par); - - return res; - } - --static void metronomefb_dpy_update(struct metronomefb_par *par) -+static uint16_t metronomefb_update_img_buffer_rotated(struct metronomefb_par *par) - { -- int fbsize; -- u16 cksum; -- unsigned char *buf = (unsigned char __force *)par->info->screen_base; -+ int x, y; -+ int xstep, ystep; -+ int i, j; -+ uint16_t cksum = 0; -+ uint8_t *buf = par->info->screen_base; -+ uint32_t *img = (uint32_t *)(par->metromem_img); -+ int fw = par->epd_frame->fw; -+ int fh = par->epd_frame->fh; -+ int fw_buf = fw / 4; -+ uint32_t *fxbuckets = par->fxbuckets; -+ uint32_t *fybuckets = par->fybuckets; -+ uint32_t diff; -+ uint32_t tmp; -+ -+ switch (par->rotation) { -+ case FB_ROTATE_CW: -+ xstep = -fh; -+ ystep = fw * fh + 1; -+ j = (fw - 1) * fh; -+ break; -+ case FB_ROTATE_UD: -+ xstep = -1; -+ ystep = 0; -+ j = fw * fh - 1; -+ break; -+ case FB_ROTATE_CCW: -+ xstep = fh; -+ ystep = -fw * fh - 1; -+ j = fh - 1; -+ break; -+ default: -+ BUG(); -+ break; -+ } - -- fbsize = par->info->fix.smem_len; -- /* copy from vm to metromem */ -- memcpy(par->metromem_img, buf, fbsize); -+ memset(fxbuckets, 0, fw_buf * sizeof(*fxbuckets)); -+ memset(fybuckets, 0, fh * sizeof(*fybuckets)); -+ -+ i = 0; -+ for (y = 0; y < fh; y++) { -+ for(x = 0; x < fw_buf; x++, i++) { -+ tmp = (buf[j] << 5); -+ j += xstep; -+ tmp |= (buf[j] << 13); -+ j += xstep; -+ tmp |= (buf[j] << 21); -+ j += xstep; -+ tmp |= (buf[j] << 29); -+ j += xstep; -+ tmp &= 0xe0e0e0e0; -+ -+ img[i] &= 0xf0f0f0f0; -+ diff = img[i] ^ tmp; -+ -+ fxbuckets[x] |= diff; -+ fybuckets[y] |= diff; -+ -+ img[i] = (img[i] >> 4) | tmp; -+ cksum += img[i] & 0x0000ffff; -+ cksum += (img[i] >> 16); - -- cksum = calc_img_cksum((u16 *) par->metromem_img, fbsize/2); -- *((u16 *)(par->metromem_img) + fbsize/2) = cksum; -- metronome_display_cmd(par); -+ } -+ j += ystep; -+ } -+ -+ return cksum; - } - --static u16 metronomefb_dpy_update_page(struct metronomefb_par *par, int index) -+static uint16_t metronomefb_update_img_buffer_normal(struct metronomefb_par *par) - { -- int i; -- u16 csum = 0; -- u16 *buf = (u16 __force *)(par->info->screen_base + index); -- u16 *img = (u16 *)(par->metromem_img + index); -- -- /* swizzle from vm to metromem and recalc cksum at the same time*/ -- for (i = 0; i < PAGE_SIZE/2; i++) { -- *(img + i) = (buf[i] << 5) & 0xE0E0; -- csum += *(img + i); -+ int x, y, i; -+ uint16_t cksum = 0; -+ uint32_t *buf = (uint32_t __force *)par->info->screen_base; -+ uint32_t *img = (uint32_t *)(par->metromem_img); -+ uint32_t diff; -+ uint32_t tmp; -+ int fw = par->epd_frame->fw; -+ int fh = par->epd_frame->fh; -+ int fw_buf = fw / sizeof(*buf); -+ uint32_t *fxbuckets = par->fxbuckets; -+ uint32_t *fybuckets = par->fybuckets; -+ -+ memset(fxbuckets, 0, fw_buf * sizeof(*fxbuckets)); -+ memset(fybuckets, 0, fh * sizeof(*fybuckets)); -+ -+ i = 0; -+ for (y = 0; y < fh; y++) { -+ for(x = 0; x < fw_buf; x++, i++) { -+ tmp = (buf[i] << 5) & 0xe0e0e0e0; -+ img[i] &= 0xf0f0f0f0; -+ diff = img[i] ^ tmp; -+ -+ fxbuckets[x] |= diff; -+ fybuckets[y] |= diff; -+ -+ img[i] = (img[i] >> 4) | tmp; -+ cksum += img[i] & 0x0000ffff; -+ cksum += (img[i] >> 16); -+ } - } -- return csum; -+ -+ return cksum; -+} -+ -+static unsigned int metronomefb_get_change_count(struct metronomefb_par *par) -+{ -+ int min_x; -+ int max_x; -+ int min_y; -+ int max_y; -+ int fw = par->epd_frame->fw / 4; -+ int fh = par->epd_frame->fh; -+ unsigned int change_count; -+ uint32_t *fxbuckets = par->fxbuckets; -+ uint32_t *fybuckets = par->fybuckets; -+ -+ for (min_x = 0; min_x < fw; ++min_x) { -+ if(fxbuckets[min_x]) -+ break; -+ } -+ -+ for (max_x = fw - 1; max_x >= 0; --max_x) { -+ if(fxbuckets[max_x]) -+ break; -+ } -+ -+ for (min_y = 0; min_y < fh; min_y++) { -+ if(fybuckets[min_y]) -+ break; -+ } -+ -+ for (max_y = fh - 1; max_y >= 0; --max_y) { -+ if(fybuckets[max_y]) -+ break; -+ } -+ -+ if ((min_x > max_x) || (min_y > max_y)) -+ change_count = 0; -+ else -+ change_count = (max_x - min_x + 1) * (max_y - min_y + 1) * 4; -+ -+ dev_dbg(&par->pdev->dev, "min_x = %d, max_x = %d, min_y = %d, max_y = %d\n", -+ min_x, max_x, min_y, max_y); -+ -+ return change_count; -+} -+ -+static void metronomefb_dpy_update(struct metronomefb_par *par, int clear_all) -+{ -+ unsigned int fbsize = par->info->fix.smem_len; -+ uint16_t cksum; -+ int m; -+ -+ wait_for_rdy(par); -+ -+ if (par->rotation == 0) -+ cksum = metronomefb_update_img_buffer_normal(par); -+ else -+ cksum = metronomefb_update_img_buffer_rotated(par); -+ -+ *par->metromem_img_csum = __cpu_to_le16(cksum); -+ -+ if (clear_all || par->is_first_update || -+ (par->partial_updates_count == par->partial_autorefresh_interval)) { -+ m = WF_MODE_GC; -+ par->partial_updates_count = 0; -+ } else { -+ int change_count = metronomefb_get_change_count(par); -+ if (change_count < fbsize / 100 * par->manual_refresh_threshold) -+ m = WF_MODE_GU; -+ else -+ m = WF_MODE_GC; -+ -+ dev_dbg(&par->pdev->dev, "change_count = %u, treshold = %u%% (%u pixels)\n", -+ change_count, par->manual_refresh_threshold, -+ fbsize / 100 * par->manual_refresh_threshold); -+ ++par->partial_updates_count; -+ } -+ -+ if (m != par->current_wf_mode) -+ load_waveform((u8 *) par->firmware->data, par->firmware->size, -+ m, par->current_wf_temp, par); -+ -+ for (;;) { -+ if (likely(!check_err(par))) { -+ metronome_display_cmd(par); -+ break; -+ } -+ -+ par->board->set_stdby(par, 0); -+ dev_warn(&par->pdev->dev, "Resetting Metronome\n"); -+ par->board->set_rst(par, 0); -+ mdelay(1); -+ if (par->board->power_ctl) -+ par->board->power_ctl(par, METRONOME_POWER_OFF); -+ -+ mdelay(1); -+ load_waveform((u8 *) par->firmware->data, par->firmware->size, -+ WF_MODE_GC, par->current_wf_temp, par); -+ -+ if (par->board->power_ctl) -+ par->board->power_ctl(par, METRONOME_POWER_ON); -+ metronome_bootup(par); -+ } -+ -+ par->is_first_update = 0; - } - - /* this is called back from the deferred io workqueue */ - static void metronomefb_dpy_deferred_io(struct fb_info *info, - struct list_head *pagelist) - { -- u16 cksum; -- struct page *cur; -- struct fb_deferred_io *fbdefio = info->fbdefio; - struct metronomefb_par *par = info->par; - -- /* walk the written page list and swizzle the data */ -- list_for_each_entry(cur, &fbdefio->pagelist, lru) { -- cksum = metronomefb_dpy_update_page(par, -- (cur->index << PAGE_SHIFT)); -- par->metromem_img_csum -= par->csum_table[cur->index]; -- par->csum_table[cur->index] = cksum; -- par->metromem_img_csum += cksum; -- } -- -- metronome_display_cmd(par); -+ /* We will update entire display because we need to change -+ * 'previous image' field in pixels which was changed at -+ * previous refresh -+ */ -+ mutex_lock(&par->lock); -+ metronomefb_dpy_update(par, 0); -+ mutex_unlock(&par->lock); - } - - static void metronomefb_fillrect(struct fb_info *info, -@@ -488,8 +745,10 @@ static void metronomefb_fillrect(struct - { - struct metronomefb_par *par = info->par; - -+ mutex_lock(&par->lock); - sys_fillrect(info, rect); -- metronomefb_dpy_update(par); -+ metronomefb_dpy_update(par, 0); -+ mutex_unlock(&par->lock); - } - - static void metronomefb_copyarea(struct fb_info *info, -@@ -497,8 +756,10 @@ static void metronomefb_copyarea(struct - { - struct metronomefb_par *par = info->par; - -+ mutex_lock(&par->lock); - sys_copyarea(info, area); -- metronomefb_dpy_update(par); -+ metronomefb_dpy_update(par, 0); -+ mutex_unlock(&par->lock); - } - - static void metronomefb_imageblit(struct fb_info *info, -@@ -506,8 +767,10 @@ static void metronomefb_imageblit(struct - { - struct metronomefb_par *par = info->par; - -+ mutex_lock(&par->lock); - sys_imageblit(info, image); -- metronomefb_dpy_update(par); -+ metronomefb_dpy_update(par, 0); -+ mutex_unlock(&par->lock); - } - - /* -@@ -545,30 +808,229 @@ static ssize_t metronomefb_write(struct - - dst = (void __force *)(info->screen_base + p); - -+ mutex_lock(&par->lock); -+ - if (copy_from_user(dst, buf, count)) - err = -EFAULT; - - if (!err) - *ppos += count; - -- metronomefb_dpy_update(par); -+ metronomefb_dpy_update(par, 0); -+ mutex_unlock(&par->lock); - - return (err) ? err : count; - } - -+static int metronome_check_var(struct fb_var_screeninfo *var, struct fb_info *info) -+{ -+ struct metronomefb_par *par = info->par; -+ -+ var->grayscale = 1; -+ -+ switch (par->rotation) { -+ case FB_ROTATE_CW: -+ case FB_ROTATE_CCW: -+ if (par->epd_frame->fw == var->yres && par->epd_frame->fh == var->xres) -+ return 0; -+ break; -+ case FB_ROTATE_UD: -+ default: -+ if (par->epd_frame->fw == var->xres && par->epd_frame->fh == var->yres) -+ return 0; -+ break; -+ } -+ -+ return -EINVAL; -+} -+ -+static int metronomefb_set_par(struct fb_info *info) -+{ -+ struct metronomefb_par *par = info->par; -+ -+ par->rotation = (par->board->panel_rotation + info->var.rotate) % 4; -+ -+ switch (par->rotation) { -+ case FB_ROTATE_CW: -+ case FB_ROTATE_CCW: -+ info->fix.line_length = par->epd_frame->fh; -+ break; -+ case FB_ROTATE_UD: -+ default: -+ info->fix.line_length = par->epd_frame->fw; -+ break; -+ } -+ -+ mutex_lock(&par->lock); -+ metronomefb_dpy_update(info->par, 1); -+ mutex_unlock(&par->lock); -+ -+ return 0; -+} -+ - static struct fb_ops metronomefb_ops = { - .owner = THIS_MODULE, - .fb_write = metronomefb_write, - .fb_fillrect = metronomefb_fillrect, - .fb_copyarea = metronomefb_copyarea, - .fb_imageblit = metronomefb_imageblit, -+ .fb_check_var = metronome_check_var, -+ .fb_set_par = metronomefb_set_par, - }; - - static struct fb_deferred_io metronomefb_defio = { -- .delay = HZ, -+ .delay = HZ / 4, - .deferred_io = metronomefb_dpy_deferred_io, - }; - -+static ssize_t metronomefb_defio_delay_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct fb_info *info = dev_get_drvdata(dev); -+ -+ sprintf(buf, "%lu\n", info->fbdefio->delay * 1000 / HZ); -+ return strlen(buf) + 1; -+} -+ -+static ssize_t metronomefb_defio_delay_store(struct device *dev, -+ struct device_attribute *attr, const char *buf, size_t size) -+{ -+ struct fb_info *info = dev_get_drvdata(dev); -+ char *after; -+ unsigned long state = simple_strtoul(buf, &after, 10); -+ size_t count = after - buf; -+ ssize_t ret = -EINVAL; -+ -+ if (*after && isspace(*after)) -+ count++; -+ -+ state = state * HZ / 1000; -+ -+ if (!state) -+ state = 1; -+ -+ if (count == size) { -+ ret = count; -+ info->fbdefio->delay = state; -+ } -+ -+ return ret; -+} -+ -+static ssize_t metronomefb_manual_refresh_thr_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct fb_info *info = dev_get_drvdata(dev); -+ struct metronomefb_par *par = info->par; -+ -+ return sprintf(buf, "%u\n", par->manual_refresh_threshold); -+} -+ -+static ssize_t metronomefb_manual_refresh_thr_store(struct device *dev, -+ struct device_attribute *attr, const char *buf, size_t size) -+{ -+ struct fb_info *info = dev_get_drvdata(dev); -+ struct metronomefb_par *par = info->par; -+ char *after; -+ unsigned long val = simple_strtoul(buf, &after, 10); -+ size_t count = after - buf; -+ ssize_t ret = -EINVAL; -+ -+ if (*after && isspace(*after)) -+ count++; -+ -+ if (val > 100) -+ return -EINVAL; -+ -+ -+ if (count == size) { -+ ret = count; -+ par->manual_refresh_threshold = val; -+ } -+ -+ return ret; -+} -+ -+static ssize_t metronomefb_autorefresh_interval_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct fb_info *info = dev_get_drvdata(dev); -+ struct metronomefb_par *par = info->par; -+ -+ return sprintf(buf, "%u\n", par->partial_autorefresh_interval); -+} -+ -+static ssize_t metronomefb_autorefresh_interval_store(struct device *dev, -+ struct device_attribute *attr, const char *buf, size_t size) -+{ -+ struct fb_info *info = dev_get_drvdata(dev); -+ struct metronomefb_par *par = info->par; -+ char *after; -+ unsigned long val = simple_strtoul(buf, &after, 10); -+ size_t count = after - buf; -+ ssize_t ret = -EINVAL; -+ -+ if (*after && isspace(*after)) -+ count++; -+ -+ if (val > 100) -+ return -EINVAL; -+ -+ -+ if (count == size) { -+ ret = count; -+ par->partial_autorefresh_interval = val; -+ } -+ -+ return ret; -+} -+ -+static ssize_t metronomefb_temp_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct fb_info *info = dev_get_drvdata(dev); -+ struct metronomefb_par *par = info->par; -+ -+ return sprintf(buf, "%u\n", par->current_wf_temp); -+} -+ -+static ssize_t metronomefb_temp_store(struct device *dev, -+ struct device_attribute *attr, const char *buf, size_t size) -+{ -+ struct fb_info *info = dev_get_drvdata(dev); -+ struct metronomefb_par *par = info->par; -+ char *after; -+ unsigned long val = simple_strtoul(buf, &after, 10); -+ size_t count = after - buf; -+ ssize_t ret = -EINVAL; -+ -+ if (*after && isspace(*after)) -+ count++; -+ -+ if (val > 100) -+ return -EINVAL; -+ -+ -+ if (count == size) { -+ ret = count; -+ if (val != par->current_wf_temp) -+ load_waveform((u8 *) par->firmware->data, par->firmware->size, -+ par->current_wf_mode, val, par); -+ } -+ -+ return ret; -+} -+ -+DEVICE_ATTR(defio_delay, 0644, -+ metronomefb_defio_delay_show, metronomefb_defio_delay_store); -+DEVICE_ATTR(manual_refresh_threshold, 0644, -+ metronomefb_manual_refresh_thr_show, metronomefb_manual_refresh_thr_store); -+DEVICE_ATTR(temp, 0644, -+ metronomefb_temp_show, metronomefb_temp_store); -+DEVICE_ATTR(autorefresh_interval, 0644, -+ metronomefb_autorefresh_interval_show, metronomefb_autorefresh_interval_store); -+ -+ - static int __devinit metronomefb_probe(struct platform_device *dev) - { - struct fb_info *info; -@@ -607,6 +1069,9 @@ static int __devinit metronomefb_probe(s - - panel_type = board->get_panel_type(); - switch (panel_type) { -+ case 5: -+ epd_dt_index = 3; -+ break; - case 6: - epd_dt_index = 0; - break; -@@ -632,29 +1097,59 @@ static int __devinit metronomefb_probe(s - if (!videomemory) - goto err_fb_rel; - -- memset(videomemory, 0, videomemorysize); -+ memset(videomemory, 0xff, videomemorysize); - - info->screen_base = (char __force __iomem *)videomemory; - info->fbops = &metronomefb_ops; - -- metronomefb_fix.line_length = fw; -- metronomefb_var.xres = fw; -- metronomefb_var.yres = fh; -- metronomefb_var.xres_virtual = fw; -- metronomefb_var.yres_virtual = fh; - info->var = metronomefb_var; - info->fix = metronomefb_fix; -- info->fix.smem_len = videomemorysize; -+ switch (board->panel_rotation) { -+ case FB_ROTATE_CW: -+ case FB_ROTATE_CCW: -+ info->var.xres = fh; -+ info->var.yres = fw; -+ info->var.xres_virtual = fh; -+ info->var.yres_virtual = fw; -+ info->fix.line_length = fh; -+ break; -+ case FB_ROTATE_UD: -+ default: -+ info->var.xres = fw; -+ info->var.yres = fh; -+ info->var.xres_virtual = fw; -+ info->var.yres_virtual = fh; -+ info->fix.line_length = fw; -+ break; -+ } -+ info->fix.smem_len = fw * fh; /* Real size of image area */ - par = info->par; - par->info = info; - par->board = board; -- par->dt = epd_dt_index; -+ par->epd_frame = &epd_frame_table[epd_dt_index]; -+ par->pdev = dev; -+ -+ par->rotation = board->panel_rotation; -+ -+ par->fxbuckets = kmalloc((fw / 4 + 1) * sizeof(*par->fxbuckets), GFP_KERNEL); -+ if (!par->fxbuckets) -+ goto err_vfree; -+ -+ par->fybuckets = kmalloc(fh * sizeof(*par->fybuckets), GFP_KERNEL); -+ if (!par->fybuckets) -+ goto err_fxbuckets; -+ - init_waitqueue_head(&par->waitq); -+ par->manual_refresh_threshold = DEFAULT_MANUAL_REFRESH_THRESHOLD; -+ par->partial_autorefresh_interval = 256; -+ par->partial_updates_count = 0; -+ par->is_first_update = 1; -+ mutex_init(&par->lock); - - /* this table caches per page csum values. */ - par->csum_table = vmalloc(videomemorysize/PAGE_SIZE); - if (!par->csum_table) -- goto err_vfree; -+ goto err_fybuckets; - - /* the physical framebuffer that we use is setup by - * the platform device driver. It will provide us -@@ -684,13 +1179,19 @@ static int __devinit metronomefb_probe(s - goto err_csum_table; - } - -- retval = load_waveform((u8 *) fw_entry->data, fw_entry->size, 3, 31, -+ retval = load_waveform((u8 *) fw_entry->data, fw_entry->size, WF_MODE_GC, temp, - par); -- release_firmware(fw_entry); - if (retval < 0) { - dev_err(&dev->dev, "Failed processing waveform\n"); - goto err_csum_table; - } -+ par->firmware = fw_entry; -+ -+ retval = board->setup_io(par); -+ if (retval) { -+ dev_err(&dev->dev, "metronomefb: setup_io() failed\n"); -+ goto err_csum_table; -+ } - - if (board->setup_irq(info)) - goto err_csum_table; -@@ -712,7 +1213,7 @@ static int __devinit metronomefb_probe(s - - /* set cmap */ - for (i = 0; i < 8; i++) -- info->cmap.red[i] = (((2*i)+1)*(0xFFFF))/16; -+ info->cmap.red[i] = ((2 * i + 1)*(0xFFFF))/16; - memcpy(info->cmap.green, info->cmap.red, sizeof(u16)*8); - memcpy(info->cmap.blue, info->cmap.red, sizeof(u16)*8); - -@@ -722,18 +1223,47 @@ static int __devinit metronomefb_probe(s - - platform_set_drvdata(dev, info); - -- dev_dbg(&dev->dev, -+ retval = device_create_file(info->dev, &dev_attr_defio_delay); -+ if (retval) -+ goto err_devattr_defio_delay; -+ -+ retval = device_create_file(info->dev, &dev_attr_manual_refresh_threshold); -+ if (retval) -+ goto err_devattr_manual_refresh_thr; -+ -+ retval = device_create_file(info->dev, &dev_attr_temp); -+ if (retval) -+ goto err_devattr_temp; -+ -+ retval = device_create_file(info->dev, &dev_attr_autorefresh_interval); -+ if (retval) -+ goto err_devattr_autorefresh; -+ -+ dev_info(&dev->dev, - "fb%d: Metronome frame buffer device, using %dK of video" - " memory\n", info->node, videomemorysize >> 10); - - return 0; - -+ device_remove_file(info->dev, &dev_attr_autorefresh_interval); -+err_devattr_autorefresh: -+ device_remove_file(info->dev, &dev_attr_temp); -+err_devattr_temp: -+ device_remove_file(info->dev, &dev_attr_manual_refresh_threshold); -+err_devattr_manual_refresh_thr: -+ device_remove_file(info->dev, &dev_attr_defio_delay); -+err_devattr_defio_delay: -+ unregister_framebuffer(info); - err_cmap: - fb_dealloc_cmap(&info->cmap); - err_free_irq: - board->cleanup(par); - err_csum_table: - vfree(par->csum_table); -+err_fybuckets: -+ kfree(par->fybuckets); -+err_fxbuckets: -+ kfree(par->fxbuckets); - err_vfree: - vfree(videomemory); - err_fb_rel: -@@ -750,26 +1280,76 @@ static int __devexit metronomefb_remove( - if (info) { - struct metronomefb_par *par = info->par; - -+ par->board->set_stdby(par, 0); -+ mdelay(1); -+ if (par->board->power_ctl) -+ par->board->power_ctl(par, METRONOME_POWER_OFF); -+ -+ device_remove_file(info->dev, &dev_attr_autorefresh_interval); -+ device_remove_file(info->dev, &dev_attr_temp); -+ device_remove_file(info->dev, &dev_attr_manual_refresh_threshold); -+ device_remove_file(info->dev, &dev_attr_defio_delay); - unregister_framebuffer(info); - fb_deferred_io_cleanup(info); - fb_dealloc_cmap(&info->cmap); - par->board->cleanup(par); - vfree(par->csum_table); -+ kfree(par->fybuckets); -+ kfree(par->fxbuckets); - vfree((void __force *)info->screen_base); - module_put(par->board->owner); -+ release_firmware(par->firmware); - dev_dbg(&dev->dev, "calling release\n"); - framebuffer_release(info); - } - return 0; - } - -+#ifdef CONFIG_PM -+static int metronomefb_suspend(struct platform_device *pdev, pm_message_t message) -+{ -+ struct fb_info *info = platform_get_drvdata(pdev); -+ struct metronomefb_par *par = info->par; -+ -+ par->board->set_stdby(par, 0); -+ par->board->set_rst(par, 0); -+ if (par->board->power_ctl) -+ par->board->power_ctl(par, METRONOME_POWER_OFF); -+ -+ -+ return 0; -+} -+ -+static int metronomefb_resume(struct platform_device *pdev) -+{ -+ struct fb_info *info = platform_get_drvdata(pdev); -+ struct metronomefb_par *par = info->par; -+ -+ if (par->board->power_ctl) -+ par->board->power_ctl(par, METRONOME_POWER_ON); -+ -+ mutex_lock(&par->lock); -+ metronome_bootup(par); -+ mutex_unlock(&par->lock); -+ -+ return 0; -+} -+ -+#else -+#define metronomefb_suspend NULL -+#define metronomefb_resume NULL -+#endif -+ -+ - static struct platform_driver metronomefb_driver = { -- .probe = metronomefb_probe, -- .remove = metronomefb_remove, -- .driver = { -- .owner = THIS_MODULE, -- .name = "metronomefb", -- }, -+ .driver = { -+ .owner = THIS_MODULE, -+ .name = "metronomefb", -+ }, -+ .probe = metronomefb_probe, -+ .remove = __devexit_p(metronomefb_remove), -+ .suspend = metronomefb_suspend, -+ .resume = metronomefb_resume, - }; - - static int __init metronomefb_init(void) -@@ -782,8 +1362,8 @@ static void __exit metronomefb_exit(void - platform_driver_unregister(&metronomefb_driver); - } - --module_param(user_wfm_size, uint, 0); --MODULE_PARM_DESC(user_wfm_size, "Set custom waveform size"); -+module_param(temp, int, 0); -+MODULE_PARM_DESC(temp, "Set current temperature"); - - module_init(metronomefb_init); - module_exit(metronomefb_exit); ---- a/include/video/metronomefb.h -+++ b/include/video/metronomefb.h -@@ -17,7 +17,9 @@ struct metromem_cmd { - u16 opcode; - u16 args[((64-2)/2)]; - u16 csum; --}; -+} __attribute__((packed)); -+ -+struct epd_frame; - - /* struct used by metronome. board specific stuff comes from *board */ - struct metronomefb_par { -@@ -27,19 +29,40 @@ struct metronomefb_par { - u16 *metromem_img_csum; - u16 *csum_table; - dma_addr_t metromem_dma; -+ const struct firmware *firmware; - struct fb_info *info; - struct metronome_board *board; -+ struct platform_device *pdev; - wait_queue_head_t waitq; - u8 frame_count; - int extra_size; -- int dt; -+ int current_wf_mode; -+ int current_wf_temp; -+ unsigned int manual_refresh_threshold; -+ unsigned int partial_autorefresh_interval; -+ const struct epd_frame *epd_frame; -+ u32 *fxbuckets; -+ u32 *fybuckets; -+ -+ int rotation; -+ -+ unsigned int partial_updates_count; -+ unsigned is_first_update:1; -+ -+ struct mutex lock; - }; - -+#define METRONOME_POWER_OFF 0 -+#define METRONOME_POWER_ON 1 -+ - /* board specific routines and data */ - struct metronome_board { - struct module *owner; /* the platform device */ -+ void (*power_ctl)(struct metronomefb_par *, int); - void (*set_rst)(struct metronomefb_par *, int); - void (*set_stdby)(struct metronomefb_par *, int); -+ int (*get_err)(struct metronomefb_par *); -+ int (*get_rdy)(struct metronomefb_par *); - void (*cleanup)(struct metronomefb_par *); - int (*met_wait_event)(struct metronomefb_par *); - int (*met_wait_event_intr)(struct metronomefb_par *); -@@ -47,11 +70,7 @@ struct metronome_board { - int (*setup_fb)(struct metronomefb_par *); - int (*setup_io)(struct metronomefb_par *); - int (*get_panel_type)(void); -- unsigned char *metromem; -- int fw; -- int fh; -- int wfm_size; -- struct fb_info *host_fbinfo; /* the host LCD controller's fbi */ -+ int panel_rotation; - }; - - #endif |