omapfb_lcdc.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 263 行

C
263
字号
/* * File: drivers/video/omap/omapfb_main.c * * Support code for the internal LCD controller on TI OMAP boards * * Copyright (C) 2004 Nokia Corporation * Author: Imre Deak <imre.deak@nokia.com> * * Acknowledgements: *   Juha Yrjola <juha.yrjola@nokia.com>   - Modifications * * 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 program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * General Public License for more details. * * 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., * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. */#include <linux/config.h>#include <linux/module.h>#include <linux/mm.h>#include <linux/fb.h>#include <asm/arch/dma.h>#include "omapfb.h"#include "lcdc.h"#include "debug.h"/* Configure the LCD DMA according to the current mode specified by parameters * in fbdev and fbdev->var. */static void lcddma_setup_mode(struct omapfb_device *fbdev){	static const int dma_elem_type[] = {		0,		OMAP_DMA_DATA_TYPE_S8,		OMAP_DMA_DATA_TYPE_S16,		0,		OMAP_DMA_DATA_TYPE_S32,	};	struct fb_var_screeninfo *var = &fbdev->fb_info->var;	unsigned long	src;	int		esize, xelem, yelem;	src = fbdev->lcddma_handle + fbdev->vis_frame_org + fbdev->view_org;	switch (var->rotate) {	case 0:		esize = fbdev->mirror || (src & 3) ? 2 : 4;		xelem = var->xres * var->bits_per_pixel / 8 / esize;		yelem = var->yres;		break;	case 90:	case 180:	case 270:		esize = 2;		xelem = var->xres * var->bits_per_pixel / 16;		yelem = var->yres;		break;	default:		BUG();		return;	}	DBGPRINT(1, "setup_dma: src=%#010x esize=%d xelem=%d yelem=%d\n",		 src, esize, xelem, yelem);	omap_set_lcd_dma_b1(src, xelem, yelem, dma_elem_type[esize]);	omap_set_lcd_dma_single_transfer(0);	if (!cpu_is_omap1510()) {		/* Set virtual xres elem size */		omap_set_lcd_dma_b1_vxres(			fbdev->fb_info->fix.line_length / esize);		/* Setup transformations */		omap_set_lcd_dma_b1_rotation(var->rotate);		omap_set_lcd_dma_b1_mirror(fbdev->mirror);		omap_set_lcd_dma_b1_scale(fbdev->xscale, fbdev->yscale);	}}/* Change to a new video mode. We defer this to a later time to avoid any * flicker and not to mess up the current LCD DMA context. For this we disable * the LCD controler, which will generate a DONE irq after the last frame has * been transferred. Then it'll be safe to reconfigure both the LCD controller * as well as the LCD DMA. */static void omapfb_lcdc_change_mode(struct omapfb_device *fbdev){	DBGENTER(1);	if (fbdev->ext_lcdc) {		BUG();		return;	}	omap_stop_lcd_dma();	if (!irqs_disabled()) {		/* Defer LCD DMA reprogramming for a safe time to avoid		 * the tearing effect.		 */		omap_lcdc_enable_irqs(OMAP_LCDC_IRQ_DONE);		fbdev->state = OMAPFB_MODE_CHANGE;		omap_lcdc_disable_async();	} else {		/* If IRQs are disabled change mode here synchronously. */		omap_lcdc_disable();		lcddma_setup_mode(fbdev);		omap_setup_lcd_dma();		omap_lcdc_enable();	}	DBGLEAVE(1);}/* Called by the LCD DMA core when the last frame has been transferred after * disabling the LCD controller, or when palette loading has been finished. * We use the DONE event for changing to a new mode to avoid any flicker. */static void lcdc_irq_handler(u32 status, unsigned long data){	struct omapfb_device *fbdev = (struct omapfb_device *)data;	DBGENTER(2);	DBGPRINT(2, "status=%#010x\n", status);	if (likely((status & OMAP_LCDC_STAT_DONE) &&	    fbdev->state == OMAPFB_MODE_CHANGE)) {		/* Reprogram DMA and restart lcdc */		lcddma_setup_mode(fbdev);		omap_setup_lcd_dma();		fbdev->state = OMAPFB_ACTIVE;		omap_lcdc_enable();	}	if (status & OMAP_LCDC_STAT_LOADED_PALETTE) {		omap_lcdc_disable_async();		complete(&fbdev->load_complete);	}	DBGLEAVE(2);}/* Configure the LCD DMA for a palette load operation and do the palette * downloading synchronously. We don't use the frame+palette load mode of * the controller, since the palette can always be downloaded seperately. */static void omapfb_lcdc_load_palette(struct omapfb_device *fbdev){	DBGENTER(1);	omap_lcdc_init_palette(fbdev->panel->video_mode,				fbdev->lcddma_base + fbdev->palette_org,				fbdev->palette_size);	omap_set_lcd_dma_b1(fbdev->lcddma_handle + fbdev->palette_org,			    fbdev->palette_size / 4 + 1, 1,			    OMAP_DMA_DATA_TYPE_S32);	omap_set_lcd_dma_single_transfer(1);	omap_setup_lcd_dma();	init_completion(&fbdev->load_complete);	omap_lcdc_enable_irqs(OMAP_LCDC_IRQ_LOADED_PALETTE);	omap_lcdc_set_load_mode(OMAP_LCDC_LOAD_PALETTE);	omap_lcdc_enable();	wait_for_completion(&fbdev->load_complete);	/* The controller gets disabled in the irq handler */	omap_lcdc_disable_irqs(OMAP_LCDC_IRQ_LOADED_PALETTE);	omap_stop_lcd_dma();	DBGLEAVE(1);}/* Configure the LCD controller, download the color palette and start a looped * DMA transfer of the frame image data. */static void omapfb_lcdc_start(struct omapfb_device *fbdev){	DBGENTER(1);	omap_lcdc_set_config(fbdev->panel->config & LCD_PANEL_TFT,			     fbdev->panel->signals);	omap_lcdc_set_video_mode(fbdev->panel->video_mode);	omapfb_lcdc_load_palette(fbdev);	/* Setup and start LCD DMA */	lcddma_setup_mode(fbdev);	omap_setup_lcd_dma();	omap_lcdc_set_load_mode(OMAP_LCDC_LOAD_FRAME);	omap_lcdc_enable_irqs(OMAP_LCDC_IRQ_DONE);	/* This will start the actual DMA transfer */	omap_lcdc_enable();	DBGLEAVE(1);}/* Stop the looped LCD DMA transfer */static void omapfb_lcdc_stop(struct omapfb_device *fbdev){	DBGENTER(1);	omap_lcdc_disable();	omap_stop_lcd_dma();	DBGLEAVE(1);}static int omapfb_lcdc_init(struct omapfb_device *fbdev){	int size, xres, yres, r;	r = omap_lcdc_init();	if (r < 0) {		PRNERR("LCDC initialization failed\n");		return r;	}	xres = fbdev->panel->video_mode->x_res;	yres = fbdev->panel->video_mode->y_res;	fbdev->palette_size = omap_lcdc_get_palette_size(fbdev->panel->video_mode);	size = (fbdev->palette_size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);	size += xres * fbdev->panel->video_mode->bpp / 8 * yres;	fbdev->lcddma_mem_size = size;	fbdev->frame0_org = (fbdev->palette_size + PAGE_SIZE - 1) &							~(PAGE_SIZE - 1);	fbdev->palette_org = fbdev->frame0_org - fbdev->palette_size;	r = omap_request_lcd_dma(NULL, NULL);	if (r) {		PRNERR("unable to get LCD DMA\n");		goto lcdc_cleanup;	}	r = omap_lcdc_request(fbdev, lcdc_irq_handler, (unsigned long)fbdev);	if (r) {		PRNERR("unable to request LCD controller\n");		goto free_dma;	}	return 0;free_dma:	omap_free_lcd_dma();lcdc_cleanup:	omap_lcdc_cleanup();        return r;}static void omapfb_lcdc_cleanup(struct omapfb_device *fbdev){	omap_lcdc_release(fbdev);	omap_free_lcd_dma();	omap_lcdc_cleanup();}struct lcd_ctrl omapfb_lcdc_ctrl = {	.name = "internal",	.init = omapfb_lcdc_init,	.cleanup = omapfb_lcdc_cleanup,	.start = omapfb_lcdc_start,	.stop = omapfb_lcdc_stop,	.suspend = NULL,	.resume = NULL,	.change_mode = omapfb_lcdc_change_mode,};

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?