* [RFC 2.6.27-rc3 1/1] n411 and hecubafb improvements
@ 2008-08-20 13:11 Jaya Kumar
0 siblings, 0 replies; only message in thread
From: Jaya Kumar @ 2008-08-20 13:11 UTC (permalink / raw)
To: linux-fbdev-devel; +Cc: Jaya Kumar, krzysztof.h1, geert
Hi Krzysztof, Geert, Tony, and fbdev friends,
These changes are in order to improve the state of n411 and hecubafb.
It adds 2 bit support, basic partial update support, cleans up the error
handling sequence, enables n411 build, and increases timeout on n411 to
handle clocked down devices.
I would be grateful for any feedback and advice.
Thanks,
jaya
Signed-off-by: Jaya Kumar <jayakumar.lkml@gmail.com>
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index a6b5529..b20a8bd 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -75,6 +75,7 @@ obj-$(CONFIG_FB_ACORN) += acornfb.o
obj-$(CONFIG_FB_ATARI) += atafb.o c2p.o atafb_mfb.o \
atafb_iplan2p2.o atafb_iplan2p4.o atafb_iplan2p8.o
obj-$(CONFIG_FB_MAC) += macfb.o
+obj-$(CONFIG_FB_N411) += n411.o
obj-$(CONFIG_FB_HECUBA) += hecubafb.o
obj-$(CONFIG_FB_HGA) += hgafb.o
obj-$(CONFIG_FB_XVR500) += sunxvr500.o
diff --git a/drivers/video/hecubafb.c b/drivers/video/hecubafb.c
index 0b4bffb..c3f8b7f 100644
--- a/drivers/video/hecubafb.c
+++ b/drivers/video/hecubafb.c
@@ -44,14 +44,18 @@
#include <video/hecubafb.h>
+static unsigned int panel_mode;
+static void (*hecubafb_do_display)(struct hecubafb_par *par,
+ unsigned char *buf, u16 y1, u16 y2);
+
/* Display specific information */
-#define DPY_W 600
-#define DPY_H 800
+#define DPY_W 800
+#define DPY_H 600
static struct fb_fix_screeninfo hecubafb_fix __devinitdata = {
.id = "hecubafb",
.type = FB_TYPE_PACKED_PIXELS,
- .visual = FB_VISUAL_MONO01,
+ .visual = FB_VISUAL_STATIC_PSEUDOCOLOR,
.xpanstep = 0,
.ypanstep = 0,
.ywrapstep = 0,
@@ -64,8 +68,13 @@ static struct fb_var_screeninfo hecubafb_var __devinitdata = {
.yres = DPY_H,
.xres_virtual = DPY_W,
.yres_virtual = DPY_H,
- .bits_per_pixel = 1,
+ .bits_per_pixel = 8,
+ .grayscale = 1,
.nonstd = 1,
+ .red = { 0, 1, 0 },
+ .green = { 0, 1, 0 },
+ .blue = { 0, 1, 0 },
+ .transp = { 0, 0, 0 },
};
/* main hecubafb functions */
@@ -100,26 +109,135 @@ static void apollo_send_command(struct hecubafb_par *par, unsigned char data)
par->board->set_ctl(par, HCB_CD_BIT, 0);
}
-static void hecubafb_dpy_update(struct hecubafb_par *par)
+static void hecubafb_1bit_raw_displayer(struct hecubafb_par *par,
+ unsigned char *buf, u16 j, u16 y2)
{
int i;
+
+ buf += j * par->info->var.xres;
+ for (; j < y2; j++) {
+ for (i = 0; i < par->info->var.xres/8; i++)
+ apollo_send_data(par, *(buf++));
+ }
+}
+
+static void hecubafb_1bit_displayer(struct hecubafb_par *par,
+ unsigned char *buf, u16 j, u16 y2)
+{
+ int i, k;
+
+ buf += j * par->info->var.xres;
+ for (; j < y2; j++) {
+ for (i = 0; i < par->info->var.xres/8; i++) {
+ u8 output = 0;
+
+ /* input=1bpp, output byte has 8 pixels */
+ for (k = 0; k < 8; k++)
+ output |= (((*(buf++) >> 1) & 0x01) << (7 - k));
+
+ output = ~output;
+ apollo_send_data(par, output);
+ }
+ }
+}
+
+static void hecubafb_2bit_displayer(struct hecubafb_par *par,
+ unsigned char *buf, u16 j, u16 y2)
+{
+ int i, k;
+
+ buf += j * par->info->var.xres;
+ for (; j < y2; j++) {
+ for (i = 0; i < par->info->var.xres/4; i++) {
+ u8 output = 0;
+
+ /* input=2bpp, output byte has 4 pixels */
+ for (k = 0; k < 4; k++)
+ output |= (((*(buf++)) & 0x03) << (6 - (2*k)));
+
+ apollo_send_data(par, output);
+ }
+ }
+}
+
+static void hecubafb_dpy_update(struct hecubafb_par *par, int j, int y2)
+{
unsigned char *buf = (unsigned char __force *)par->info->screen_base;
apollo_send_command(par, APOLLO_START_NEW_IMG);
- for (i=0; i < (DPY_W*DPY_H/8); i++) {
- apollo_send_data(par, *(buf++));
- }
+ hecubafb_do_display(par, buf, j, y2);
apollo_send_command(par, APOLLO_STOP_IMG_DATA);
apollo_send_command(par, APOLLO_DISPLAY_IMG);
}
+static void hecubafb_dpy_update_pages(struct hecubafb_par *par, u16 y1, u16 y2)
+{
+ u16 x2;
+ unsigned char *buf = (unsigned char __force *)par->info->screen_base;
+
+ /* y1 must be a multiple of 4 so drop the lower bits */
+ y1 &= 0xFFFC;
+ /* y2 must be a multiple of 4 , but - 1 so up the lower bits */
+ y2 |= 0x0003;
+ apollo_send_command(par, APOLLO_START_PART_IMG);
+ apollo_send_data(par, 0);
+ apollo_send_data(par, 0);
+ apollo_send_data(par, cpu_to_le16(y1) >> 8);
+ apollo_send_data(par, cpu_to_le16(y1));
+ x2 = par->info->var.xres - 1;
+ apollo_send_data(par, cpu_to_le16(x2) >> 8);
+ apollo_send_data(par, cpu_to_le16(x2));
+ apollo_send_data(par, cpu_to_le16(y2) >> 8);
+ apollo_send_data(par, cpu_to_le16(y2));
+ hecubafb_do_display(par, buf, y1, y2 + 1);
+ apollo_send_command(par, APOLLO_STOP_IMG_DATA);
+ apollo_send_command(par, APOLLO_DISPLAY_PART_IMG);
+}
+
/* this is called back from the deferred io workqueue */
static void hecubafb_dpy_deferred_io(struct fb_info *info,
struct list_head *pagelist)
{
- hecubafb_dpy_update(info->par);
+ u16 y1 = 0, h = 0;
+ int prev_index = -1;
+ struct page *cur;
+ struct fb_deferred_io *fbdefio = info->fbdefio;
+ int h_inc;
+ u16 yres = info->var.yres;
+ u16 xres = info->var.xres;
+
+ /* height increment is fixed per page */
+ h_inc = DIV_ROUND_UP(PAGE_SIZE , xres);
+
+ /* walk the written page list and swizzle the data */
+ list_for_each_entry(cur, &fbdefio->pagelist, lru) {
+ if (prev_index < 0) {
+ /* just starting so assign first page */
+ y1 = (cur->index << PAGE_SHIFT) / xres;
+ h = h_inc;
+ } else if ((prev_index + 1) == cur->index) {
+ /* this page is consecutive so increase our height */
+ h += h_inc;
+ } else {
+ /* page not consecutive, issue previous update first */
+ hecubafb_dpy_update_pages(info->par, y1, y1 + h);
+ /* start over with our non consecutive page */
+ y1 = (cur->index << PAGE_SHIFT) / xres;
+ h = h_inc;
+ }
+ prev_index = cur->index;
+ }
+
+ /* if we still have any pages to update we do so now */
+ if (h >= yres) {
+ /* its a full screen update, just do it */
+ hecubafb_dpy_update(info->par, 0, yres);
+ } else {
+ hecubafb_dpy_update_pages(info->par, y1,
+ min((u16) (y1 + h), yres));
+ }
}
static void hecubafb_fillrect(struct fb_info *info,
@@ -129,7 +247,7 @@ static void hecubafb_fillrect(struct fb_info *info,
sys_fillrect(info, rect);
- hecubafb_dpy_update(par);
+ hecubafb_dpy_update(par, 0, info->var.yres);
}
static void hecubafb_copyarea(struct fb_info *info,
@@ -139,7 +257,7 @@ static void hecubafb_copyarea(struct fb_info *info,
sys_copyarea(info, area);
- hecubafb_dpy_update(par);
+ hecubafb_dpy_update(par, 0, info->var.yres);
}
static void hecubafb_imageblit(struct fb_info *info,
@@ -149,7 +267,7 @@ static void hecubafb_imageblit(struct fb_info *info,
sys_imageblit(info, image);
- hecubafb_dpy_update(par);
+ hecubafb_dpy_update(par, 0, info->var.yres);
}
/*
@@ -193,11 +311,72 @@ static ssize_t hecubafb_write(struct fb_info *info, const char __user *buf,
if (!err)
*ppos += count;
- hecubafb_dpy_update(par);
+ hecubafb_dpy_update(par, 0, info->var.yres);
return (err) ? err : count;
}
+static int hecubafb_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ switch (info->var.bits_per_pixel) {
+ case 1:
+ info->fix.visual = FB_VISUAL_MONO01;
+ var->red.offset = 0; var->red.length = 1;
+ var->green.offset = 0; var->green.length = 1;
+ var->blue.offset = 0; var->blue.length = 1;
+ var->transp.offset = var->transp.length = 0;
+ var->bits_per_pixel = 1;
+ break;
+ default:
+ info->fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
+ var->red.offset = 0; var->red.length = 2;
+ var->green.offset = 0; var->green.length = 2;
+ var->blue.offset = 0; var->blue.length = 2;
+ var->transp.offset = var->transp.length = 0;
+ var->bits_per_pixel = 8;
+ break;
+ }
+
+ var->xres = DPY_W; var->yres = DPY_H;
+
+ return 0;
+}
+
+static int hecubafb_set_par(struct fb_info *info)
+{
+ struct hecubafb_par *par = info->par;
+
+ switch (panel_mode) {
+ case 2:
+ apollo_send_command(par, APOLLO_SET_DEPTH);
+ apollo_send_data(par, 0x02);
+ info->fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
+ hecubafb_do_display = hecubafb_2bit_displayer;
+ break;
+ case 1:
+ default:
+ apollo_send_command(par, APOLLO_SET_DEPTH);
+ apollo_send_data(par, 0x00);
+ switch (info->var.bits_per_pixel) {
+ case 1:
+ /* if the app asks 1bit, provide mono */
+ info->fix.visual = FB_VISUAL_MONO01;
+ hecubafb_do_display = hecubafb_1bit_raw_displayer;
+ break;
+ default:
+ /* otherwise stick with 8bpp */
+ info->var.bits_per_pixel = 8;
+ info->fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
+ hecubafb_do_display = hecubafb_1bit_displayer;
+ break;
+ }
+ break;
+ }
+
+ return 0;
+}
+
static struct fb_ops hecubafb_ops = {
.owner = THIS_MODULE,
.fb_read = fb_sys_read,
@@ -205,6 +384,8 @@ static struct fb_ops hecubafb_ops = {
.fb_fillrect = hecubafb_fillrect,
.fb_copyarea = hecubafb_copyarea,
.fb_imageblit = hecubafb_imageblit,
+ .fb_check_var = hecubafb_check_var,
+ .fb_set_par = hecubafb_set_par,
};
static struct fb_deferred_io hecubafb_defio = {
@@ -212,6 +393,38 @@ static struct fb_deferred_io hecubafb_defio = {
.deferred_io = hecubafb_dpy_deferred_io,
};
+static int __devinit handle_cmap(struct fb_info *info, int mode)
+{
+ int i;
+ int retval;
+ int cmap_size;
+
+ switch (mode) {
+ case 2:
+ cmap_size = 4;
+ break;
+ case 1:
+ default:
+ cmap_size = 2;
+ break;
+ }
+
+ retval = fb_alloc_cmap(&info->cmap, cmap_size, 0);
+ if (retval < 0) {
+ printk(KERN_ERR "Failed to allocate colormap\n");
+ return retval;
+ }
+
+ /* find mid points for cmap */
+ for (i = 0; i < cmap_size; i++)
+ info->cmap.red[i] = (((2*i)+1)*(0xFFFF))/(2*cmap_size);
+
+ memcpy(info->cmap.green, info->cmap.red, sizeof(u16)*cmap_size);
+ memcpy(info->cmap.blue, info->cmap.red, sizeof(u16)*cmap_size);
+
+ return 0;
+}
+
static int __devinit hecubafb_probe(struct platform_device *dev)
{
struct fb_info *info;
@@ -230,17 +443,17 @@ static int __devinit hecubafb_probe(struct platform_device *dev)
if (!try_module_get(board->owner))
return -ENODEV;
- videomemorysize = (DPY_W*DPY_H)/8;
+ info = framebuffer_alloc(sizeof(struct hecubafb_par), &dev->dev);
+ if (!info)
+ goto err;
- if (!(videomemory = vmalloc(videomemorysize)))
- return retval;
+ videomemorysize = (DPY_W*DPY_H);
+ videomemory = vmalloc(videomemorysize);
+ if (!videomemory)
+ goto err_fb_rel;
memset(videomemory, 0, videomemorysize);
- info = framebuffer_alloc(sizeof(struct hecubafb_par), &dev->dev);
- if (!info)
- goto err_fballoc;
-
info->screen_base = (char __force __iomem *)videomemory;
info->fbops = &hecubafb_ops;
@@ -258,25 +471,39 @@ static int __devinit hecubafb_probe(struct platform_device *dev)
info->fbdefio = &hecubafb_defio;
fb_deferred_io_init(info);
+ retval = handle_cmap(info, panel_mode);
+ if (retval < 0)
+ goto err_vfree;
+
+ /* this inits the dpy */
+ retval = par->board->init(par);
+ if (retval < 0)
+ goto err_cmap;
+
+ hecubafb_set_par(info);
+
retval = register_framebuffer(info);
if (retval < 0)
- goto err_fbreg;
+ goto err_board;
+
platform_set_drvdata(dev, info);
printk(KERN_INFO
"fb%d: Hecuba frame buffer device, using %dK of video memory\n",
info->node, videomemorysize >> 10);
- /* this inits the dpy */
- retval = par->board->init(par);
- if (retval < 0)
- goto err_fbreg;
-
return 0;
-err_fbreg:
- framebuffer_release(info);
-err_fballoc:
+
+err_cmap:
+ fb_dealloc_cmap(&info->cmap);
+err_board:
+ if (par->board->remove)
+ par->board->remove(par);
+err_vfree:
vfree(videomemory);
+err_fb_rel:
+ framebuffer_release(info);
+err:
module_put(board->owner);
return retval;
}
@@ -287,11 +514,15 @@ static int __devexit hecubafb_remove(struct platform_device *dev)
if (info) {
struct hecubafb_par *par = info->par;
- fb_deferred_io_cleanup(info);
+
unregister_framebuffer(info);
- vfree((void __force *)info->screen_base);
+ fb_deferred_io_cleanup(info);
+ fb_dealloc_cmap(&info->cmap);
+
if (par->board->remove)
par->board->remove(par);
+
+ vfree((void __force *)info->screen_base);
module_put(par->board->owner);
framebuffer_release(info);
}
@@ -317,6 +548,9 @@ static void __exit hecubafb_exit(void)
platform_driver_unregister(&hecubafb_driver);
}
+module_param(panel_mode, uint, 0);
+MODULE_PARM_DESC(panel_mode, "Panel mode: 1 for 1 bit, 2 for 2 bit");
+
module_init(hecubafb_init);
module_exit(hecubafb_exit);
diff --git a/drivers/video/n411.c b/drivers/video/n411.c
index 935830f..9f6e570 100644
--- a/drivers/video/n411.c
+++ b/drivers/video/n411.c
@@ -80,7 +80,7 @@ static void n411_wait_for_ack(struct hecubafb_par *par, int clear)
int timeout;
unsigned char tmp;
- timeout = 500;
+ timeout = 3000;
do {
tmp = n411_get_ctl(par);
if ((tmp & HCB_ACK_BIT) && (!clear))
@@ -130,12 +130,13 @@ static int n411_init_board(struct hecubafb_par *par)
par->send_data(par, 0x81);
/* have to wait while display resets */
- udelay(1000);
+ mdelay(3000);
/* if we were told to splash the screen, we just clear it */
if (!nosplash) {
par->send_command(par, APOLLO_ERASE_DISPLAY);
par->send_data(par, splashval);
+ mdelay(2000);
}
return 0;
diff --git a/include/video/hecubafb.h b/include/video/hecubafb.h
index 7b99523..5ba77ba 100644
--- a/include/video/hecubafb.h
+++ b/include/video/hecubafb.h
@@ -18,6 +18,9 @@
#define APOLLO_DISPLAY_IMG 0xA2
#define APOLLO_ERASE_DISPLAY 0xA3
#define APOLLO_INIT_DISPLAY 0xA4
+#define APOLLO_START_PART_IMG 0xB0
+#define APOLLO_DISPLAY_PART_IMG 0xB1
+#define APOLLO_SET_DEPTH 0xF3
/* Hecuba interface specific defines */
#define HCB_WUP_BIT 0x01
-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2008-08-20 13:11 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-08-20 13:11 [RFC 2.6.27-rc3 1/1] n411 and hecubafb improvements Jaya Kumar
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).