From 824fc22a0aaacf942eb3b3dfa6aad32c7285669f Mon Sep 17 00:00:00 2001
From: Andrzej Zaborowski <balrog@zabor.org>
Date: Fri, 25 Jul 2008 23:06:11 +0100
Subject: [PATCH] Subject: [PATCH] Hardware glamo-fb cursor, some clean-up.

---
 drivers/mfd/glamo/glamo-fb.c |  105 +++++++++++++++++++++--------------------
 include/linux/fb.h           |    1 +
 2 files changed, 55 insertions(+), 51 deletions(-)

diff --git a/drivers/mfd/glamo/glamo-fb.c b/drivers/mfd/glamo/glamo-fb.c
index edc6d9c..30cdb38 100644
--- a/drivers/mfd/glamo/glamo-fb.c
+++ b/drivers/mfd/glamo/glamo-fb.c
@@ -117,6 +117,8 @@ static struct glamo_script glamo_regs[] = {
 	   * 01 00 0 100 0 000 01 0 0 */
 	{ GLAMO_REG_LCD_A_BASE1, 0x0000 }, /* display A base address 15:0 */
 	{ GLAMO_REG_LCD_A_BASE2, 0x0000 }, /* display A base address 22:16 */
+	{ GLAMO_REG_LCD_CURSOR_BASE1, 0x0000 }, /* cursor base address 15:0 */
+	{ GLAMO_REG_LCD_CURSOR_BASE2, 0x000f }, /* cursor base address 22:16 */
 };
 
 static int glamofb_run_script(struct glamofb_handle *glamo,
@@ -200,7 +202,6 @@ static int glamofb_check_var(struct fb_var_screeninfo *var,
 		printk(KERN_ERR
 		       "Smedia driver does not [yet?] support 24/32bpp\n");
 		return -EINVAL;
-		break;
 	}
 
 	return 0;
@@ -497,22 +498,19 @@ static int glamofb_setcolreg(unsigned regno,
 	return 0;
 }
 
+#ifdef CONFIG_MFD_GLAMO_HWACCEL
 static int glamofb_cursor(struct fb_info *info, struct fb_cursor *cursor)
 {
 	struct glamofb_handle *glamo = info->par;
-	u_int16_t reg;
+	unsigned long flags;
 
 	if (cursor->image.depth > 2)
 		return -EINVAL;
 
-	reg = reg_read(glamo, GLAMO_REG_LCD_MODE1);
+	spin_lock_irqsave(&glamo->lock_cmd, flags);
 
-	if (cursor->enable)
-		reg_write(glamo, GLAMO_REG_LCD_MODE1,
-			  reg | GLAMO_LCD_MODE1_CURSOR_EN);
-	else
-		reg_write(glamo, GLAMO_REG_LCD_MODE1,
-			  reg & ~GLAMO_LCD_MODE1_CURSOR_EN);
+	reg_set_bit_mask(glamo, GLAMO_REG_LCD_MODE1,
+			GLAMO_LCD_MODE1_CURSOR_EN, 0);
 
 	if (cursor->set & FB_CUR_SETPOS) {
 		reg_write(glamo, GLAMO_REG_LCD_CURSOR_X_POS,
@@ -522,29 +520,36 @@ static int glamofb_cursor(struct fb_info *info, struct fb_cursor *cursor)
 	}
 
 	if (cursor->set & FB_CUR_SETCMAP) {
-		/* FIXME */
+		uint16_t fg = cursor->image.fg_color;
+		uint16_t bg = cursor->image.bg_color;
+
+		reg_write(glamo, GLAMO_REG_LCD_CURSOR_FG_COLOR, fg);
+		reg_write(glamo, GLAMO_REG_LCD_CURSOR_BG_COLOR, bg);
+		reg_write(glamo, GLAMO_REG_LCD_CURSOR_DST_COLOR, bg);
 	}
 
-	if (cursor->set & FB_CUR_SETSIZE ||
-	    cursor->set & (FB_CUR_SETIMAGE | FB_CUR_SETSHAPE)) {
-		int x, y, op;
+	if (cursor->set & FB_CUR_SETHOT)
+		reg_write(glamo, GLAMO_REG_LCD_CURSOR_PRESET,
+				(cursor->hot.x << 8) | cursor->hot.y);
+
+	if ((cursor->set & FB_CUR_SETSIZE) ||
+	    (cursor->set & (FB_CUR_SETIMAGE | FB_CUR_SETSHAPE))) {
+		int x, y, pitch;
 		const unsigned char *pcol = cursor->image.data;
 		const unsigned char *pmsk = cursor->mask;
 		void __iomem *dst = glamo->cursor_addr;
 		unsigned char dcol = 0;
 		unsigned char dmsk = 0;
+		unsigned char byte = 0;
 
+		pitch = (cursor->image.width + 3) >> 2;
 		reg_write(glamo, GLAMO_REG_LCD_CURSOR_X_SIZE,
 			  cursor->image.width);
 		reg_write(glamo, GLAMO_REG_LCD_CURSOR_PITCH,
-			  cursor->image.width * 2);
+			  pitch);
 		reg_write(glamo, GLAMO_REG_LCD_CURSOR_Y_SIZE,
 			  cursor->image.height);
 
-		for (op = 0; op < (cursor->image.width *
-				   cursor->image.height * 2)/8; op += 4)
-			writel(0x0, dst + op);
-
 		for (y = 0; y < cursor->image.height; y++) {
 			for (x = 0; x < cursor->image.width; x++) {
 				if ((x % 8) == 0) {
@@ -559,15 +564,29 @@ static int glamofb_cursor(struct fb_info *info, struct fb_cursor *cursor)
 					unsigned int op;
 
 					op = (dcol & 1) ? 1 : 3;
-					op <<= ((x % 4) * 2);
+					byte |= op << ((x % 4) * 2);
+				}
 
-					op |= readb(dst + (x / 4));
-					writeb(op, dst + (x / 4));
+				if ((x % 4) == 0) {
+					writeb(byte, dst + x / 4);
+					byte = 0;
 				}
 			}
+
+			dst += pitch;
 		}
 	}
+
+	if (cursor->enable)
+		reg_set_bit_mask(glamo, GLAMO_REG_LCD_MODE1,
+				GLAMO_LCD_MODE1_CURSOR_EN,
+				GLAMO_LCD_MODE1_CURSOR_EN);
+
+	spin_unlock_irqrestore(&glamo->lock_cmd, flags);
+
+	return 0;
 }
+#endif
 
 static inline int glamofb_cmdq_empty(struct glamofb_handle *gfb)
 {
@@ -576,15 +595,14 @@ static inline int glamofb_cmdq_empty(struct glamofb_handle *gfb)
 }
 
 /* call holding gfb->lock_cmd  when locking, until you unlock */
-
 int glamofb_cmd_mode(struct glamofb_handle *gfb, int on)
 {
 	int timeout = 200000;
 
-/*	dev_dbg(gfb->dev, "glamofb_cmd_mode(gfb=%p, on=%d)\n", gfb, on); */
+	dev_dbg(gfb->dev, "glamofb_cmd_mode(gfb=%p, on=%d)\n", gfb, on);
 	if (on) {
-/*		dev_dbg(gfb->dev, "%s: waiting for cmdq empty: ",
-			__FUNCTION__); */
+		dev_dbg(gfb->dev, "%s: waiting for cmdq empty: ",
+			__FUNCTION__);
 		while ((!glamofb_cmdq_empty(gfb)) && (timeout--))
 			yield();
 		if (timeout < 0) {
@@ -593,7 +611,7 @@ int glamofb_cmd_mode(struct glamofb_handle *gfb, int on)
 				       "*************\n");
 			return -EIO;
 		}
-/*		dev_dbg(gfb->dev, "empty!\n"); */
+		dev_dbg(gfb->dev, "empty!\n");
 
 		/* display the entire frame then switch to command */
 		reg_write(gfb, GLAMO_REG_LCD_COMMAND1,
@@ -601,7 +619,7 @@ int glamofb_cmd_mode(struct glamofb_handle *gfb, int on)
 			  GLAMO_LCD_CMD_DATA_FIRE_VSYNC);
 
 		/* wait until LCD is idle */
-/*		dev_dbg(gfb->dev, "waiting for LCD idle: "); */
+		dev_dbg(gfb->dev, "waiting for LCD idle: ");
 		timeout = 200000;
 		while ((!reg_read(gfb, GLAMO_REG_LCD_STATUS2) & (1 << 12)) &&
 		      (timeout--))
@@ -612,7 +630,7 @@ int glamofb_cmd_mode(struct glamofb_handle *gfb, int on)
 				       "*************\n");
 			return -EIO;
 		}
-/*		dev_dbg(gfb->dev, "idle!\n"); */
+		dev_dbg(gfb->dev, "idle!\n");
 
 		mdelay(100);
 	} else {
@@ -635,8 +653,7 @@ int glamofb_cmd_write(struct glamofb_handle *gfb, u_int16_t val)
 {
 	int timeout = 200000;
 
-/*	dev_dbg(gfb->dev, "%s: waiting for cmdq empty\n",
-		__FUNCTION__); */
+	dev_dbg(gfb->dev, "%s: waiting for cmdq empty\n", __FUNCTION__);
 	while ((!glamofb_cmdq_empty(gfb)) && (timeout--))
 		yield();
 	if (timeout < 0) {
@@ -645,7 +662,7 @@ int glamofb_cmd_write(struct glamofb_handle *gfb, u_int16_t val)
 				"*************\n");
 		return 1;
 	}
-/*	dev_dbg(gfb->dev, "idle, writing 0x%04x\n", val); */
+	dev_dbg(gfb->dev, "idle, writing 0x%04x\n", val);
 
 	reg_write(gfb, GLAMO_REG_LCD_COMMAND1, val);
 
@@ -659,7 +676,9 @@ static struct fb_ops glamofb_ops = {
 	.fb_set_par	= glamofb_set_par,
 	.fb_blank	= glamofb_blank,
 	.fb_setcolreg	= glamofb_setcolreg,
-	//.fb_cursor	= glamofb_cursor,
+#ifdef CONFIG_MFD_GLAMO_HWACCEL
+	.fb_cursor	= glamofb_cursor,
+#endif
 	.fb_fillrect	= cfb_fillrect,
 	.fb_copyarea	= cfb_copyarea,
 	.fb_imageblit	= cfb_imageblit,
@@ -743,6 +762,7 @@ static int __init glamofb_probe(struct platform_device *pdev)
 		dev_err(&pdev->dev, "failed to ioremap() vram memory\n");
 		goto out_release_fb;
 	}
+	glamofb->cursor_addr = fbinfo->screen_base + 0xf0000;
 
 	platform_set_drvdata(pdev, fbinfo);
 
@@ -754,13 +774,13 @@ static int __init glamofb_probe(struct platform_device *pdev)
 	fbinfo->fix.xpanstep = 0;
 	fbinfo->fix.ypanstep = 0;
 	fbinfo->fix.ywrapstep = 0;
-	fbinfo->fix.accel = FB_ACCEL_NONE; /* FIXME */
+	fbinfo->fix.accel = FB_ACCEL_GLAMO;
 
 	fbinfo->var.nonstd = 0;
 	fbinfo->var.activate = FB_ACTIVATE_NOW;
 	fbinfo->var.height = mach_info->height;
 	fbinfo->var.width = mach_info->width;
-	fbinfo->var.accel_flags = 0;
+	fbinfo->var.accel_flags = 0;	/* FIXME */
 	fbinfo->var.vmode = FB_VMODE_NONINTERLACED;
 
 	fbinfo->fbops = &glamofb_ops;
@@ -833,26 +853,9 @@ static int glamofb_remove(struct platform_device *pdev)
 	return 0;
 }
 
