📄 pxafb.c
字号:
/* * linux/drivers/video/pxafb.c * * Copyright (C) 1999 Eric A. Thomas * Based on acornfb.c Copyright (C) Russell King. * * 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. * * Intel PXA250/210 LCD Controller Frame Buffer Driver * * Please direct your questions and comments on this driver to the following * email address: * * linux-arm-kernel@lists.arm.linux.org.uk * * Clean patches should be sent to the ARM Linux Patch System. Please see the * following web page for more information: * * http://www.arm.linux.org.uk/developer/patches/info.shtml * * Thank you. * * * 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: Nicolas Pitre <nico@cam.org> * - Big cleanup for dynamic selection of machine type at run time. * * 2000/07/19: Jamey Hicks <jamey@crl.dec.com> * - Support for Bitsy aka Compaq iPAQ H3600 added. * * 2000/08/07: Tak-Shing Chan <tchan.rd@idthk.com> * Jeff Sutherland <jsutherland@accelent.com> * - 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. * * 2000/08/09: Cliff Brake <cbrake@accelent.com> * - modified for Accelent * * 2000/08/09: Kunihiko IMAI <imai@vasara.co.jp> * - XP860 support added * * 2000/08/19: Mark Huang <mhuang@livetoy.com> * - Allows standard options to be passed on the kernel command line * for most common passive displays. * * 2000/08/29: * - s/save_flags_cli/local_irq_save/ * - remove unneeded extra save_flags_cli in sa1100fb_enable_lcd_controller * * 2000/10/10: Erik Mouw <J.A.K.Mouw@its.tudelft.nl> * - Updated LART stuff. Fixed some minor bugs. * * 2000/10/30: Murphy Chen <murphy@mail.dialogue.com.tw> * - Pangolin support added * * 2000/10/31: Roman Jordan <jor@hoeft-wessel.de> * - Huw Webpanel support added * * 2000/11/23: Eric Peng <ericpeng@coventive.com> * - Freebird add * * 2001/02/07: Jamey Hicks <jamey.hicks@compaq.com> * Cliff Brake <cbrake@accelent.com> * - Added PM callback * * 2001/05/26: <rmk@arm.linux.org.uk> * - Fix 16bpp so that (a) we use the right colours rather than some * totally random colour depending on what was in page 0, and (b) * we don't de-reference a NULL pointer. * - remove duplicated implementation of consistent_alloc() * - convert dma address types to dma_addr_t * - remove unused 'montype' stuff * - remove redundant zero inits of init_var after the initial * memzero. * - remove allow_modeset (acornfb idea does not belong here) * * 2001/05/28: <rmk@arm.linux.org.uk> * - massive cleanup - move machine dependent data into structures * - I've left various #warnings in - if you see one, and know * the hardware concerned, please get in contact with me. * * 2001/05/31: <rmk@arm.linux.org.uk> * - Fix LCCR1 HSW value, fix all machine type specifications to * keep values in line. (Please check your machine type specs) * * 2001/06/10: <rmk@arm.linux.org.uk> * - Fiddle with the LCD controller from task context only; mainly * so that we can run with interrupts on, and sleep. * - Convert #warnings into #errors. No pain, no gain. ;) * * 2001/06/14: <rmk@arm.linux.org.uk> * - Make the palette BPS value for 12bpp come out correctly. * - Take notice of "greyscale" on any colour depth. * - Make truecolor visuals use the RGB channel encoding information. * * 2001/07/02: <rmk@arm.linux.org.uk> * - Fix colourmap problems. * * 2001/08/03: <cbrake@accelent.com> * - Ported from SA1100 to PXA250 */#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/interrupt.h>#include <linux/slab.h>#include <linux/fb.h>#include <linux/delay.h>#include <linux/pm.h>#include <linux/init.h>#include <linux/cpufreq.h>#include <asm/hardware.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/mach-types.h>#include <asm/uaccess.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>/* * debugging? */#define DEBUG 1/* * Complain if VAR is out of range. */#define DEBUG_VAR 1#undef ASSABET_PAL_VIDEO#include "pxafb.h"void (*pxafb_blank_helper)(int blank);EXPORT_SYMBOL(pxafb_blank_helper);/* * IMHO this looks wrong. In 8BPP, length should be 8. */static struct pxafb_rgb rgb_8 = { red: { offset: 8, length: 4, }, green: { offset: 4, length: 4, }, blue: { offset: 0, length: 4, }, transp: { offset: 0, length: 0, },};static struct pxafb_rgb def_rgb_16 = { red: { offset: 11, length: 5, }, green: { offset: 5, length: 6, }, blue: { offset: 0, length: 5, }, transp: { offset: 0, length: 0, },};static struct pxafb_mach_info pxa_fb_info __initdata = { pixclock: LCD_PIXCLOCK, /* clock period in ps */ bpp: LCD_BPP, xres: LCD_XRES, yres: LCD_YRES, hsync_len: LCD_HORIZONTAL_SYNC_PULSE_WIDTH, vsync_len: LCD_VERTICAL_SYNC_PULSE_WIDTH, left_margin: LCD_BEGIN_OF_LINE_WAIT_COUNT, upper_margin: LCD_BEGIN_FRAME_WAIT_COUNT, right_margin: LCD_END_OF_LINE_WAIT_COUNT, lower_margin: LCD_END_OF_FRAME_WAIT_COUNT, sync: LCD_SYNC, lccr0: LCD_LCCR0, lccr3: LCD_LCCR3};static struct pxafb_mach_info * __initpxafb_get_machine_info(struct pxafb_info *fbi){ return &pxa_fb_info;}static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *);static void set_ctrlr_state(struct pxafb_info *fbi, u_int state);static inline void pxafb_schedule_task(struct pxafb_info *fbi, u_int state){ unsigned long flags; local_irq_save(flags); /* * We need to handle two requests being made at the same time. * There are two important cases: * 1. When we are changing VT (C_REENABLE) while unblanking (C_ENABLE) * We must perform the unblanking, which will do our REENABLE for us. * 2. When we are blanking, but immediately unblank before we have * blanked. We do the "REENABLE" thing here as well, just to be sure. */ if (fbi->task_state == C_ENABLE && state == C_REENABLE) state = (u_int) -1; if (fbi->task_state == C_DISABLE && state == C_ENABLE) state = C_REENABLE; if (state != (u_int)-1) { fbi->task_state = state; schedule_task(&fbi->task); } local_irq_restore(flags);}/* * Get the VAR structure pointer for the specified console */static inline struct fb_var_screeninfo *get_con_var(struct fb_info *info, int con){ struct pxafb_info *fbi = (struct pxafb_info *)info; return (con == fbi->currcon || con == -1) ? &fbi->fb.var : &fb_display[con].var;}/* * Get the DISPLAY structure pointer for the specified console */static inline struct display *get_con_display(struct fb_info *info, int con){ struct pxafb_info *fbi = (struct pxafb_info *)info; return (con < 0) ? fbi->fb.disp : &fb_display[con];}/* * Get the CMAP pointer for the specified console */static inline struct fb_cmap *get_con_cmap(struct fb_info *info, int con){ struct pxafb_info *fbi = (struct pxafb_info *)info; return (con == fbi->currcon || con == -1) ? &fbi->fb.cmap : &fb_display[con].cmap;}static inline u_intchan_to_field(u_int chan, struct fb_bitfield *bf){ chan &= 0xffff; chan >>= 16 - bf->length; return chan << bf->offset;}static intpxafb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue, u_int trans, struct fb_info *info){ struct pxafb_info *fbi = (struct pxafb_info *)info; u_int val, ret = 1; if (regno < fbi->palette_size) { val = ((red >> 0) & 0xf800); val |= ((green >> 5) & 0x07e0); val |= ((blue >> 11) & 0x001f); fbi->palette_cpu[regno] = val; ret = 0; } return ret;}static intpxafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int trans, struct fb_info *info){ struct pxafb_info *fbi = (struct pxafb_info *)info; u_int val; int ret = 1; /* * If greyscale is true, then we convert the RGB value * to greyscale no mater what visual we are using. */ if (fbi->fb.var.grayscale) red = green = blue = (19595 * red + 38470 * green + 7471 * blue) >> 16; switch (fbi->fb.disp->visual) { case FB_VISUAL_TRUECOLOR: /* * 12 or 16-bit True Colour. We encode the RGB value * according to the RGB bitfield information. */ if (regno < 16) { u16 *pal = fbi->fb.pseudo_palette; val = chan_to_field(red, &fbi->fb.var.red); val |= chan_to_field(green, &fbi->fb.var.green); val |= chan_to_field(blue, &fbi->fb.var.blue); pal[regno] = val; ret = 0; } break; case FB_VISUAL_PSEUDOCOLOR: ret = pxafb_setpalettereg(regno, red, green, blue, trans, info); break; } return ret;}/* * pxafb_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 int pxafb_validate_var(struct fb_var_screeninfo *var, struct pxafb_info *fbi){ int ret = -EINVAL; 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 = var->xres_virtual < var->xres ? var->xres : var->xres_virtual; var->yres_virtual = var->yres_virtual < var->yres ? var->yres : var->yres_virtual; DPRINTK("var->bits_per_pixel=%d\n", var->bits_per_pixel); switch (var->bits_per_pixel) {#ifdef FBCON_HAS_CFB4 case 4: ret = 0; break;#endif#ifdef FBCON_HAS_CFB8 case 8: ret = 0; break;#endif#ifdef FBCON_HAS_CFB16 case 12: /* make sure we are in passive mode */ if (!(fbi->lccr0 & LCCR0_PAS)) ret = 0; break; case 16: /* cerf pda 16 bits works fine in passive mode, so don't complain */ if (machine_is_xhyper255()) { ret = 0; } else /* make sure we are in active mode */ if ((fbi->lccr0 & LCCR0_PAS)) ret = 0; break;#endif default: break; } return ret;}static inline void pxafb_set_truecolor(u_int is_true_color){ DPRINTK("true_color = %d\n", is_true_color);#ifdef CONFIG_SA1100_ASSABET if (machine_is_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 voidpxafb_hw_set_var(struct fb_var_screeninfo *var, struct pxafb_info *fbi){ fb_set_cmap(&fbi->fb.cmap, 1, pxafb_setcolreg, &fbi->fb); /* Set board control register to handle new color depth */ pxafb_set_truecolor(var->bits_per_pixel >= 16); pxafb_activate_var(var, fbi);}/* * pxafb_set_var(): * Set the user defined part of the display for the specified console */static intpxafb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info){ struct pxafb_info *fbi = (struct pxafb_info *)info; struct fb_var_screeninfo *dvar = get_con_var(&fbi->fb, con); struct display *display = get_con_display(&fbi->fb, con); int err, chgvar = 0, rgbidx; DPRINTK("set_var\n"); /* * Decode var contents into a par structure, adjusting any * out of range values. */ err = pxafb_validate_var(var, fbi); if (err) return err; if (var->activate & FB_ACTIVATE_TEST) return 0; if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW) return -EINVAL; if (dvar->xres != var->xres) chgvar = 1; if (dvar->yres != var->yres) chgvar = 1; if (dvar->xres_virtual != var->xres_virtual) chgvar = 1; if (dvar->yres_virtual != var->yres_virtual) chgvar = 1; if (dvar->bits_per_pixel != var->bits_per_pixel) chgvar = 1; if (con < 0) chgvar = 0; switch (var->bits_per_pixel) {#ifdef FBCON_HAS_CFB4 case 4: if (fbi->cmap_static) display->visual = FB_VISUAL_STATIC_PSEUDOCOLOR; else display->visual = FB_VISUAL_PSEUDOCOLOR; display->line_length = var->xres / 2; display->dispsw = &fbcon_cfb4; rgbidx = RGB_8; break;#endif#ifdef FBCON_HAS_CFB8 case 8: if (fbi->cmap_static) display->visual = FB_VISUAL_STATIC_PSEUDOCOLOR; else display->visual = FB_VISUAL_PSEUDOCOLOR; display->line_length = var->xres; display->dispsw = &fbcon_cfb8; rgbidx = RGB_8; break;#endif#ifdef FBCON_HAS_CFB16 case 12: case 16: display->visual = FB_VISUAL_TRUECOLOR; display->line_length = var->xres * 2; display->dispsw = &fbcon_cfb16; display->dispsw_data = fbi->fb.pseudo_palette; rgbidx = RGB_16; break;#endif default: rgbidx = 0; display->dispsw = &fbcon_dummy; break; } display->screen_base = fbi->screen_cpu; display->next_line = display->line_length; display->type = fbi->fb.fix.type; display->type_aux = fbi->fb.fix.type_aux;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -