diff options
Diffstat (limited to 'drivers/video')
-rw-r--r-- | drivers/video/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/console/vgacon.c | 1 | ||||
-rw-r--r-- | drivers/video/omap/dispc.c | 6 | ||||
-rw-r--r-- | drivers/video/sh_mobile_lcdcfb.c | 292 |
9 files changed, 226 insertions, 707 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index cef3e1d..11af4cb 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -1869,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/console/.gitignore b/drivers/video/console/.gitignore deleted file mode 100644 index 0c258b4..0000000 --- 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 2f50a80..fc7d9bb 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 ac46cc3..a862e91 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 58f9c04..0000000 --- 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 ae02e4e..0000000 --- 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/console/vgacon.c b/drivers/video/console/vgacon.c index 59d7d5e..74e96cf 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -180,7 +180,6 @@ static inline void vga_set_mem_top(struct vc_data *c) } #ifdef CONFIG_VGACON_SOFT_SCROLLBACK -#include <linux/slab.h> /* software scrollback */ static void *vgacon_scrollback; static int vgacon_scrollback_tail; diff --git a/drivers/video/omap/dispc.c b/drivers/video/omap/dispc.c index 148cbcc..915439d 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/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index 07f22b6..3ad5157 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); |