-#ifdef CONFIG_PM
-static int glamofb_suspend(struct platform_device *pdev, pm_message_t state)
-{
-	return 0;
-}
-
-static int glamofb_resume(struct platform_device *pdev)
-{
-	return 0;
-}
-#else
-#define glamofb_suspend NULL
-#define glamofb_resume  NULL
-#endif
-
 static struct platform_driver glamofb_driver = {
 	.probe		= glamofb_probe,
 	.remove		= glamofb_remove,
-	.suspend	= glamofb_suspend,
-	.resume		= glamofb_resume,
 	.driver		= {
 		.name	= "glamo-fb",
 		.owner	= THIS_MODULE,
diff --git a/include/linux/fb.h b/include/linux/fb.h
index 72295b0..1df1225 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -120,6 +120,7 @@ struct dentry;
 #define FB_ACCEL_XGI_VOLARI_V	47	/* XGI Volari V3XT, V5, V8      */
 #define FB_ACCEL_XGI_VOLARI_Z	48	/* XGI Volari Z7                */
 #define FB_ACCEL_OMAP1610	49	/* TI OMAP16xx                  */
+#define FB_ACCEL_GLAMO		50	/* SMedia Glamo                 */
 #define FB_ACCEL_NEOMAGIC_NM2070 90	/* NeoMagic NM2070              */
 #define FB_ACCEL_NEOMAGIC_NM2090 91	/* NeoMagic NM2090              */
 #define FB_ACCEL_NEOMAGIC_NM2093 92	/* NeoMagic NM2093              */
-- 
1.5.6.3