From: Lars-Peter Clausen Date: Thu, 11 Mar 2010 00:29:21 +0000 (+0000) Subject: metronomefb: Add rotation support and some minor cleanups X-Git-Tag: reboot~20709 X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=bf31e79489516263529ac047188fc72e2e404e25;p=openwrt%2Fopenwrt.git metronomefb: Add rotation support and some minor cleanups SVN-Revision: 20128 --- diff --git a/target/linux/xburst/files-2.6.32/drivers/video/metronomefb.c b/target/linux/xburst/files-2.6.32/drivers/video/metronomefb.c index 0d6a1cf4d9..390d26e0d5 100644 --- a/target/linux/xburst/files-2.6.32/drivers/video/metronomefb.c +++ b/target/linux/xburst/files-2.6.32/drivers/video/metronomefb.c @@ -19,8 +19,6 @@ * */ -#define DEBUG - #include #include #include @@ -44,10 +42,6 @@ #include -/* Display specific information */ -#define DPY_W 832 -#define DPY_H 622 - #define WF_MODE_INIT 0 /* Initialization */ #define WF_MODE_MU 1 /* Monochrome update */ #define WF_MODE_GU 2 /* Grayscale update */ @@ -63,7 +57,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, @@ -130,22 +124,17 @@ static struct epd_frame epd_frame_table[] = { }, }; -static const 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 const 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, @@ -365,7 +354,6 @@ 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); @@ -442,8 +430,8 @@ static int __devinit metronome_config_cmd(struct metronomefb_par *par) will try parse the command before we've set it all up */ dev_dbg(&par->pdev->dev, "%s: ENTER\n", __func__); - memcpy(par->metromem_cmd->args, epd_frame_table[par->dt].config, - sizeof(epd_frame_table[par->dt].config)); + 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); @@ -520,35 +508,102 @@ static int __devinit metronome_init_regs(struct metronomefb_par *par) return res; } -static void metronomefb_dpy_update(struct metronomefb_par *par, int clear_all) +static uint16_t metronomefb_update_img_buffer_rotated(struct metronomefb_par *par) { int x, y; - int i; - u16 cksum = 0; - u32 *buf = (u32 __force *)par->info->screen_base; - u32 *img = (u32 *)(par->metromem_img); - u32 diff; - u32 tmp; - unsigned int fbsize = par->info->fix.smem_len; - int fx = par->info->fix.line_length; - int fy = fbsize / fx; - int fx_buf = fx / sizeof(*buf); - int m; - static int is_first_update = 1; - static int partial_updates_count = 0; - u32 *fxbuckets = par->fxbuckets; - u32 *fybuckets = par->fybuckets; + 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->info->var.rotate) { + 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; + } - wait_for_rdy(par); + 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++) { + if (j < 0 || j >= fw * fh) { + printk("moo: %d %d %d %d %d\n", j, x, y, fw_buf, fh); + return 0; + } + 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); - memset(fxbuckets, 0, fx_buf * sizeof(*fxbuckets)); - memset(fybuckets, 0, fy * sizeof(*fybuckets)); + } + j += ystep; + } + + return cksum; +} + +static uint16_t metronomefb_update_img_buffer_normal(struct metronomefb_par *par) +{ + 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 < fy; y++) { - for(x = 0; x < fx_buf; x++, i++) { - tmp = (buf[i] << 5) & 0xE0E0E0E0; - img[i] &= 0xF0F0F0F0; + 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; @@ -560,73 +615,92 @@ static void metronomefb_dpy_update(struct metronomefb_par *par, int clear_all) } } - *((u16 *)(par->metromem_img) + fbsize/2) = cksum; + return cksum; +} - if (clear_all || is_first_update || - (partial_updates_count == par->partial_autorefresh_interval)) { - m = WF_MODE_GC; - partial_updates_count = 0; - } else { - int min_x = fx_buf; - int max_x = 0; - int min_y = fy; - int max_y = 0; - int change_count; - - for (x = 0; x < fx_buf; x++) - if(fxbuckets[x]) { - min_x = x; - break; - } +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 (x = fx_buf - 1; x >= 0; x--) - if(fxbuckets[x]) { - max_x = x; - break; - } + for (max_x = fw - 1; max_x >= 0; --max_x) { + if(fxbuckets[max_x]) + break; + } - for (y = 0; y < fy; y++) - if(fybuckets[y]) { - min_y = y; - break; - } + for (min_y = 0; min_y < fh; min_y++) { + if(fybuckets[min_y]) + break; + } - for (y = fy - 1; y >= 0; y--) - if(fybuckets[y]) { - max_y = 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) * sizeof(*buf); + 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->info->var.rotate == 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, "min_x = %d, max_x = %d, min_y = %d, max_y = %d\n", - min_x, max_x, min_y, max_y); 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); - - partial_updates_count++; + ++par->partial_updates_count; } - if (m != par->current_wf_mode) { + 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; - } +again: + metronome_display_cmd(par); + wait_for_rdy(par); + if (unlikely(check_err(par))) { par->board->set_stdby(par, 0); printk("Resetting Metronome\n"); par->board->set_rst(par, 0); @@ -637,12 +711,15 @@ static void metronomefb_dpy_update(struct metronomefb_par *par, int clear_all) 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); + + goto again; } - is_first_update = 0; + par->is_first_update = 0; } /* this is called back from the deferred io workqueue */ @@ -742,12 +819,46 @@ static ssize_t metronomefb_write(struct fb_info *info, const char __user *buf, return (err) ? err : count; } +static int metronome_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct metronomefb_par *par = info->par; + + if (par->epd_frame->fw == var->xres && par->epd_frame->fh == var->yres) + return 0; + + return -EINVAL; +} + +static int metronomefb_set_par(struct fb_info *info) +{ + struct metronomefb_par *par = info->par; + + switch (info->var.rotate) { + case FB_ROTATE_CW: + case FB_ROTATE_CCW: + info->fix.line_length = info->var.yres; + break; + case FB_ROTATE_UD: + default: + info->fix.line_length = info->var.xres; + 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 = { @@ -979,15 +1090,13 @@ static int __devinit metronomefb_probe(struct platform_device *dev) info->var.yres = fh; info->var.xres_virtual = fw; info->var.yres_virtual = fh; - info->fix = metronomefb_fix; - info->fix.smem_len = fw * fh; /* Real size of image area */ info->fix.line_length = fw; - + 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->fxbuckets = kmalloc((fw / 4 + 1) * sizeof(*par->fxbuckets), GFP_KERNEL); @@ -1001,6 +1110,8 @@ static int __devinit metronomefb_probe(struct platform_device *dev) init_waitqueue_head(&par->waitq); par->manual_refresh_threshold = 60; 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. */ @@ -1025,7 +1136,7 @@ static int __devinit metronomefb_probe(struct platform_device *dev) goto err_csum_table; } - info->fix.smem_start = 0; + info->fix.smem_start = par->metromem_dma; /* load the waveform in. assume mode 3, temp 31 for now a) request the waveform file from userspace @@ -1173,6 +1284,7 @@ static int metronomefb_suspend(struct platform_device *pdev, pm_message_t messag if (par->board->power_ctl) par->board->power_ctl(par, METRONOME_POWER_OFF); + return 0; } diff --git a/target/linux/xburst/files-2.6.32/include/video/metronomefb.h b/target/linux/xburst/files-2.6.32/include/video/metronomefb.h index 8c7bdbec70..ea446ae85c 100644 --- a/target/linux/xburst/files-2.6.32/include/video/metronomefb.h +++ b/target/linux/xburst/files-2.6.32/include/video/metronomefb.h @@ -17,7 +17,9 @@ struct metromem_cmd { u16 opcode; u16 args[((64-2)/2)]; u16 csum; -} __attribute__(packed); +} __attribute__((packed)); + +struct epd_frame; /* struct used by metronome. board specific stuff comes from *board */ struct metronomefb_par { @@ -38,9 +40,13 @@ struct metronomefb_par { int current_wf_temp; unsigned int manual_refresh_threshold; unsigned int partial_autorefresh_interval; - int dt; + const struct epd_frame *epd_frame; u32 *fxbuckets; u32 *fybuckets; + + unsigned int partial_updates_count; + unsigned is_first_update:1; + struct mutex lock; };