diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/video/Kconfig | 16 | ||||
-rw-r--r-- | drivers/video/Makefile | 1 | ||||
-rw-r--r-- | drivers/video/au1200fb.c | 297 | ||||
-rw-r--r-- | drivers/video/backlight/adp8860_bl.c | 1 | ||||
-rw-r--r-- | drivers/video/backlight/adp8870_bl.c | 1 | ||||
-rw-r--r-- | drivers/video/carminefb.c | 6 | ||||
-rw-r--r-- | drivers/video/controlfb.c | 2 | ||||
-rw-r--r-- | drivers/video/da8xx-fb.c | 151 | ||||
-rw-r--r-- | drivers/video/fb_defio.c | 3 | ||||
-rw-r--r-- | drivers/video/fsl-diu-fb.c | 74 | ||||
-rw-r--r-- | drivers/video/grvga.c | 579 | ||||
-rw-r--r-- | drivers/video/msm/mdp.c | 4 | ||||
-rw-r--r-- | drivers/video/platinumfb.c | 2 | ||||
-rw-r--r-- | drivers/video/pm2fb.c | 2 | ||||
-rw-r--r-- | drivers/video/pm3fb.c | 2 | ||||
-rw-r--r-- | drivers/video/pxa3xx-gcu.c | 2 | ||||
-rw-r--r-- | drivers/video/s3c2410fb.c | 1 | ||||
-rw-r--r-- | drivers/video/s3fb.c | 2 | ||||
-rw-r--r-- | drivers/video/skeletonfb.c | 2 | ||||
-rw-r--r-- | drivers/video/udlfb.c | 21 | ||||
-rw-r--r-- | drivers/video/valkyriefb.c | 2 | ||||
-rw-r--r-- | drivers/video/via/via_modesetting.h | 5 | ||||
-rw-r--r-- | drivers/video/via/viafbdev.c | 16 | ||||
-rw-r--r-- | drivers/video/xilinxfb.c | 1 |
24 files changed, 966 insertions, 227 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 963b8b7..903ace5 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -259,6 +259,15 @@ config FB_TILEBLITTING comment "Frame buffer hardware drivers" depends on FB +config FB_GRVGA + tristate "Aeroflex Gaisler framebuffer support" + depends on FB && SPARC + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + ---help--- + This enables support for the SVGACTRL framebuffer in the GRLIB IP library from Aeroflex Gaisler. + config FB_CIRRUS tristate "Cirrus Logic support" depends on FB && (ZORRO || PCI) @@ -1756,9 +1765,10 @@ config FB_AU1100 config FB_AU1200 bool "Au1200 LCD Driver" depends on (FB = y) && MIPS && SOC_AU1200 - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT + select FB_SYS_FILLRECT + select FB_SYS_COPYAREA + select FB_SYS_IMAGEBLIT + select FB_SYS_FOPS help This is the framebuffer driver for the AMD Au1200 SOC. It can drive various panels and CRTs by passing in kernel cmd line option diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 8b83129..4307910 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -33,6 +33,7 @@ obj-$(CONFIG_FB_AMIGA) += amifb.o c2p_planar.o obj-$(CONFIG_FB_ARC) += arcfb.o obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o +obj-$(CONFIG_FB_GRVGA) += grvga.o obj-$(CONFIG_FB_PM2) += pm2fb.o obj-$(CONFIG_FB_PM3) += pm3fb.o diff --git a/drivers/video/au1200fb.c b/drivers/video/au1200fb.c index 5dff32a..ed5dcdb 100644 --- a/drivers/video/au1200fb.c +++ b/drivers/video/au1200fb.c @@ -46,14 +46,6 @@ #include <asm/mach-au1x00/au1000.h> #include "au1200fb.h" -#ifdef CONFIG_PM -#include <asm/mach-au1x00/au1xxx_pm.h> -#endif - -#ifndef CONFIG_FB_AU1200_DEVS -#define CONFIG_FB_AU1200_DEVS 4 -#endif - #define DRIVER_NAME "au1200fb" #define DRIVER_DESC "LCD controller driver for AU1200 processors" @@ -150,7 +142,7 @@ struct au1200_lcd_iodata_t { /* Private, per-framebuffer management information (independent of the panel itself) */ struct au1200fb_device { - struct fb_info fb_info; /* FB driver info record */ + struct fb_info *fb_info; /* FB driver info record */ int plane; unsigned char* fb_mem; /* FrameBuffer memory map */ @@ -158,7 +150,6 @@ struct au1200fb_device { dma_addr_t fb_phys; }; -static struct au1200fb_device _au1200fb_devices[CONFIG_FB_AU1200_DEVS]; /********************************************************************/ /* LCD controller restrictions */ @@ -171,10 +162,18 @@ static struct au1200fb_device _au1200fb_devices[CONFIG_FB_AU1200_DEVS]; /* Default number of visible screen buffer to allocate */ #define AU1200FB_NBR_VIDEO_BUFFERS 1 +/* Default maximum number of fb devices to create */ +#define MAX_DEVICE_COUNT 4 + +/* Default window configuration entry to use (see windows[]) */ +#define DEFAULT_WINDOW_INDEX 2 + /********************************************************************/ +static struct fb_info *_au1200fb_infos[MAX_DEVICE_COUNT]; static struct au1200_lcd *lcd = (struct au1200_lcd *) AU1200_LCD_ADDR; -static int window_index = 2; /* default is zero */ +static int device_count = MAX_DEVICE_COUNT; +static int window_index = DEFAULT_WINDOW_INDEX; /* default is zero */ static int panel_index = 2; /* default is zero */ static struct window_settings *win; static struct panel_settings *panel; @@ -205,12 +204,6 @@ struct window_settings { extern int board_au1200fb_panel_init (void); extern int board_au1200fb_panel_shutdown (void); -#ifdef CONFIG_PM -int au1200fb_pm_callback(au1xxx_power_dev_t *dev, - au1xxx_request_t request, void *data); -au1xxx_power_dev_t *LCD_pm_dev; -#endif - /* * Default window configurations */ @@ -652,25 +645,6 @@ static struct panel_settings known_lcd_panels[] = /********************************************************************/ -#ifdef CONFIG_PM -static int set_brightness(unsigned int brightness) -{ - unsigned int hi1, divider; - - /* limit brightness pwm duty to >= 30/1600 */ - if (brightness < 30) { - brightness = 30; - } - divider = (lcd->pwmdiv & 0x3FFFF) + 1; - hi1 = (lcd->pwmhi >> 16) + 1; - hi1 = (((brightness & 0xFF) + 1) * divider >> 8); - lcd->pwmhi &= 0xFFFF; - lcd->pwmhi |= (hi1 << 16); - - return brightness; -} -#endif /* CONFIG_PM */ - static int winbpp (unsigned int winctrl1) { int bits = 0; @@ -712,8 +686,8 @@ static int fbinfo2index (struct fb_info *fb_info) { int i; - for (i = 0; i < CONFIG_FB_AU1200_DEVS; ++i) { - if (fb_info == (struct fb_info *)(&_au1200fb_devices[i].fb_info)) + for (i = 0; i < device_count; ++i) { + if (fb_info == _au1200fb_infos[i]) return i; } printk("au1200fb: ERROR: fbinfo2index failed!\n"); @@ -962,7 +936,7 @@ static void au1200_setmode(struct au1200fb_device *fbdev) lcd->window[plane].winctrl2 = ( 0 | LCD_WINCTRL2_CKMODE_00 | LCD_WINCTRL2_DBM - | LCD_WINCTRL2_BX_N( fbdev->fb_info.fix.line_length) + | LCD_WINCTRL2_BX_N(fbdev->fb_info->fix.line_length) | LCD_WINCTRL2_SCX_1 | LCD_WINCTRL2_SCY_1 ) ; @@ -1050,7 +1024,7 @@ static void au1200fb_update_fbinfo(struct fb_info *fbi) static int au1200fb_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi) { - struct au1200fb_device *fbdev = (struct au1200fb_device *)fbi; + struct au1200fb_device *fbdev = fbi->par; u32 pixclock; int screen_size, plane; @@ -1142,7 +1116,7 @@ static int au1200fb_fb_check_var(struct fb_var_screeninfo *var, */ static int au1200fb_fb_set_par(struct fb_info *fbi) { - struct au1200fb_device *fbdev = (struct au1200fb_device *)fbi; + struct au1200fb_device *fbdev = fbi->par; au1200fb_update_fbinfo(fbi); au1200_setmode(fbdev); @@ -1246,11 +1220,7 @@ static int au1200fb_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) { unsigned int len; unsigned long start=0, off; - struct au1200fb_device *fbdev = (struct au1200fb_device *) info; - -#ifdef CONFIG_PM - au1xxx_pm_access(LCD_pm_dev); -#endif + struct au1200fb_device *fbdev = info->par; if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) { return -EINVAL; @@ -1461,10 +1431,6 @@ static int au1200fb_ioctl(struct fb_info *info, unsigned int cmd, int plane; int val; -#ifdef CONFIG_PM - au1xxx_pm_access(LCD_pm_dev); -#endif - plane = fbinfo2index(info); print_dbg("au1200fb: ioctl %d on plane %d\n", cmd, plane); @@ -1536,9 +1502,11 @@ static struct fb_ops au1200fb_fb_ops = { .fb_set_par = au1200fb_fb_set_par, .fb_setcolreg = au1200fb_fb_setcolreg, .fb_blank = au1200fb_fb_blank, - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, - .fb_imageblit = cfb_imageblit, + .fb_fillrect = sys_fillrect, + .fb_copyarea = sys_copyarea, + .fb_imageblit = sys_imageblit, + .fb_read = fb_sys_read, + .fb_write = fb_sys_write, .fb_sync = NULL, .fb_ioctl = au1200fb_ioctl, .fb_mmap = au1200fb_fb_mmap, @@ -1561,10 +1529,9 @@ static irqreturn_t au1200fb_handle_irq(int irq, void* dev_id) static int au1200fb_init_fbinfo(struct au1200fb_device *fbdev) { - struct fb_info *fbi = &fbdev->fb_info; + struct fb_info *fbi = fbdev->fb_info; int bpp; - memset(fbi, 0, sizeof(struct fb_info)); fbi->fbops = &au1200fb_fb_ops; bpp = winbpp(win->w[fbdev->plane].mode_winctrl1); @@ -1623,24 +1590,36 @@ static int au1200fb_init_fbinfo(struct au1200fb_device *fbdev) /* AU1200 LCD controller device driver */ -static int au1200fb_drv_probe(struct platform_device *dev) +static int __devinit au1200fb_drv_probe(struct platform_device *dev) { struct au1200fb_device *fbdev; + struct fb_info *fbi = NULL; unsigned long page; - int bpp, plane, ret; + int bpp, plane, ret, irq; - if (!dev) - return -EINVAL; + /* shut gcc up */ + ret = 0; + fbdev = NULL; + + /* Kickstart the panel */ + au1200_setpanel(panel); - for (plane = 0; plane < CONFIG_FB_AU1200_DEVS; ++plane) { + for (plane = 0; plane < device_count; ++plane) { bpp = winbpp(win->w[plane].mode_winctrl1); if (win->w[plane].xres == 0) win->w[plane].xres = panel->Xres; if (win->w[plane].yres == 0) win->w[plane].yres = panel->Yres; - fbdev = &_au1200fb_devices[plane]; - memset(fbdev, 0, sizeof(struct au1200fb_device)); + fbi = framebuffer_alloc(sizeof(struct au1200fb_device), + &dev->dev); + if (!fbi) + goto failed; + + _au1200fb_infos[plane] = fbi; + fbdev = fbi->par; + fbdev->fb_info = fbi; + fbdev->plane = plane; /* Allocate the framebuffer to the maximum screen size */ @@ -1673,30 +1652,31 @@ static int au1200fb_drv_probe(struct platform_device *dev) goto failed; /* Register new framebuffer */ - if ((ret = register_framebuffer(&fbdev->fb_info)) < 0) { + ret = register_framebuffer(fbi); + if (ret < 0) { print_err("cannot register new framebuffer"); goto failed; } - au1200fb_fb_set_par(&fbdev->fb_info); + au1200fb_fb_set_par(fbi); #if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO) if (plane == 0) - if (fb_prepare_logo(&fbdev->fb_info, FB_ROTATE_UR)) { + if (fb_prepare_logo(fbi, FB_ROTATE_UR)) { /* Start display and show logo on boot */ - fb_set_cmap(&fbdev->fb_info.cmap, - &fbdev->fb_info); - - fb_show_logo(&fbdev->fb_info, FB_ROTATE_UR); + fb_set_cmap(&fbi->cmap, fbi); + fb_show_logo(fbi, FB_ROTATE_UR); } #endif } /* Now hook interrupt too */ - if ((ret = request_irq(AU1200_LCD_INT, au1200fb_handle_irq, - IRQF_DISABLED | IRQF_SHARED, "lcd", (void *)dev)) < 0) { + irq = platform_get_irq(dev, 0); + ret = request_irq(irq, au1200fb_handle_irq, + IRQF_DISABLED | IRQF_SHARED, "lcd", (void *)dev); + if (ret) { print_err("fail to request interrupt line %d (err: %d)", - AU1200_LCD_INT, ret); + irq, ret); goto failed; } @@ -1705,84 +1685,108 @@ static int au1200fb_drv_probe(struct platform_device *dev) failed: /* NOTE: This only does the current plane/window that failed; others are still active */ if (fbdev->fb_mem) - dma_free_noncoherent(dev, PAGE_ALIGN(fbdev->fb_len), + dma_free_noncoherent(&dev->dev, PAGE_ALIGN(fbdev->fb_len), fbdev->fb_mem, fbdev->fb_phys); - if (fbdev->fb_info.cmap.len != 0) - fb_dealloc_cmap(&fbdev->fb_info.cmap); - if (fbdev->fb_info.pseudo_palette) - kfree(fbdev->fb_info.pseudo_palette); + if (fbi) { + if (fbi->cmap.len != 0) + fb_dealloc_cmap(&fbi->cmap); + kfree(fbi->pseudo_palette); + } if (plane == 0) free_irq(AU1200_LCD_INT, (void*)dev); return ret; } -static int au1200fb_drv_remove(struct platform_device *dev) +static int __devexit au1200fb_drv_remove(struct platform_device *dev) { struct au1200fb_device *fbdev; + struct fb_info *fbi; int plane; - if (!dev) - return -ENODEV; - /* Turn off the panel */ au1200_setpanel(NULL); - for (plane = 0; plane < CONFIG_FB_AU1200_DEVS; ++plane) - { - fbdev = &_au1200fb_devices[plane]; + for (plane = 0; plane < device_count; ++plane) { + fbi = _au1200fb_infos[plane]; + fbdev = fbi->par; /* Clean up all probe data */ - unregister_framebuffer(&fbdev->fb_info); + unregister_framebuffer(fbi); if (fbdev->fb_mem) dma_free_noncoherent(&dev->dev, PAGE_ALIGN(fbdev->fb_len), fbdev->fb_mem, fbdev->fb_phys); - if (fbdev->fb_info.cmap.len != 0) - fb_dealloc_cmap(&fbdev->fb_info.cmap); - if (fbdev->fb_info.pseudo_palette) - kfree(fbdev->fb_info.pseudo_palette); + if (fbi->cmap.len != 0) + fb_dealloc_cmap(&fbi->cmap); + kfree(fbi->pseudo_palette); + + framebuffer_release(fbi); + _au1200fb_infos[plane] = NULL; } - free_irq(AU1200_LCD_INT, (void *)dev); + free_irq(platform_get_irq(dev, 0), (void *)dev); return 0; } #ifdef CONFIG_PM -static int au1200fb_drv_suspend(struct platform_device *dev, u32 state) +static int au1200fb_drv_suspend(struct device *dev) { - /* TODO */ + au1200_setpanel(NULL); + + lcd->outmask = 0; + au_sync(); + return 0; } -static int au1200fb_drv_resume(struct platform_device *dev) +static int au1200fb_drv_resume(struct device *dev) { - /* TODO */ + struct fb_info *fbi; + int i; + + /* Kickstart the panel */ + au1200_setpanel(panel); + + for (i = 0; i < device_count; i++) { + fbi = _au1200fb_infos[i]; + au1200fb_fb_set_par(fbi); + } + return 0; } + +static const struct dev_pm_ops au1200fb_pmops = { + .suspend = au1200fb_drv_suspend, + .resume = au1200fb_drv_resume, + .freeze = au1200fb_drv_suspend, + .thaw = au1200fb_drv_resume, +}; + +#define AU1200FB_PMOPS (&au1200fb_pmops) + +#else +#define AU1200FB_PMOPS NULL #endif /* CONFIG_PM */ static struct platform_driver au1200fb_driver = { .driver = { - .name = "au1200-lcd", - .owner = THIS_MODULE, + .name = "au1200-lcd", + .owner = THIS_MODULE, + .pm = AU1200FB_PMOPS, }, .probe = au1200fb_drv_probe, - .remove = au1200fb_drv_remove, -#ifdef CONFIG_PM - .suspend = au1200fb_drv_suspend, - .resume = au1200fb_drv_resume, -#endif + .remove = __devexit_p(au1200fb_drv_remove), }; /*-------------------------------------------------------------------------*/ /* Kernel driver */ -static void au1200fb_setup(void) +static int au1200fb_setup(void) { - char* options = NULL; - char* this_opt; + char *options = NULL; + char *this_opt, *endptr; int num_panels = ARRAY_SIZE(known_lcd_panels); int panel_idx = -1; @@ -1827,70 +1831,42 @@ static void au1200fb_setup(void) nohwcursor = 1; } - /* Unsupported option */ - else { - print_warn("Unsupported option \"%s\"", this_opt); + else if (strncmp(this_opt, "devices:", 8) == 0) { + this_opt += 8; + device_count = simple_strtol(this_opt, + &endptr, 0); + if ((device_count < 0) || + (device_count > MAX_DEVICE_COUNT)) + device_count = MAX_DEVICE_COUNT; } - } - } -} -#ifdef CONFIG_PM -static int au1200fb_pm_callback(au1xxx_power_dev_t *dev, - au1xxx_request_t request, void *data) { - int retval = -1; - unsigned int d = 0; - unsigned int brightness = 0; - - if (request == AU1XXX_PM_SLEEP) { - board_au1200fb_panel_shutdown(); - } - else if (request == AU1XXX_PM_WAKEUP) { - if(dev->prev_state == SLEEP_STATE) - { - int plane; - au1200_setpanel(panel); - for (plane = 0; plane < CONFIG_FB_AU1200_DEVS; ++plane) { - struct au1200fb_device *fbdev; - fbdev = &_au1200fb_devices[plane]; - au1200fb_fb_set_par(&fbdev->fb_info); + else if (strncmp(this_opt, "wincfg:", 7) == 0) { + this_opt += 7; + window_index = simple_strtol(this_opt, + &endptr, 0); + if ((window_index < 0) || + (window_index >= ARRAY_SIZE(windows))) + window_index = DEFAULT_WINDOW_INDEX; } - } - d = *((unsigned int*)data); - if(d <=10) brightness = 26; - else if(d<=20) brightness = 51; - else if(d<=30) brightness = 77; - else if(d<=40) brightness = 102; - else if(d<=50) brightness = 128; - else if(d<=60) brightness = 153; - else if(d<=70) brightness = 179; - else if(d<=80) brightness = 204; - else if(d<=90) brightness = 230; - else brightness = 255; - set_brightness(brightness); - } else if (request == AU1XXX_PM_GETSTATUS) { - return dev->cur_state; - } else if (request == AU1XXX_PM_ACCESS) { - if (dev->cur_state != SLEEP_STATE) - return retval; - else { - au1200_setpanel(panel); + else if (strncmp(this_opt, "off", 3) == 0) + return 1; + /* Unsupported option */ + else { + print_warn("Unsupported option \"%s\"", this_opt); + } } - } else if (request == AU1XXX_PM_IDLE) { - } else if (request == AU1XXX_PM_CLEANUP) { } - - return retval; + return 0; } -#endif static int __init au1200fb_init(void) { print_info("" DRIVER_DESC ""); /* Setup driver with options */ - au1200fb_setup(); + if (au1200fb_setup()) + return -ENODEV; /* Point to the panel selected */ panel = &known_lcd_panels[panel_index]; @@ -1899,17 +1875,6 @@ static int __init au1200fb_init(void) printk(DRIVER_NAME ": Panel %d %s\n", panel_index, panel->name); printk(DRIVER_NAME ": Win %d %s\n", window_index, win->name); - /* Kickstart the panel, the framebuffers/windows come soon enough */ - au1200_setpanel(panel); - - #ifdef CONFIG_PM - LCD_pm_dev = new_au1xxx_power_device("LCD", &au1200fb_pm_callback, NULL); - if ( LCD_pm_dev == NULL) - printk(KERN_INFO "Unable to create a power management device entry for the au1200fb.\n"); - else - printk(KERN_INFO "Power management device entry for the au1200fb loaded.\n"); - #endif - return platform_driver_register(&au1200fb_driver); } diff --git a/drivers/video/backlight/adp8860_bl.c b/drivers/video/backlight/adp8860_bl.c index 183b6f6..66bc74d 100644 --- a/drivers/video/backlight/adp8860_bl.c +++ b/drivers/video/backlight/adp8860_bl.c @@ -7,7 +7,6 @@ */ #include <linux/module.h> -#include <linux/version.h> #include <linux/init.h> #include <linux/errno.h> #include <linux/pm.h> diff --git a/drivers/video/backlight/adp8870_bl.c b/drivers/video/backlight/adp8870_bl.c index 05a8832..383c4c3 100644 --- a/drivers/video/backlight/adp8870_bl.c +++ b/drivers/video/backlight/adp8870_bl.c @@ -7,7 +7,6 @@ */ #include <linux/module.h> -#include <linux/version.h> #include <linux/init.h> #include <linux/errno.h> #include <linux/pm.h> diff --git a/drivers/video/carminefb.c b/drivers/video/carminefb.c index caaa27d..cb09aa1f 100644 --- a/drivers/video/carminefb.c +++ b/drivers/video/carminefb.c @@ -32,11 +32,11 @@ #define CARMINEFB_DEFAULT_VIDEO_MODE 1 static unsigned int fb_mode = CARMINEFB_DEFAULT_VIDEO_MODE; -module_param(fb_mode, uint, 444); +module_param(fb_mode, uint, 0444); MODULE_PARM_DESC(fb_mode, "Initial video mode as integer."); static char *fb_mode_str; -module_param(fb_mode_str, charp, 444); +module_param(fb_mode_str, charp, 0444); MODULE_PARM_DESC(fb_mode_str, "Initial video mode in characters."); /* @@ -46,7 +46,7 @@ MODULE_PARM_DESC(fb_mode_str, "Initial video mode in characters."); * 0b010 Display 1 */ static int fb_displays = CARMINE_USE_DISPLAY0 | CARMINE_USE_DISPLAY1; -module_param(fb_displays, int, 444); +module_param(fb_displays, int, 0444); MODULE_PARM_DESC(fb_displays, "Bit mode, which displays are used"); struct carmine_hw { diff --git a/drivers/video/controlfb.c b/drivers/video/controlfb.c index 9075bea5..7b2c40a 100644 --- a/drivers/video/controlfb.c +++ b/drivers/video/controlfb.c @@ -550,7 +550,7 @@ static void control_set_hardware(struct fb_info_control *p, struct fb_par_contro /* - * Parse user speficied options (`video=controlfb:') + * Parse user specified options (`video=controlfb:') */ static void __init control_setup(char *options) { diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c index 8d4e4eb..217c05f 100644 --- a/drivers/video/da8xx-fb.c +++ b/drivers/video/da8xx-fb.c @@ -35,6 +35,9 @@ #define DRIVER_NAME "da8xx_lcdc" +#define LCD_VERSION_1 1 +#define LCD_VERSION_2 2 + /* LCD Status Register */ #define LCD_END_OF_FRAME1 BIT(9) #define LCD_END_OF_FRAME0 BIT(8) @@ -49,7 +52,9 @@ #define LCD_DMA_BURST_4 0x2 #define LCD_DMA_BURST_8 0x3 #define LCD_DMA_BURST_16 0x4 -#define LCD_END_OF_FRAME_INT_ENA BIT(2) +#define LCD_V1_END_OF_FRAME_INT_ENA BIT(2) +#define LCD_V2_END_OF_FRAME0_INT_ENA BIT(8) +#define LCD_V2_END_OF_FRAME1_INT_ENA BIT(9) #define LCD_DUAL_FRAME_BUFFER_ENABLE BIT(0) /* LCD Control Register */ @@ -65,12 +70,18 @@ #define LCD_MONO_8BIT_MODE BIT(9) #define LCD_RASTER_ORDER BIT(8) #define LCD_TFT_MODE BIT(7) -#define LCD_UNDERFLOW_INT_ENA BIT(6) -#define LCD_PL_ENABLE BIT(4) +#define LCD_V1_UNDERFLOW_INT_ENA BIT(6) +#define LCD_V2_UNDERFLOW_INT_ENA BIT(5) +#define LCD_V1_PL_INT_ENA BIT(4) +#define LCD_V2_PL_INT_ENA BIT(6) #define LCD_MONOCHROME_MODE BIT(1) #define LCD_RASTER_ENABLE BIT(0) #define LCD_TFT_ALT_ENABLE BIT(23) #define LCD_STN_565_ENABLE BIT(24) +#define LCD_V2_DMA_CLK_EN BIT(2) +#define LCD_V2_LIDD_CLK_EN BIT(1) +#define LCD_V2_CORE_CLK_EN BIT(0) +#define LCD_V2_LPP_B10 26 /* LCD Raster Timing 2 Register */ #define LCD_AC_BIAS_TRANSITIONS_PER_INT(x) ((x) << 16) @@ -82,6 +93,7 @@ #define LCD_INVERT_FRAME_CLOCK BIT(20) /* LCD Block */ +#define LCD_PID_REG 0x0 #define LCD_CTRL_REG 0x4 #define LCD_STAT_REG 0x8 #define LCD_RASTER_CTRL_REG 0x28 @@ -94,6 +106,17 @@ #define LCD_DMA_FRM_BUF_BASE_ADDR_1_REG 0x4C #define LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG 0x50 +/* Interrupt Registers available only in Version 2 */ +#define LCD_RAW_STAT_REG 0x58 +#define LCD_MASKED_STAT_REG 0x5c +#define LCD_INT_ENABLE_SET_REG 0x60 +#define LCD_INT_ENABLE_CLR_REG 0x64 +#define LCD_END_OF_INT_IND_REG 0x68 + +/* Clock registers available only on Version 2 */ +#define LCD_CLK_ENABLE_REG 0x6c +#define LCD_CLK_RESET_REG 0x70 + #define LCD_NUM_BUFFERS 2 #define WSI_TIMEOUT 50 @@ -105,6 +128,8 @@ static resource_size_t da8xx_fb_reg_base; static struct resource *lcdc_regs; +static unsigned int lcd_revision; +static irq_handler_t lcdc_irq_handler; static inline unsigned int lcdc_read(unsigned int addr) { @@ -240,6 +265,7 @@ static void lcd_blit(int load_mode, struct da8xx_fb_par *par) u32 end; u32 reg_ras; u32 reg_dma; + u32 reg_int; /* init reg to clear PLM (loading mode) fields */ reg_ras = lcdc_read(LCD_RASTER_CTRL_REG); @@ -252,7 +278,14 @@ static void lcd_blit(int load_mode, struct da8xx_fb_par *par) end = par->dma_end; reg_ras |= LCD_PALETTE_LOAD_MODE(DATA_ONLY); - reg_dma |= LCD_END_OF_FRAME_INT_ENA; + if (lcd_revision == LCD_VERSION_1) { + reg_dma |= LCD_V1_END_OF_FRAME_INT_ENA; + } else { + reg_int = lcdc_read(LCD_INT_ENABLE_SET_REG) | + LCD_V2_END_OF_FRAME0_INT_ENA | + LCD_V2_END_OF_FRAME1_INT_ENA; + lcdc_write(reg_int, LCD_INT_ENABLE_SET_REG); + } reg_dma |= LCD_DUAL_FRAME_BUFFER_ENABLE; lcdc_write(start, LCD_DMA_FRM_BUF_BASE_ADDR_0_REG); @@ -264,7 +297,14 @@ static void lcd_blit(int load_mode, struct da8xx_fb_par *par) end = start + par->palette_sz - 1; reg_ras |= LCD_PALETTE_LOAD_MODE(PALETTE_ONLY); - reg_ras |= LCD_PL_ENABLE; + + if (lcd_revision == LCD_VERSION_1) { + reg_ras |= LCD_V1_PL_INT_ENA; + } else { + reg_int = lcdc_read(LCD_INT_ENABLE_SET_REG) | + LCD_V2_PL_INT_ENA; + lcdc_write(reg_int, LCD_INT_ENABLE_SET_REG); + } lcdc_write(start, LCD_DMA_FRM_BUF_BASE_ADDR_0_REG); lcdc_write(end, LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG); @@ -348,6 +388,7 @@ static void lcd_cfg_vertical_sync(int back_porch, int pulse_width, static int lcd_cfg_display(const struct lcd_ctrl_config *cfg) { u32 reg; + u32 reg_int; reg = lcdc_read(LCD_RASTER_CTRL_REG) & ~(LCD_TFT_MODE | LCD_MONO_8BIT_MODE | @@ -375,7 +416,13 @@ static int lcd_cfg_display(const struct lcd_ctrl_config *cfg) } /* enable additional interrupts here */ - reg |= LCD_UNDERFLOW_INT_ENA; + if (lcd_revision == LCD_VERSION_1) { + reg |= LCD_V1_UNDERFLOW_INT_ENA; + } else { + reg_int = lcdc_read(LCD_INT_ENABLE_SET_REG) | + LCD_V2_UNDERFLOW_INT_ENA; + lcdc_write(reg_int, LCD_INT_ENABLE_SET_REG); + } lcdc_write(reg, LCD_RASTER_CTRL_REG); @@ -511,6 +558,9 @@ static void lcd_reset(struct da8xx_fb_par *par) /* DMA has to be disabled */ lcdc_write(0, LCD_DMA_CTRL_REG); lcdc_write(0, LCD_RASTER_CTRL_REG); + + if (lcd_revision == LCD_VERSION_2) + lcdc_write(0, LCD_INT_ENABLE_SET_REG); } static void lcd_calc_clk_divider(struct da8xx_fb_par *par) @@ -523,6 +573,11 @@ static void lcd_calc_clk_divider(struct da8xx_fb_par *par) /* Configure the LCD clock divisor. */ lcdc_write(LCD_CLK_DIVISOR(div) | (LCD_RASTER_MODE & 0x1), LCD_CTRL_REG); + + if (lcd_revision == LCD_VERSION_2) + lcdc_write(LCD_V2_DMA_CLK_EN | LCD_V2_LIDD_CLK_EN | + LCD_V2_CORE_CLK_EN, LCD_CLK_ENABLE_REG); + } static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg, @@ -583,7 +638,63 @@ static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg, return 0; } -static irqreturn_t lcdc_irq_handler(int irq, void *arg) +/* IRQ handler for version 2 of LCDC */ +static irqreturn_t lcdc_irq_handler_rev02(int irq, void *arg) +{ + struct da8xx_fb_par *par = arg; + u32 stat = lcdc_read(LCD_MASKED_STAT_REG); + u32 reg_int; + + if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) { + lcd_disable_raster(); + lcdc_write(stat, LCD_MASKED_STAT_REG); + lcd_enable_raster(); + } else if (stat & LCD_PL_LOAD_DONE) { + /* + * Must disable raster before changing state of any control bit. + * And also must be disabled before clearing the PL loading + * interrupt via the following write to the status register. If + * this is done after then one gets multiple PL done interrupts. + */ + lcd_disable_raster(); + + lcdc_write(stat, LCD_MASKED_STAT_REG); + + /* Disable PL completion inerrupt */ + reg_int = lcdc_read(LCD_INT_ENABLE_CLR_REG) | + (LCD_V2_PL_INT_ENA); + lcdc_write(reg_int, LCD_INT_ENABLE_CLR_REG); + + /* Setup and start data loading mode */ + lcd_blit(LOAD_DATA, par); + } else { + lcdc_write(stat, LCD_MASKED_STAT_REG); + + if (stat & LCD_END_OF_FRAME0) { + lcdc_write(par->dma_start, + LCD_DMA_FRM_BUF_BASE_ADDR_0_REG); + lcdc_write(par->dma_end, + LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG); + par->vsync_flag = 1; + wake_up_interruptible(&par->vsync_wait); + } + + if (stat & LCD_END_OF_FRAME1) { + lcdc_write(par->dma_start, + LCD_DMA_FRM_BUF_BASE_ADDR_1_REG); + lcdc_write(par->dma_end, + LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG); + par->vsync_flag = 1; + wake_up_interruptible(&par->vsync_wait); + } + } + + lcdc_write(0, LCD_END_OF_INT_IND_REG); + return IRQ_HANDLED; +} + +/* IRQ handler for version 1 LCDC */ +static irqreturn_t lcdc_irq_handler_rev01(int irq, void *arg) { struct da8xx_fb_par *par = arg; u32 stat = lcdc_read(LCD_STAT_REG); @@ -606,7 +717,7 @@ static irqreturn_t lcdc_irq_handler(int irq, void *arg) /* Disable PL completion inerrupt */ reg_ras = lcdc_read(LCD_RASTER_CTRL_REG); - reg_ras &= ~LCD_PL_ENABLE; + reg_ras &= ~LCD_V1_PL_INT_ENA; lcdc_write(reg_ras, LCD_RASTER_CTRL_REG); /* Setup and start data loading mode */ @@ -945,6 +1056,22 @@ static int __devinit fb_probe(struct platform_device *device) if (ret) goto err_clk_put; + /* Determine LCD IP Version */ + switch (lcdc_read(LCD_PID_REG)) { + case 0x4C100102: + lcd_revision = LCD_VERSION_1; + break; + case 0x4F200800: + lcd_revision = LCD_VERSION_2; + break; + default: + dev_warn(&device->dev, "Unknown PID Reg value 0x%x, " + "defaulting to LCD revision 1\n", + lcdc_read(LCD_PID_REG)); + lcd_revision = LCD_VERSION_1; + break; + } + for (i = 0, lcdc_info = known_lcd_panels; i < ARRAY_SIZE(known_lcd_panels); i++, lcdc_info++) { @@ -1085,7 +1212,13 @@ static int __devinit fb_probe(struct platform_device *device) } #endif - ret = request_irq(par->irq, lcdc_irq_handler, 0, DRIVER_NAME, par); + if (lcd_revision == LCD_VERSION_1) + lcdc_irq_handler = lcdc_irq_handler_rev01; + else + lcdc_irq_handler = lcdc_irq_handler_rev02; + + ret = request_irq(par->irq, lcdc_irq_handler, 0, + DRIVER_NAME, par); if (ret) goto irq_freq; return 0; diff --git a/drivers/video/fb_defio.c b/drivers/video/fb_defio.c index 32814e8..c27e153 100644 --- a/drivers/video/fb_defio.c +++ b/drivers/video/fb_defio.c @@ -223,8 +223,7 @@ void fb_deferred_io_cleanup(struct fb_info *info) int i; BUG_ON(!fbdefio); - cancel_delayed_work(&info->deferred_work); - flush_scheduled_work(); + cancel_delayed_work_sync(&info->deferred_work); /* clear out the mapping that we setup */ for (i = 0 ; i < info->fix.smem_len; i += PAGE_SIZE) { diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c index 0acc7d6..0f1933b 100644 --- a/drivers/video/fsl-diu-fb.c +++ b/drivers/video/fsl-diu-fb.c @@ -31,8 +31,6 @@ #include <linux/uaccess.h> #include <linux/vmalloc.h> -#include <linux/of_platform.h> - #include <sysdev/fsl_soc.h> #include <linux/fsl-diu-fb.h> #include "edid.h" @@ -183,7 +181,8 @@ static struct fb_videomode __devinitdata fsl_diu_mode_db[] = { static char *fb_mode = "1024x768-32@60"; static unsigned long default_bpp = 32; -static int monitor_port; +static enum fsl_diu_monitor_port monitor_port; +static char *monitor_string; #if defined(CONFIG_NOT_COHERENT_CACHE) static u8 *coherence_data; @@ -201,7 +200,7 @@ struct fsl_diu_data { void *dummy_aoi_virt; unsigned int irq; int fb_enabled; - int monitor_port; + enum fsl_diu_monitor_port monitor_port; }; struct mfb_info { @@ -282,6 +281,37 @@ static struct diu_hw dr = { static struct diu_pool pool; /** + * fsl_diu_name_to_port - convert a port name to a monitor port enum + * + * Takes the name of a monitor port ("dvi", "lvds", or "dlvds") and returns + * the enum fsl_diu_monitor_port that corresponds to that string. + * + * For compatibility with older versions, a number ("0", "1", or "2") is also + * supported. + * + * If the string is unknown, DVI is assumed. + * + * If the particular port is not supported by the platform, another port + * (platform-specific) is chosen instead. + */ +static enum fsl_diu_monitor_port fsl_diu_name_to_port(const char *s) +{ + enum fsl_diu_monitor_port port = FSL_DIU_PORT_DVI; + unsigned long val; + + if (s) { + if (!strict_strtoul(s, 10, &val) && (val <= 2)) + port = (enum fsl_diu_monitor_port) val; + else if (strncmp(s, "lvds", 4) == 0) + port = FSL_DIU_PORT_LVDS; + else if (strncmp(s, "dlvds", 5) == 0) + port = FSL_DIU_PORT_DLVDS; + } + + return diu_ops.valid_monitor_port(port); +} + +/** * fsl_diu_alloc - allocate memory for the DIU * @size: number of bytes to allocate * @param: returned physical address of memory @@ -831,9 +861,8 @@ static int fsl_diu_set_par(struct fb_info *info) } } - ad->pix_fmt = - diu_ops.get_pixel_format(var->bits_per_pixel, - machine_data->monitor_port); + ad->pix_fmt = diu_ops.get_pixel_format(machine_data->monitor_port, + var->bits_per_pixel); ad->addr = cpu_to_le32(info->fix.smem_start); ad->src_size_g_alpha = cpu_to_le32((var->yres_virtual << 12) | var->xres_virtual) | mfbi->g_alpha; @@ -1439,16 +1468,12 @@ static void free_buf(struct device *dev, struct diu_addr *buf, u32 size, static ssize_t store_monitor(struct device *device, struct device_attribute *attr, const char *buf, size_t count) { - int old_monitor_port; - unsigned long val; + enum fsl_diu_monitor_port old_monitor_port; struct fsl_diu_data *machine_data = container_of(attr, struct fsl_diu_data, dev_attr); - if (strict_strtoul(buf, 10, &val)) - return 0; - old_monitor_port = machine_data->monitor_port; - machine_data->monitor_port = diu_ops.set_sysfs_monitor_port(val); + machine_data->monitor_port = fsl_diu_name_to_port(buf); if (old_monitor_port != machine_data->monitor_port) { /* All AOIs need adjust pixel format @@ -1468,7 +1493,17 @@ static ssize_t show_monitor(struct device *device, { struct fsl_diu_data *machine_data = container_of(attr, struct fsl_diu_data, dev_attr); - return diu_ops.show_monitor_port(machine_data->monitor_port, buf); + + switch (machine_data->monitor_port) { + case FSL_DIU_PORT_DVI: + return sprintf(buf, "DVI\n"); + case FSL_DIU_PORT_LVDS: + return sprintf(buf, "Single-link LVDS\n"); + case FSL_DIU_PORT_DLVDS: + return sprintf(buf, "Dual-link LVDS\n"); + } + + return 0; } static int __devinit fsl_diu_probe(struct platform_device *ofdev) @@ -1692,8 +1727,7 @@ static int __init fsl_diu_setup(char *options) if (!*opt) continue; if (!strncmp(opt, "monitor=", 8)) { - if (!strict_strtoul(opt + 8, 10, &val) && (val <= 2)) - monitor_port = val; + monitor_port = fsl_diu_name_to_port(opt + 8); } else if (!strncmp(opt, "bpp=", 4)) { if (!strict_strtoul(opt + 4, 10, &val)) default_bpp = val; @@ -1746,6 +1780,8 @@ static int __init fsl_diu_init(void) if (fb_get_options("fslfb", &option)) return -ENODEV; fsl_diu_setup(option); +#else + monitor_port = fsl_diu_name_to_port(monitor_string); #endif printk(KERN_INFO "Freescale DIU driver\n"); @@ -1812,7 +1848,7 @@ MODULE_PARM_DESC(mode, "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" "); module_param_named(bpp, default_bpp, ulong, 0); MODULE_PARM_DESC(bpp, "Specify bit-per-pixel if not specified mode"); -module_param_named(monitor, monitor_port, int, 0); -MODULE_PARM_DESC(monitor, - "Specify the monitor port (0, 1 or 2) if supported by the platform"); +module_param_named(monitor, monitor_string, charp, 0); +MODULE_PARM_DESC(monitor, "Specify the monitor port " + "(\"dvi\", \"lvds\", or \"dlvds\") if supported by the platform"); diff --git a/drivers/video/grvga.c b/drivers/video/grvga.c new file mode 100644 index 0000000..f37e025 --- /dev/null +++ b/drivers/video/grvga.c @@ -0,0 +1,579 @@ +/* + * Driver for Aeroflex Gaisler SVGACTRL framebuffer device. + * + * 2011 (c) Aeroflex Gaisler AB + * + * Full documentation of the core can be found here: + * http://www.gaisler.com/products/grlib/grip.pdf + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Contributors: Kristoffer Glembo <kristoffer@gaisler.com> + * + */ + +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <linux/of_platform.h> +#include <linux/of_device.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/tty.h> +#include <linux/mm.h> +#include <linux/fb.h> +#include <linux/io.h> + +struct grvga_regs { + u32 status; /* 0x00 */ + u32 video_length; /* 0x04 */ + u32 front_porch; /* 0x08 */ + u32 sync_length; /* 0x0C */ + u32 line_length; /* 0x10 */ + u32 fb_pos; /* 0x14 */ + u32 clk_vector[4]; /* 0x18 */ + u32 clut; /* 0x20 */ +}; + +struct grvga_par { + struct grvga_regs *regs; + u32 color_palette[16]; /* 16 entry pseudo palette used by fbcon in true color mode */ + int clk_sel; + int fb_alloced; /* = 1 if framebuffer is allocated in main memory */ +}; + + +static const struct fb_videomode grvga_modedb[] = { + { + /* 640x480 @ 60 Hz */ + NULL, 60, 640, 480, 40000, 48, 16, 39, 11, 96, 2, + 0, FB_VMODE_NONINTERLACED + }, { + /* 800x600 @ 60 Hz */ + NULL, 60, 800, 600, 25000, 88, 40, 23, 1, 128, 4, + 0, FB_VMODE_NONINTERLACED + }, { + /* 800x600 @ 72 Hz */ + NULL, 72, 800, 600, 20000, 64, 56, 23, 37, 120, 6, + 0, FB_VMODE_NONINTERLACED + }, { + /* 1024x768 @ 60 Hz */ + NULL, 60, 1024, 768, 15385, 160, 24, 29, 3, 136, 6, + 0, FB_VMODE_NONINTERLACED + } + }; + +static struct fb_fix_screeninfo grvga_fix __initdata = { + .id = "AG SVGACTRL", + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_PSEUDOCOLOR, + .xpanstep = 0, + .ypanstep = 1, + .ywrapstep = 0, + .accel = FB_ACCEL_NONE, +}; + +static int grvga_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct grvga_par *par = info->par; + int i; + + if (!var->xres) + var->xres = 1; + if (!var->yres) + var->yres = 1; + if (var->bits_per_pixel <= 8) + var->bits_per_pixel = 8; + else if (var->bits_per_pixel <= 16) + var->bits_per_pixel = 16; + else if (var->bits_per_pixel <= 24) + var->bits_per_pixel = 24; + else if (var->bits_per_pixel <= 32) + var->bits_per_pixel = 32; + else + return -EINVAL; + + var->xres_virtual = var->xres; + var->yres_virtual = 2*var->yres; + + if (info->fix.smem_len) { + if ((var->yres_virtual*var->xres_virtual*var->bits_per_pixel/8) > info->fix.smem_len) + return -ENOMEM; + } + + /* Which clocks that are available can be read out in these registers */ + for (i = 0; i <= 3 ; i++) { + if (var->pixclock == par->regs->clk_vector[i]) + break; + } + if (i <= 3) + par->clk_sel = i; + else + return -EINVAL; + + switch (info->var.bits_per_pixel) { + case 8: + var->red = (struct fb_bitfield) {0, 8, 0}; /* offset, length, msb-right */ + var->green = (struct fb_bitfield) {0, 8, 0}; + var->blue = (struct fb_bitfield) {0, 8, 0}; + var->transp = (struct fb_bitfield) {0, 0, 0}; + break; + case 16: + var->red = (struct fb_bitfield) {11, 5, 0}; + var->green = (struct fb_bitfield) {5, 6, 0}; + var->blue = (struct fb_bitfield) {0, 5, 0}; + var->transp = (struct fb_bitfield) {0, 0, 0}; + break; + case 24: + case 32: + var->red = (struct fb_bitfield) {16, 8, 0}; + var->green = (struct fb_bitfield) {8, 8, 0}; + var->blue = (struct fb_bitfield) {0, 8, 0}; + var->transp = (struct fb_bitfield) {24, 8, 0}; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int grvga_set_par(struct fb_info *info) +{ + + u32 func = 0; + struct grvga_par *par = info->par; + + __raw_writel(((info->var.yres - 1) << 16) | (info->var.xres - 1), + &par->regs->video_length); + + __raw_writel((info->var.lower_margin << 16) | (info->var.right_margin), + &par->regs->front_porch); + + __raw_writel((info->var.vsync_len << 16) | (info->var.hsync_len), + &par->regs->sync_length); + + __raw_writel(((info->var.yres + info->var.lower_margin + info->var.upper_margin + info->var.vsync_len - 1) << 16) | + (info->var.xres + info->var.right_margin + info->var.left_margin + info->var.hsync_len - 1), + &par->regs->line_length); + + switch (info->var.bits_per_pixel) { + case 8: + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; + func = 1; + break; + case 16: + info->fix.visual = FB_VISUAL_TRUECOLOR; + func = 2; + break; + case 24: + case 32: + info->fix.visual = FB_VISUAL_TRUECOLOR; + func = 3; + break; + default: + return -EINVAL; + } + + __raw_writel((par->clk_sel << 6) | (func << 4) | 1, + &par->regs->status); + + info->fix.line_length = (info->var.xres_virtual*info->var.bits_per_pixel)/8; + return 0; +} + +static int grvga_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info) +{ + struct grvga_par *par; + par = info->par; + + if (regno >= 256) /* Size of CLUT */ + return -EINVAL; + + if (info->var.grayscale) { + /* grayscale = 0.30*R + 0.59*G + 0.11*B */ + red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; + } + + + +#define CNVT_TOHW(val, width) ((((val)<<(width))+0x7FFF-(val))>>16) + + red = CNVT_TOHW(red, info->var.red.length); + green = CNVT_TOHW(green, info->var.green.length); + blue = CNVT_TOHW(blue, info->var.blue.length); + transp = CNVT_TOHW(transp, info->var.transp.length); + +#undef CNVT_TOHW + + /* In PSEUDOCOLOR we use the hardware CLUT */ + if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) + __raw_writel((regno << 24) | (red << 16) | (green << 8) | blue, + &par->regs->clut); + + /* Truecolor uses the pseudo palette */ + else if (info->fix.visual == FB_VISUAL_TRUECOLOR) { + u32 v; + if (regno >= 16) + return -EINVAL; + + + v = (red << info->var.red.offset) | + (green << info->var.green.offset) | + (blue << info->var.blue.offset) | + (transp << info->var.transp.offset); + + ((u32 *) (info->pseudo_palette))[regno] = v; + } + return 0; +} + +static int grvga_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct grvga_par *par = info->par; + struct fb_fix_screeninfo *fix = &info->fix; + u32 base_addr; + + if (var->xoffset != 0) + return -EINVAL; + + base_addr = fix->smem_start + (var->yoffset * fix->line_length); + base_addr &= ~3UL; + + /* Set framebuffer base address */ + __raw_writel(base_addr, + &par->regs->fb_pos); + + return 0; +} + +static struct fb_ops grvga_ops = { + .owner = THIS_MODULE, + .fb_check_var = grvga_check_var, + .fb_set_par = grvga_set_par, + .fb_setcolreg = grvga_setcolreg, + .fb_pan_display = grvga_pan_display, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit +}; + +static int __init grvga_parse_custom(char *options, + struct fb_var_screeninfo *screendata) +{ + char *this_opt; + int count = 0; + if (!options || !*options) + return -1; + + while ((this_opt = strsep(&options, " ")) != NULL) { + if (!*this_opt) + continue; + + switch (count) { + case 0: + screendata->pixclock = simple_strtoul(this_opt, NULL, 0); + count++; + break; + case 1: + screendata->xres = screendata->xres_virtual = simple_strtoul(this_opt, NULL, 0); + count++; + break; + case 2: + screendata->right_margin = simple_strtoul(this_opt, NULL, 0); + count++; + break; + case 3: + screendata->hsync_len = simple_strtoul(this_opt, NULL, 0); + count++; + break; + case 4: + screendata->left_margin = simple_strtoul(this_opt, NULL, 0); + count++; + break; + case 5: + screendata->yres = screendata->yres_virtual = simple_strtoul(this_opt, NULL, 0); + count++; + break; + case 6: + screendata->lower_margin = simple_strtoul(this_opt, NULL, 0); + count++; + break; + case 7: + screendata->vsync_len = simple_strtoul(this_opt, NULL, 0); + count++; + break; + case 8: + screendata->upper_margin = simple_strtoul(this_opt, NULL, 0); + count++; + break; + case 9: + screendata->bits_per_pixel = simple_strtoul(this_opt, NULL, 0); + count++; + break; + default: + return -1; + } + } + screendata->activate = FB_ACTIVATE_NOW; + screendata->vmode = FB_VMODE_NONINTERLACED; + return 0; +} + +static int __devinit grvga_probe(struct platform_device *dev) +{ + struct fb_info *info; + int retval = -ENOMEM; + unsigned long virtual_start; + unsigned long grvga_fix_addr = 0; + unsigned long physical_start = 0; + unsigned long grvga_mem_size = 0; + struct grvga_par *par = NULL; + char *options = NULL, *mode_opt = NULL; + + info = framebuffer_alloc(sizeof(struct grvga_par), &dev->dev); + if (!info) { + dev_err(&dev->dev, "framebuffer_alloc failed\n"); + return -ENOMEM; + } + + /* Expecting: "grvga: modestring, [addr:<framebuffer physical address>], [size:<framebuffer size>] + * + * If modestring is custom:<custom mode string> we parse the string which then contains all videoparameters + * If address is left out, we allocate memory, + * if size is left out we only allocate enough to support the given mode. + */ + if (fb_get_options("grvga", &options)) { + retval = -ENODEV; + goto err; + } + + if (!options || !*options) + options = "640x480-8@60"; + + while (1) { + char *this_opt = strsep(&options, ","); + + if (!this_opt) + break; + + if (!strncmp(this_opt, "custom", 6)) { + if (grvga_parse_custom(this_opt, &info->var) < 0) { + dev_err(&dev->dev, "Failed to parse custom mode (%s).\n", this_opt); + retval = -EINVAL; + goto err1; + } + } else if (!strncmp(this_opt, "addr", 4)) + grvga_fix_addr = simple_strtoul(this_opt + 5, NULL, 16); + else if (!strncmp(this_opt, "size", 4)) + grvga_mem_size = simple_strtoul(this_opt + 5, NULL, 0); + else + mode_opt = this_opt; + } + + par = info->par; + info->fbops = &grvga_ops; + info->fix = grvga_fix; + info->pseudo_palette = par->color_palette; + info->flags = FBINFO_DEFAULT | FBINFO_PARTIAL_PAN_OK | FBINFO_HWACCEL_YPAN; + info->fix.smem_len = grvga_mem_size; + + if (!request_mem_region(dev->resource[0].start, resource_size(&dev->resource[0]), "grlib-svgactrl regs")) { + dev_err(&dev->dev, "registers already mapped\n"); + retval = -EBUSY; + goto err; + } + + par->regs = of_ioremap(&dev->resource[0], 0, + resource_size(&dev->resource[0]), + "grlib-svgactrl regs"); + + if (!par->regs) { + dev_err(&dev->dev, "failed to map registers\n"); + retval = -ENOMEM; + goto err1; + } + + retval = fb_alloc_cmap(&info->cmap, 256, 0); + if (retval < 0) { + dev_err(&dev->dev, "failed to allocate mem with fb_alloc_cmap\n"); + retval = -ENOMEM; + goto err2; + } + + if (mode_opt) { + retval = fb_find_mode(&info->var, info, mode_opt, + grvga_modedb, sizeof(grvga_modedb), &grvga_modedb[0], 8); + if (!retval || retval == 4) { + retval = -EINVAL; + goto err3; + } + } + + if (!grvga_mem_size) + grvga_mem_size = info->var.xres_virtual * info->var.yres_virtual * info->var.bits_per_pixel/8; + + if (grvga_fix_addr) { + /* Got framebuffer base address from argument list */ + + physical_start = grvga_fix_addr; + + if (!request_mem_region(physical_start, grvga_mem_size, dev->name)) { + dev_err(&dev->dev, "failed to request memory region\n"); + retval = -ENOMEM; + goto err3; + } + + virtual_start = (unsigned long) ioremap(physical_start, grvga_mem_size); + + if (!virtual_start) { + dev_err(&dev->dev, "error mapping framebuffer memory\n"); + retval = -ENOMEM; + goto err4; + } + } else { /* Allocate frambuffer memory */ + + unsigned long page; + + virtual_start = (unsigned long) __get_free_pages(GFP_DMA, + get_order(grvga_mem_size)); + if (!virtual_start) { + dev_err(&dev->dev, + "unable to allocate framebuffer memory (%lu bytes)\n", + grvga_mem_size); + retval = -ENOMEM; + goto err3; + } + + physical_start = dma_map_single(&dev->dev, (void *)virtual_start, grvga_mem_size, DMA_TO_DEVICE); + + /* Set page reserved so that mmap will work. This is necessary + * since we'll be remapping normal memory. + */ + for (page = virtual_start; + page < PAGE_ALIGN(virtual_start + grvga_mem_size); + page += PAGE_SIZE) { + SetPageReserved(virt_to_page(page)); + } + + par->fb_alloced = 1; + } + + memset((unsigned long *) virtual_start, 0, grvga_mem_size); + + info->screen_base = (char __iomem *) virtual_start; + info->fix.smem_start = physical_start; + info->fix.smem_len = grvga_mem_size; + + dev_set_drvdata(&dev->dev, info); + + dev_info(&dev->dev, + "Aeroflex Gaisler framebuffer device (fb%d), %dx%d-%d, using %luK of video memory @ %p\n", + info->node, info->var.xres, info->var.yres, info->var.bits_per_pixel, + grvga_mem_size >> 10, info->screen_base); + + retval = register_framebuffer(info); + if (retval < 0) { + dev_err(&dev->dev, "failed to register framebuffer\n"); + goto err4; + } + + __raw_writel(physical_start, &par->regs->fb_pos); + __raw_writel(__raw_readl(&par->regs->status) | 1, /* Enable framebuffer */ + &par->regs->status); + + return 0; + +err4: + dev_set_drvdata(&dev->dev, NULL); + if (grvga_fix_addr) { + release_mem_region(physical_start, grvga_mem_size); + iounmap((void *)virtual_start); + } else + kfree((void *)virtual_start); +err3: + fb_dealloc_cmap(&info->cmap); +err2: + of_iounmap(&dev->resource[0], par->regs, + resource_size(&dev->resource[0])); +err1: + release_mem_region(dev->resource[0].start, resource_size(&dev->resource[0])); +err: + framebuffer_release(info); + + return retval; +} + +static int __devexit grvga_remove(struct platform_device *device) +{ + struct fb_info *info = dev_get_drvdata(&device->dev); + struct grvga_par *par = info->par; + + if (info) { + unregister_framebuffer(info); + fb_dealloc_cmap(&info->cmap); + + of_iounmap(&device->resource[0], par->regs, + resource_size(&device->resource[0])); + release_mem_region(device->resource[0].start, resource_size(&device->resource[0])); + + if (!par->fb_alloced) { + release_mem_region(info->fix.smem_start, info->fix.smem_len); + iounmap(info->screen_base); + } else + kfree((void *)info->screen_base); + + framebuffer_release(info); + dev_set_drvdata(&device->dev, NULL); + } + + return 0; +} + +static struct of_device_id svgactrl_of_match[] = { + { + .name = "GAISLER_SVGACTRL", + }, + { + .name = "01_063", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, svgactrl_of_match); + +static struct platform_driver grvga_driver = { + .driver = { + .name = "grlib-svgactrl", + .owner = THIS_MODULE, + .of_match_table = svgactrl_of_match, + }, + .probe = grvga_probe, + .remove = __devexit_p(grvga_remove), +}; + + +static int __init grvga_init(void) +{ + return platform_driver_register(&grvga_driver); +} + +static void __exit grvga_exit(void) +{ + platform_driver_unregister(&grvga_driver); +} + +module_init(grvga_init); +module_exit(grvga_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Aeroflex Gaisler"); +MODULE_DESCRIPTION("Aeroflex Gaisler framebuffer device driver"); diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c index 243d16f..01fa660 100644 --- a/drivers/video/msm/mdp.c +++ b/drivers/video/msm/mdp.c @@ -421,7 +421,8 @@ int mdp_probe(struct platform_device *pdev) clk = clk_get(&pdev->dev, "mdp_clk"); if (IS_ERR(clk)) { printk(KERN_INFO "mdp: failed to get mdp clk"); - return PTR_ERR(clk); + ret = PTR_ERR(clk); + goto error_get_clk; } ret = request_irq(mdp->irq, mdp_isr, IRQF_DISABLED, "msm_mdp", mdp); @@ -495,6 +496,7 @@ int mdp_probe(struct platform_device *pdev) error_device_register: free_irq(mdp->irq, mdp); error_request_irq: +error_get_clk: iounmap(mdp->base); error_get_irq: error_ioremap: diff --git a/drivers/video/platinumfb.c b/drivers/video/platinumfb.c index f27ae16..6694923 100644 --- a/drivers/video/platinumfb.c +++ b/drivers/video/platinumfb.c @@ -490,7 +490,7 @@ static int platinum_var_to_par(struct fb_var_screeninfo *var, /* - * Parse user speficied options (`video=platinumfb:') + * Parse user specified options (`video=platinumfb:') */ static int __init platinumfb_setup(char *options) { diff --git a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c index f4f8ce8..dc7bfa9 100644 --- a/drivers/video/pm2fb.c +++ b/drivers/video/pm2fb.c @@ -1773,7 +1773,7 @@ MODULE_DEVICE_TABLE(pci, pm2fb_id_table); #ifndef MODULE /** - * Parse user speficied options. + * Parse user specified options. * * This is, comma-separated options following `video=pm2fb:'. */ diff --git a/drivers/video/pm3fb.c b/drivers/video/pm3fb.c index 8221b5b..6632ee5 100644 --- a/drivers/video/pm3fb.c +++ b/drivers/video/pm3fb.c @@ -1525,7 +1525,7 @@ static int __init pm3fb_setup(char *options) { char *this_opt; - /* Parse user speficied options (`video=pm3fb:') */ + /* Parse user specified options (`video=pm3fb:') */ if (!options || !*options) return 0; diff --git a/drivers/video/pxa3xx-gcu.c b/drivers/video/pxa3xx-gcu.c index 0283c70..d8de557 100644 --- a/drivers/video/pxa3xx-gcu.c +++ b/drivers/video/pxa3xx-gcu.c @@ -31,8 +31,6 @@ */ #include <linux/module.h> -#include <linux/version.h> - #include <linux/platform_device.h> #include <linux/dma-mapping.h> #include <linux/miscdevice.h> diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c index 0aa1376..798144a 100644 --- a/drivers/video/s3c2410fb.c +++ b/drivers/video/s3c2410fb.c @@ -767,7 +767,6 @@ static irqreturn_t s3c2410fb_irq(int irq, void *dev_id) static int s3c2410fb_cpufreq_transition(struct notifier_block *nb, unsigned long val, void *data) { - struct cpufreq_freqs *freqs = data; struct s3c2410fb_info *info; struct fb_info *fbinfo; long delta_f; diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c index 0f9af1a..946a949 100644 --- a/drivers/video/s3fb.c +++ b/drivers/video/s3fb.c @@ -1505,7 +1505,7 @@ static struct pci_driver s3fb_pci_driver = { .resume = s3_pci_resume, }; -/* Parse user speficied options */ +/* Parse user specified options */ #ifndef MODULE static int __init s3fb_setup(char *options) diff --git a/drivers/video/skeletonfb.c b/drivers/video/skeletonfb.c index 89158bc..30f7a81 100644 --- a/drivers/video/skeletonfb.c +++ b/drivers/video/skeletonfb.c @@ -989,7 +989,7 @@ static struct platform_device *xxxfb_device; */ int __init xxxfb_setup(char *options) { - /* Parse user speficied options (`video=xxxfb:') */ + /* Parse user specified options (`video=xxxfb:') */ } #endif /* MODULE */ diff --git a/drivers/video/udlfb.c b/drivers/video/udlfb.c index 101846c..3473e75 100644 --- a/drivers/video/udlfb.c +++ b/drivers/video/udlfb.c @@ -48,13 +48,22 @@ static const u32 udlfb_info_flags = FBINFO_DEFAULT | FBINFO_READS_FAST | FBINFO_HWACCEL_COPYAREA | FBINFO_MISC_ALWAYS_SETPAR; /* - * There are many DisplayLink-based products, all with unique PIDs. We are able - * to support all volume ones (circa 2009) with a single driver, so we match - * globally on VID. TODO: Probe() needs to detect when we might be running - * "future" chips, and bail on those, so a compatible driver can match. + * There are many DisplayLink-based graphics products, all with unique PIDs. + * So we match on DisplayLink's VID + Vendor-Defined Interface Class (0xff) + * We also require a match on SubClass (0x00) and Protocol (0x00), + * which is compatible with all known USB 2.0 era graphics chips and firmware, + * but allows DisplayLink to increment those for any future incompatible chips */ static struct usb_device_id id_table[] = { - {.idVendor = 0x17e9, .match_flags = USB_DEVICE_ID_MATCH_VENDOR,}, + {.idVendor = 0x17e9, + .bInterfaceClass = 0xff, + .bInterfaceSubClass = 0x00, + .bInterfaceProtocol = 0x00, + .match_flags = USB_DEVICE_ID_MATCH_VENDOR | + USB_DEVICE_ID_MATCH_INT_CLASS | + USB_DEVICE_ID_MATCH_INT_SUBCLASS | + USB_DEVICE_ID_MATCH_INT_PROTOCOL, + }, {}, }; MODULE_DEVICE_TABLE(usb, id_table); @@ -1613,7 +1622,7 @@ static int dlfb_usb_probe(struct usb_interface *interface, /* We don't register a new USB class. Our client interface is fbdev */ /* allocates framebuffer driver structure, not framebuffer memory */ - info = framebuffer_alloc(0, &usbdev->dev); + info = framebuffer_alloc(0, &interface->dev); if (!info) { retval = -ENOMEM; pr_err("framebuffer_alloc failed\n"); diff --git a/drivers/video/valkyriefb.c b/drivers/video/valkyriefb.c index 6b52bf6..3f5a041 100644 --- a/drivers/video/valkyriefb.c +++ b/drivers/video/valkyriefb.c @@ -555,7 +555,7 @@ static int __init valkyrie_init_info(struct fb_info *info, /* - * Parse user speficied options (`video=valkyriefb:') + * Parse user specified options (`video=valkyriefb:') */ int __init valkyriefb_setup(char *options) { diff --git a/drivers/video/via/via_modesetting.h b/drivers/video/via/via_modesetting.h index ae35cfd..0138845 100644 --- a/drivers/video/via/via_modesetting.h +++ b/drivers/video/via/via_modesetting.h @@ -28,6 +28,11 @@ #include <linux/types.h> + +#define VIA_PITCH_SIZE (1<<3) +#define VIA_PITCH_MAX 0x3FF8 + + void via_set_primary_address(u32 addr); void via_set_secondary_address(u32 addr); void via_set_primary_pitch(u32 pitch); diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c index 53aa443..09fa57c 100644 --- a/drivers/video/via/viafbdev.c +++ b/drivers/video/via/viafbdev.c @@ -151,7 +151,8 @@ static void viafb_update_fix(struct fb_info *info) info->fix.visual = bpp == 8 ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; - info->fix.line_length = (info->var.xres_virtual * bpp / 8 + 7) & ~7; + info->fix.line_length = ALIGN(info->var.xres_virtual * bpp / 8, + VIA_PITCH_SIZE); } static void viafb_setup_fixinfo(struct fb_fix_screeninfo *fix, @@ -238,8 +239,12 @@ static int viafb_check_var(struct fb_var_screeninfo *var, depth = 24; viafb_fill_var_color_info(var, depth); - line = (var->xres_virtual * var->bits_per_pixel / 8 + 7) & ~7; - if (line * var->yres_virtual > ppar->memsize) + if (var->xres_virtual < var->xres) + var->xres_virtual = var->xres; + + line = ALIGN(var->xres_virtual * var->bits_per_pixel / 8, + VIA_PITCH_SIZE); + if (line > VIA_PITCH_MAX || line * var->yres_virtual > ppar->memsize) return -EINVAL; /* Based on var passed in to calculate the refresh, @@ -348,8 +353,9 @@ static int viafb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) { struct viafb_par *viapar = info->par; - u32 vram_addr = (var->yoffset * var->xres_virtual + var->xoffset) - * (var->bits_per_pixel / 8) + viapar->vram_addr; + u32 vram_addr = viapar->vram_addr + + var->yoffset * info->fix.line_length + + var->xoffset * info->var.bits_per_pixel / 8; DEBUG_MSG(KERN_DEBUG "viafb_pan_display, address = %d\n", vram_addr); if (!viafb_dual_fb) { diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c index 77dea01..fcb6cd9 100644 --- a/drivers/video/xilinxfb.c +++ b/drivers/video/xilinxfb.c @@ -23,7 +23,6 @@ #include <linux/device.h> #include <linux/module.h> #include <linux/kernel.h> -#include <linux/version.h> #include <linux/errno.h> #include <linux/string.h> #include <linux/mm.h> |