diff options
Diffstat (limited to 'drivers/video')
-rw-r--r-- | drivers/video/Kconfig | 8 | ||||
-rw-r--r-- | drivers/video/atmel_lcdfb.c | 6 | ||||
-rw-r--r-- | drivers/video/backlight/Kconfig | 2 | ||||
-rw-r--r-- | drivers/video/console/.gitignore | 2 | ||||
-rw-r--r-- | drivers/video/console/Kconfig | 9 | ||||
-rw-r--r-- | drivers/video/console/Makefile | 12 | ||||
-rw-r--r-- | drivers/video/console/prom.uni | 11 | ||||
-rw-r--r-- | drivers/video/console/promcon.c | 598 | ||||
-rw-r--r-- | drivers/video/imxfb.c | 184 | ||||
-rw-r--r-- | drivers/video/omap/dispc.c | 6 | ||||
-rw-r--r-- | drivers/video/ps3fb.c | 2 | ||||
-rw-r--r-- | drivers/video/sa1100fb.c | 2 | ||||
-rw-r--r-- | drivers/video/sh_mobile_lcdcfb.c | 292 | ||||
-rw-r--r-- | drivers/video/uvesafb.c | 3 |
14 files changed, 363 insertions, 774 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 3b54b394017..11af4cb8924 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -7,6 +7,8 @@ menu "Graphics support" source "drivers/char/agp/Kconfig" +source "drivers/gpu/vga/Kconfig" + source "drivers/gpu/drm/Kconfig" config VGASTATE @@ -935,7 +937,7 @@ config FB_S1D13XXX config FB_ATMEL tristate "AT91/AT32 LCD Controller support" - depends on FB && (ARCH_AT91SAM9261 || ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || ARCH_AT91CAP9 || AVR32) + depends on FB && (ARCH_AT91SAM9261 || ARCH_AT91SAM9G10 || ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45 || ARCH_AT91CAP9 || AVR32) select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT @@ -951,7 +953,7 @@ config FB_INTSRAM config FB_ATMEL_STN bool "Use a STN display with AT91/AT32 LCD Controller" - depends on FB_ATMEL && MACH_AT91SAM9261EK + depends on FB_ATMEL && (MACH_AT91SAM9261EK || MACH_AT91SAM9G10EK) default n help Say Y if you want to connect a STN LCD display to the AT91/AT32 LCD @@ -1867,7 +1869,7 @@ config FB_W100 config FB_SH_MOBILE_LCDC tristate "SuperH Mobile LCDC framebuffer support" - depends on FB && SUPERH + depends on FB && SUPERH && HAVE_CLK select FB_SYS_FILLRECT select FB_SYS_COPYAREA select FB_SYS_IMAGEBLIT diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c index da05f0801bb..2830ffd7297 100644 --- a/drivers/video/atmel_lcdfb.c +++ b/drivers/video/atmel_lcdfb.c @@ -182,7 +182,8 @@ static unsigned long compute_hozval(unsigned long xres, unsigned long lcdcon2) { unsigned long value; - if (!(cpu_is_at91sam9261() || cpu_is_at32ap7000())) + if (!(cpu_is_at91sam9261() || cpu_is_at91sam9g10() + || cpu_is_at32ap7000())) return xres; value = xres; @@ -824,7 +825,8 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev) info->fix = atmel_lcdfb_fix; /* Enable LCDC Clocks */ - if (cpu_is_at91sam9261() || cpu_is_at32ap7000()) { + if (cpu_is_at91sam9261() || cpu_is_at91sam9g10() + || cpu_is_at32ap7000()) { sinfo->bus_clk = clk_get(dev, "hck1"); if (IS_ERR(sinfo->bus_clk)) { ret = PTR_ERR(sinfo->bus_clk); diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index f9d19be0554..90861cd9316 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -110,7 +110,7 @@ config BACKLIGHT_CLASS_DEVICE config BACKLIGHT_ATMEL_LCDC bool "Atmel LCDC Contrast-as-Backlight control" depends on BACKLIGHT_CLASS_DEVICE && FB_ATMEL - default y if MACH_SAM9261EK || MACH_SAM9263EK + default y if MACH_SAM9261EK || MACH_SAM9G10EK || MACH_SAM9263EK help This provides a backlight control internal to the Atmel LCDC driver. If the LCD "contrast control" on your board is wired diff --git a/drivers/video/console/.gitignore b/drivers/video/console/.gitignore deleted file mode 100644 index 0c258b45439..00000000000 --- a/drivers/video/console/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# conmakehash generated file -promcon_tbl.c diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig index 2f50a80b413..fc7d9bbb548 100644 --- a/drivers/video/console/Kconfig +++ b/drivers/video/console/Kconfig @@ -67,16 +67,9 @@ config SGI_NEWPORT_CONSOLE # bool 'IODC console' CONFIG_IODC_CONSOLE -config PROM_CONSOLE - bool "PROM console" - depends on SPARC - help - Say Y to build a console driver for Sun machines that uses the - terminal emulation built into their console PROMS. - config DUMMY_CONSOLE bool - depends on PROM_CONSOLE!=y || VGA_CONSOLE!=y || SGI_NEWPORT_CONSOLE!=y + depends on VGA_CONSOLE!=y || SGI_NEWPORT_CONSOLE!=y default y config DUMMY_CONSOLE_COLUMNS diff --git a/drivers/video/console/Makefile b/drivers/video/console/Makefile index ac46cc3f6a2..a862e9173eb 100644 --- a/drivers/video/console/Makefile +++ b/drivers/video/console/Makefile @@ -22,7 +22,6 @@ font-objs += $(font-objs-y) obj-$(CONFIG_DUMMY_CONSOLE) += dummycon.o obj-$(CONFIG_SGI_NEWPORT_CONSOLE) += newport_con.o font.o -obj-$(CONFIG_PROM_CONSOLE) += promcon.o promcon_tbl.o obj-$(CONFIG_STI_CONSOLE) += sticon.o sticore.o font.o obj-$(CONFIG_VGA_CONSOLE) += vgacon.o obj-$(CONFIG_MDA_CONSOLE) += mdacon.o @@ -40,14 +39,3 @@ obj-$(CONFIG_FB_STI) += sticore.o font.o ifeq ($(CONFIG_USB_SISUSBVGA_CON),y) obj-$(CONFIG_USB_SISUSBVGA) += font.o endif - -# Targets that kbuild needs to know about -targets := promcon_tbl.c - -quiet_cmd_conmakehash = CNMKHSH $@ - cmd_conmakehash = scripts/conmakehash $< | \ - sed -e '/\#include <[^>]*>/p' -e 's/types/init/' \ - -e 's/dfont\(_uni.*\]\)/promfont\1 /' > $@ - -$(obj)/promcon_tbl.c: $(src)/prom.uni - $(call cmd,conmakehash) diff --git a/drivers/video/console/prom.uni b/drivers/video/console/prom.uni deleted file mode 100644 index 58f9c04ed9d..00000000000 --- a/drivers/video/console/prom.uni +++ /dev/null @@ -1,11 +0,0 @@ -# -# Unicode mapping table for font in Sun PROM -# -# -0x20-0x7e idem -0xa0-0xff idem -# -0x7c U+2502 -0x2d U+2500 -0x2b U+250c U+2510 U+2514 U+2518 U+251c U+2524 U+252c U+2534 U+253c -0xa4 U+fffd diff --git a/drivers/video/console/promcon.c b/drivers/video/console/promcon.c deleted file mode 100644 index ae02e4eb18e..00000000000 --- a/drivers/video/console/promcon.c +++ /dev/null @@ -1,598 +0,0 @@ -/* $Id: promcon.c,v 1.17 2000/07/26 23:02:52 davem Exp $ - * Console driver utilizing PROM sun terminal emulation - * - * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) - * Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz) - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/string.h> -#include <linux/mm.h> -#include <linux/slab.h> -#include <linux/delay.h> -#include <linux/console.h> -#include <linux/vt_kern.h> -#include <linux/selection.h> -#include <linux/fb.h> -#include <linux/init.h> -#include <linux/kd.h> - -#include <asm/oplib.h> -#include <asm/uaccess.h> - -static short pw = 80 - 1, ph = 34 - 1; -static short px, py; -static unsigned long promcon_uni_pagedir[2]; - -extern u8 promfont_unicount[]; -extern u16 promfont_unitable[]; - -#define PROMCON_COLOR 0 - -#if PROMCON_COLOR -#define inverted(s) ((((s) & 0x7700) == 0x0700) ? 0 : 1) -#else -#define inverted(s) (((s) & 0x0800) ? 1 : 0) -#endif - -static __inline__ void -promcon_puts(char *buf, int cnt) -{ - prom_printf("%*.*s", cnt, cnt, buf); -} - -static int -promcon_start(struct vc_data *conp, char *b) -{ - unsigned short *s = (unsigned short *) - (conp->vc_origin + py * conp->vc_size_row + (px << 1)); - u16 cs; - - cs = scr_readw(s); - if (px == pw) { - unsigned short *t = s - 1; - u16 ct = scr_readw(t); - - if (inverted(cs) && inverted(ct)) - return sprintf(b, "\b\033[7m%c\b\033[@%c\033[m", cs, - ct); - else if (inverted(cs)) - return sprintf(b, "\b\033[7m%c\033[m\b\033[@%c", cs, - ct); - else if (inverted(ct)) - return sprintf(b, "\b%c\b\033[@\033[7m%c\033[m", cs, - ct); - else - return sprintf(b, "\b%c\b\033[@%c", cs, ct); - } - - if (inverted(cs)) - return sprintf(b, "\033[7m%c\033[m\b", cs); - else - return sprintf(b, "%c\b", cs); -} - -static int -promcon_end(struct vc_data *conp, char *b) -{ - unsigned short *s = (unsigned short *) - (conp->vc_origin + py * conp->vc_size_row + (px << 1)); - char *p = b; - u16 cs; - - b += sprintf(b, "\033[%d;%dH", py + 1, px + 1); - - cs = scr_readw(s); - if (px == pw) { - unsigned short *t = s - 1; - u16 ct = scr_readw(t); - - if (inverted(cs) && inverted(ct)) - b += sprintf(b, "\b%c\b\033[@\033[7m%c\033[m", cs, ct); - else if (inverted(cs)) - b += sprintf(b, "\b%c\b\033[@%c", cs, ct); - else if (inverted(ct)) - b += sprintf(b, "\b\033[7m%c\b\033[@%c\033[m", cs, ct); - else - b += sprintf(b, "\b\033[7m%c\033[m\b\033[@%c", cs, ct); - return b - p; - } - - if (inverted(cs)) - b += sprintf(b, "%c\b", cs); - else - b += sprintf(b, "\033[7m%c\033[m\b", cs); - return b - p; -} - -const char *promcon_startup(void) -{ - const char *display_desc = "PROM"; - int node; - char buf[40]; - - node = prom_getchild(prom_root_node); - node = prom_searchsiblings(node, "options"); - if (prom_getproperty(node, "screen-#columns", buf, 40) != -1) { - pw = simple_strtoul(buf, NULL, 0); - if (pw < 10 || pw > 256) - pw = 80; - pw--; - } - if (prom_getproperty(node, "screen-#rows", buf, 40) != -1) { - ph = simple_strtoul(buf, NULL, 0); - if (ph < 10 || ph > 256) - ph = 34; - ph--; - } - promcon_puts("\033[H\033[J", 6); - return display_desc; -} - -static void -promcon_init_unimap(struct vc_data *conp) -{ - mm_segment_t old_fs = get_fs(); - struct unipair *p, *p1; - u16 *q; - int i, j, k; - - p = kmalloc(256*sizeof(struct unipair), GFP_KERNEL); - if (!p) return; - - q = promfont_unitable; - p1 = p; - k = 0; - for (i = 0; i < 256; i++) - for (j = promfont_unicount[i]; j; j--) { - p1->unicode = *q++; - p1->fontpos = i; - p1++; - k++; - } - set_fs(KERNEL_DS); - con_clear_unimap(conp, NULL); - con_set_unimap(conp, k, p); - con_protect_unimap(conp, 1); - set_fs(old_fs); - kfree(p); -} - -static void -promcon_init(struct vc_data *conp, int init) -{ - unsigned long p; - - conp->vc_can_do_color = PROMCON_COLOR; - if (init) { - conp->vc_cols = pw + 1; - conp->vc_rows = ph + 1; - } - p = *conp->vc_uni_pagedir_loc; - if (conp->vc_uni_pagedir_loc == &conp->vc_uni_pagedir || - !--conp->vc_uni_pagedir_loc[1]) - con_free_unimap(conp); - conp->vc_uni_pagedir_loc = promcon_uni_pagedir; - promcon_uni_pagedir[1]++; - if (!promcon_uni_pagedir[0] && p) { - promcon_init_unimap(conp); - } - if (!init) { - if (conp->vc_cols != pw + 1 || conp->vc_rows != ph + 1) - vc_resize(conp, pw + 1, ph + 1); - } -} - -static void -promcon_deinit(struct vc_data *conp) -{ - /* When closing the last console, reset video origin */ - if (!--promcon_uni_pagedir[1]) - con_free_unimap(conp); - conp->vc_uni_pagedir_loc = &conp->vc_uni_pagedir; - con_set_default_unimap(conp); -} - -static int -promcon_switch(struct vc_data *conp) -{ - return 1; -} - -static unsigned short * -promcon_repaint_line(unsigned short *s, unsigned char *buf, unsigned char **bp) -{ - int cnt = pw + 1; - int attr = -1; - unsigned char *b = *bp; - - while (cnt--) { - u16 c = scr_readw(s); - if (attr != inverted(c)) { - attr = inverted(c); - if (attr) { - strcpy (b, "\033[7m"); - b += 4; - } else { - strcpy (b, "\033[m"); - b += 3; - } - } - *b++ = c; - s++; - if (b - buf >= 224) { - promcon_puts(buf, b - buf); - b = buf; - } - } - *bp = b; - return s; -} - -static void -promcon_putcs(struct vc_data *conp, const unsigned short *s, - int count, int y, int x) -{ - unsigned char buf[256], *b = buf; - unsigned short attr = scr_readw(s); - unsigned char save; - int i, last = 0; - - if (console_blanked) - return; - - if (count <= 0) - return; - - b += promcon_start(conp, b); - - if (x + count >= pw + 1) { - if (count == 1) { - x -= 1; - save = scr_readw((unsigned short *)(conp->vc_origin - + y * conp->vc_size_row - + (x << 1))); - - if (px != x || py != y) { - b += sprintf(b, "\033[%d;%dH", y + 1, x + 1); - px = x; - py = y; - } - - if (inverted(attr)) - b += sprintf(b, "\033[7m%c\033[m", scr_readw(s++)); - else - b += sprintf(b, "%c", scr_readw(s++)); - - strcpy(b, "\b\033[@"); - b += 4; - - if (inverted(save)) - b += sprintf(b, "\033[7m%c\033[m", save); - else - b += sprintf(b, "%c", save); - - px++; - - b += promcon_end(conp, b); - promcon_puts(buf, b - buf); - return; - } else { - last = 1; - count = pw - x - 1; - } - } - - if (inverted(attr)) { - strcpy(b, "\033[7m"); - b += 4; - } - - if (px != x || py != y) { - b += sprintf(b, "\033[%d;%dH", y + 1, x + 1); - px = x; - py = y; - } - - for (i = 0; i < count; i++) { - if (b - buf >= 224) { - promcon_puts(buf, b - buf); - b = buf; - } - *b++ = scr_readw(s++); - } - - px += count; - - if (last) { - save = scr_readw(s++); - b += sprintf(b, "%c\b\033[@%c", scr_readw(s++), save); - px++; - } - - if (inverted(attr)) { - strcpy(b, "\033[m"); - b += 3; - } - - b += promcon_end(conp, b); - promcon_puts(buf, b - buf); -} - -static void -promcon_putc(struct vc_data *conp, int c, int y, int x) -{ - unsigned short s; - - if (console_blanked) - return; - - scr_writew(c, &s); - promcon_putcs(conp, &s, 1, y, x); -} - -static void -promcon_clear(struct vc_data *conp, int sy, int sx, int height, int width) -{ - unsigned char buf[256], *b = buf; - int i, j; - - if (console_blanked) - return; - - b += promcon_start(conp, b); - - if (!sx && width == pw + 1) { - - if (!sy && height == ph + 1) { - strcpy(b, "\033[H\033[J"); - b += 6; - b += promcon_end(conp, b); - promcon_puts(buf, b - buf); - return; - } else if (sy + height == ph + 1) { - b += sprintf(b, "\033[%dH\033[J", sy + 1); - b += promcon_end(conp, b); - promcon_puts(buf, b - buf); - return; - } - - b += sprintf(b, "\033[%dH", sy + 1); - for (i = 1; i < height; i++) { - strcpy(b, "\033[K\n"); - b += 4; - } - - strcpy(b, "\033[K"); - b += 3; - - b += promcon_end(conp, b); - promcon_puts(buf, b - buf); - return; - - } else if (sx + width == pw + 1) { - - b += sprintf(b, "\033[%d;%dH", sy + 1, sx + 1); - for (i = 1; i < height; i++) { - strcpy(b, "\033[K\n"); - b += 4; - } - - strcpy(b, "\033[K"); - b += 3; - - b += promcon_end(conp, b); - promcon_puts(buf, b - buf); - return; - } - - for (i = sy + 1; i <= sy + height; i++) { - b += sprintf(b, "\033[%d;%dH", i, sx + 1); - for (j = 0; j < width; j++) - *b++ = ' '; - if (b - buf + width >= 224) { - promcon_puts(buf, b - buf); - b = buf; - } - } - - b += promcon_end(conp, b); - promcon_puts(buf, b - buf); -} - -static void -promcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx, - int height, int width) -{ - char buf[256], *b = buf; - - if (console_blanked) - return; - - b += promcon_start(conp, b); - if (sy == dy && height == 1) { - if (dx > sx && dx + width == conp->vc_cols) - b += sprintf(b, "\033[%d;%dH\033[%d@\033[%d;%dH", - sy + 1, sx + 1, dx - sx, py + 1, px + 1); - else if (dx < sx && sx + width == conp->vc_cols) - b += sprintf(b, "\033[%d;%dH\033[%dP\033[%d;%dH", - dy + 1, dx + 1, sx - dx, py + 1, px + 1); - - b += promcon_end(conp, b); - promcon_puts(buf, b - buf); - return; - } - - /* - * FIXME: What to do here??? - * Current console.c should not call it like that ever. - */ - prom_printf("\033[7mFIXME: bmove not handled\033[m\n"); -} - -static void -promcon_cursor(struct vc_data *conp, int mode) -{ - char buf[32], *b = buf; - - switch (mode) { - case CM_ERASE: - break; - - case CM_MOVE: - case CM_DRAW: - b += promcon_start(conp, b); - if (px != conp->vc_x || py != conp->vc_y) { - px = conp->vc_x; - py = conp->vc_y; - b += sprintf(b, "\033[%d;%dH", py + 1, px + 1); - } - promcon_puts(buf, b - buf); - break; - } -} - -static int -promcon_blank(struct vc_data *conp, int blank, int mode_switch) -{ - if (blank) { - promcon_puts("\033[H\033[J\033[7m \033[m\b", 15); - return 0; - } else { - /* Let console.c redraw */ - return 1; - } -} - -static int -promcon_scroll(struct vc_data *conp, int t, int b, int dir, int count) -{ - unsigned char buf[256], *p = buf; - unsigned short *s; - int i; - - if (console_blanked) - return 0; - - p += promcon_start(conp, p); - - switch (dir) { - case SM_UP: - if (b == ph + 1) { - p += sprintf(p, "\033[%dH\033[%dM", t + 1, count); - px = 0; - py = t; - p += promcon_end(conp, p); - promcon_puts(buf, p - buf); - break; - } - - s = (unsigned short *)(conp->vc_origin - + (t + count) * conp->vc_size_row); - - p += sprintf(p, "\033[%dH", t + 1); - - for (i = t; i < b - count; i++) - s = promcon_repaint_line(s, buf, &p); - - for (; i < b - 1; i++) { - strcpy(p, "\033[K\n"); - p += 4; - if (p - buf >= 224) { - promcon_puts(buf, p - buf); - p = buf; - } - } - - strcpy(p, "\033[K"); - p += 3; - - p += promcon_end(conp, p); - promcon_puts(buf, p - buf); - break; - - case SM_DOWN: - if (b == ph + 1) { - p += sprintf(p, "\033[%dH\033[%dL", t + 1, count); - px = 0; - py = t; - p += promcon_end(conp, p); - promcon_puts(buf, p - buf); - break; - } - - s = (unsigned short *)(conp->vc_origin + t * conp->vc_size_row); - - p += sprintf(p, "\033[%dH", t + 1); - - for (i = t; i < t + count; i++) { - strcpy(p, "\033[K\n"); - p += 4; - if (p - buf >= 224) { - promcon_puts(buf, p - buf); - p = buf; - } - } - - for (; i < b; i++) - s = promcon_repaint_line(s, buf, &p); - - p += promcon_end(conp, p); - promcon_puts(buf, p - buf); - break; - } - - return 0; -} - -#if !(PROMCON_COLOR) -static u8 promcon_build_attr(struct vc_data *conp, u8 _color, u8 _intensity, - u8 _blink, u8 _underline, u8 _reverse, u8 _italic) -{ - return (_reverse) ? 0xf : 0x7; -} -#endif - -/* - * The console 'switch' structure for the VGA based console - */ - -static int promcon_dummy(void) -{ - return 0; -} - -#define DUMMY (void *) promcon_dummy - -const struct consw prom_con = { - .owner = THIS_MODULE, - .con_startup = promcon_startup, - .con_init = promcon_init, - .con_deinit = promcon_deinit, - .con_clear = promcon_clear, - .con_putc = promcon_putc, - .con_putcs = promcon_putcs, - .con_cursor = promcon_cursor, - .con_scroll = promcon_scroll, - .con_bmove = promcon_bmove, - .con_switch = promcon_switch, - .con_blank = promcon_blank, - .con_set_palette = DUMMY, - .con_scrolldelta = DUMMY, -#if !(PROMCON_COLOR) - .con_build_attr = promcon_build_attr, -#endif -}; - -void __init prom_con_init(void) -{ -#ifdef CONFIG_DUMMY_CONSOLE - if (conswitchp == &dummy_con) - take_over_console(&prom_con, 0, MAX_NR_CONSOLES-1, 1); - else -#endif - if (conswitchp == &prom_con) - promcon_init_unimap(vc_cons[fg_console].d); -} diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c index 15a0ee6d8e2..30ae3022f63 100644 --- a/drivers/video/imxfb.c +++ b/drivers/video/imxfb.c @@ -33,6 +33,7 @@ #include <linux/math64.h> #include <mach/imxfb.h> +#include <mach/hardware.h> /* * Complain if VAR is out of range. @@ -129,6 +130,10 @@ #define LCDISR_EOF (1<<1) #define LCDISR_BOF (1<<0) +/* Used fb-mode. Can be set on kernel command line, therefore file-static. */ +static const char *fb_mode; + + /* * These are the bitfields for each * display depth that we support. @@ -145,10 +150,6 @@ struct imxfb_info { void __iomem *regs; struct clk *clk; - u_int max_bpp; - u_int max_xres; - u_int max_yres; - /* * These are the addresses we mapped * the framebuffer memory region to. @@ -172,6 +173,9 @@ struct imxfb_info { cmap_static:1, unused:30; + struct imx_fb_videomode *mode; + int num_modes; + void (*lcd_power)(int); void (*backlight_power)(int); }; @@ -298,6 +302,18 @@ static int imxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, return ret; } +static const struct imx_fb_videomode *imxfb_find_mode(struct imxfb_info *fbi) +{ + struct imx_fb_videomode *m; + int i; + + for (i = 0, m = &fbi->mode[0]; i < fbi->num_modes; i++, m++) { + if (!strcmp(m->mode.name, fb_mode)) + return m; + } + return NULL; +} + /* * imxfb_check_var(): * Round up in the following order: bits_per_pixel, xres, @@ -308,35 +324,81 @@ static int imxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { struct imxfb_info *fbi = info->par; struct imxfb_rgb *rgb; + const struct imx_fb_videomode *imxfb_mode; + unsigned long lcd_clk; + unsigned long long tmp; + u32 pcr = 0; if (var->xres < MIN_XRES) var->xres = MIN_XRES; if (var->yres < MIN_YRES) var->yres = MIN_YRES; - if (var->xres > fbi->max_xres) - var->xres = fbi->max_xres; - if (var->yres > fbi->max_yres) - var->yres = fbi->max_yres; - var->xres_virtual = max(var->xres_virtual, var->xres); - var->yres_virtual = max(var->yres_virtual, var->yres); + + imxfb_mode = imxfb_find_mode(fbi); + if (!imxfb_mode) + return -EINVAL; + + var->xres = imxfb_mode->mode.xres; + var->yres = imxfb_mode->mode.yres; + var->bits_per_pixel = imxfb_mode->bpp; + var->pixclock = imxfb_mode->mode.pixclock; + var->hsync_len = imxfb_mode->mode.hsync_len; + var->left_margin = imxfb_mode->mode.left_margin; + var->right_margin = imxfb_mode->mode.right_margin; + var->vsync_len = imxfb_mode->mode.vsync_len; + var->upper_margin = imxfb_mode->mode.upper_margin; + var->lower_margin = imxfb_mode->mode.lower_margin; + var->sync = imxfb_mode->mode.sync; + var->xres_virtual = max(var->xres_virtual, var->xres); + var->yres_virtual = max(var->yres_virtual, var->yres); pr_debug("var->bits_per_pixel=%d\n", var->bits_per_pixel); + + lcd_clk = clk_get_rate(fbi->clk); + + tmp = var->pixclock * (unsigned long long)lcd_clk; + + do_div(tmp, 1000000); + + if (do_div(tmp, 1000000) > 500000) + tmp++; + + pcr = (unsigned int)tmp; + + if (--pcr > 0x3F) { + pcr = 0x3F; + printk(KERN_WARNING "Must limit pixel clock to %luHz\n", + lcd_clk / pcr); + } + switch (var->bits_per_pixel) { case 32: + pcr |= PCR_BPIX_18; rgb = &def_rgb_18; break; case 16: default: - if (fbi->pcr & PCR_TFT) + if (cpu_is_mx1()) + pcr |= PCR_BPIX_12; + else + pcr |= PCR_BPIX_16; + + if (imxfb_mode->pcr & PCR_TFT) rgb = &def_rgb_16_tft; else rgb = &def_rgb_16_stn; break; case 8: + pcr |= PCR_BPIX_8; rgb = &def_rgb_8; break; } + /* add sync polarities */ + pcr |= imxfb_mode->pcr & ~(0x3f | (7 << 25)); + + fbi->pcr = pcr; + /* * Copy the RGB parameters for this display * from the machine specific parameters. @@ -393,10 +455,6 @@ static void imxfb_enable_controller(struct imxfb_info *fbi) writel(fbi->screen_dma, fbi->regs + LCDC_SSA); - /* physical screen start address */ - writel(VPW_VPW(fbi->max_xres * fbi->max_bpp / 8 / 4), - fbi->regs + LCDC_VPW); - /* panning offset 0 (0 pixel offset) */ writel(0x00000000, fbi->regs + LCDC_POS); @@ -468,8 +526,6 @@ static struct fb_ops imxfb_ops = { static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *info) { struct imxfb_info *fbi = info->par; - unsigned int pcr, lcd_clk; - unsigned long long tmp; pr_debug("var: xres=%d hslen=%d lm=%d rm=%d\n", var->xres, var->hsync_len, @@ -505,6 +561,10 @@ static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *inf info->fix.id, var->lower_margin); #endif + /* physical screen start address */ + writel(VPW_VPW(var->xres * var->bits_per_pixel / 8 / 4), + fbi->regs + LCDC_VPW); + writel(HCR_H_WIDTH(var->hsync_len - 1) | HCR_H_WAIT_1(var->right_margin - 1) | HCR_H_WAIT_2(var->left_margin - 3), @@ -518,22 +578,7 @@ static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *inf writel(SIZE_XMAX(var->xres) | SIZE_YMAX(var->yres), fbi->regs + LCDC_SIZE); - lcd_clk = clk_get_rate(fbi->clk); - tmp = var->pixclock * (unsigned long long)lcd_clk; - do_div(tmp, 1000000); - if (do_div(tmp, 1000000) > 500000) - tmp++; - pcr = (unsigned int)tmp; - if (--pcr > 0x3F) { - pcr = 0x3F; - printk(KERN_WARNING "Must limit pixel clock to %uHz\n", - lcd_clk / pcr); - } - - /* add sync polarities */ - pcr |= fbi->pcr & ~0x3F; - - writel(pcr, fbi->regs + LCDC_PCR); + writel(fbi->pcr, fbi->regs + LCDC_PCR); writel(fbi->pwmr, fbi->regs + LCDC_PWMR); writel(fbi->lscr1, fbi->regs + LCDC_LSCR1); writel(fbi->dmacr, fbi->regs + LCDC_DMACR); @@ -575,6 +620,8 @@ static int __init imxfb_init_fbinfo(struct platform_device *pdev) struct imx_fb_platform_data *pdata = pdev->dev.platform_data; struct fb_info *info = dev_get_drvdata(&pdev->dev); struct imxfb_info *fbi = info->par; + struct imx_fb_videomode *m; + int i; pr_debug("%s\n",__func__); @@ -603,35 +650,18 @@ static int __init imxfb_init_fbinfo(struct platform_device *pdev) info->fbops = &imxfb_ops; info->flags = FBINFO_FLAG_DEFAULT | FBINFO_READS_FAST; - - fbi->max_xres = pdata->xres; - info->var.xres = pdata->xres; - info->var.xres_virtual = pdata->xres; - fbi->max_yres = pdata->yres; - info->var.yres = pdata->yres; - info->var.yres_virtual = pdata->yres; - fbi->max_bpp = pdata->bpp; - info->var.bits_per_pixel = pdata->bpp; - info->var.nonstd = pdata->nonstd; - info->var.pixclock = pdata->pixclock; - info->var.hsync_len = pdata->hsync_len; - info->var.left_margin = pdata->left_margin; - info->var.right_margin = pdata->right_margin; - info->var.vsync_len = pdata->vsync_len; - info->var.upper_margin = pdata->upper_margin; - info->var.lower_margin = pdata->lower_margin; - info->var.sync = pdata->sync; info->var.grayscale = pdata->cmap_greyscale; fbi->cmap_inverse = pdata->cmap_inverse; fbi->cmap_static = pdata->cmap_static; - fbi->pcr = pdata->pcr; fbi->lscr1 = pdata->lscr1; fbi->dmacr = pdata->dmacr; fbi->pwmr = pdata->pwmr; fbi->lcd_power = pdata->lcd_power; fbi->backlight_power = pdata->backlight_power; - info->fix.smem_len = fbi->max_xres * fbi->max_yres * - fbi->max_bpp / 8; + + for (i = 0, m = &pdata->mode[0]; i < pdata->num_modes; i++, m++) + info->fix.smem_len = max_t(size_t, info->fix.smem_len, + m->mode.xres * m->mode.yres * m->bpp / 8); return 0; } @@ -642,9 +672,9 @@ static int __init imxfb_probe(struct platform_device *pdev) struct fb_info *info; struct imx_fb_platform_data *pdata; struct resource *res; - int ret; + int ret, i; - printk("i.MX Framebuffer driver\n"); + dev_info(&pdev->dev, "i.MX Framebuffer driver\n"); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) @@ -662,6 +692,9 @@ static int __init imxfb_probe(struct platform_device *pdev) fbi = info->par; + if (!fb_mode) + fb_mode = pdata->mode[0].mode.name; + platform_set_drvdata(pdev, info); ret = imxfb_init_fbinfo(pdev); @@ -684,7 +717,7 @@ static int __init imxfb_probe(struct platform_device *pdev) fbi->regs = ioremap(res->start, resource_size(res)); if (fbi->regs == NULL) { - printk(KERN_ERR"Cannot map frame buffer registers\n"); + dev_err(&pdev->dev, "Cannot map frame buffer registers\n"); goto failed_ioremap; } @@ -719,6 +752,13 @@ static int __init imxfb_probe(struct platform_device *pdev) goto failed_platform_init; } + fbi->mode = pdata->mode; + fbi->num_modes = pdata->num_modes; + + INIT_LIST_HEAD(&info->modelist); + for (i = 0; i < pdata->num_modes; i++) + fb_add_videomode(&pdata->mode[i].mode, &info->modelist); + /* * This makes sure that our colour bitfield * descriptors are correctly initialised. @@ -754,7 +794,7 @@ failed_map: failed_getclock: iounmap(fbi->regs); failed_ioremap: - release_mem_region(res->start, res->end - res->start); + release_mem_region(res->start, resource_size(res)); failed_req: kfree(info->pseudo_palette); failed_init: @@ -785,7 +825,7 @@ static int __devexit imxfb_remove(struct platform_device *pdev) framebuffer_release(info); iounmap(fbi->regs); - release_mem_region(res->start, res->end - res->start + 1); + release_mem_region(res->start, resource_size(res)); clk_disable(fbi->clk); clk_put(fbi->clk); @@ -811,8 +851,34 @@ static struct platform_driver imxfb_driver = { }, }; +static int imxfb_setup(void) +{ +#ifndef MODULE + char *opt, *options = NULL; + + if (fb_get_options("imxfb", &options)) + return -ENODEV; + + if (!options || !*options) + return 0; + + while ((opt = strsep(&options, ",")) != NULL) { + if (!*opt) + continue; + else + fb_mode = opt; + } +#endif + return 0; +} + int __init imxfb_init(void) { + int ret = imxfb_setup(); + + if (ret < 0) + return ret; + return platform_driver_probe(&imxfb_driver, imxfb_probe); } diff --git a/drivers/video/omap/dispc.c b/drivers/video/omap/dispc.c index 148cbcc3960..915439dc05a 100644 --- a/drivers/video/omap/dispc.c +++ b/drivers/video/omap/dispc.c @@ -212,9 +212,9 @@ static void enable_rfbi_mode(int enable) dispc_write_reg(DISPC_CONTROL, l); /* Set bypass mode in RFBI module */ - l = __raw_readl(IO_ADDRESS(RFBI_CONTROL)); + l = __raw_readl(OMAP2_IO_ADDRESS(RFBI_CONTROL)); l |= enable ? 0 : (1 << 1); - __raw_writel(l, IO_ADDRESS(RFBI_CONTROL)); + __raw_writel(l, OMAP2_IO_ADDRESS(RFBI_CONTROL)); } static void set_lcd_data_lines(int data_lines) @@ -1421,7 +1421,7 @@ static int omap_dispc_init(struct omapfb_device *fbdev, int ext_mode, } /* L3 firewall setting: enable access to OCM RAM */ - __raw_writel(0x402000b0, IO_ADDRESS(0x680050a0)); + __raw_writel(0x402000b0, OMAP2_IO_ADDRESS(0x680050a0)); if ((r = alloc_palette_ram()) < 0) goto fail2; diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c index c0af638fe70..9c0144ee7ae 100644 --- a/drivers/video/ps3fb.c +++ b/drivers/video/ps3fb.c @@ -32,7 +32,7 @@ #include <linux/init.h> #include <asm/abs_addr.h> -#include <asm/iommu.h> +#include <asm/cell-regs.h> #include <asm/lv1call.h> #include <asm/ps3av.h> #include <asm/ps3fb.h> diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c index 10ddad8e17d..cdaa873a605 100644 --- a/drivers/video/sa1100fb.c +++ b/drivers/video/sa1100fb.c @@ -66,7 +66,7 @@ * - FrameBuffer memory is now allocated at run-time when the * driver is initialized. * - * 2000/04/10: Nicolas Pitre <nico@cam.org> + * 2000/04/10: Nicolas Pitre <nico@fluxnic.net> * - Big cleanup for dynamic selection of machine type at run time. * * 2000/07/19: Jamey Hicks <jamey@crl.dec.com> diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index 07f22b62563..3ad5157f989 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -14,6 +14,7 @@ #include <linux/mm.h> #include <linux/fb.h> #include <linux/clk.h> +#include <linux/pm_runtime.h> #include <linux/platform_device.h> #include <linux/dma-mapping.h> #include <linux/interrupt.h> @@ -22,35 +23,8 @@ #include <asm/atomic.h> #define PALETTE_NR 16 - -struct sh_mobile_lcdc_priv; -struct sh_mobile_lcdc_chan { - struct sh_mobile_lcdc_priv *lcdc; - unsigned long *reg_offs; - unsigned long ldmt1r_value; - unsigned long enabled; /* ME and SE in LDCNT2R */ - struct sh_mobile_lcdc_chan_cfg cfg; - u32 pseudo_palette[PALETTE_NR]; - struct fb_info *info; - dma_addr_t dma_handle; - struct fb_deferred_io defio; - struct scatterlist *sglist; - unsigned long frame_end; - wait_queue_head_t frame_end_wait; -}; - -struct sh_mobile_lcdc_priv { - void __iomem *base; - int irq; -#ifdef CONFIG_HAVE_CLK - atomic_t clk_usecnt; - struct clk *dot_clk; - struct clk *clk; -#endif - unsigned long lddckr; - struct sh_mobile_lcdc_chan ch[2]; - int started; -}; +#define SIDE_B_OFFSET 0x1000 +#define MIRROR_OFFSET 0x2000 /* shared registers */ #define _LDDCKR 0x410 @@ -59,17 +33,30 @@ struct sh_mobile_lcdc_priv { #define _LDSR 0x46c #define _LDCNT1R 0x470 #define _LDCNT2R 0x474 +#define _LDRCNTR 0x478 #define _LDDDSR 0x47c #define _LDDWD0R 0x800 #define _LDDRDR 0x840 #define _LDDWAR 0x900 #define _LDDRAR 0x904 +/* shared registers and their order for context save/restore */ +static int lcdc_shared_regs[] = { + _LDDCKR, + _LDDCKSTPR, + _LDINTR, + _LDDDSR, + _LDCNT1R, + _LDCNT2R, +}; +#define NR_SHARED_REGS ARRAY_SIZE(lcdc_shared_regs) + /* per-channel registers */ enum { LDDCKPAT1R, LDDCKPAT2R, LDMT1R, LDMT2R, LDMT3R, LDDFR, LDSM1R, - LDSM2R, LDSA1R, LDMLSR, LDHCNR, LDHSYNR, LDVLNR, LDVSYNR, LDPMR }; + LDSM2R, LDSA1R, LDMLSR, LDHCNR, LDHSYNR, LDVLNR, LDVSYNR, LDPMR, + NR_CH_REGS }; -static unsigned long lcdc_offs_mainlcd[] = { +static unsigned long lcdc_offs_mainlcd[NR_CH_REGS] = { [LDDCKPAT1R] = 0x400, [LDDCKPAT2R] = 0x404, [LDMT1R] = 0x418, @@ -87,7 +74,7 @@ static unsigned long lcdc_offs_mainlcd[] = { [LDPMR] = 0x460, }; -static unsigned long lcdc_offs_sublcd[] = { +static unsigned long lcdc_offs_sublcd[NR_CH_REGS] = { [LDDCKPAT1R] = 0x408, [LDDCKPAT2R] = 0x40c, [LDMT1R] = 0x600, @@ -110,12 +97,80 @@ static unsigned long lcdc_offs_sublcd[] = { #define DISPLAY_BEU 0x00000008 #define LCDC_ENABLE 0x00000001 #define LDINTR_FE 0x00000400 +#define LDINTR_VSE 0x00000200 +#define LDINTR_VEE 0x00000100 #define LDINTR_FS 0x00000004 +#define LDINTR_VSS 0x00000002 +#define LDINTR_VES 0x00000001 +#define LDRCNTR_SRS 0x00020000 +#define LDRCNTR_SRC 0x00010000 +#define LDRCNTR_MRS 0x00000002 +#define LDRCNTR_MRC 0x00000001 + +struct sh_mobile_lcdc_priv; +struct sh_mobile_lcdc_chan { + struct sh_mobile_lcdc_priv *lcdc; + unsigned long *reg_offs; + unsigned long ldmt1r_value; + unsigned long enabled; /* ME and SE in LDCNT2R */ + struct sh_mobile_lcdc_chan_cfg cfg; + u32 pseudo_palette[PALETTE_NR]; + unsigned long saved_ch_regs[NR_CH_REGS]; + struct fb_info *info; + dma_addr_t dma_handle; + struct fb_deferred_io defio; + struct scatterlist *sglist; + unsigned long frame_end; + unsigned long pan_offset; + unsigned long new_pan_offset; + wait_queue_head_t frame_end_wait; +}; + +struct sh_mobile_lcdc_priv { + void __iomem *base; + int irq; + atomic_t hw_usecnt; + struct device *dev; + struct clk *dot_clk; + unsigned long lddckr; + struct sh_mobile_lcdc_chan ch[2]; + unsigned long saved_shared_regs[NR_SHARED_REGS]; + int started; +}; + +static bool banked(int reg_nr) +{ + switch (reg_nr) { + case LDMT1R: + case LDMT2R: + case LDMT3R: + case LDDFR: + case LDSM1R: + case LDSA1R: + case LDMLSR: + case LDHCNR: + case LDHSYNR: + case LDVLNR: + case LDVSYNR: + return true; + } + return false; +} static void lcdc_write_chan(struct sh_mobile_lcdc_chan *chan, int reg_nr, unsigned long data) { iowrite32(data, chan->lcdc->base + chan->reg_offs[reg_nr]); + if (banked(reg_nr)) + iowrite32(data, chan->lcdc->base + chan->reg_offs[reg_nr] + + SIDE_B_OFFSET); +} + +static void lcdc_write_chan_mirror(struct sh_mobile_lcdc_chan *chan, + int reg_nr, unsigned long data) +{ + iowrite32(data, chan->lcdc->base + chan->reg_offs[reg_nr] + + MIRROR_OFFSET); } static unsigned long lcdc_read_chan(struct sh_mobile_lcdc_chan *chan, @@ -156,6 +211,7 @@ static void lcdc_sys_write_index(void *handle, unsigned long data) lcdc_write(ch->lcdc, _LDDWD0R, data | 0x10000000); lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0); lcdc_write(ch->lcdc, _LDDWAR, 1 | (lcdc_chan_is_sublcd(ch) ? 2 : 0)); + lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0); } static void lcdc_sys_write_data(void *handle, unsigned long data) @@ -165,6 +221,7 @@ static void lcdc_sys_write_data(void *handle, unsigned long data) lcdc_write(ch->lcdc, _LDDWD0R, data | 0x11000000); lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0); lcdc_write(ch->lcdc, _LDDWAR, 1 | (lcdc_chan_is_sublcd(ch) ? 2 : 0)); + lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0); } static unsigned long lcdc_sys_read_data(void *handle) @@ -175,8 +232,9 @@ static unsigned long lcdc_sys_read_data(void *handle) lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0); lcdc_write(ch->lcdc, _LDDRAR, 1 | (lcdc_chan_is_sublcd(ch) ? 2 : 0)); udelay(1); + lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0); - return lcdc_read(ch->lcdc, _LDDRDR) & 0xffff; + return lcdc_read(ch->lcdc, _LDDRDR) & 0x3ffff; } struct sh_mobile_lcdc_sys_bus_ops sh_mobile_lcdc_sys_bus_ops = { @@ -185,11 +243,10 @@ struct sh_mobile_lcdc_sys_bus_ops sh_mobile_lcdc_sys_bus_ops = { lcdc_sys_read_data, }; -#ifdef CONFIG_HAVE_CLK static void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv) { - if (atomic_inc_and_test(&priv->clk_usecnt)) { - clk_enable(priv->clk); + if (atomic_inc_and_test(&priv->hw_usecnt)) { + pm_runtime_get_sync(priv->dev); if (priv->dot_clk) clk_enable(priv->dot_clk); } @@ -197,16 +254,12 @@ static void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv) static void sh_mobile_lcdc_clk_off(struct sh_mobile_lcdc_priv *priv) { - if (atomic_sub_return(1, &priv->clk_usecnt) == -1) { + if (atomic_sub_return(1, &priv->hw_usecnt) == -1) { if (priv->dot_clk) clk_disable(priv->dot_clk); - clk_disable(priv->clk); + pm_runtime_put(priv->dev); } } -#else -static void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv) {} -static void sh_mobile_lcdc_clk_off(struct sh_mobile_lcdc_priv *priv) {} -#endif static int sh_mobile_lcdc_sginit(struct fb_info *info, struct list_head *pagelist) @@ -255,30 +308,52 @@ static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data) struct sh_mobile_lcdc_priv *priv = data; struct sh_mobile_lcdc_chan *ch; unsigned long tmp; + unsigned long ldintr; int is_sub; int k; /* acknowledge interrupt */ - tmp = lcdc_read(priv, _LDINTR); - tmp &= 0xffffff00; /* mask in high 24 bits */ - tmp |= 0x000000ff ^ LDINTR_FS; /* status in low 8 */ + ldintr = tmp = lcdc_read(priv, _LDINTR); + /* + * disable further VSYNC End IRQs, preserve all other enabled IRQs, + * write 0 to bits 0-6 to ack all triggered IRQs. + */ + tmp &= 0xffffff00 & ~LDINTR_VEE; lcdc_write(priv, _LDINTR, tmp); /* figure out if this interrupt is for main or sub lcd */ is_sub = (lcdc_read(priv, _LDSR) & (1 << 10)) ? 1 : 0; - /* wake up channel and disable clocks*/ + /* wake up channel and disable clocks */ for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { ch = &priv->ch[k]; if (!ch->enabled) continue; - if (is_sub == lcdc_chan_is_sublcd(ch)) { - ch->frame_end = 1; - wake_up(&ch->frame_end_wait); + /* Frame Start */ + if (ldintr & LDINTR_FS) { + if (is_sub == lcdc_chan_is_sublcd(ch)) { + ch->frame_end = 1; + wake_up(&ch->frame_end_wait); - sh_mobile_lcdc_clk_off(priv); + sh_mobile_lcdc_clk_off(priv); + } + } + + /* VSYNC End */ + if (ldintr & LDINTR_VES) { + unsigned long ldrcntr = lcdc_read(priv, _LDRCNTR); + /* Set the source address for the next refresh */ + lcdc_write_chan_mirror(ch, LDSA1R, ch->dma_handle + + ch->new_pan_offset); + if (lcdc_chan_is_sublcd(ch)) + lcdc_write(ch->lcdc, _LDRCNTR, + ldrcntr ^ LDRCNTR_SRS); + else + lcdc_write(ch->lcdc, _LDRCNTR, + ldrcntr ^ LDRCNTR_MRS); + ch->pan_offset = ch->new_pan_offset; } } @@ -520,7 +595,6 @@ static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv) board_cfg = &ch->cfg.board_cfg; if (board_cfg->display_off) board_cfg->display_off(board_cfg->board_data); - } /* stop the lcdc */ @@ -579,9 +653,6 @@ static int sh_mobile_lcdc_setup_clocks(struct platform_device *pdev, int clock_source, struct sh_mobile_lcdc_priv *priv) { -#ifdef CONFIG_HAVE_CLK - char clk_name[8]; -#endif char *str; int icksel; @@ -595,25 +666,21 @@ static int sh_mobile_lcdc_setup_clocks(struct platform_device *pdev, priv->lddckr = icksel << 16; -#ifdef CONFIG_HAVE_CLK - atomic_set(&priv->clk_usecnt, -1); - snprintf(clk_name, sizeof(clk_name), "lcdc%d", pdev->id); - priv->clk = clk_get(&pdev->dev, clk_name); - if (IS_ERR(priv->clk)) { - dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name); - return PTR_ERR(priv->clk); - } - if (str) { priv->dot_clk = clk_get(&pdev->dev, str); if (IS_ERR(priv->dot_clk)) { dev_err(&pdev->dev, "cannot get dot clock %s\n", str); - clk_put(priv->clk); return PTR_ERR(priv->dot_clk); } } -#endif - + atomic_set(&priv->hw_usecnt, -1); + + /* Runtime PM support involves two step for this driver: + * 1) Enable Runtime PM + * 2) Force Runtime PM Resume since hardware is accessed from probe() + */ + pm_runtime_enable(priv->dev); + pm_runtime_resume(priv->dev); return 0; } @@ -646,6 +713,9 @@ static struct fb_fix_screeninfo sh_mobile_lcdc_fix = { .type = FB_TYPE_PACKED_PIXELS, .visual = FB_VISUAL_TRUECOLOR, .accel = FB_ACCEL_NONE, + .xpanstep = 0, + .ypanstep = 1, + .ywrapstep = 0, }; static void sh_mobile_lcdc_fillrect(struct fb_info *info, @@ -669,13 +739,38 @@ static void sh_mobile_lcdc_imageblit(struct fb_info *info, sh_mobile_lcdc_deferred_io_touch(info); } +static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct sh_mobile_lcdc_chan *ch = info->par; + + if (info->var.xoffset == var->xoffset && + info->var.yoffset == var->yoffset) + return 0; /* No change, do nothing */ + + ch->new_pan_offset = (var->yoffset * info->fix.line_length) + + (var->xoffset * (info->var.bits_per_pixel / 8)); + + if (ch->new_pan_offset != ch->pan_offset) { + unsigned long ldintr; + ldintr = lcdc_read(ch->lcdc, _LDINTR); + ldintr |= LDINTR_VEE; + lcdc_write(ch->lcdc, _LDINTR, ldintr); + sh_mobile_lcdc_deferred_io_touch(info); + } + + return 0; +} + static struct fb_ops sh_mobile_lcdc_ops = { + .owner = THIS_MODULE, .fb_setcolreg = sh_mobile_lcdc_setcolreg, .fb_read = fb_sys_read, .fb_write = fb_sys_write, .fb_fillrect = sh_mobile_lcdc_fillrect, .fb_copyarea = sh_mobile_lcdc_copyarea, .fb_imageblit = sh_mobile_lcdc_imageblit, + .fb_pan_display = sh_mobile_fb_pan_display, }; static int sh_mobile_lcdc_set_bpp(struct fb_var_screeninfo *var, int bpp) @@ -731,9 +826,59 @@ static int sh_mobile_lcdc_resume(struct device *dev) return sh_mobile_lcdc_start(platform_get_drvdata(pdev)); } +static int sh_mobile_lcdc_runtime_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct sh_mobile_lcdc_priv *p = platform_get_drvdata(pdev); + struct sh_mobile_lcdc_chan *ch; + int k, n; + + /* save per-channel registers */ + for (k = 0; k < ARRAY_SIZE(p->ch); k++) { + ch = &p->ch[k]; + if (!ch->enabled) + continue; + for (n = 0; n < NR_CH_REGS; n++) + ch->saved_ch_regs[n] = lcdc_read_chan(ch, n); + } + + /* save shared registers */ + for (n = 0; n < NR_SHARED_REGS; n++) + p->saved_shared_regs[n] = lcdc_read(p, lcdc_shared_regs[n]); + + /* turn off LCDC hardware */ + lcdc_write(p, _LDCNT1R, 0); + return 0; +} + +static int sh_mobile_lcdc_runtime_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct sh_mobile_lcdc_priv *p = platform_get_drvdata(pdev); + struct sh_mobile_lcdc_chan *ch; + int k, n; + + /* restore per-channel registers */ + for (k = 0; k < ARRAY_SIZE(p->ch); k++) { + ch = &p->ch[k]; + if (!ch->enabled) + continue; + for (n = 0; n < NR_CH_REGS; n++) + lcdc_write_chan(ch, n, ch->saved_ch_regs[n]); + } + + /* restore shared registers */ + for (n = 0; n < NR_SHARED_REGS; n++) + lcdc_write(p, lcdc_shared_regs[n], p->saved_shared_regs[n]); + + return 0; +} + static struct dev_pm_ops sh_mobile_lcdc_dev_pm_ops = { .suspend = sh_mobile_lcdc_suspend, .resume = sh_mobile_lcdc_resume, + .runtime_suspend = sh_mobile_lcdc_runtime_suspend, + .runtime_resume = sh_mobile_lcdc_runtime_resume, }; static int sh_mobile_lcdc_remove(struct platform_device *pdev); @@ -778,6 +923,7 @@ static int __init sh_mobile_lcdc_probe(struct platform_device *pdev) } priv->irq = i; + priv->dev = &pdev->dev; platform_set_drvdata(pdev, priv); pdata = pdev->dev.platform_data; @@ -792,6 +938,8 @@ static int __init sh_mobile_lcdc_probe(struct platform_device *pdev) goto err1; } init_waitqueue_head(&priv->ch[i].frame_end_wait); + priv->ch[j].pan_offset = 0; + priv->ch[j].new_pan_offset = 0; switch (pdata->ch[i].chan) { case LCDC_CHAN_MAINLCD: @@ -834,7 +982,9 @@ static int __init sh_mobile_lcdc_probe(struct platform_device *pdev) info = priv->ch[i].info; info->fbops = &sh_mobile_lcdc_ops; info->var.xres = info->var.xres_virtual = cfg->lcd_cfg.xres; - info->var.yres = info->var.yres_virtual = cfg->lcd_cfg.yres; + info->var.yres = cfg->lcd_cfg.yres; + /* Default Y virtual resolution is 2x panel size */ + info->var.yres_virtual = info->var.yres * 2; info->var.width = cfg->lcd_size_cfg.width; info->var.height = cfg->lcd_size_cfg.height; info->var.activate = FB_ACTIVATE_NOW; @@ -844,7 +994,8 @@ static int __init sh_mobile_lcdc_probe(struct platform_device *pdev) info->fix = sh_mobile_lcdc_fix; info->fix.line_length = cfg->lcd_cfg.xres * (cfg->bpp / 8); - info->fix.smem_len = info->fix.line_length * cfg->lcd_cfg.yres; + info->fix.smem_len = info->fix.line_length * + info->var.yres_virtual; buf = dma_alloc_coherent(&pdev->dev, info->fix.smem_len, &priv->ch[i].dma_handle, GFP_KERNEL); @@ -947,11 +1098,10 @@ static int sh_mobile_lcdc_remove(struct platform_device *pdev) framebuffer_release(info); } -#ifdef CONFIG_HAVE_CLK if (priv->dot_clk) clk_put(priv->dot_clk); - clk_put(priv->clk); -#endif + + pm_runtime_disable(priv->dev); if (priv->base) iounmap(priv->base); diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c index ca5b4643a40..e98baf6916b 100644 --- a/drivers/video/uvesafb.c +++ b/drivers/video/uvesafb.c @@ -67,9 +67,8 @@ static DEFINE_MUTEX(uvfb_lock); * find the kernel part of the task struct, copy the registers and * the buffer contents and then complete the task. */ -static void uvesafb_cn_callback(void *data) +static void uvesafb_cn_callback(struct cn_msg *msg) { - struct cn_msg *msg = data; struct uvesafb_task *utask; struct uvesafb_ktask *task; |