aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/xburst/patches-2.6.36/440-metronome.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/xburst/patches-2.6.36/440-metronome.patch')
-rw-r--r--target/linux/xburst/patches-2.6.36/440-metronome.patch1213
1 files changed, 0 insertions, 1213 deletions
diff --git a/target/linux/xburst/patches-2.6.36/440-metronome.patch b/target/linux/xburst/patches-2.6.36/440-metronome.patch
deleted file mode 100644
index a9b8781dd7..0000000000
--- a/target/linux/xburst/patches-2.6.36/440-metronome.patch
+++ /dev/null
@@ -1,1213 +0,0 @@
-From a3777b7407a9ce96a6904a6942881bbb1049594d 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] 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