📄 sa1100fb.c
字号:
/* * linux/drivers/video/sa1100fb.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. * * StrongARM 1100 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. * * Known problems: * - With the Neponset plugged into an Assabet, LCD powerdown * doesn't work (LCD stays powered up). Therefore we shouldn't * blank the screen. * - We don't limit the CPU clock rate nor the mode selection * according to the available SDRAM bandwidth. * * Other notes: * - Linear grayscale palettes and the kernel. * Such code does not belong in the kernel. The kernel frame buffer * drivers do not expect a linear colourmap, but a colourmap based on * the VT100 standard mapping. * * If your _userspace_ requires a linear colourmap, then the setup of * such a colourmap belongs _in userspace_, not in the kernel. Code * to set the colourmap correctly from user space has been sent to * David Neuer. It's around 8 lines of C code, plus another 4 to * detect if we are using grayscale. * * - The following must never be specified in a panel definition: * LCCR0_LtlEnd, LCCR3_PixClkDiv, LCCR3_VrtSnchL, LCCR3_HorSnchL * * - The following should be specified: * either LCCR0_Color or LCCR0_Mono * either LCCR0_Sngl or LCCR0_Dual * either LCCR0_Act or LCCR0_Pas * either LCCR3_OutEnH or LCCD3_OutEnL * either LCCR3_PixRsEdg or LCCR3_PixFlEdg * either LCCR3_ACBsDiv or LCCR3_ACBsCntOff * * 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: 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 * memset. * - 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/07/13: <abraham@2d3d.co.za> * - Added support for the ICP LCD-Kit01 on LART. This LCD is * manufactured by Prime View, model no V16C6448AB * * 2001/07/23: <rmk@arm.linux.org.uk> * - Hand merge version from handhelds.org CVS tree. See patch * notes for 595/1 for more information. * - Drop 12bpp (it's 16bpp with different colour register mappings). * - This hardware can not do direct colour. Therefore we don't * support it. * * 2001/07/27: <rmk@arm.linux.org.uk> * - Halve YRES on dual scan LCDs. * * 2001/08/22: <rmk@arm.linux.org.uk> * - Add b/w iPAQ pixclock value. * * 2001/10/12: <rmk@arm.linux.org.uk> * - Add patch 681/1 and clean up stork definitions. */#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/mm.h>#include <linux/fb.h>#include <linux/delay.h>#include <linux/init.h>#include <linux/ioport.h>#include <linux/cpufreq.h>#include <linux/platform_device.h>#include <linux/dma-mapping.h>#include <linux/mutex.h>#include <mach/hardware.h>#include <asm/io.h>#include <asm/mach-types.h>#include <mach/assabet.h>#include <mach/shannon.h>/* * debugging? */#define DEBUG 0/* * Complain if VAR is out of range. */#define DEBUG_VAR 1#undef ASSABET_PAL_VIDEO#include "sa1100fb.h"extern void (*sa1100fb_backlight_power)(int on);extern void (*sa1100fb_lcd_power)(int on);/* * IMHO this looks wrong. In 8BPP, length should be 8. */static struct sa1100fb_rgb rgb_8 = { .red = { .offset = 0, .length = 4, }, .green = { .offset = 0, .length = 4, }, .blue = { .offset = 0, .length = 4, }, .transp = { .offset = 0, .length = 0, },};static struct sa1100fb_rgb def_rgb_16 = { .red = { .offset = 11, .length = 5, }, .green = { .offset = 5, .length = 6, }, .blue = { .offset = 0, .length = 5, }, .transp = { .offset = 0, .length = 0, },};#ifdef CONFIG_SA1100_ASSABET#ifndef ASSABET_PAL_VIDEO/* * The assabet uses a sharp LQ039Q2DS54 LCD module. It is actually * takes an RGB666 signal, but we provide it with an RGB565 signal * instead (def_rgb_16). */static struct sa1100fb_mach_info lq039q2ds54_info __initdata = { .pixclock = 171521, .bpp = 16, .xres = 320, .yres = 240, .hsync_len = 5, .vsync_len = 1, .left_margin = 61, .upper_margin = 3, .right_margin = 9, .lower_margin = 0, .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act, .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),};#elsestatic struct sa1100fb_mach_info pal_info __initdata = { .pixclock = 67797, .bpp = 16, .xres = 640, .yres = 512, .hsync_len = 64, .vsync_len = 6, .left_margin = 125, .upper_margin = 70, .right_margin = 115, .lower_margin = 36, .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act, .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(512),};#endif#endif#ifdef CONFIG_SA1100_H3800static struct sa1100fb_mach_info h3800_info __initdata = { .pixclock = 174757, .bpp = 16, .xres = 320, .yres = 240, .hsync_len = 3, .vsync_len = 3, .left_margin = 12, .upper_margin = 10, .right_margin = 17, .lower_margin = 1, .cmap_static = 1, .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act, .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),};#endif#ifdef CONFIG_SA1100_H3600static struct sa1100fb_mach_info h3600_info __initdata = { .pixclock = 174757, .bpp = 16, .xres = 320, .yres = 240, .hsync_len = 3, .vsync_len = 3, .left_margin = 12, .upper_margin = 10, .right_margin = 17, .lower_margin = 1, .cmap_static = 1, .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act, .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),};static struct sa1100fb_rgb h3600_rgb_16 = { .red = { .offset = 12, .length = 4, }, .green = { .offset = 7, .length = 4, }, .blue = { .offset = 1, .length = 4, }, .transp = { .offset = 0, .length = 0, },};#endif#ifdef CONFIG_SA1100_H3100static struct sa1100fb_mach_info h3100_info __initdata = { .pixclock = 406977, .bpp = 4, .xres = 320, .yres = 240, .hsync_len = 26, .vsync_len = 41, .left_margin = 4, .upper_margin = 0, .right_margin = 4, .lower_margin = 0, .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, .cmap_greyscale = 1, .cmap_inverse = 1, .lccr0 = LCCR0_Mono | LCCR0_4PixMono | LCCR0_Sngl | LCCR0_Pas, .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),};#endif#ifdef CONFIG_SA1100_COLLIEstatic struct sa1100fb_mach_info collie_info __initdata = { .pixclock = 171521, .bpp = 16, .xres = 320, .yres = 240, .hsync_len = 5, .vsync_len = 1, .left_margin = 11, .upper_margin = 2, .right_margin = 30, .lower_margin = 0, .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act, .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),};#endif#ifdef LART_GREY_LCDstatic struct sa1100fb_mach_info lart_grey_info __initdata = { .pixclock = 150000, .bpp = 4, .xres = 320, .yres = 240, .hsync_len = 1, .vsync_len = 1, .left_margin = 4, .upper_margin = 0, .right_margin = 2, .lower_margin = 0, .cmap_greyscale = 1, .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, .lccr0 = LCCR0_Mono | LCCR0_Sngl | LCCR0_Pas | LCCR0_4PixMono, .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(512),};#endif#ifdef LART_COLOR_LCDstatic struct sa1100fb_mach_info lart_color_info __initdata = { .pixclock = 150000, .bpp = 16, .xres = 320, .yres = 240, .hsync_len = 2, .vsync_len = 3, .left_margin = 69, .upper_margin = 14, .right_margin = 8, .lower_margin = 4, .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act, .lccr3 = LCCR3_OutEnH | LCCR3_PixFlEdg | LCCR3_ACBsDiv(512),};#endif#ifdef LART_VIDEO_OUTstatic struct sa1100fb_mach_info lart_video_info __initdata = { .pixclock = 39721, .bpp = 16, .xres = 640, .yres = 480, .hsync_len = 95, .vsync_len = 2, .left_margin = 40, .upper_margin = 32, .right_margin = 24, .lower_margin = 11, .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act, .lccr3 = LCCR3_OutEnL | LCCR3_PixFlEdg | LCCR3_ACBsDiv(512),};#endif#ifdef LART_KIT01_LCDstatic struct sa1100fb_mach_info lart_kit01_info __initdata = { .pixclock = 63291, .bpp = 16, .xres = 640, .yres = 480, .hsync_len = 64, .vsync_len = 3, .left_margin = 122, .upper_margin = 45, .right_margin = 10, .lower_margin = 10, .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act, .lccr3 = LCCR3_OutEnH | LCCR3_PixFlEdg};#endif#ifdef CONFIG_SA1100_SHANNONstatic struct sa1100fb_mach_info shannon_info __initdata = { .pixclock = 152500, .bpp = 8, .xres = 640, .yres = 480, .hsync_len = 4, .vsync_len = 3, .left_margin = 2, .upper_margin = 0, .right_margin = 1, .lower_margin = 0, .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, .lccr0 = LCCR0_Color | LCCR0_Dual | LCCR0_Pas, .lccr3 = LCCR3_ACBsDiv(512),};#endifstatic struct sa1100fb_mach_info * __initsa1100fb_get_machine_info(struct sa1100fb_info *fbi){ struct sa1100fb_mach_info *inf = NULL; /* * R G B T * default {11,5}, { 5,6}, { 0,5}, { 0,0} * h3600 {12,4}, { 7,4}, { 1,4}, { 0,0} * freebird { 8,4}, { 4,4}, { 0,4}, {12,4} */#ifdef CONFIG_SA1100_ASSABET if (machine_is_assabet()) {#ifndef ASSABET_PAL_VIDEO inf = &lq039q2ds54_info;#else inf = &pal_info;#endif }#endif#ifdef CONFIG_SA1100_H3100 if (machine_is_h3100()) { inf = &h3100_info; }#endif#ifdef CONFIG_SA1100_H3600 if (machine_is_h3600()) { inf = &h3600_info; fbi->rgb[RGB_16] = &h3600_rgb_16; }#endif#ifdef CONFIG_SA1100_H3800 if (machine_is_h3800()) { inf = &h3800_info; }#endif#ifdef CONFIG_SA1100_COLLIE if (machine_is_collie()) { inf = &collie_info; }#endif#ifdef CONFIG_SA1100_LART if (machine_is_lart()) {#ifdef LART_GREY_LCD inf = &lart_grey_info;#endif#ifdef LART_COLOR_LCD inf = &lart_color_info;#endif#ifdef LART_VIDEO_OUT inf = &lart_video_info;#endif#ifdef LART_KIT01_LCD inf = &lart_kit01_info;#endif }#endif#ifdef CONFIG_SA1100_SHANNON if (machine_is_shannon()) { inf = &shannon_info; }#endif return inf;}static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_info *);static void set_ctrlr_state(struct sa1100fb_info *fbi, u_int state);static inline void sa1100fb_schedule_work(struct sa1100fb_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_work(&fbi->task); } local_irq_restore(flags);}static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf){ chan &= 0xffff; chan >>= 16 - bf->length; return chan << bf->offset;}/* * Convert bits-per-pixel to a hardware palette PBS value. */static inline u_int palette_pbs(struct fb_var_screeninfo *var){ int ret = 0; switch (var->bits_per_pixel) { case 4: ret = 0 << 12; break; case 8: ret = 1 << 12; break; case 16: ret = 2 << 12; break; } return ret;}static intsa1100fb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue, u_int trans, struct fb_info *info){ struct sa1100fb_info *fbi = (struct sa1100fb_info *)info; u_int val, ret = 1; if (regno < fbi->palette_size) { val = ((red >> 4) & 0xf00); val |= ((green >> 8) & 0x0f0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -