aboutsummaryrefslogtreecommitdiff
path: root/drivers/mfd/glamo/glamo-fb.c
diff options
context:
space:
mode:
authorAndy Green <andy@openmoko.com>2008-11-19 17:09:37 +0000
committerAndy Green <agreen@pads.home.warmcat.com>2008-11-19 17:09:37 +0000
commit3bd5363964121687a1c7131dcb984f83dce5a4b7 (patch)
tree55e1a2b3fb11a3419ad8ba1da0a0af2497430cc6 /drivers/mfd/glamo/glamo-fb.c
parent0762384f24778657524c4aff890a5ba140164751 (diff)
fix-glamofb-cmd-mode-locking.patch
Glamo "cmd mode" is modal, but nothing took care about locking. Also cmd mode was entered recursively in rotate_lcd(). Signed-off-by: Andy Green <andy@openmoko.com>
Diffstat (limited to 'drivers/mfd/glamo/glamo-fb.c')
-rw-r--r--drivers/mfd/glamo/glamo-fb.c106
1 files changed, 68 insertions, 38 deletions
diff --git a/drivers/mfd/glamo/glamo-fb.c b/drivers/mfd/glamo/glamo-fb.c
index 87c742007e4..8633e444cb6 100644
--- a/drivers/mfd/glamo/glamo-fb.c
+++ b/drivers/mfd/glamo/glamo-fb.c
@@ -36,6 +36,7 @@
#include <linux/wait.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
+#include <linux/spinlock.h>
#include <asm/io.h>
#include <asm/uaccess.h>
@@ -50,7 +51,7 @@
#include "glamo-regs.h"
#include "glamo-core.h"
-#ifdef DEBUG
+#ifndef DEBUG
#define GLAMO_LOG(...)
#else
#define GLAMO_LOG(...) \
@@ -72,6 +73,7 @@ struct glamofb_handle {
struct glamofb_platform_data *mach_info;
char __iomem *cursor_addr;
u_int32_t pseudo_pal[16];
+ spinlock_t lock_cmd;
};
/* 'sibling' spi device for lcm init */
@@ -237,6 +239,7 @@ static void rotate_lcd(struct glamofb_handle *glamo,
__u32 rotation)
{
int glamo_rot;
+ unsigned long flags;
switch (rotation) {
case FB_ROTATE_UR:
@@ -255,7 +258,15 @@ static void rotate_lcd(struct glamofb_handle *glamo,
glamo_rot = GLAMO_LCD_ROT_MODE_0;
break;
}
- glamofb_cmd_mode(glamo, 1);
+
+ /*
+ * ha ha we are only called when we are in cmd mode already
+ * printk(KERN_ERR"rotate_lcd spin_lock_irqsave\n");
+ * spin_lock_irqsave(&glamo->lock_cmd, flags);
+ *
+ * if (glamofb_cmd_mode(glamo, 1))
+ * goto out_unlock;
+ */
reg_set_bit_mask(glamo,
GLAMO_REG_LCD_WIDTH,
GLAMO_LCD_ROT_MODE_MASK,
@@ -265,17 +276,19 @@ static void rotate_lcd(struct glamofb_handle *glamo,
GLAMO_LCD_MODE1_ROTATE_EN,
(glamo_rot != GLAMO_LCD_ROT_MODE_0)?
GLAMO_LCD_MODE1_ROTATE_EN : 0);
- glamofb_cmd_mode(glamo, 0);
+/* glamofb_cmd_mode(glamo, 0);
+
+out_unlock:
+ printk(KERN_ERR"rotate_lcd spin_unlock_irqrestore\n");
+ spin_unlock_irqrestore(&glamo->lock_cmd, flags);
+*/
}
static enum orientation get_orientation(struct fb_var_screeninfo *var)
{
- GLAMO_LOG("mark\n")
- if (var->xres <= var->yres) {
- GLAMO_LOG("portrait\n")
+ if (var->xres <= var->yres)
return ORIENTATION_PORTRAIT;
- }
- GLAMO_LOG("landscape\n")
+
return ORIENTATION_LANDSCAPE;
}
@@ -299,12 +312,18 @@ static void glamofb_update_lcd_controller(struct glamofb_handle *glamo,
struct fb_var_screeninfo *var)
{
int sync, bp, disp, fp, total, xres, yres, pitch, orientation_changing;
+ unsigned long flags;
- GLAMO_LOG("enter: glamo:%#x, var:%#x\n", (unsigned)glamo, (unsigned)var);
+/* GLAMO_LOG("enter: glamo:%#x, var:%#x\n", (unsigned)glamo, (unsigned)var);
+*/
if (!glamo || !var)
return;
- glamofb_cmd_mode(glamo, 1);
+ printk(KERN_ERR"glamofb_update_lcd_controller spin_lock_irqsave\n");
+ spin_lock_irqsave(&glamo->lock_cmd, flags);
+
+ if (glamofb_cmd_mode(glamo, 1))
+ goto out_unlock;
if (var->pixclock)
glamo_engine_reclock(glamo->mach_info->glamo,
@@ -313,14 +332,14 @@ static void glamofb_update_lcd_controller(struct glamofb_handle *glamo,
xres = var->xres;
yres = var->yres;
- GLAMO_LOG("xres:%d, yres:%d, rotate:%d\n", xres, yres, var->rotate);
-
+/* GLAMO_LOG("xres:%d, yres:%d, rotate:%d\n", xres, yres, var->rotate);
+*/
/*
* figure out if orientation is going to change
*/
orientation_changing = will_orientation_change(var);
- GLAMO_LOG("orientation_changing:%d\n", orientation_changing);
-
+/* GLAMO_LOG("orientation_changing:%d\n", orientation_changing);
+*/
/*
* adjust the pitch according to new orientation to come
*/
@@ -329,8 +348,8 @@ static void glamofb_update_lcd_controller(struct glamofb_handle *glamo,
} else {
pitch = var->xres * var->bits_per_pixel / 8;
}
- GLAMO_LOG("pitch:%d\n", pitch);
-
+/* GLAMO_LOG("pitch:%d\n", pitch);
+*/
/*
* set the awaiten LCD geometry
*/
@@ -347,7 +366,7 @@ static void glamofb_update_lcd_controller(struct glamofb_handle *glamo,
GLAMO_LCD_PITCH_MASK,
pitch);
- GLAMO_LOG("mark:\n");
+/* GLAMO_LOG("mark:\n");*/
/*
* honour the rotation request
*/
@@ -365,7 +384,8 @@ static void glamofb_update_lcd_controller(struct glamofb_handle *glamo,
var->yres_virtual = var->yres = yres;
}
- GLAMO_LOG("reported res:(%d,%d)\n", var->xres, var->yres);
+/* GLAMO_LOG("reported res:(%d,%d)\n", var->xres, var->yres);
+*/
/*
* update scannout timings
*/
@@ -386,8 +406,8 @@ static void glamofb_update_lcd_controller(struct glamofb_handle *glamo,
reg_set_bit_mask(glamo, GLAMO_REG_LCD_HORIZ_DISP_END,
GLAMO_LCD_HV_RETR_DISP_END_MASK, fp);
- GLAMO_LOG("mark:\n");
-
+/* GLAMO_LOG("mark:\n");
+*/
sync = 0;
bp = sync + var->vsync_len;
disp = bp + var->upper_margin;
@@ -405,10 +425,13 @@ static void glamofb_update_lcd_controller(struct glamofb_handle *glamo,
reg_set_bit_mask(glamo, GLAMO_REG_LCD_VERT_DISP_END,
GLAMO_LCD_HV_RETR_DISP_END_MASK, fp);
- GLAMO_LOG("mark:\n");
+/* GLAMO_LOG("mark:\n"); */
glamofb_cmd_mode(glamo, 0);
- GLAMO_LOG("leave:\n");
+/* GLAMO_LOG("leave:\n"); */
+out_unlock:
+ printk(KERN_ERR"glamofb_update_lcd_controller spin_unlock_irqrestore\n");
+ spin_unlock_irqrestore(&glamo->lock_cmd, flags);
}
static int glamofb_set_par(struct fb_info *info)
@@ -552,23 +575,25 @@ static inline int glamofb_cmdq_empty(struct glamofb_handle *gfb)
return reg_read(gfb, GLAMO_REG_LCD_STATUS1) & (1 << 15);
}
-void glamofb_cmd_mode(struct glamofb_handle *gfb, int on)
+/* call holding gfb->lock_cmd when locking, until you unlock */
+
+int glamofb_cmd_mode(struct glamofb_handle *gfb, int on)
{
- int timeout = 20000;
+ 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) {
printk(KERN_ERR"*************"
"glamofb cmd_queue never got empty"
"*************\n");
- return;
+ 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,
@@ -576,8 +601,8 @@ void 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: ");
- timeout = 2000;
+/* dev_dbg(gfb->dev, "waiting for LCD idle: "); */
+ timeout = 200000;
while ((!reg_read(gfb, GLAMO_REG_LCD_STATUS2) & (1 << 12)) &&
(timeout--))
yield();
@@ -585,11 +610,11 @@ void glamofb_cmd_mode(struct glamofb_handle *gfb, int on)
printk(KERN_ERR"*************"
"glamofb lcd never idle"
"*************\n");
- return;
+ return -EIO;
}
- dev_dbg(gfb->dev, "idle!\n");
+/* dev_dbg(gfb->dev, "idle!\n"); */
- msleep(90);
+ mdelay(100);
} else {
/* RGB interface needs vsync/hsync */
if (reg_read(gfb, GLAMO_REG_LCD_MODE3) & GLAMO_LCD_MODE3_RGB)
@@ -601,15 +626,17 @@ void glamofb_cmd_mode(struct glamofb_handle *gfb, int on)
GLAMO_LCD_CMD_TYPE_DISP |
GLAMO_LCD_CMD_DATA_DISP_FIRE);
}
+
+ return 0;
}
EXPORT_SYMBOL_GPL(glamofb_cmd_mode);
int glamofb_cmd_write(struct glamofb_handle *gfb, u_int16_t val)
{
- int timeout = 20000;
+ 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) {
@@ -618,7 +645,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);
@@ -758,6 +785,9 @@ static int __init glamofb_probe(struct platform_device *pdev)
glamo_engine_enable(mach_info->glamo, GLAMO_ENGINE_LCD);
glamo_engine_reset(mach_info->glamo, GLAMO_ENGINE_LCD);
+
+ printk(KERN_ERR"spin_lock_init\n");
+ spin_lock_init(&glamofb->lock_cmd);
glamofb_init_regs(glamofb);
rc = register_framebuffer(fbinfo);