From 80f036923d92f1f1bc5435366e6af35905d9d927 Mon Sep 17 00:00:00 2001 From: Nelson Castillo Date: Mon, 20 Apr 2009 21:39:56 -0500 Subject: Make Xglamo workaround opt-out. Fixes #2255. To disable the workaround at run-time run: echo 0 > /sys/class/i2c-adapter/i2c-0/0-0073/pcf50633-regltr.9/glamo3362.0/glamo-fb.0/xglamo_hack I guess I should add a compile option now to completely disable the workaround but let's call this an enhancement and let's close the bug now. By default the workaround is enabled. Signed-off-by: Nelson Castillo Reported-by: Timo Juhani Lindfors --- drivers/mfd/glamo/glamo-fb.c | 171 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 144 insertions(+), 27 deletions(-) (limited to 'drivers/mfd/glamo/glamo-fb.c') diff --git a/drivers/mfd/glamo/glamo-fb.c b/drivers/mfd/glamo/glamo-fb.c index 5491dadbf8a..43bb2359054 100644 --- a/drivers/mfd/glamo/glamo-fb.c +++ b/drivers/mfd/glamo/glamo-fb.c @@ -259,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) @@ -306,34 +307,78 @@ static void __rotate_lcd(struct glamofb_handle *glamo, __u32 rotation) 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); +/* + * 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 (glamofb_cmd_mode(glamo, 1)) - goto out_unlock; +static unsigned xglamo_hack_enabled = 1; - if (var->pixclock) - glamo_engine_reclock(glamo->mach_info->glamo, - GLAMO_ENGINE_LCD, - var->pixclock); +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) { /* @@ -365,23 +410,71 @@ static void glamofb_update_lcd_controller(struct glamofb_handle *glamo, 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; +} + +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 (will_orientation_change(var)) + 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, @@ -390,11 +483,28 @@ 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->xres = xres; /* Unneeded. */ + var->yres_virtual = yres; + var->yres = yres; /* Unneeded. */ + 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, @@ -411,7 +521,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, @@ -950,6 +1060,13 @@ static int __init glamofb_probe(struct platform_device *pdev) glamofb_cursor_onoff(glamofb, 1); #endif + /* 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; + } + rc = register_framebuffer(fbinfo); if (rc < 0) { dev_err(&pdev->dev, "failed to register framebuffer\n"); -- cgit v1.2.3