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

📄 fsl-diu-fb.c

📁 Linux环境下视频显示卡设备的驱动程序源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	info->var.activate = FB_ACTIVATE_NOW;	info->fbops = &fsl_diu_ops;	info->flags = FBINFO_FLAG_DEFAULT;	info->pseudo_palette = &mfbi->pseudo_palette;	/* Allocate colormap */	fb_alloc_cmap(&info->cmap, 16, 0);	return 0;}static int __devinit install_fb(struct fb_info *info){	int rc;	struct mfb_info *mfbi = info->par;	const char *aoi_mode, *init_aoi_mode = "320x240";	if (init_fbinfo(info))		return -EINVAL;	if (mfbi->index == 0)	/* plane 0 */		aoi_mode = fb_mode;	else		aoi_mode = init_aoi_mode;	pr_debug("mode used = %s\n", aoi_mode);	rc = fb_find_mode(&info->var, info, aoi_mode, fsl_diu_mode_db,	     ARRAY_SIZE(fsl_diu_mode_db), &fsl_diu_default_mode, default_bpp);	switch (rc) {	case 1:		pr_debug("using mode specified in @mode\n");		break;	case 2:		pr_debug("using mode specified in @mode "			"with ignored refresh rate\n");		break;	case 3:		pr_debug("using mode default mode\n");		break;	case 4:		pr_debug("using mode from list\n");		break;	default:		pr_debug("rc = %d\n", rc);		pr_debug("failed to find mode\n");		return -EINVAL;		break;	}	pr_debug("xres_virtual %d\n", info->var.xres_virtual);	pr_debug("bits_per_pixel %d\n", info->var.bits_per_pixel);	pr_debug("info->var.yres_virtual = %d\n", info->var.yres_virtual);	pr_debug("info->fix.line_length = %d\n", info->fix.line_length);	if (mfbi->type == MFB_TYPE_OFF)		mfbi->blank = FB_BLANK_NORMAL;	else		mfbi->blank = FB_BLANK_UNBLANK;	if (fsl_diu_check_var(&info->var, info)) {		printk(KERN_ERR "fb_check_var failed");		fb_dealloc_cmap(&info->cmap);		return -EINVAL;	}	if (fsl_diu_set_par(info)) {		printk(KERN_ERR "fb_set_par failed");		fb_dealloc_cmap(&info->cmap);		return -EINVAL;	}	if (register_framebuffer(info) < 0) {		printk(KERN_ERR "register_framebuffer failed");		unmap_video_memory(info);		fb_dealloc_cmap(&info->cmap);		return -EINVAL;	}	mfbi->registered = 1;	printk(KERN_INFO "fb%d: %s fb device registered successfully.\n",		 info->node, info->fix.id);	return 0;}static void uninstall_fb(struct fb_info *info){	struct mfb_info *mfbi = info->par;	if (!mfbi->registered)		return;	unregister_framebuffer(info);	unmap_video_memory(info);	if (&info->cmap)		fb_dealloc_cmap(&info->cmap);	mfbi->registered = 0;}static irqreturn_t fsl_diu_isr(int irq, void *dev_id){	struct diu *hw = dr.diu_reg;	unsigned int status = in_be32(&hw->int_status);	if (status) {		/* This is the workaround for underrun */		if (status & INT_UNDRUN) {			out_be32(&hw->diu_mode, 0);			pr_debug("Err: DIU occurs underrun!\n");			udelay(1);			out_be32(&hw->diu_mode, 1);		}#if defined(CONFIG_NOT_COHERENT_CACHE)		else if (status & INT_VSYNC) {			unsigned int i;			for (i = 0; i < coherence_data_size;				i += d_cache_line_size)				__asm__ __volatile__ (					"dcbz 0, %[input]"				::[input]"r"(&coherence_data[i]));		}#endif		return IRQ_HANDLED;	}	return IRQ_NONE;}static int request_irq_local(int irq){	unsigned long status, ints;	struct diu *hw;	int ret;	hw = dr.diu_reg;	/* Read to clear the status */	status = in_be32(&hw->int_status);	ret = request_irq(irq, fsl_diu_isr, 0, "diu", NULL);	if (ret)		pr_info("Request diu IRQ failed.\n");	else {		ints = INT_PARERR | INT_LS_BF_VS;#if !defined(CONFIG_NOT_COHERENT_CACHE)		ints |=	INT_VSYNC;#endif		if (dr.mode == MFB_MODE2 || dr.mode == MFB_MODE3)			ints |= INT_VSYNC_WB;		/* Read to clear the status */		status = in_be32(&hw->int_status);		out_be32(&hw->int_mask, ints);	}	return ret;}static void free_irq_local(int irq){	struct diu *hw = dr.diu_reg;	/* Disable all LCDC interrupt */	out_be32(&hw->int_mask, 0x1f);	free_irq(irq, NULL);}#ifdef CONFIG_PM/* * Power management hooks. Note that we won't be called from IRQ context, * unlike the blank functions above, so we may sleep. */static int fsl_diu_suspend(struct of_device *ofdev, pm_message_t state){	struct fsl_diu_data *machine_data;	machine_data = dev_get_drvdata(&ofdev->dev);	disable_lcdc(machine_data->fsl_diu_info[0]);	return 0;}static int fsl_diu_resume(struct of_device *ofdev){	struct fsl_diu_data *machine_data;	machine_data = dev_get_drvdata(&ofdev->dev);	enable_lcdc(machine_data->fsl_diu_info[0]);	return 0;}#else#define fsl_diu_suspend NULL#define fsl_diu_resume NULL#endif				/* CONFIG_PM *//* Align to 64-bit(8-byte), 32-byte, etc. */static int allocate_buf(struct diu_addr *buf, u32 size, u32 bytes_align){	u32 offset, ssize;	u32 mask;	dma_addr_t paddr = 0;	ssize = size + bytes_align;	buf->vaddr = dma_alloc_coherent(NULL, ssize, &paddr, GFP_DMA |							     __GFP_ZERO);	if (!buf->vaddr)		return -ENOMEM;	buf->paddr = (__u32) paddr;	mask = bytes_align - 1;	offset = (u32)buf->paddr & mask;	if (offset) {		buf->offset = bytes_align - offset;		buf->paddr = (u32)buf->paddr + offset;	} else		buf->offset = 0;	return 0;}static void free_buf(struct diu_addr *buf, u32 size, u32 bytes_align){	dma_free_coherent(NULL, size + bytes_align,				buf->vaddr, (buf->paddr - buf->offset));	return;}static ssize_t store_monitor(struct device *device,	struct device_attribute *attr, const char *buf, size_t count){	int old_monitor_port;	unsigned long val;	struct fsl_diu_data *machine_data =		container_of(attr, struct fsl_diu_data, dev_attr);	if (strict_strtoul(buf, 10, &val))		return 0;	old_monitor_port = machine_data->monitor_port;	machine_data->monitor_port = diu_ops.set_sysfs_monitor_port(val);	if (old_monitor_port != machine_data->monitor_port) {		/* All AOIs need adjust pixel format		 * fsl_diu_set_par only change the pixsel format here		 * unlikely to fail. */		fsl_diu_set_par(machine_data->fsl_diu_info[0]);		fsl_diu_set_par(machine_data->fsl_diu_info[1]);		fsl_diu_set_par(machine_data->fsl_diu_info[2]);		fsl_diu_set_par(machine_data->fsl_diu_info[3]);		fsl_diu_set_par(machine_data->fsl_diu_info[4]);	}	return count;}static ssize_t show_monitor(struct device *device,	struct device_attribute *attr, char *buf){	struct fsl_diu_data *machine_data =		container_of(attr, struct fsl_diu_data, dev_attr);	return diu_ops.show_monitor_port(machine_data->monitor_port, buf);}static int __devinit fsl_diu_probe(struct of_device *ofdev,	const struct of_device_id *match){	struct device_node *np = ofdev->node;	struct mfb_info *mfbi;	phys_addr_t dummy_ad_addr;	int ret, i, error = 0;	struct resource res;	struct fsl_diu_data *machine_data;	machine_data = kzalloc(sizeof(struct fsl_diu_data), GFP_KERNEL);	if (!machine_data)		return -ENOMEM;	for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) {		machine_data->fsl_diu_info[i] =			framebuffer_alloc(sizeof(struct mfb_info), &ofdev->dev);		if (!machine_data->fsl_diu_info[i]) {			dev_err(&ofdev->dev, "cannot allocate memory\n");			ret = -ENOMEM;			goto error2;		}		mfbi = machine_data->fsl_diu_info[i]->par;		memcpy(mfbi, &mfb_template[i], sizeof(struct mfb_info));		mfbi->parent = machine_data;	}	ret = of_address_to_resource(np, 0, &res);	if (ret) {		dev_err(&ofdev->dev, "could not obtain DIU address\n");		goto error;	}	if (!res.start) {		dev_err(&ofdev->dev, "invalid DIU address\n");		goto error;	}	dev_dbg(&ofdev->dev, "%s, res.start: 0x%08x\n", __func__, res.start);	dr.diu_reg = ioremap(res.start, sizeof(struct diu));	if (!dr.diu_reg) {		dev_err(&ofdev->dev, "Err: can't map DIU registers!\n");		ret = -EFAULT;		goto error2;	}	out_be32(&dr.diu_reg->diu_mode, 0);		/* disable DIU anyway*/	/* Get the IRQ of the DIU */	machine_data->irq = irq_of_parse_and_map(np, 0);	if (!machine_data->irq) {		dev_err(&ofdev->dev, "could not get DIU IRQ\n");		ret = -EINVAL;		goto error;	}	machine_data->monitor_port = monitor_port;	/* Area descriptor memory pool aligns to 64-bit boundary */	if (allocate_buf(&pool.ad, sizeof(struct diu_ad) * FSL_AOI_NUM, 8))		return -ENOMEM;	/* Get memory for Gamma Table  - 32-byte aligned memory */	if (allocate_buf(&pool.gamma, 768, 32)) {		ret = -ENOMEM;		goto error;	}	/* For performance, cursor bitmap buffer aligns to 32-byte boundary */	if (allocate_buf(&pool.cursor, MAX_CURS * MAX_CURS * 2, 32)) {		ret = -ENOMEM;		goto error;	}	i = ARRAY_SIZE(machine_data->fsl_diu_info);	machine_data->dummy_ad = (struct diu_ad *)			((u32)pool.ad.vaddr + pool.ad.offset) + i;	machine_data->dummy_ad->paddr = pool.ad.paddr +			i * sizeof(struct diu_ad);	machine_data->dummy_aoi_virt = fsl_diu_alloc(64, &dummy_ad_addr);	if (!machine_data->dummy_aoi_virt) {		ret = -ENOMEM;		goto error;	}	machine_data->dummy_ad->addr = cpu_to_le32(dummy_ad_addr);	machine_data->dummy_ad->pix_fmt = 0x88882317;	machine_data->dummy_ad->src_size_g_alpha = cpu_to_le32((4 << 12) | 4);	machine_data->dummy_ad->aoi_size = cpu_to_le32((4 << 16) |  2);	machine_data->dummy_ad->offset_xyi = 0;	machine_data->dummy_ad->offset_xyd = 0;	machine_data->dummy_ad->next_ad = 0;	out_be32(&dr.diu_reg->desc[0], machine_data->dummy_ad->paddr);	out_be32(&dr.diu_reg->desc[1], machine_data->dummy_ad->paddr);	out_be32(&dr.diu_reg->desc[2], machine_data->dummy_ad->paddr);	for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) {		machine_data->fsl_diu_info[i]->fix.smem_start = 0;		mfbi = machine_data->fsl_diu_info[i]->par;		mfbi->ad = (struct diu_ad *)((u32)pool.ad.vaddr					+ pool.ad.offset) + i;		mfbi->ad->paddr = pool.ad.paddr + i * sizeof(struct diu_ad);		ret = install_fb(machine_data->fsl_diu_info[i]);		if (ret) {			dev_err(&ofdev->dev,				"Failed to register framebuffer %d\n",				i);			goto error;		}	}	if (request_irq_local(machine_data->irq)) {		dev_err(machine_data->fsl_diu_info[0]->dev,			"could not request irq for diu.");		goto error;	}	machine_data->dev_attr.attr.name = "monitor";	machine_data->dev_attr.attr.mode = S_IRUGO|S_IWUSR;	machine_data->dev_attr.show = show_monitor;	machine_data->dev_attr.store = store_monitor;	error = device_create_file(machine_data->fsl_diu_info[0]->dev,				  &machine_data->dev_attr);	if (error) {		dev_err(machine_data->fsl_diu_info[0]->dev,			"could not create sysfs %s file\n",			machine_data->dev_attr.attr.name);	}	dev_set_drvdata(&ofdev->dev, machine_data);	return 0;error:	for (i = ARRAY_SIZE(machine_data->fsl_diu_info);		i > 0; i--)		uninstall_fb(machine_data->fsl_diu_info[i - 1]);	if (pool.ad.vaddr)		free_buf(&pool.ad, sizeof(struct diu_ad) * FSL_AOI_NUM, 8);	if (pool.gamma.vaddr)		free_buf(&pool.gamma, 768, 32);	if (pool.cursor.vaddr)		free_buf(&pool.cursor, MAX_CURS * MAX_CURS * 2, 32);	if (machine_data->dummy_aoi_virt)		fsl_diu_free(machine_data->dummy_aoi_virt, 64);	iounmap(dr.diu_reg);error2:	for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++)		if (machine_data->fsl_diu_info[i])			framebuffer_release(machine_data->fsl_diu_info[i]);	kfree(machine_data);	return ret;}static int fsl_diu_remove(struct of_device *ofdev){	struct fsl_diu_data *machine_data;	int i;	machine_data = dev_get_drvdata(&ofdev->dev);	disable_lcdc(machine_data->fsl_diu_info[0]);	free_irq_local(machine_data->irq);	for (i = ARRAY_SIZE(machine_data->fsl_diu_info); i > 0; i--)		uninstall_fb(machine_data->fsl_diu_info[i - 1]);	if (pool.ad.vaddr)		free_buf(&pool.ad, sizeof(struct diu_ad) * FSL_AOI_NUM, 8);	if (pool.gamma.vaddr)		free_buf(&pool.gamma, 768, 32);	if (pool.cursor.vaddr)		free_buf(&pool.cursor, MAX_CURS * MAX_CURS * 2, 32);	if (machine_data->dummy_aoi_virt)		fsl_diu_free(machine_data->dummy_aoi_virt, 64);	iounmap(dr.diu_reg);	for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++)		if (machine_data->fsl_diu_info[i])			framebuffer_release(machine_data->fsl_diu_info[i]);	kfree(machine_data);	return 0;}#ifndef MODULEstatic int __init fsl_diu_setup(char *options){	char *opt;	unsigned long val;	if (!options || !*options)		return 0;	while ((opt = strsep(&options, ",")) != NULL) {		if (!*opt)			continue;		if (!strncmp(opt, "monitor=", 8)) {			if (!strict_strtoul(opt + 8, 10, &val) && (val <= 2))				monitor_port = val;		} else if (!strncmp(opt, "bpp=", 4)) {			if (!strict_strtoul(opt + 4, 10, &val))				default_bpp = val;		} else			fb_mode = opt;	}	return 0;}#endifstatic struct of_device_id fsl_diu_match[] = {	{		.compatible = "fsl,diu",	},	{}};MODULE_DEVICE_TABLE(of, fsl_diu_match);static struct of_platform_driver fsl_diu_driver = {	.owner  	= THIS_MODULE,	.name   	= "fsl_diu",	.match_table    = fsl_diu_match,	.probe  	= fsl_diu_probe,	.remove 	= fsl_diu_remove,	.suspend	= fsl_diu_suspend,	.resume		= fsl_diu_resume,};static int __init fsl_diu_init(void){#ifdef CONFIG_NOT_COHERENT_CACHE	struct device_node *np;	const u32 *prop;#endif	int ret;#ifndef MODULE	char *option;	/*	 * For kernel boot options (in 'video=xxxfb:<options>' format)	 */	if (fb_get_options("fslfb", &option))		return -ENODEV;	fsl_diu_setup(option);#endif	printk(KERN_INFO "Freescale DIU driver\n");#ifdef CONFIG_NOT_COHERENT_CACHE	np = of_find_node_by_type(NULL, "cpu");	if (!np) {		printk(KERN_ERR "Err: can't find device node 'cpu'\n");		return -ENODEV;	}	prop = of_get_property(np, "d-cache-size", NULL);	if (prop == NULL) {		of_node_put(np);		return -ENODEV;	}	/* Freescale PLRU requires 13/8 times the cache size to do a proper	   displacement flush	 */	coherence_data_size = *prop * 13;	coherence_data_size /= 8;	prop = of_get_property(np, "d-cache-line-size", NULL);	if (prop == NULL) {		of_node_put(np);		return -ENODEV;	}	d_cache_line_size = *prop;	of_node_put(np);	coherence_data = vmalloc(coherence_data_size);	if (!coherence_data)		return -ENOMEM;#endif	ret = of_register_platform_driver(&fsl_diu_driver);	if (ret) {		printk(KERN_ERR			"fsl-diu: failed to register platform driver\n");#if defined(CONFIG_NOT_COHERENT_CACHE)		vfree(coherence_data);#endif		iounmap(dr.diu_reg);	}	return ret;}static void __exit fsl_diu_exit(void){	of_unregister_platform_driver(&fsl_diu_driver);#if defined(CONFIG_NOT_COHERENT_CACHE)	vfree(coherence_data);#endif}module_init(fsl_diu_init);module_exit(fsl_diu_exit);MODULE_AUTHOR("York Sun <yorksun@freescale.com>");MODULE_DESCRIPTION("Freescale DIU framebuffer driver");MODULE_LICENSE("GPL");module_param_named(mode, fb_mode, charp, 0);MODULE_PARM_DESC(mode,	"Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" ");module_param_named(bpp, default_bpp, ulong, 0);MODULE_PARM_DESC(bpp, "Specify bit-per-pixel if not specified mode");module_param_named(monitor, monitor_port, int, 0);MODULE_PARM_DESC(monitor,	"Specify the monitor port (0, 1 or 2) if supported by the platform");

⌨️ 快捷键说明

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