epson1355fb.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:11k
- /*
- * linux/drivers/video/epson1355fb.c
- * -- Support for the Epson SED1355 LCD/CRT controller
- *
- * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
- *
- * based on linux/drivers/video/skeletonfb.c, which was
- * Created 28 Dec 1997 by Geert Uytterhoeven
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive
- * for more details.
- */
- /* TODO (roughly in order of priority):
- * 16 bpp support
- * crt support
- * hw cursor support
- * SwivelView
- */
- #include <asm/io.h>
- #include <linux/config.h>
- #include <linux/delay.h>
- #include <linux/errno.h>
- #include <linux/fb.h>
- #include <linux/init.h>
- #include <linux/kernel.h>
- #include <linux/slab.h>
- #include <linux/mm.h>
- #include <linux/module.h>
- #include <linux/sched.h>
- #include <linux/string.h>
- #include <linux/tty.h>
- #include <video/fbcon-cfb8.h>
- #include <video/fbcon-mfb.h>
- #include <video/fbcon.h>
- /* Register defines. The docs don't seem to provide nice mnemonic names
- * so I made them up myself ... */
- #define E1355_PANEL 0x02
- #define E1355_DISPLAY 0x0D
- #define E1355_MISC 0x1B
- #define E1355_GPIO 0x20
- #define E1355_LUT_INDEX 0x24
- #define E1355_LUT_DATA 0x26
- #ifdef CONFIG_SUPERH
- #define E1355_REG_BASE CONFIG_E1355_REG_BASE
- #define E1355_FB_BASE CONFIG_E1355_FB_BASE
- static inline u8 e1355_read_reg(int index)
- {
- return ctrl_inb(E1355_REG_BASE + index);
- }
- static inline void e1355_write_reg(u8 data, int index)
- {
- ctrl_outb(data, E1355_REG_BASE + index);
- }
- static inline u16 e1355_read_reg16(int index)
- {
- return e1355_read_reg(index) + (e1355_read_reg(index+1) << 8);
- }
- static inline void e1355_write_reg16(u16 data, int index)
- {
- e1355_write_reg((data&0xff), index);
- e1355_write_reg(((data>>8)&0xff), index + 1);
- }
- #else
- #error unknown architecture
- #endif
- struct e1355fb_info {
- struct fb_info_gen gen;
- };
- static int current_par_valid = 0;
- static struct display disp;
- static struct fb_var_screeninfo default_var;
- int e1355fb_init(void);
- int e1355fb_setup(char*);
- static int e1355_encode_var(struct fb_var_screeninfo *var, const void *par,
- struct fb_info_gen *info);
- /* ------------------- chipset specific functions -------------------------- */
- static void disable_hw_cursor(void)
- {
- u8 curs;
- curs = e1355_read_reg(0x27);
- curs &= ~0xc0;
- e1355_write_reg(curs, 0x27);
- }
- static void e1355_detect(void)
- {
- u8 rev;
- e1355_write_reg(0x00, E1355_MISC);
- rev = e1355_read_reg(0x00);
- if ((rev & 0xfc) != 0x0c) {
- printk(KERN_WARNING "Epson 1355 not detectedn");
- }
- /* XXX */
- disable_hw_cursor();
- e1355_encode_var(&default_var, NULL, NULL);
- }
- struct e1355_par {
- u32 xres;
- u32 yres;
- int bpp;
- int mem_bpp;
- u32 panel_xres;
- u32 panel_yres;
-
- int panel_width;
- int panel_ymul;
- };
- static int e1355_encode_fix(struct fb_fix_screeninfo *fix,
- const void *raw_par,
- struct fb_info_gen *info)
- {
- const struct e1355_par *par = raw_par;
-
- memset(fix, 0, sizeof *fix);
-
- fix->type= FB_TYPE_PACKED_PIXELS;
- if (!par)
- BUG();
- if (par->bpp == 1) {
- fix->visual = FB_VISUAL_MONO10;
- } else if (par->bpp <= 8) {
- fix->visual = FB_VISUAL_PSEUDOCOLOR;
- } else {
- fix->visual = FB_VISUAL_TRUECOLOR;
- }
- return 0;
- }
- static int e1355_set_bpp(struct e1355_par *par, int bpp)
- {
- int code;
- u8 disp;
- u16 bytes_per_line;
- switch(bpp) {
- case 1:
- code = 0; break;
- case 2:
- code = 1; break;
- case 4:
- code = 2; break;
- case 8:
- code = 3; break;
- case 16:
- code = 5; break;
- default:
- return -EINVAL; break;
- }
- disp = e1355_read_reg(E1355_DISPLAY);
- disp &= ~0x1c;
- disp |= code << 2;
- e1355_write_reg(disp, E1355_DISPLAY);
-
- bytes_per_line = (par->xres * bpp) >> 3;
-
- e1355_write_reg16(bytes_per_line, 0x16);
- par->bpp = bpp;
- return 0;
- }
-
- static int e1355_decode_var(const struct fb_var_screeninfo *var,
- void *raw_par,
- struct fb_info_gen *info)
- {
- struct e1355_par *par = raw_par;
- int ret;
- if (!par)
- BUG();
- /*
- * Don't allow setting any of these yet: xres and yres don't
- * make sense for LCD panels; xres_virtual and yres_virtual
- * should be supported fine by our hardware though.
- */
- if (var->xres != par->xres ||
- var->yres != par->yres ||
- var->xres != var->xres_virtual ||
- var->yres != var->yres_virtual ||
- var->xoffset != 0 ||
- var->yoffset != 0)
- return -EINVAL;
- if(var->bits_per_pixel != par->bpp) {
- ret = e1355_set_bpp(par, var->bits_per_pixel);
- if (ret)
- goto out_err;
- }
-
- return 0;
- out_err:
- return ret;
- }
- static void dump_panel_data(void)
- {
- u8 panel = e1355_read_reg(E1355_PANEL);
- int width[2][4] = { { 4, 8, 16, -1 }, { 9, 12, 16, -1 } };
- printk("%s %s %s panel, width %d bitsn",
- panel & 2 ? "dual" : "single",
- panel & 4 ? "color" : "mono",
- panel & 1 ? "TFT" : "passive",
- width[panel&1][(panel>>4)&3]);
- printk("resolution %d x %dn",
- (e1355_read_reg(0x04) + 1) * 8,
- ((e1355_read_reg16(0x08) + 1) * (1 + ((panel & 3) == 2))));
- }
- static int e1355_bpp_to_var(int bpp, struct fb_var_screeninfo *var)
- {
- switch(bpp) {
- case 1:
- case 2:
- case 4:
- case 8:
- var->bits_per_pixel = bpp;
- var->red.offset = var->green.offset = var->blue.offset = 0;
- var->red.length = var->green.length = var->blue.length = bpp;
- break;
- case 16:
- var->bits_per_pixel = 16;
- var->red.offset = 11;
- var->red.length = 5;
- var->green.offset = 5;
- var->green.length = 6;
- var->blue.offset = 0;
- var->blue.length = 5;
- break;
- }
- return 0;
- }
- static int e1355_encode_var(struct fb_var_screeninfo *var, const void *raw_par,
- struct fb_info_gen *info)
- {
- u8 panel, display;
- u32 xres, xres_virtual, yres;
- static int width[2][4] = { { 4, 8, 16, -1 }, { 9, 12, 16, -1 } };
- static int bpp_tab[8] = { 1, 2, 4, 8, 15, 16 };
- int bpp, hw_bpp;
- int is_color, is_dual, is_tft;
- int lcd_enabled, crt_enabled;
- panel = e1355_read_reg(E1355_PANEL);
- display = e1355_read_reg(E1355_DISPLAY);
- is_color = (panel & 0x04) != 0;
- is_dual = (panel & 0x02) != 0;
- is_tft = (panel & 0x01) != 0;
- bpp = bpp_tab[(display>>2)&7];
- e1355_bpp_to_var(bpp, var);
- crt_enabled = (display & 0x02) != 0;
- lcd_enabled = (display & 0x02) != 0;
- hw_bpp = width[is_tft][(panel>>4)&3];
- xres = e1355_read_reg(0x04) + 1;
- yres = e1355_read_reg16(0x08) + 1;
-
- xres *= 8;
- /* talk about weird hardware .. */
- yres *= (is_dual && !crt_enabled) ? 2 : 1;
- xres_virtual = e1355_read_reg16(0x16);
- /* it's in 2-byte words initially */
- xres_virtual *= 16;
- xres_virtual /= var->bits_per_pixel;
- var->xres = xres;
- var->yres = yres;
- var->xres_virtual = xres_virtual;
- var->yres_virtual = yres;
- var->xoffset = var->yoffset = 0;
- var->grayscale = !is_color;
-
- return 0;
- }
- #define is_dual(panel) (((panel)&3)==2)
- static void get_panel_data(struct e1355_par *par)
- {
- u8 panel;
- int width[2][4] = { { 4, 8, 16, -1 }, { 9, 12, 16, -1 } };
- panel = e1355_read_reg(E1355_PANEL);
- par->panel_width = width[panel&1][(panel>>4)&3];
- par->panel_xres = (e1355_read_reg(0x04) + 1) * 8;
- par->panel_ymul = is_dual(panel) ? 2 : 1;
- par->panel_yres = ((e1355_read_reg16(0x08) + 1)
- * par->panel_ymul);
- }
- static void e1355_get_par(void *raw_par, struct fb_info_gen *info)
- {
- struct e1355_par *par = raw_par;
- get_panel_data(par);
- }
- static void e1355_set_par(const void *par, struct fb_info_gen *info)
- {
- }
- static int e1355_getcolreg(unsigned regno, unsigned *red, unsigned *green,
- unsigned *blue, unsigned *transp,
- struct fb_info *info)
- {
- u8 r, g, b;
- e1355_write_reg(regno, E1355_LUT_INDEX);
- r = e1355_read_reg(E1355_LUT_DATA);
- g = e1355_read_reg(E1355_LUT_DATA);
- b = e1355_read_reg(E1355_LUT_DATA);
- *red = r << 8;
- *green = g << 8;
- *blue = b << 8;
- return 0;
- }
- static int e1355_setcolreg(unsigned regno, unsigned red, unsigned green,
- unsigned blue, unsigned transp,
- struct fb_info *info)
- {
- u8 r = (red >> 8) & 0xf0;
- u8 g = (green>>8) & 0xf0;
- u8 b = (blue>> 8) & 0xf0;
- e1355_write_reg(regno, E1355_LUT_INDEX);
- e1355_write_reg(r, E1355_LUT_DATA);
- e1355_write_reg(g, E1355_LUT_DATA);
- e1355_write_reg(b, E1355_LUT_DATA);
-
- return 0;
- }
- static int e1355_pan_display(const struct fb_var_screeninfo *var,
- struct fb_info_gen *info)
- {
- BUG();
-
- return -EINVAL;
- }
- /*
- * The AERO_HACKS parts disable/enable the backlight on the Compaq Aero 8000.
- * I'm not sure they aren't dangerous to the hardware, so be warned.
- */
- #undef AERO_HACKS
- static int e1355_blank(int blank_mode, struct fb_info_gen *info)
- {
- u8 disp;
- switch (blank_mode) {
- case VESA_NO_BLANKING:
- disp = e1355_read_reg(E1355_DISPLAY);
- disp |= 1;
- e1355_write_reg(disp, E1355_DISPLAY);
-
- #ifdef AERO_HACKS
- e1355_write_reg(0x6, 0x20);
- #endif
- break;
- case VESA_VSYNC_SUSPEND:
- case VESA_HSYNC_SUSPEND:
- case VESA_POWERDOWN:
- disp = e1355_read_reg(E1355_DISPLAY);
- disp &= ~1;
- e1355_write_reg(disp, E1355_DISPLAY);
- #ifdef AERO_HACKS
- e1355_write_reg(0x0, 0x20);
- #endif
- break;
- default:
- return -EINVAL;
- }
- return 0;
- }
- static struct display_switch e1355_dispsw;
- static void e1355_set_disp(const void *unused, struct display *disp,
- struct fb_info_gen *info)
- {
- struct display_switch *d;
- disp->screen_base = (void *)E1355_FB_BASE;
- disp->dispsw = &e1355_dispsw;
-
- switch(disp->var.bits_per_pixel) {
- #ifdef FBCON_HAS_MFB
- case 1:
- d = &fbcon_mfb; break;
- #endif
- #ifdef FBCON_HAS_CFB8
- case 8:
- d = &fbcon_cfb8; break;
- #endif
- default:
- BUG(); break;
- }
- memcpy(&e1355_dispsw, d, sizeof *d);
- /* reading is terribly slow for us */
- #if 0 /* XXX: need to work out why this doesn't work */
- e1355_dispsw.bmove = fbcon_redraw_bmove;
- #endif
- }
- /* ------------ Interfaces to hardware functions ------------ */
- struct fbgen_hwswitch e1355_switch = {
- detect: e1355_detect,
- encode_fix: e1355_encode_fix,
- decode_var: e1355_decode_var,
- encode_var: e1355_encode_var,
- get_par: e1355_get_par,
- set_par: e1355_set_par,
- getcolreg: e1355_getcolreg,
- setcolreg: e1355_setcolreg,
- pan_display: e1355_pan_display,
- blank: e1355_blank,
- set_disp: e1355_set_disp,
- };
- /* ------------ Hardware Independent Functions ------------ */
- static struct fb_ops e1355fb_ops = {
- owner: THIS_MODULE,
- fb_get_fix: fbgen_get_fix,
- fb_get_var: fbgen_get_var,
- fb_set_var: fbgen_set_var,
- fb_get_cmap: fbgen_get_cmap,
- fb_set_cmap: fbgen_set_cmap,
- fb_pan_display: fbgen_pan_display,
- };
- static struct e1355fb_info fb_info;
- int __init e1355fb_setup(char *str)
- {
- return 0;
- }
- int __init e1355fb_init(void)
- {
- fb_info.gen.fbhw = &e1355_switch;
- fb_info.gen.fbhw->detect();
- strcpy(fb_info.gen.info.modename, "SED1355");
- fb_info.gen.info.changevar = NULL;
- fb_info.gen.info.node = -1;
- fb_info.gen.info.fbops = &e1355fb_ops;
- fb_info.gen.info.disp = &disp;
- fb_info.gen.parsize = sizeof(struct e1355_par);
- fb_info.gen.info.switch_con = &fbgen_switch;
- fb_info.gen.info.updatevar = &fbgen_update_var;
- fb_info.gen.info.blank = &fbgen_blank;
- fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT;
- /* This should give a reasonable default video mode */
- fbgen_get_var(&disp.var, -1, &fb_info.gen.info);
- fbgen_do_set_var(&disp.var, 1, &fb_info.gen);
- fbgen_set_disp(-1, &fb_info.gen);
- if (disp.var.bits_per_pixel > 1)
- fbgen_install_cmap(0, &fb_info.gen);
- if (register_framebuffer(&fb_info.gen.info) < 0)
- return -EINVAL;
- printk(KERN_INFO "fb%d: %s frame buffer devicen", GET_FB_IDX(fb_info.gen.info.node),
- fb_info.gen.info.modename);
- return 0;
- }
- /*
- * Cleanup
- */
- void e1355fb_cleanup(struct fb_info *info)
- {
- /*
- * If your driver supports multiple boards, you should unregister and
- * clean up all instances.
- */
-
- unregister_framebuffer(info);
- /* ... */
- }
- MODULE_LICENSE("GPL");