⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fsl-diu-fb.c

📁 Linux环境下视频显示卡设备的驱动程序源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved. * *  Freescale DIU Frame Buffer device driver * *  Authors: Hongjun Chen <hong-jun.chen@freescale.com> *           Paul Widmer <paul.widmer@freescale.com> *           Srikanth Srinivasan <srikanth.srinivasan@freescale.com> *           York Sun <yorksun@freescale.com> * *   Based on imxfb.c Copyright (C) 2004 S.Hauer, Pengutronix * * 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. * */#include <linux/module.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/string.h>#include <linux/slab.h>#include <linux/fb.h>#include <linux/init.h>#include <linux/dma-mapping.h>#include <linux/platform_device.h>#include <linux/interrupt.h>#include <linux/clk.h>#include <linux/uaccess.h>#include <linux/vmalloc.h>#include <linux/of_platform.h>#include <sysdev/fsl_soc.h>#include "fsl-diu-fb.h"/* * These parameters give default parameters * for video output 1024x768, * FIXME - change timing to proper amounts * hsync 31.5kHz, vsync 60Hz */static struct fb_videomode __devinitdata fsl_diu_default_mode = {	.refresh	= 60,	.xres		= 1024,	.yres		= 768,	.pixclock	= 15385,	.left_margin	= 160,	.right_margin	= 24,	.upper_margin	= 29,	.lower_margin	= 3,	.hsync_len	= 136,	.vsync_len	= 6,	.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,	.vmode		= FB_VMODE_NONINTERLACED};static struct fb_videomode __devinitdata fsl_diu_mode_db[] = {	{		.name		= "1024x768-60",		.refresh	= 60,		.xres		= 1024,		.yres		= 768,		.pixclock	= 15385,		.left_margin	= 160,		.right_margin	= 24,		.upper_margin	= 29,		.lower_margin	= 3,		.hsync_len	= 136,		.vsync_len	= 6,		.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,		.vmode		= FB_VMODE_NONINTERLACED	},	{		.name		= "1024x768-70",		.refresh	= 70,		.xres		= 1024,		.yres		= 768,		.pixclock	= 16886,		.left_margin	= 3,		.right_margin	= 3,		.upper_margin	= 2,		.lower_margin	= 2,		.hsync_len	= 40,		.vsync_len	= 18,		.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,		.vmode		= FB_VMODE_NONINTERLACED	},	{		.name		= "1024x768-75",		.refresh	= 75,		.xres		= 1024,		.yres		= 768,		.pixclock	= 15009,		.left_margin	= 3,		.right_margin	= 3,		.upper_margin	= 2,		.lower_margin	= 2,		.hsync_len	= 80,		.vsync_len	= 32,		.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,		.vmode		= FB_VMODE_NONINTERLACED	},	{		.name		= "1280x1024-60",		.refresh	= 60,		.xres		= 1280,		.yres		= 1024,		.pixclock	= 9375,		.left_margin	= 38,		.right_margin	= 128,		.upper_margin	= 2,		.lower_margin	= 7,		.hsync_len	= 216,		.vsync_len	= 37,		.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,		.vmode		= FB_VMODE_NONINTERLACED	},	{		.name		= "1280x1024-70",		.refresh	= 70,		.xres		= 1280,		.yres		= 1024,		.pixclock	= 9380,		.left_margin	= 6,		.right_margin	= 6,		.upper_margin	= 4,		.lower_margin	= 4,		.hsync_len	= 60,		.vsync_len	= 94,		.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,		.vmode		= FB_VMODE_NONINTERLACED	},	{		.name		= "1280x1024-75",		.refresh	= 75,		.xres		= 1280,		.yres		= 1024,		.pixclock	= 9380,		.left_margin	= 6,		.right_margin	= 6,		.upper_margin	= 4,		.lower_margin	= 4,		.hsync_len	= 60,		.vsync_len	= 15,		.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,		.vmode		= FB_VMODE_NONINTERLACED	},	{		.name		= "320x240",		/* for AOI only */		.refresh	= 60,		.xres		= 320,		.yres		= 240,		.pixclock	= 15385,		.left_margin	= 0,		.right_margin	= 0,		.upper_margin	= 0,		.lower_margin	= 0,		.hsync_len	= 0,		.vsync_len	= 0,		.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,		.vmode		= FB_VMODE_NONINTERLACED	},	{		.name		= "1280x480-60",		.refresh	= 60,		.xres		= 1280,		.yres		= 480,		.pixclock	= 18939,		.left_margin	= 353,		.right_margin	= 47,		.upper_margin	= 39,		.lower_margin	= 4,		.hsync_len	= 8,		.vsync_len	= 2,		.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,		.vmode		= FB_VMODE_NONINTERLACED	},};static char *fb_mode = "1024x768-32@60";static unsigned long default_bpp = 32;static int monitor_port;#if defined(CONFIG_NOT_COHERENT_CACHE)static u8 *coherence_data;static size_t coherence_data_size;static unsigned int d_cache_line_size;#endifstatic DEFINE_SPINLOCK(diu_lock);struct fsl_diu_data {	struct fb_info *fsl_diu_info[FSL_AOI_NUM - 1];				/*FSL_AOI_NUM has one dummy AOI */	struct device_attribute dev_attr;	struct diu_ad *dummy_ad;	void *dummy_aoi_virt;	unsigned int irq;	int fb_enabled;	int monitor_port;};struct mfb_info {	int index;	int type;	char *id;	int registered;	int blank;	unsigned long pseudo_palette[16];	struct diu_ad *ad;	int cursor_reset;	unsigned char g_alpha;	unsigned int count;	int x_aoi_d;		/* aoi display x offset to physical screen */	int y_aoi_d;		/* aoi display y offset to physical screen */	struct fsl_diu_data *parent;};static struct mfb_info mfb_template[] = {	{		/* AOI 0 for plane 0 */	.index = 0,	.type = MFB_TYPE_OUTPUT,	.id = "Panel0",	.registered = 0,	.count = 0,	.x_aoi_d = 0,	.y_aoi_d = 0,	},	{		/* AOI 0 for plane 1 */	.index = 1,	.type = MFB_TYPE_OUTPUT,	.id = "Panel1 AOI0",	.registered = 0,	.g_alpha = 0xff,	.count = 0,	.x_aoi_d = 0,	.y_aoi_d = 0,	},	{		/* AOI 1 for plane 1 */	.index = 2,	.type = MFB_TYPE_OUTPUT,	.id = "Panel1 AOI1",	.registered = 0,	.g_alpha = 0xff,	.count = 0,	.x_aoi_d = 0,	.y_aoi_d = 480,	},	{		/* AOI 0 for plane 2 */	.index = 3,	.type = MFB_TYPE_OUTPUT,	.id = "Panel2 AOI0",	.registered = 0,	.g_alpha = 0xff,	.count = 0,	.x_aoi_d = 640,	.y_aoi_d = 0,	},	{		/* AOI 1 for plane 2 */	.index = 4,	.type = MFB_TYPE_OUTPUT,	.id = "Panel2 AOI1",	.registered = 0,	.g_alpha = 0xff,	.count = 0,	.x_aoi_d = 640,	.y_aoi_d = 480,	},};static struct diu_hw dr = {	.mode = MFB_MODE1,	.reg_lock = __SPIN_LOCK_UNLOCKED(diu_hw.reg_lock),};static struct diu_pool pool;/** * fsl_diu_alloc - allocate memory for the DIU * @size: number of bytes to allocate * @param: returned physical address of memory * * This function allocates a physically-contiguous block of memory. */static void *fsl_diu_alloc(size_t size, phys_addr_t *phys){	void *virt;	pr_debug("size=%zu\n", size);	virt = alloc_pages_exact(size, GFP_DMA | __GFP_ZERO);	if (virt) {		*phys = virt_to_phys(virt);		pr_debug("virt=%p phys=%llx\n", virt,			(unsigned long long)*phys);	}	return virt;}/** * fsl_diu_free - release DIU memory * @virt: pointer returned by fsl_diu_alloc() * @size: number of bytes allocated by fsl_diu_alloc() * * This function releases memory allocated by fsl_diu_alloc(). */static void fsl_diu_free(void *virt, size_t size){	pr_debug("virt=%p size=%zu\n", virt, size);	if (virt && size)		free_pages_exact(virt, size);}static int fsl_diu_enable_panel(struct fb_info *info){	struct mfb_info *pmfbi, *cmfbi, *mfbi = info->par;	struct diu *hw = dr.diu_reg;	struct diu_ad *ad = mfbi->ad;	struct fsl_diu_data *machine_data = mfbi->parent;	int res = 0;	pr_debug("enable_panel index %d\n", mfbi->index);	if (mfbi->type != MFB_TYPE_OFF) {		switch (mfbi->index) {		case 0:				/* plane 0 */			if (hw->desc[0] != ad->paddr)				out_be32(&hw->desc[0], ad->paddr);			break;		case 1:				/* plane 1 AOI 0 */			cmfbi = machine_data->fsl_diu_info[2]->par;			if (hw->desc[1] != ad->paddr) {	/* AOI0 closed */				if (cmfbi->count > 0)	/* AOI1 open */					ad->next_ad =						cpu_to_le32(cmfbi->ad->paddr);				else					ad->next_ad = 0;				out_be32(&hw->desc[1], ad->paddr);			}			break;		case 3:				/* plane 2 AOI 0 */			cmfbi = machine_data->fsl_diu_info[4]->par;			if (hw->desc[2] != ad->paddr) {	/* AOI0 closed */				if (cmfbi->count > 0)	/* AOI1 open */					ad->next_ad =						cpu_to_le32(cmfbi->ad->paddr);				else					ad->next_ad = 0;				out_be32(&hw->desc[2], ad->paddr);			}			break;		case 2:				/* plane 1 AOI 1 */			pmfbi = machine_data->fsl_diu_info[1]->par;			ad->next_ad = 0;			if (hw->desc[1] == machine_data->dummy_ad->paddr)				out_be32(&hw->desc[1], ad->paddr);			else					/* AOI0 open */				pmfbi->ad->next_ad = cpu_to_le32(ad->paddr);			break;		case 4:				/* plane 2 AOI 1 */			pmfbi = machine_data->fsl_diu_info[3]->par;			ad->next_ad = 0;			if (hw->desc[2] == machine_data->dummy_ad->paddr)				out_be32(&hw->desc[2], ad->paddr);			else				/* AOI0 was open */				pmfbi->ad->next_ad = cpu_to_le32(ad->paddr);			break;		default:			res = -EINVAL;			break;		}	} else		res = -EINVAL;	return res;}static int fsl_diu_disable_panel(struct fb_info *info){	struct mfb_info *pmfbi, *cmfbi, *mfbi = info->par;	struct diu *hw = dr.diu_reg;	struct diu_ad *ad = mfbi->ad;	struct fsl_diu_data *machine_data = mfbi->parent;	int res = 0;	switch (mfbi->index) {	case 0:					/* plane 0 */		if (hw->desc[0] != machine_data->dummy_ad->paddr)			out_be32(&hw->desc[0],				machine_data->dummy_ad->paddr);		break;	case 1:					/* plane 1 AOI 0 */		cmfbi = machine_data->fsl_diu_info[2]->par;		if (cmfbi->count > 0)	/* AOI1 is open */			out_be32(&hw->desc[1], cmfbi->ad->paddr);					/* move AOI1 to the first */		else			/* AOI1 was closed */			out_be32(&hw->desc[1],				machine_data->dummy_ad->paddr);					/* close AOI 0 */		break;	case 3:					/* plane 2 AOI 0 */		cmfbi = machine_data->fsl_diu_info[4]->par;		if (cmfbi->count > 0)	/* AOI1 is open */			out_be32(&hw->desc[2], cmfbi->ad->paddr);					/* move AOI1 to the first */		else			/* AOI1 was closed */			out_be32(&hw->desc[2],				machine_data->dummy_ad->paddr);					/* close AOI 0 */		break;	case 2:					/* plane 1 AOI 1 */		pmfbi = machine_data->fsl_diu_info[1]->par;		if (hw->desc[1] != ad->paddr) {				/* AOI1 is not the first in the chain */			if (pmfbi->count > 0)					/* AOI0 is open, must be the first */				pmfbi->ad->next_ad = 0;		} else			/* AOI1 is the first in the chain */			out_be32(&hw->desc[1], machine_data->dummy_ad->paddr);					/* close AOI 1 */		break;	case 4:					/* plane 2 AOI 1 */		pmfbi = machine_data->fsl_diu_info[3]->par;		if (hw->desc[2] != ad->paddr) {				/* AOI1 is not the first in the chain */			if (pmfbi->count > 0)				/* AOI0 is open, must be the first */				pmfbi->ad->next_ad = 0;		} else		/* AOI1 is the first in the chain */			out_be32(&hw->desc[2], machine_data->dummy_ad->paddr);				/* close AOI 1 */		break;	default:		res = -EINVAL;		break;	}	return res;}static void enable_lcdc(struct fb_info *info){	struct diu *hw = dr.diu_reg;	struct mfb_info *mfbi = info->par;	struct fsl_diu_data *machine_data = mfbi->parent;	if (!machine_data->fb_enabled) {		out_be32(&hw->diu_mode, dr.mode);		machine_data->fb_enabled++;	}}static void disable_lcdc(struct fb_info *info){	struct diu *hw = dr.diu_reg;	struct mfb_info *mfbi = info->par;	struct fsl_diu_data *machine_data = mfbi->parent;	if (machine_data->fb_enabled) {		out_be32(&hw->diu_mode, 0);		machine_data->fb_enabled = 0;	}}static void adjust_aoi_size_position(struct fb_var_screeninfo *var,				struct fb_info *info){	struct mfb_info *lower_aoi_mfbi, *upper_aoi_mfbi, *mfbi = info->par;	struct fsl_diu_data *machine_data = mfbi->parent;	int available_height, upper_aoi_bottom, index = mfbi->index;	int lower_aoi_is_open, upper_aoi_is_open;	__u32 base_plane_width, base_plane_height, upper_aoi_height;	base_plane_width = machine_data->fsl_diu_info[0]->var.xres;	base_plane_height = machine_data->fsl_diu_info[0]->var.yres;	if (mfbi->x_aoi_d < 0)		mfbi->x_aoi_d = 0;	if (mfbi->y_aoi_d < 0)		mfbi->y_aoi_d = 0;	switch (index) {	case 0:		if (mfbi->x_aoi_d != 0)			mfbi->x_aoi_d = 0;		if (mfbi->y_aoi_d != 0)			mfbi->y_aoi_d = 0;		break;	case 1:			/* AOI 0 */	case 3:		lower_aoi_mfbi = machine_data->fsl_diu_info[index+1]->par;		lower_aoi_is_open = lower_aoi_mfbi->count > 0 ? 1 : 0;		if (var->xres > base_plane_width)			var->xres = base_plane_width;		if ((mfbi->x_aoi_d + var->xres) > base_plane_width)			mfbi->x_aoi_d = base_plane_width - var->xres;		if (lower_aoi_is_open)			available_height = lower_aoi_mfbi->y_aoi_d;		else			available_height = base_plane_height;		if (var->yres > available_height)			var->yres = available_height;		if ((mfbi->y_aoi_d + var->yres) > available_height)			mfbi->y_aoi_d = available_height - var->yres;		break;	case 2:			/* AOI 1 */	case 4:		upper_aoi_mfbi = machine_data->fsl_diu_info[index-1]->par;		upper_aoi_height =				machine_data->fsl_diu_info[index-1]->var.yres;		upper_aoi_bottom = upper_aoi_mfbi->y_aoi_d + upper_aoi_height;		upper_aoi_is_open = upper_aoi_mfbi->count > 0 ? 1 : 0;		if (var->xres > base_plane_width)			var->xres = base_plane_width;		if ((mfbi->x_aoi_d + var->xres) > base_plane_width)			mfbi->x_aoi_d = base_plane_width - var->xres;		if (mfbi->y_aoi_d < 0)			mfbi->y_aoi_d = 0;		if (upper_aoi_is_open) {			if (mfbi->y_aoi_d < upper_aoi_bottom)				mfbi->y_aoi_d = upper_aoi_bottom;			available_height = base_plane_height						- upper_aoi_bottom;		} else			available_height = base_plane_height;		if (var->yres > available_height)			var->yres = available_height;		if ((mfbi->y_aoi_d + var->yres) > base_plane_height)			mfbi->y_aoi_d = base_plane_height - var->yres;		break;	}}/* * Checks to see if the hardware supports the state requested by var passed * in. This function does not alter the hardware state! If the var passed in * is slightly off by what the hardware can support then we alter the var * PASSED in to what we can do. If the hardware doesn't support mode change * a -EINVAL will be returned by the upper layers. */static int fsl_diu_check_var(struct fb_var_screeninfo *var,				struct fb_info *info){	unsigned long htotal, vtotal;	pr_debug("check_var xres: %d\n", var->xres);	pr_debug("check_var yres: %d\n", var->yres);	if (var->xres_virtual < var->xres)		var->xres_virtual = var->xres;	if (var->yres_virtual < var->yres)		var->yres_virtual = var->yres;	if (var->xoffset < 0)		var->xoffset = 0;	if (var->yoffset < 0)		var->yoffset = 0;	if (var->xoffset + info->var.xres > info->var.xres_virtual)		var->xoffset = info->var.xres_virtual - info->var.xres;	if (var->yoffset + info->var.yres > info->var.yres_virtual)		var->yoffset = info->var.yres_virtual - info->var.yres;	if ((var->bits_per_pixel != 32) && (var->bits_per_pixel != 24) &&	    (var->bits_per_pixel != 16))		var->bits_per_pixel = default_bpp;	switch (var->bits_per_pixel) {	case 16:		var->red.length = 5;		var->red.offset = 11;		var->red.msb_right = 0;

⌨️ 快捷键说明

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