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

📄 s3c2410fb.c

📁 Linux环境下视频显示卡设备的驱动程序源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	local_irq_restore(flags);}/* *      s3c2410fb_blank *	@blank_mode: the blank mode we want. *	@info: frame buffer structure that represents a single frame buffer * *	Blank the screen if blank_mode != 0, else unblank. Return 0 if *	blanking succeeded, != 0 if un-/blanking failed due to e.g. a *	video mode which doesn't support it. Implements VESA suspend *	and powerdown modes on hardware that supports disabling hsync/vsync: * *	Returns negative errno on error, or zero on success. * */static int s3c2410fb_blank(int blank_mode, struct fb_info *info){	struct s3c2410fb_info *fbi = info->par;	void __iomem *tpal_reg = fbi->io;	dprintk("blank(mode=%d, info=%p)\n", blank_mode, info);	tpal_reg += is_s3c2412(fbi) ? S3C2412_TPAL : S3C2410_TPAL;	if (blank_mode == FB_BLANK_POWERDOWN) {		s3c2410fb_lcd_enable(fbi, 0);	} else {		s3c2410fb_lcd_enable(fbi, 1);	}	if (blank_mode == FB_BLANK_UNBLANK)		writel(0x0, tpal_reg);	else {		dprintk("setting TPAL to output 0x000000\n");		writel(S3C2410_TPAL_EN, tpal_reg);	}	return 0;}static int s3c2410fb_debug_show(struct device *dev,				struct device_attribute *attr, char *buf){	return snprintf(buf, PAGE_SIZE, "%s\n", debug ? "on" : "off");}static int s3c2410fb_debug_store(struct device *dev,				 struct device_attribute *attr,				 const char *buf, size_t len){	if (len < 1)		return -EINVAL;	if (strnicmp(buf, "on", 2) == 0 ||	    strnicmp(buf, "1", 1) == 0) {		debug = 1;		printk(KERN_DEBUG "s3c2410fb: Debug On");	} else if (strnicmp(buf, "off", 3) == 0 ||		   strnicmp(buf, "0", 1) == 0) {		debug = 0;		printk(KERN_DEBUG "s3c2410fb: Debug Off");	} else {		return -EINVAL;	}	return len;}static DEVICE_ATTR(debug, 0666, s3c2410fb_debug_show, s3c2410fb_debug_store);static struct fb_ops s3c2410fb_ops = {	.owner		= THIS_MODULE,	.fb_check_var	= s3c2410fb_check_var,	.fb_set_par	= s3c2410fb_set_par,	.fb_blank	= s3c2410fb_blank,	.fb_setcolreg	= s3c2410fb_setcolreg,	.fb_fillrect	= cfb_fillrect,	.fb_copyarea	= cfb_copyarea,	.fb_imageblit	= cfb_imageblit,};/* * s3c2410fb_map_video_memory(): *	Allocates the DRAM memory for the frame buffer.  This buffer is *	remapped into a non-cached, non-buffered, memory region to *	allow palette and pixel writes to occur without flushing the *	cache.  Once this area is remapped, all virtual memory *	access to the video memory should occur at the new region. */static int __init s3c2410fb_map_video_memory(struct fb_info *info){	struct s3c2410fb_info *fbi = info->par;	dma_addr_t map_dma;	unsigned map_size = PAGE_ALIGN(info->fix.smem_len);	dprintk("map_video_memory(fbi=%p) map_size %u\n", fbi, map_size);	info->screen_base = dma_alloc_writecombine(fbi->dev, map_size,						   &map_dma, GFP_KERNEL);	if (info->screen_base) {		/* prevent initial garbage on screen */		dprintk("map_video_memory: clear %p:%08x\n",			info->screen_base, map_size);		memset(info->screen_base, 0x00, map_size);		info->fix.smem_start = map_dma;		dprintk("map_video_memory: dma=%08lx cpu=%p size=%08x\n",			info->fix.smem_start, info->screen_base, map_size);	}	return info->screen_base ? 0 : -ENOMEM;}static inline void s3c2410fb_unmap_video_memory(struct fb_info *info){	struct s3c2410fb_info *fbi = info->par;	dma_free_writecombine(fbi->dev, PAGE_ALIGN(info->fix.smem_len),			      info->screen_base, info->fix.smem_start);}static inline void modify_gpio(void __iomem *reg,			       unsigned long set, unsigned long mask){	unsigned long tmp;	tmp = readl(reg) & ~mask;	writel(tmp | set, reg);}/* * s3c2410fb_init_registers - Initialise all LCD-related registers */static int s3c2410fb_init_registers(struct fb_info *info){	struct s3c2410fb_info *fbi = info->par;	struct s3c2410fb_mach_info *mach_info = fbi->dev->platform_data;	unsigned long flags;	void __iomem *regs = fbi->io;	void __iomem *tpal;	void __iomem *lpcsel;	if (is_s3c2412(fbi)) {		tpal = regs + S3C2412_TPAL;		lpcsel = regs + S3C2412_TCONSEL;	} else {		tpal = regs + S3C2410_TPAL;		lpcsel = regs + S3C2410_LPCSEL;	}	/* Initialise LCD with values from haret */	local_irq_save(flags);	/* modify the gpio(s) with interrupts set (bjd) */	modify_gpio(S3C2410_GPCUP,  mach_info->gpcup,  mach_info->gpcup_mask);	modify_gpio(S3C2410_GPCCON, mach_info->gpccon, mach_info->gpccon_mask);	modify_gpio(S3C2410_GPDUP,  mach_info->gpdup,  mach_info->gpdup_mask);	modify_gpio(S3C2410_GPDCON, mach_info->gpdcon, mach_info->gpdcon_mask);	local_irq_restore(flags);	dprintk("LPCSEL    = 0x%08lx\n", mach_info->lpcsel);	writel(mach_info->lpcsel, lpcsel);	dprintk("replacing TPAL %08x\n", readl(tpal));	/* ensure temporary palette disabled */	writel(0x00, tpal);	return 0;}static void s3c2410fb_write_palette(struct s3c2410fb_info *fbi){	unsigned int i;	void __iomem *regs = fbi->io;	fbi->palette_ready = 0;	for (i = 0; i < 256; i++) {		unsigned long ent = fbi->palette_buffer[i];		if (ent == PALETTE_BUFF_CLEAR)			continue;		writel(ent, regs + S3C2410_TFTPAL(i));		/* it seems the only way to know exactly		 * if the palette wrote ok, is to check		 * to see if the value verifies ok		 */		if (readw(regs + S3C2410_TFTPAL(i)) == ent)			fbi->palette_buffer[i] = PALETTE_BUFF_CLEAR;		else			fbi->palette_ready = 1;   /* retry */	}}static irqreturn_t s3c2410fb_irq(int irq, void *dev_id){	struct s3c2410fb_info *fbi = dev_id;	void __iomem *irq_base = fbi->irq_base;	unsigned long lcdirq = readl(irq_base + S3C24XX_LCDINTPND);	if (lcdirq & S3C2410_LCDINT_FRSYNC) {		if (fbi->palette_ready)			s3c2410fb_write_palette(fbi);		writel(S3C2410_LCDINT_FRSYNC, irq_base + S3C24XX_LCDINTPND);		writel(S3C2410_LCDINT_FRSYNC, irq_base + S3C24XX_LCDSRCPND);	}	return IRQ_HANDLED;}static char driver_name[] = "s3c2410fb";static int __init s3c24xxfb_probe(struct platform_device *pdev,				  enum s3c_drv_type drv_type){	struct s3c2410fb_info *info;	struct s3c2410fb_display *display;	struct fb_info *fbinfo;	struct s3c2410fb_mach_info *mach_info;	struct resource *res;	int ret;	int irq;	int i;	int size;	u32 lcdcon1;	mach_info = pdev->dev.platform_data;	if (mach_info == NULL) {		dev_err(&pdev->dev,			"no platform data for lcd, cannot attach\n");		return -EINVAL;	}	if (mach_info->default_display >= mach_info->num_displays) {		dev_err(&pdev->dev, "default is %d but only %d displays\n",			mach_info->default_display, mach_info->num_displays);		return -EINVAL;	}	display = mach_info->displays + mach_info->default_display;	irq = platform_get_irq(pdev, 0);	if (irq < 0) {		dev_err(&pdev->dev, "no irq for device\n");		return -ENOENT;	}	fbinfo = framebuffer_alloc(sizeof(struct s3c2410fb_info), &pdev->dev);	if (!fbinfo)		return -ENOMEM;	platform_set_drvdata(pdev, fbinfo);	info = fbinfo->par;	info->dev = &pdev->dev;	info->drv_type = drv_type;	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);	if (res == NULL) {		dev_err(&pdev->dev, "failed to get memory registers\n");		ret = -ENXIO;		goto dealloc_fb;	}	size = (res->end - res->start) + 1;	info->mem = request_mem_region(res->start, size, pdev->name);	if (info->mem == NULL) {		dev_err(&pdev->dev, "failed to get memory region\n");		ret = -ENOENT;		goto dealloc_fb;	}	info->io = ioremap(res->start, size);	if (info->io == NULL) {		dev_err(&pdev->dev, "ioremap() of registers failed\n");		ret = -ENXIO;		goto release_mem;	}	info->irq_base = info->io + ((drv_type == DRV_S3C2412) ? S3C2412_LCDINTBASE : S3C2410_LCDINTBASE);	dprintk("devinit\n");	strcpy(fbinfo->fix.id, driver_name);	/* Stop the video */	lcdcon1 = readl(info->io + S3C2410_LCDCON1);	writel(lcdcon1 & ~S3C2410_LCDCON1_ENVID, info->io + S3C2410_LCDCON1);	fbinfo->fix.type	    = FB_TYPE_PACKED_PIXELS;	fbinfo->fix.type_aux	    = 0;	fbinfo->fix.xpanstep	    = 0;	fbinfo->fix.ypanstep	    = 0;	fbinfo->fix.ywrapstep	    = 0;	fbinfo->fix.accel	    = FB_ACCEL_NONE;	fbinfo->var.nonstd	    = 0;	fbinfo->var.activate	    = FB_ACTIVATE_NOW;	fbinfo->var.accel_flags     = 0;	fbinfo->var.vmode	    = FB_VMODE_NONINTERLACED;	fbinfo->fbops		    = &s3c2410fb_ops;	fbinfo->flags		    = FBINFO_FLAG_DEFAULT;	fbinfo->pseudo_palette      = &info->pseudo_pal;	for (i = 0; i < 256; i++)		info->palette_buffer[i] = PALETTE_BUFF_CLEAR;	ret = request_irq(irq, s3c2410fb_irq, IRQF_DISABLED, pdev->name, info);	if (ret) {		dev_err(&pdev->dev, "cannot get irq %d - err %d\n", irq, ret);		ret = -EBUSY;		goto release_regs;	}	info->clk = clk_get(NULL, "lcd");	if (!info->clk || IS_ERR(info->clk)) {		printk(KERN_ERR "failed to get lcd clock source\n");		ret = -ENOENT;		goto release_irq;	}	clk_enable(info->clk);	dprintk("got and enabled clock\n");	msleep(1);	/* find maximum required memory size for display */	for (i = 0; i < mach_info->num_displays; i++) {		unsigned long smem_len = mach_info->displays[i].xres;		smem_len *= mach_info->displays[i].yres;		smem_len *= mach_info->displays[i].bpp;		smem_len >>= 3;		if (fbinfo->fix.smem_len < smem_len)			fbinfo->fix.smem_len = smem_len;	}	/* Initialize video memory */	ret = s3c2410fb_map_video_memory(fbinfo);	if (ret) {		printk(KERN_ERR "Failed to allocate video RAM: %d\n", ret);		ret = -ENOMEM;		goto release_clock;	}	dprintk("got video memory\n");	fbinfo->var.xres = display->xres;	fbinfo->var.yres = display->yres;	fbinfo->var.bits_per_pixel = display->bpp;	s3c2410fb_init_registers(fbinfo);	s3c2410fb_check_var(&fbinfo->var, fbinfo);	ret = register_framebuffer(fbinfo);	if (ret < 0) {		printk(KERN_ERR "Failed to register framebuffer device: %d\n",			ret);		goto free_video_memory;	}	/* create device files */	ret = device_create_file(&pdev->dev, &dev_attr_debug);	if (ret) {		printk(KERN_ERR "failed to add debug attribute\n");	}	printk(KERN_INFO "fb%d: %s frame buffer device\n",		fbinfo->node, fbinfo->fix.id);	return 0;free_video_memory:	s3c2410fb_unmap_video_memory(fbinfo);release_clock:	clk_disable(info->clk);	clk_put(info->clk);release_irq:	free_irq(irq, info);release_regs:	iounmap(info->io);release_mem:	release_resource(info->mem);	kfree(info->mem);dealloc_fb:	platform_set_drvdata(pdev, NULL);	framebuffer_release(fbinfo);	return ret;}static int __init s3c2410fb_probe(struct platform_device *pdev){	return s3c24xxfb_probe(pdev, DRV_S3C2410);}static int __init s3c2412fb_probe(struct platform_device *pdev){	return s3c24xxfb_probe(pdev, DRV_S3C2412);}/* *  Cleanup */static int s3c2410fb_remove(struct platform_device *pdev){	struct fb_info *fbinfo = platform_get_drvdata(pdev);	struct s3c2410fb_info *info = fbinfo->par;	int irq;	unregister_framebuffer(fbinfo);	s3c2410fb_lcd_enable(info, 0);	msleep(1);	s3c2410fb_unmap_video_memory(fbinfo);	if (info->clk) {		clk_disable(info->clk);		clk_put(info->clk);		info->clk = NULL;	}	irq = platform_get_irq(pdev, 0);	free_irq(irq, info);	iounmap(info->io);	release_resource(info->mem);	kfree(info->mem);	platform_set_drvdata(pdev, NULL);	framebuffer_release(fbinfo);	return 0;}#ifdef CONFIG_PM/* suspend and resume support for the lcd controller */static int s3c2410fb_suspend(struct platform_device *dev, pm_message_t state){	struct fb_info	   *fbinfo = platform_get_drvdata(dev);	struct s3c2410fb_info *info = fbinfo->par;	s3c2410fb_lcd_enable(info, 0);	/* sleep before disabling the clock, we need to ensure	 * the LCD DMA engine is not going to get back on the bus	 * before the clock goes off again (bjd) */	msleep(1);	clk_disable(info->clk);	return 0;}static int s3c2410fb_resume(struct platform_device *dev){	struct fb_info	   *fbinfo = platform_get_drvdata(dev);	struct s3c2410fb_info *info = fbinfo->par;	clk_enable(info->clk);	msleep(1);	s3c2410fb_init_registers(fbinfo);	return 0;}#else#define s3c2410fb_suspend NULL#define s3c2410fb_resume  NULL#endifstatic struct platform_driver s3c2410fb_driver = {	.probe		= s3c2410fb_probe,	.remove		= s3c2410fb_remove,	.suspend	= s3c2410fb_suspend,	.resume		= s3c2410fb_resume,	.driver		= {		.name	= "s3c2410-lcd",		.owner	= THIS_MODULE,	},};static struct platform_driver s3c2412fb_driver = {	.probe		= s3c2412fb_probe,	.remove		= s3c2410fb_remove,	.suspend	= s3c2410fb_suspend,	.resume		= s3c2410fb_resume,	.driver		= {		.name	= "s3c2412-lcd",		.owner	= THIS_MODULE,	},};int __init s3c2410fb_init(void){	int ret = platform_driver_register(&s3c2410fb_driver);	if (ret == 0)		ret = platform_driver_register(&s3c2412fb_driver);;	return ret;}static void __exit s3c2410fb_cleanup(void){	platform_driver_unregister(&s3c2410fb_driver);	platform_driver_unregister(&s3c2412fb_driver);}module_init(s3c2410fb_init);module_exit(s3c2410fb_cleanup);MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>, "	      "Ben Dooks <ben-linux@fluff.org>");MODULE_DESCRIPTION("Framebuffer driver for the s3c2410");MODULE_LICENSE("GPL");MODULE_ALIAS("platform:s3c2410-lcd");MODULE_ALIAS("platform:s3c2412-lcd");

⌨️ 快捷键说明

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