diff options
author | Thomas White <taw@bitwiz.org.uk> | 2009-04-25 19:23:57 +0100 |
---|---|---|
committer | Thomas White <taw@bitwiz.org.uk> | 2009-04-25 19:23:57 +0100 |
commit | ca8cdf043c7c6d8e1b4b3d86f3cae12fc37756a2 (patch) | |
tree | dad605a1b3142e85d9ddc08a77d62f6bf09f22cc /drivers/mfd/glamo/glamo-fb.c | |
parent | 16696dd08020690cff796fc4705b4d6bd14e91b0 (diff) | |
parent | b4136a36f31a65d0998a328465df9e8e2ba93166 (diff) |
Merge branch 'andy-tracking' into drm-tracking
Conflicts:
drivers/mfd/glamo/Kconfig
Diffstat (limited to 'drivers/mfd/glamo/glamo-fb.c')
-rw-r--r-- | drivers/mfd/glamo/glamo-fb.c | 304 |
1 files changed, 226 insertions, 78 deletions
diff --git a/drivers/mfd/glamo/glamo-fb.c b/drivers/mfd/glamo/glamo-fb.c index 77725a370e9..589b924b6bf 100644 --- a/drivers/mfd/glamo/glamo-fb.c +++ b/drivers/mfd/glamo/glamo-fb.c @@ -37,9 +37,9 @@ #include <linux/platform_device.h> #include <linux/clk.h> #include <linux/spinlock.h> +#include <linux/io.h> +#include <linux/uaccess.h> -#include <asm/io.h> -#include <asm/uaccess.h> #include <asm/div64.h> #ifdef CONFIG_PM @@ -76,6 +76,7 @@ struct glamofb_handle { u_int32_t pseudo_pal[16]; spinlock_t lock_cmd; int angle; /* Current rotation angle */ + int blank_mode; }; /* 'sibling' spi device for lcm init */ @@ -89,7 +90,7 @@ static int reg_read(struct glamofb_handle *glamo, { int i = 0; - for (i = 0; i != 2; i ++) + for (i = 0; i != 2; i++) nop(); return readw(glamo->base + reg); @@ -100,7 +101,7 @@ static void reg_write(struct glamofb_handle *glamo, { int i = 0; - for (i = 0; i != 2; i ++) + for (i = 0; i != 2; i++) nop(); writew(val, glamo->base + reg); @@ -141,7 +142,8 @@ static int glamofb_run_script(struct glamofb_handle *glamo, int i; if (glamo->mach_info->glamo->suspending) { - dev_err(&glamo->mach_info->glamo->pdev->dev, "IGNORING glamofb_run_script while " + dev_err(&glamo->mach_info->glamo->pdev->dev, + "IGNORING glamofb_run_script while " "suspended\n"); return -EBUSY; } @@ -166,7 +168,8 @@ static int glamofb_check_var(struct fb_var_screeninfo *var, struct glamofb_handle *glamo = info->par; if (glamo->mach_info->glamo->suspending) { - dev_err(&glamo->mach_info->glamo->pdev->dev, "IGNORING glamofb_check_var while " + dev_err(&glamo->mach_info->glamo->pdev->dev, + "IGNORING glamofb_check_var while " "suspended\n"); return -EBUSY; } @@ -256,6 +259,7 @@ static void reg_set_bit_mask(struct glamofb_handle *glamo, #define GLAMO_LCD_HV_RETR_DISP_START_MASK 0x03FF #define GLAMO_LCD_HV_RETR_DISP_END_MASK 0x03FF +enum orientation {ORIENTATION_PORTRAIT, ORIENTATION_LANDSCAPE}; /* the caller has to enxure lock_cmd is held and we are in cmd mode */ static void __rotate_lcd(struct glamofb_handle *glamo, __u32 rotation) @@ -263,32 +267,33 @@ static void __rotate_lcd(struct glamofb_handle *glamo, __u32 rotation) int glamo_rot; if (glamo->mach_info->glamo->suspending) { - dev_err(&glamo->mach_info->glamo->pdev->dev, "IGNORING rotate_lcd while " + dev_err(&glamo->mach_info->glamo->pdev->dev, + "IGNORING rotate_lcd while " "suspended\n"); return; } switch (rotation) { - case FB_ROTATE_UR: - glamo_rot = GLAMO_LCD_ROT_MODE_0; - glamo->angle = 0; - break; - case FB_ROTATE_CW: - glamo_rot = GLAMO_LCD_ROT_MODE_90; - glamo->angle = 90; - break; - case FB_ROTATE_UD: - glamo_rot = GLAMO_LCD_ROT_MODE_180; - glamo->angle = 180; - break; - case FB_ROTATE_CCW: - glamo_rot = GLAMO_LCD_ROT_MODE_270; - glamo->angle = 270; - break; - default: - glamo->angle = 0; - glamo_rot = GLAMO_LCD_ROT_MODE_0; - break; + case FB_ROTATE_UR: + glamo_rot = GLAMO_LCD_ROT_MODE_0; + glamo->angle = 0; + break; + case FB_ROTATE_CW: + glamo_rot = GLAMO_LCD_ROT_MODE_90; + glamo->angle = 90; + break; + case FB_ROTATE_UD: + glamo_rot = GLAMO_LCD_ROT_MODE_180; + glamo->angle = 180; + break; + case FB_ROTATE_CCW: + glamo_rot = GLAMO_LCD_ROT_MODE_270; + glamo->angle = 270; + break; + default: + glamo->angle = 0; + glamo_rot = GLAMO_LCD_ROT_MODE_0; + break; } reg_set_bit_mask(glamo, @@ -298,43 +303,90 @@ static void __rotate_lcd(struct glamofb_handle *glamo, __u32 rotation) reg_set_bit_mask(glamo, GLAMO_REG_LCD_MODE1, GLAMO_LCD_MODE1_ROTATE_EN, - (glamo_rot != GLAMO_LCD_ROT_MODE_0)? + (glamo_rot != GLAMO_LCD_ROT_MODE_0) ? GLAMO_LCD_MODE1_ROTATE_EN : 0); } -static void glamofb_update_lcd_controller(struct glamofb_handle *glamo, - struct fb_var_screeninfo *var) +static enum orientation get_orientation(struct fb_var_screeninfo *var) { - int sync, bp, disp, fp, total, pitch; - unsigned long flags; - int width, height; + if (var->xres <= var->yres) + return ORIENTATION_PORTRAIT; - if (!glamo || !var) - return; + return ORIENTATION_LANDSCAPE; +} - if (glamo->mach_info->glamo->suspending) { - dev_err(&glamo->mach_info->glamo->pdev->dev, "IGNORING glamofb_update_lcd_controller while " - "suspended\n"); - return; +static int will_orientation_change(struct fb_var_screeninfo *var) +{ + enum orientation orient = get_orientation(var); + + switch (orient) { + case ORIENTATION_LANDSCAPE: + if (var->rotate == FB_ROTATE_UR || var->rotate == FB_ROTATE_UD) + return 1; + break; + case ORIENTATION_PORTRAIT: + if (var->rotate == FB_ROTATE_CW || var->rotate == FB_ROTATE_CCW) + return 1; + break; } + return 0; +} - dev_dbg(&glamo->mach_info->glamo->pdev->dev, - "glamofb_update_lcd_controller spin_lock_irqsave\n"); - spin_lock_irqsave(&glamo->lock_cmd, flags); +#ifdef CONFIG_MFD_GLAMO_FB_XGLAMO_WORKAROUND - if (glamofb_cmd_mode(glamo, 1)) - goto out_unlock; +/* + * See https://docs.openmoko.org/trac/ticket/2255 + * We have a hack for some Xglamo bugs in kernel code. + * If someone fixes xglamo we can remove this hack. + * We might make xglamo_hack_enabled 0 by default in the future. + */ - if (var->pixclock) - glamo_engine_reclock(glamo->mach_info->glamo, - GLAMO_ENGINE_LCD, - var->pixclock); +static unsigned xglamo_hack_enabled = 1; + +static ssize_t xglamo_hack_read(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", xglamo_hack_enabled); +} + +static ssize_t xglamo_hack_write(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + unsigned long val; + + if (!strict_strtoul(buf, 10, &val)) + xglamo_hack_enabled = !!val; + + return count; +} + +static DEVICE_ATTR(xglamo_hack, S_IWUSR | S_IRUGO, xglamo_hack_read, + xglamo_hack_write); + +static struct attribute *glamo_fb_sysfs_entries[] = { + &dev_attr_xglamo_hack.attr, + NULL +}; + +static struct attribute_group glamo_fb_attr_group = { + .name = NULL, + .attrs = glamo_fb_sysfs_entries, +}; + +/* This function implements the actual Xglamo hack. */ + +static void glamofb_update_lcd_controller_hack(struct glamofb_handle *glamo, + struct fb_var_screeninfo *var, + int *xres, int *yres, int *pitch) +{ + int width, height; if (glamo->angle == 90 || glamo->angle == 270) { - /* + /* * But if we are going back to portrait mode from here, - * we get inverted values from Xglamo - */ + * we get inverted values from Xglamo + */ if (!(var->rotate == FB_ROTATE_UR || var->rotate == FB_ROTATE_UD)) { width = var->yres; @@ -354,28 +406,85 @@ static void glamofb_update_lcd_controller(struct glamofb_handle *glamo, /* We don't need to set xres and yres in this particular case * because Xglamo does it for us */ if (!(glamo->angle == 90 || glamo->angle == 270)) { - var->xres = width;var->yres = height; + var->xres = width; + var->yres = height; } var->xres_virtual = width; var->yres_virtual = height * 2; - pitch = width * var->bits_per_pixel / 8; + *pitch = width * var->bits_per_pixel / 8; } else { var->xres = height; var->yres = width; var->xres_virtual = height * 2; var->yres_virtual = width; - pitch = height * var->bits_per_pixel / 8; + *pitch = height * var->bits_per_pixel / 8; + } + + *xres = width; + *yres = height; +} +#else +#define xglamo_hack_enabled 0 +static void glamofb_update_lcd_controller_hack(struct glamofb_handle *glamo, + struct fb_var_screeninfo *var, + int *xres, int *yres, int *pitch) +{ +} +#endif + +static void glamofb_update_lcd_controller(struct glamofb_handle *glamo, + struct fb_var_screeninfo *var) +{ + int sync, bp, disp, fp, total, xres, yres, pitch; + int uninitialized_var(orientation_changing); + unsigned long flags; + + if (!glamo || !var) + return; + + if (glamo->mach_info->glamo->suspending) { + dev_err(&glamo->mach_info->glamo->pdev->dev, + "IGNORING glamofb_update_lcd_controller while " + "suspended\n"); + return; + } + + dev_dbg(&glamo->mach_info->glamo->pdev->dev, + "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, + GLAMO_ENGINE_LCD, + var->pixclock); + + if (xglamo_hack_enabled) { + glamofb_update_lcd_controller_hack(glamo, var, &xres, &yres, + &pitch); + } else { + xres = var->xres; + yres = var->yres; + + orientation_changing = will_orientation_change(var); + /* Adjust the pitch according to new orientation to come. */ + if (orientation_changing) + pitch = var->yres * var->bits_per_pixel / 8; + else + pitch = var->xres * var->bits_per_pixel / 8; } reg_set_bit_mask(glamo, GLAMO_REG_LCD_WIDTH, GLAMO_LCD_WIDTH_MASK, - width); + xres); reg_set_bit_mask(glamo, GLAMO_REG_LCD_HEIGHT, GLAMO_LCD_HEIGHT_MASK, - height); + yres); reg_set_bit_mask(glamo, GLAMO_REG_LCD_PITCH, GLAMO_LCD_PITCH_MASK, @@ -384,11 +493,26 @@ static void glamofb_update_lcd_controller(struct glamofb_handle *glamo, /* honour the rotation request */ __rotate_lcd(glamo, var->rotate); + if (!xglamo_hack_enabled) { + /* update the reported geometry of the framebuffer. */ + if (orientation_changing) { + var->xres_virtual = yres; + var->xres = yres; + var->xres_virtual *= 2; + var->yres_virtual = xres; + var->yres = xres; + } else { + var->xres_virtual = xres; + var->yres_virtual = yres; + var->yres_virtual *= 2; + } + } + /* update scannout timings */ sync = 0; bp = sync + var->hsync_len; disp = bp + var->left_margin; - fp = disp + width; + fp = disp + xres; total = fp + var->right_margin; reg_set_bit_mask(glamo, GLAMO_REG_LCD_HORIZ_TOTAL, @@ -405,7 +529,7 @@ static void glamofb_update_lcd_controller(struct glamofb_handle *glamo, sync = 0; bp = sync + var->vsync_len; disp = bp + var->upper_margin; - fp = disp + height; + fp = disp + yres; total = fp + var->lower_margin; reg_set_bit_mask(glamo, GLAMO_REG_LCD_VERT_TOTAL, @@ -427,7 +551,8 @@ out_unlock: spin_unlock_irqrestore(&glamo->lock_cmd, flags); } -static int glamofb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) +static int glamofb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) { struct glamofb_handle *glamo = info->par; u_int16_t page = var->yoffset / glamo->mach_info->yres.defval; @@ -442,7 +567,8 @@ static int glamofb_set_par(struct fb_info *info) struct fb_var_screeninfo *var = &info->var; if (glamo->mach_info->glamo->suspending) { - dev_err(&glamo->mach_info->glamo->pdev->dev, "IGNORING glamofb_set_par while " + dev_err(&glamo->mach_info->glamo->pdev->dev, + "IGNORING glamofb_set_par while " "suspended\n"); return -EBUSY; } @@ -488,17 +614,29 @@ static int glamofb_blank(int blank_mode, struct fb_info *info) * we should already switch off pixel clock here */ break; case FB_BLANK_POWERDOWN: + /* Simulating FB_BLANK_NORMAL allow turning off backlight */ + if (gfb->blank_mode != FB_BLANK_NORMAL) + notify_blank(info, FB_BLANK_NORMAL); + + /* LCM need notification before pixel clock is stopped */ + notify_blank(info, blank_mode); + /* disable the pixel clock */ glamo_engine_clkreg_set(gcore, GLAMO_ENGINE_LCD, GLAMO_CLOCK_LCD_EN_DCLK, 0); + gfb->blank_mode = blank_mode; break; case FB_BLANK_UNBLANK: case FB_BLANK_NORMAL: - /* enable the pixel clock */ - glamo_engine_clkreg_set(gcore, GLAMO_ENGINE_LCD, + /* enable the pixel clock if off */ + if (gfb->blank_mode == FB_BLANK_POWERDOWN) + glamo_engine_clkreg_set(gcore, + GLAMO_ENGINE_LCD, GLAMO_CLOCK_LCD_EN_DCLK, GLAMO_CLOCK_LCD_EN_DCLK); + notify_blank(info, blank_mode); + gfb->blank_mode = blank_mode; break; } @@ -524,7 +662,8 @@ static int glamofb_setcolreg(unsigned regno, unsigned int val; if (glamo->mach_info->glamo->suspending) { - dev_err(&glamo->mach_info->glamo->pdev->dev, "IGNORING glamofb_set_par while " + dev_err(&glamo->mach_info->glamo->pdev->dev, + "IGNORING glamofb_set_par while " "suspended\n"); return -EBUSY; } @@ -698,7 +837,8 @@ int glamofb_cmd_mode(struct glamofb_handle *gfb, int on) int timeout = 2000000; if (gfb->mach_info->glamo->suspending) { - dev_err(&gfb->mach_info->glamo->pdev->dev, "IGNORING glamofb_cmd_mode while " + dev_err(&gfb->mach_info->glamo->pdev->dev, + "IGNORING glamofb_cmd_mode while " "suspended\n"); return -EBUSY; } @@ -706,7 +846,7 @@ int glamofb_cmd_mode(struct glamofb_handle *gfb, int 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__); + __func__); while ((!glamofb_cmdq_empty(gfb)) && (timeout--)) /* yield() */; if (timeout < 0) { @@ -761,12 +901,13 @@ int glamofb_cmd_write(struct glamofb_handle *gfb, u_int16_t val) int timeout = 200000; if (gfb->mach_info->glamo->suspending) { - dev_err(&gfb->mach_info->glamo->pdev->dev, "IGNORING glamofb_cmd_write while " + dev_err(&gfb->mach_info->glamo->pdev->dev, + "IGNORING glamofb_cmd_write while " "suspended\n"); return -EBUSY; } - dev_dbg(gfb->dev, "%s: waiting for cmdq empty\n", __FUNCTION__); + dev_dbg(gfb->dev, "%s: waiting for cmdq empty\n", __func__); while ((!glamofb_cmdq_empty(gfb)) && (timeout--)) yield(); if (timeout < 0) { @@ -828,6 +969,7 @@ static int __init glamofb_probe(struct platform_device *pdev) glamofb->dev = &pdev->dev; glamofb->angle = 0; + glamofb->blank_mode = FB_BLANK_POWERDOWN; strcpy(fbinfo->fix.id, "SMedia Glamo"); @@ -934,6 +1076,15 @@ static int __init glamofb_probe(struct platform_device *pdev) glamofb_cursor_onoff(glamofb, 1); #endif +#ifdef CONFIG_MFD_GLAMO_FB_XGLAMO_WORKAROUND + /* sysfs */ + rc = sysfs_create_group(&pdev->dev.kobj, &glamo_fb_attr_group); + if (rc < 0) { + dev_err(&pdev->dev, "cannot create sysfs group\n"); + goto out_unmap_fb; + } +#endif + rc = register_framebuffer(fbinfo); if (rc < 0) { dev_err(&pdev->dev, "failed to register framebuffer\n"); @@ -984,38 +1135,35 @@ static int glamofb_suspend(struct platform_device *pdev, pm_message_t state) struct glamofb_handle *gfb = platform_get_drvdata(pdev); /* we need to stop anything touching our framebuffer */ -// fb_blank(gfb->fb, FB_BLANK_NORMAL); fb_set_suspend(gfb->fb, 1); /* seriously -- nobody is allowed to touch glamo memory when we * are suspended or we lock on nWAIT */ -// iounmap(gfb->fb->screen_base); + /* iounmap(gfb->fb->screen_base); */ return 0; } static int glamofb_resume(struct platform_device *pdev) { - struct glamofb_handle *glamofb = platform_get_drvdata(pdev); + struct glamofb_handle *gfb = platform_get_drvdata(pdev); struct glamofb_platform_data *mach_info = pdev->dev.platform_data; /* OK let's allow framebuffer ops again */ -// gfb->fb->screen_base = ioremap(gfb->fb_res->start, -// RESSIZE(gfb->fb_res)); + /* gfb->fb->screen_base = ioremap(gfb->fb_res->start, + RESSIZE(gfb->fb_res)); */ 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); + spin_lock_init(&gfb->lock_cmd); + glamofb_init_regs(gfb); #ifdef CONFIG_MFD_GLAMO_HWACCEL - glamofb_cursor_onoff(glamofb, 1); + glamofb_cursor_onoff(gfb, 1); #endif - - fb_set_suspend(glamofb->fb, 0); -// fb_blank(gfb->fb, FB_BLANK_UNBLANK); + fb_set_suspend(gfb->fb, 0); return 0; } |