/* * BRIEF MODULE DESCRIPTION * Au1100 LCD Driver. * * Rewritten for 2.6 by Embedded Alley Solutions * <source@embeddedalley.com>, based on submissions by * Karl Lessard <klessard@sunrisetelecom.com> * <c.pellegrin@exadron.com> * * PM support added by Rodolfo Giometti <giometti@linux.it> * Cursor enable/disable by Rodolfo Giometti <giometti@linux.it> * * Copyright 2002 MontaVista Software * Author: MontaVista Software, Inc. * ppopov@mvista.com or source@mvista.com * * Copyright 2002 Alchemy Semiconductor * Author: Alchemy Semiconductor * * Based on: * linux/drivers/video/skeletonfb.c -- Skeleton for a frame buffer device * Created 28 Dec 1997 by Geert Uytterhoeven * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA.
*/ #include <linux/clk.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> #include <linux/string.h> #include <linux/mm.h> #include <linux/fb.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/ctype.h> #include <linux/dma-mapping.h> #include <linux/platform_device.h> #include <linux/slab.h>
/* fb_blank * Blank the screen. Depending on the mode, the screen will be * activated with the backlight color, or desactivated
*/ staticint au1100fb_fb_blank(int blank_mode, struct fb_info *fbi)
{ struct au1100fb_device *fbdev = to_au1100fb_device(fbi);
print_dbg("fb_blank %d %p", blank_mode, fbi);
switch (blank_mode) {
case VESA_NO_BLANKING: /* Turn on panel */
fbdev->regs->lcd_control |= LCD_CONTROL_GO;
wmb(); /* drain writebuffer */ break;
case VESA_VSYNC_SUSPEND: case VESA_HSYNC_SUSPEND: case VESA_POWERDOWN: /* Turn off panel */
fbdev->regs->lcd_control &= ~LCD_CONTROL_GO;
wmb(); /* drain writebuffer */ break; default: break;
} return 0;
}
/* * Set hardware with var settings. This will enable the controller with a specific * mode, normally validated with the fb_check_var method
*/ int au1100fb_setmode(struct au1100fb_device *fbdev)
{ struct fb_info *info;
u32 words; int index;
if (!fbdev) return -EINVAL;
info = &fbdev->info;
/* Update var-dependent FB info */ if (panel_is_active(fbdev->panel) || panel_is_color(fbdev->panel)) { if (info->var.bits_per_pixel <= 8) { /* palettized */
info->var.red.offset = 0;
info->var.red.length = info->var.bits_per_pixel;
info->var.red.msb_right = 0;
if (panel_is_dual(fbdev->panel)) { /* Second panel display seconf half of screen if possible,
* otherwise display the same as the first panel */ if (info->var.yres_virtual >= (info->var.yres << 1)) {
fbdev->regs->lcd_dmaaddr1 = LCD_DMA_SA_N(fbdev->fb_phys +
(info->fix.line_length *
(info->var.yres_virtual >> 1)));
} else {
fbdev->regs->lcd_dmaaddr1 = LCD_DMA_SA_N(fbdev->fb_phys);
}
}
words = info->fix.line_length / sizeof(u32); if (!info->var.rotate || (info->var.rotate == 180)) {
words *= info->var.yres_virtual; if (info->var.rotate /* 180 */) {
words -= (words % 8); /* should be divisable by 8 */
}
}
fbdev->regs->lcd_words = LCD_WRD_WRDS_N(words);
if (regno > (AU1100_LCD_NBR_PALETTE_ENTRIES - 1)) return -EINVAL;
if (fbi->var.grayscale) { /* Convert color to grayscale */
red = green = blue =
(19595 * red + 38470 * green + 7471 * blue) >> 16;
}
if (fbi->fix.visual == FB_VISUAL_TRUECOLOR) { /* Place color in the pseudopalette */ if (regno > 16) return -EINVAL;
palette = (u32*)fbi->pseudo_palette;
red >>= (16 - fbi->var.red.length);
green >>= (16 - fbi->var.green.length);
blue >>= (16 - fbi->var.blue.length);
value = (red << fbi->var.red.offset) |
(green << fbi->var.green.offset)|
(blue << fbi->var.blue.offset);
value &= 0xFFFF;
} elseif (panel_is_active(fbdev->panel)) { /* COLOR TFT PALLETTIZED (use RGB 565) */
value = (red & 0xF800)|((green >> 5) & 0x07E0)|((blue >> 11) & 0x001F);
value &= 0xFFFF;
} elseif (panel_is_color(fbdev->panel)) { /* COLOR STN MODE */
value = (((panel_swap_rgb(fbdev->panel) ? blue : red) >> 12) & 0x000F) |
((green >> 8) & 0x00F0) |
(((panel_swap_rgb(fbdev->panel) ? red : blue) >> 4) & 0x0F00);
value &= 0xFFF;
} else { /* MONOCHROME MODE */
value = (green >> 12) & 0x000F;
value &= 0xF;
}
palette[regno] = value;
return 0;
}
/* fb_pan_display * Pan display in x and/or y as specified
*/ int au1100fb_fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fbi)
{ struct au1100fb_device *fbdev; int dy;
fbdev = to_au1100fb_device(fbi);
print_dbg("fb_pan_display %p %p", var, fbi);
if (!var || !fbdev) { return -EINVAL;
}
if (var->xoffset - fbi->var.xoffset) { /* No support for X panning for now! */ return -EINVAL;
}
print_dbg("fb_pan_display 2 %p %p", var, fbi);
dy = var->yoffset - fbi->var.yoffset; if (dy) {
/* fb_mmap * Map video memory in user space. We don't use the generic fb_mmap method mainly * to allow the use of the TLB streaming flag (CCA=6)
*/ int au1100fb_fb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
{ struct au1100fb_device *fbdev = to_au1100fb_device(fbi);
/* Allocate region for our registers and map them */
regs_res = platform_get_resource(dev, IORESOURCE_MEM, 0); if (!regs_res) {
print_err("fail to retrieve registers resource"); return -EFAULT;
}
if (!devm_request_mem_region(&dev->dev,
au1100fb_fix.mmio_start,
au1100fb_fix.mmio_len,
DRIVER_NAME)) {
print_err("fail to lock memory region at 0x%08lx",
au1100fb_fix.mmio_start); return -EBUSY;
}
print_dbg("Register memory map at %p", fbdev->regs);
print_dbg("phys=0x%08x, size=%d", fbdev->regs_phys, fbdev->regs_len);
c = clk_get(NULL, "lcd_intclk"); if (!IS_ERR(c)) {
fbdev->lcdclk = c;
clk_set_rate(c, 48000000);
clk_prepare_enable(c);
}
/* Allocate the framebuffer to the maximum screen size * nbr of video buffers */
fbdev->fb_len = fbdev->panel->xres * fbdev->panel->yres *
(fbdev->panel->bpp >> 3) * AU1100FB_NBR_VIDEO_BUFFERS;
/* load the panel info into the var struct */
au1100fb_var.bits_per_pixel = fbdev->panel->bpp;
au1100fb_var.xres = fbdev->panel->xres;
au1100fb_var.xres_virtual = au1100fb_var.xres;
au1100fb_var.yres = fbdev->panel->yres;
au1100fb_var.yres_virtual = au1100fb_var.yres;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.