📄 sa1100fb.c
字号:
/* * linux/drivers/video/sa1100fb.c -- StrongARM 1100 LCD Controller Frame Buffer Device * * Copyright (C) 1999 Eric A. Thomas * * 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. * *//* * Code Status: * 1999/04/01: * Driver appears to be working for Brutus 320x200x8bpp mode. Other * resolutions are working, but only the 8bpp mode is supported. * Changes need to be made to the palette encode and decode routines * to support 4 and 16 bpp modes. * Driver is not designed to be a module. The FrameBuffer is statically * allocated since dynamic allocation of a 300k buffer cannot be * guaranteed. * * 1999/06/17: * FrameBuffer memory is now allocated at run-time when the * driver is initialized. * * 2000/04/10: * Big cleanup for dynamic selection of machine type at run time. * Nicolas Pitre <nico@cam.org> * * 2000/07/19: * Support for Bitsy aka Compaq iPAQ H3600 added. * Jamey Hicks <jamey@crl.dec.com> * * 2000/08/07: * Resolved an issue caused by a change made to the Assabet's PLD * earlier this year which broke the framebuffer driver for newer * Phase 4 Assabets. Some other parameters were changed to optimize for * the Sharp display. * Tak-Shing Chan <tchan.rd@idthk.com> * Jeff Sutherland <jsutherland@accelent.com> * * 2000/08/09: * XP860 support added * Kunihiko IMAI <imai@vasara.co.jp> * * 2000/08/19: * Allows standard options to be passed on the kernel command line * for most common passive displays. * Mark Huang <mhuang@livetoy.com> * * 2000/08/29: * s/save_flags_cli/local_irq_save/ * remove unneeded extra save_flags_cli in * sa1100fb_enable_lcd_controller */#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/errno.h>#include <linux/string.h>#include <linux/ctype.h>#include <linux/mm.h>#include <linux/tty.h>#include <linux/malloc.h>#include <linux/init.h>#include <linux/fb.h>#include <linux/delay.h>#include <linux/wrapper.h>#include <asm/hardware.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/mach-types.h>#include <asm/uaccess.h>#include <asm/proc/pgtable.h>#include <video/fbcon.h>#include <video/fbcon-mfb.h>#include <video/fbcon-cfb4.h>#include <video/fbcon-cfb8.h>#include <video/fbcon-cfb16.h>/* * Debug macros *///#define DEBUG #ifdef DEBUG# define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args)#else# define DPRINTK(fmt, args...)#endif/* Memory size macros for determining required FrameBuffer size */#define MAX_PALETTE_NUM_ENTRIES 256#define MAX_PALETTE_MEM_SIZE (MAX_PALETTE_NUM_ENTRIES * 2)#define MAX_PIXEL_MEM_SIZE \ ((current_par.max_xres * current_par.max_yres * current_par.max_bpp)/8)#define MAX_FRAMEBUFFER_MEM_SIZE \ (MAX_PIXEL_MEM_SIZE + MAX_PALETTE_MEM_SIZE + 32)#define ALLOCATED_FB_MEM_SIZE \ (PAGE_ALIGN(MAX_FRAMEBUFFER_MEM_SIZE + PAGE_SIZE * 2))#define SA1100_PALETTE_MEM_SIZE(bpp) (((bpp)==8?256:16)*2)#define SA1100_PALETTE_MODE_VAL(bpp) (((bpp) & 0x018) << 9)/* Minimum X and Y resolutions */#define MIN_XRES 64#define MIN_YRES 64/* Possible controller_state modes */#define LCD_MODE_DISABLED 0 // Controller is disabled and Disable Done received#define LCD_MODE_DISABLE_BEFORE_ENABLE 1 // Re-enable after Disable Done IRQ is received#define LCD_MODE_ENABLED 2 // Controller is enabled#define SA1100_NAME "SA1100"#define NR_MONTYPES 1static inline voidsa1100fb_assabet_set_truecolor(u_int is_true_color){#ifdef CONFIG_SA1100_ASSABET#if 1 // phase 4 or newer Assabet's if (is_true_color) BCR_set(BCR_LCD_12RGB); else BCR_clear(BCR_LCD_12RGB);#else // older Assabet's if (is_true_color) BCR_clear(BCR_LCD_12RGB); else BCR_set(BCR_LCD_12RGB);#endif#endif}static u_char *VideoMemRegion;static u_char *VideoMemRegion_phys;/* Local LCD controller parameters *//* These can be reduced by making better use of fb_var_screeninfo parameters. *//* Several duplicates exist in the two structures. */struct sa1100fb_par { u_char *p_screen_base; u_char *v_screen_base; u_short *p_palette_base; u_short *v_palette_base; unsigned long screen_size; unsigned int palette_size; unsigned int max_xres; unsigned int max_yres; unsigned int xres; unsigned int yres; unsigned int xres_virtual; unsigned int yres_virtual; unsigned int max_bpp; unsigned int bits_per_pixel; signed int montype; unsigned int currcon; unsigned int visual; unsigned int allow_modeset : 1; unsigned int active_lcd : 1; unsigned int inv_4bpp : 1; volatile u_char controller_state;};/* Shadows for LCD controller registers */struct sa1100fb_lcd_reg { Address dbar1; Address dbar2; Word lccr0; Word lccr1; Word lccr2; Word lccr3;};/* Fake monspecs to fill in fbinfo structure */static struct fb_monspecs monspecs __initdata = { 30000, 70000, 50, 65, 0 /* Generic */};static struct display global_disp; /* Initial (default) Display Settings */static struct fb_info fb_info;static struct sa1100fb_par current_par;static struct fb_var_screeninfo __initdata init_var = {};static struct sa1100fb_lcd_reg lcd_shadow;static int sa1100fb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info);static int sa1100fb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info);static int sa1100fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info);static int sa1100fb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info);static int sa1100fb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info); static int sa1100fb_switch(int con, struct fb_info *info);static void sa1100fb_blank(int blank, struct fb_info *info);static int sa1100fb_map_video_memory(void);static int sa1100fb_activate_var(struct fb_var_screeninfo *var);static void sa1100fb_enable_lcd_controller(void);static void sa1100fb_disable_lcd_controller(void);static struct fb_ops sa1100fb_ops = { owner: THIS_MODULE, fb_get_fix: sa1100fb_get_fix, fb_get_var: sa1100fb_get_var, fb_set_var: sa1100fb_set_var, fb_get_cmap: sa1100fb_get_cmap, fb_set_cmap: sa1100fb_set_cmap,};/* * sa1100fb_palette_write: * Write palette data to the LCD frame buffer's palette area */static inline voidsa1100fb_palette_write(u_int regno, u_short pal){ current_par.v_palette_base[regno] = (regno ? pal : pal | SA1100_PALETTE_MODE_VAL(current_par.bits_per_pixel));}static inline u_shortsa1100fb_palette_encode(u_int regno, u_int red, u_int green, u_int blue, u_int trans){ u_int pal; if(current_par.bits_per_pixel == 4){ /* * RGB -> luminance is defined to be * Y = 0.299 * R + 0.587 * G + 0.114 * B */ pal = (19595 * red + 38470 * green + 7471 * blue) >> 28; if( current_par.inv_4bpp ) pal = 15 - pal; } else{ pal = ((red >> 4) & 0xf00); pal |= ((green >> 8) & 0x0f0); pal |= ((blue >> 12) & 0x00f); } return pal;} static inline u_shortsa1100fb_palette_read(u_int regno){ return (current_par.v_palette_base[regno] & 0x0FFF);}static voidsa1100fb_palette_decode(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *trans){ u_short pal; pal = sa1100fb_palette_read(regno); if( current_par.bits_per_pixel == 4){ if( current_par.inv_4bpp ) pal = 15 - pal; pal &= 0x000f; pal |= pal << 4; pal |= pal << 8; *blue = *green = *red = pal; } else{ *blue = (pal & 0x000f) << 12; *green = (pal & 0x00f0) << 8; *red = (pal & 0x0f00) << 4; } *trans = 0;}static intsa1100fb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *trans, struct fb_info *info){ if (regno >= current_par.palette_size) return 1; sa1100fb_palette_decode(regno, red, green, blue, trans); return 0;}static intsa1100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int trans, struct fb_info *info){ u_short pal; if (regno >= current_par.palette_size) return 1; pal = sa1100fb_palette_encode(regno, red, green, blue, trans); sa1100fb_palette_write(regno, pal); return 0;}static intsa1100fb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info){ int err = 0; DPRINTK("current_par.visual=%d\n", current_par.visual); if (con == current_par.currcon) err = fb_get_cmap(cmap, kspc, sa1100fb_getcolreg, info); else if (fb_display[con].cmap.len) fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); else fb_copy_cmap(fb_default_cmap(current_par.palette_size), cmap, kspc ? 0 : 2); return err;}static intsa1100fb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info){ int err = 0; DPRINTK("current_par.visual=%d\n", current_par.visual); if (!fb_display[con].cmap.len) err = fb_alloc_cmap(&fb_display[con].cmap, current_par.palette_size, 0); if (!err) { if (con == current_par.currcon) err = fb_set_cmap(cmap, kspc, sa1100fb_setcolreg, info); fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); } return err;}static void inlinesa1100fb_get_par(struct sa1100fb_par *par){ *par = current_par;}/* * sa1100fb_encode_var(): * Modify var structure using values in par */static int sa1100fb_encode_var(struct fb_var_screeninfo *var, struct sa1100fb_par *par){ // Don't know if really want to zero var on entry. // Look at set_var to see. If so, may need to add extra params to par // memset(var, 0, sizeof(struct fb_var_screeninfo)); var->xres = par->xres; var->yres = par->yres; var->xres_virtual = par->xres_virtual; var->yres_virtual = par->yres_virtual; var->bits_per_pixel = par->bits_per_pixel; DPRINTK("var->bits_per_pixel=%d\n", var->bits_per_pixel); switch(var->bits_per_pixel) { case 2: case 4: case 8: var->red.length = 4; var->green = var->red; var->blue = var->red; var->transp.length = 0; break; case 12: // This case should differ for Active/Passive mode case 16: if (machine_is_bitsy()) { var->red.length = 4; var->blue.length = 4; var->green.length = 4; var->transp.length = 0; var->red.offset = 12; var->green.offset = 7; var->blue.offset = 1; var->transp.offset = 0; } else { var->red.length = 5; var->blue.length = 5; var->green.length = 6; var->transp.length = 0; var->red.offset = 11; var->green.offset = 5; var->blue.offset = 0; var->transp.offset = 0; } break; } return 0;} /* * sa1100fb_decode_var(): * Get the video params out of 'var'. If a value doesn't fit, round it up, * if it's too big, return -EINVAL. * * Suggestion: Round up in the following order: bits_per_pixel, xres, * yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale, * bitfields, horizontal timing, vertical timing. */static intsa1100fb_decode_var(struct fb_var_screeninfo *var, struct sa1100fb_par *par){ u_long palette_mem_phys; u_long palette_mem_size; *par = current_par; if ((par->xres = var->xres) < MIN_XRES) par->xres = MIN_XRES; if ((par->yres = var->yres) < MIN_YRES) par->yres = MIN_YRES; if (par->xres > current_par.max_xres) par->xres = current_par.max_xres; if (par->yres > current_par.max_yres) par->yres = current_par.max_yres; par->xres_virtual = var->xres_virtual < par->xres ? par->xres : var->xres_virtual; par->yres_virtual = var->yres_virtual < par->yres ? par->yres : var->yres_virtual; par->bits_per_pixel = var->bits_per_pixel; DPRINTK("par->bits_per_pixel=%d\n", par->bits_per_pixel); switch (par->bits_per_pixel) {#ifdef FBCON_HAS_CFB4 case 4: par->visual = FB_VISUAL_PSEUDOCOLOR; par->palette_size = 16; break;#endif#ifdef FBCON_HAS_CFB8 case 8: par->visual = FB_VISUAL_PSEUDOCOLOR; par->palette_size = 256; break;#endif#ifdef FBCON_HAS_CFB16 case 16: /* RGB 565 */ par->visual = FB_VISUAL_TRUECOLOR;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -