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

📄 sh_mobile_lcdcfb.c

📁 Linux环境下视频显示卡设备的驱动程序源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
}static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv){	struct sh_mobile_lcdc_chan *ch;	struct sh_mobile_lcdc_board_cfg	*board_cfg;	int k;	/* tell the board code to disable the panel */	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {		ch = &priv->ch[k];		board_cfg = &ch->cfg.board_cfg;		if (board_cfg->display_off)			board_cfg->display_off(board_cfg->board_data);		/* cleanup deferred io if enabled */		if (ch->info.fbdefio) {			fb_deferred_io_cleanup(&ch->info);			ch->info.fbdefio = NULL;		}	}	/* stop the lcdc */	sh_mobile_lcdc_start_stop(priv, 0);	/* stop clocks */	for (k = 0; k < ARRAY_SIZE(priv->ch); k++)		if (priv->ch[k].enabled)			sh_mobile_lcdc_clk_off(priv);}static int sh_mobile_lcdc_check_interface(struct sh_mobile_lcdc_chan *ch){	int ifm, miftyp;	switch (ch->cfg.interface_type) {	case RGB8: ifm = 0; miftyp = 0; break;	case RGB9: ifm = 0; miftyp = 4; break;	case RGB12A: ifm = 0; miftyp = 5; break;	case RGB12B: ifm = 0; miftyp = 6; break;	case RGB16: ifm = 0; miftyp = 7; break;	case RGB18: ifm = 0; miftyp = 10; break;	case RGB24: ifm = 0; miftyp = 11; break;	case SYS8A: ifm = 1; miftyp = 0; break;	case SYS8B: ifm = 1; miftyp = 1; break;	case SYS8C: ifm = 1; miftyp = 2; break;	case SYS8D: ifm = 1; miftyp = 3; break;	case SYS9: ifm = 1; miftyp = 4; break;	case SYS12: ifm = 1; miftyp = 5; break;	case SYS16A: ifm = 1; miftyp = 7; break;	case SYS16B: ifm = 1; miftyp = 8; break;	case SYS16C: ifm = 1; miftyp = 9; break;	case SYS18: ifm = 1; miftyp = 10; break;	case SYS24: ifm = 1; miftyp = 11; break;	default: goto bad;	}	/* SUBLCD only supports SYS interface */	if (lcdc_chan_is_sublcd(ch)) {		if (ifm == 0)			goto bad;		else			ifm = 0;	}	ch->ldmt1r_value = (ifm << 12) | miftyp;	return 0; bad:	return -EINVAL;}static int sh_mobile_lcdc_setup_clocks(struct platform_device *pdev,				       int clock_source,				       struct sh_mobile_lcdc_priv *priv){#ifdef CONFIG_HAVE_CLK	char clk_name[8];#endif	char *str;	int icksel;	switch (clock_source) {	case LCDC_CLK_BUS: str = "bus_clk"; icksel = 0; break;	case LCDC_CLK_PERIPHERAL: str = "peripheral_clk"; icksel = 1; break;	case LCDC_CLK_EXTERNAL: str = NULL; icksel = 2; break;	default:		return -EINVAL;	}	priv->lddckr = icksel << 16;#ifdef CONFIG_HAVE_CLK	atomic_set(&priv->clk_usecnt, -1);	snprintf(clk_name, sizeof(clk_name), "lcdc%d", pdev->id);	priv->clk = clk_get(&pdev->dev, clk_name);	if (IS_ERR(priv->clk)) {		dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);		return PTR_ERR(priv->clk);	}		if (str) {		priv->dot_clk = clk_get(&pdev->dev, str);		if (IS_ERR(priv->dot_clk)) {			dev_err(&pdev->dev, "cannot get dot clock %s\n", str);			clk_put(priv->clk);			return PTR_ERR(priv->dot_clk);		}	}#endif	return 0;}static int sh_mobile_lcdc_setcolreg(u_int regno,				    u_int red, u_int green, u_int blue,				    u_int transp, struct fb_info *info){	u32 *palette = info->pseudo_palette;	if (regno >= PALETTE_NR)		return -EINVAL;	/* only FB_VISUAL_TRUECOLOR supported */	red >>= 16 - info->var.red.length;	green >>= 16 - info->var.green.length;	blue >>= 16 - info->var.blue.length;	transp >>= 16 - info->var.transp.length;	palette[regno] = (red << info->var.red.offset) |	  (green << info->var.green.offset) |	  (blue << info->var.blue.offset) |	  (transp << info->var.transp.offset);	return 0;}static struct fb_fix_screeninfo sh_mobile_lcdc_fix  = {	.id =		"SH Mobile LCDC",	.type =		FB_TYPE_PACKED_PIXELS,	.visual =	FB_VISUAL_TRUECOLOR,	.accel =	FB_ACCEL_NONE,};static void sh_mobile_lcdc_fillrect(struct fb_info *info,				    const struct fb_fillrect *rect){	sys_fillrect(info, rect);	sh_mobile_lcdc_deferred_io_touch(info);}static void sh_mobile_lcdc_copyarea(struct fb_info *info,				    const struct fb_copyarea *area){	sys_copyarea(info, area);	sh_mobile_lcdc_deferred_io_touch(info);}static void sh_mobile_lcdc_imageblit(struct fb_info *info,				     const struct fb_image *image){	sys_imageblit(info, image);	sh_mobile_lcdc_deferred_io_touch(info);}static struct fb_ops sh_mobile_lcdc_ops = {	.fb_setcolreg	= sh_mobile_lcdc_setcolreg,	.fb_read        = fb_sys_read,	.fb_write       = fb_sys_write,	.fb_fillrect	= sh_mobile_lcdc_fillrect,	.fb_copyarea	= sh_mobile_lcdc_copyarea,	.fb_imageblit	= sh_mobile_lcdc_imageblit,};static int sh_mobile_lcdc_set_bpp(struct fb_var_screeninfo *var, int bpp){	switch (bpp) {	case 16: /* PKF[4:0] = 00011 - RGB 565 */		var->red.offset = 11;		var->red.length = 5;		var->green.offset = 5;		var->green.length = 6;		var->blue.offset = 0;		var->blue.length = 5;		var->transp.offset = 0;		var->transp.length = 0;		break;	case 32: /* PKF[4:0] = 00000 - RGB 888		  * sh7722 pdf says 00RRGGBB but reality is GGBB00RR		  * this may be because LDDDSR has word swap enabled..		  */		var->red.offset = 0;		var->red.length = 8;		var->green.offset = 24;		var->green.length = 8;		var->blue.offset = 16;		var->blue.length = 8;		var->transp.offset = 0;		var->transp.length = 0;		break;	default:		return -EINVAL;	}	var->bits_per_pixel = bpp;	var->red.msb_right = 0;	var->green.msb_right = 0;	var->blue.msb_right = 0;	var->transp.msb_right = 0;	return 0;}static int sh_mobile_lcdc_remove(struct platform_device *pdev);static int __init sh_mobile_lcdc_probe(struct platform_device *pdev){	struct fb_info *info;	struct sh_mobile_lcdc_priv *priv;	struct sh_mobile_lcdc_info *pdata;	struct sh_mobile_lcdc_chan_cfg *cfg;	struct resource *res;	int error;	void *buf;	int i, j;	if (!pdev->dev.platform_data) {		dev_err(&pdev->dev, "no platform data defined\n");		error = -EINVAL;		goto err0;	}	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);	i = platform_get_irq(pdev, 0);	if (!res || i < 0) {		dev_err(&pdev->dev, "cannot get platform resources\n");		error = -ENOENT;		goto err0;	}	priv = kzalloc(sizeof(*priv), GFP_KERNEL);	if (!priv) {		dev_err(&pdev->dev, "cannot allocate device data\n");		error = -ENOMEM;		goto err0;	}	error = request_irq(i, sh_mobile_lcdc_irq, IRQF_DISABLED,			    pdev->dev.bus_id, priv);	if (error) {		dev_err(&pdev->dev, "unable to request irq\n");		goto err1;	}	priv->irq = i;	platform_set_drvdata(pdev, priv);	pdata = pdev->dev.platform_data;	j = 0;	for (i = 0; i < ARRAY_SIZE(pdata->ch); i++) {		priv->ch[j].lcdc = priv;		memcpy(&priv->ch[j].cfg, &pdata->ch[i], sizeof(pdata->ch[i]));		error = sh_mobile_lcdc_check_interface(&priv->ch[i]);		if (error) {			dev_err(&pdev->dev, "unsupported interface type\n");			goto err1;		}		switch (pdata->ch[i].chan) {		case LCDC_CHAN_MAINLCD:			priv->ch[j].enabled = 1 << 1;			priv->ch[j].reg_offs = lcdc_offs_mainlcd;			j++;			break;		case LCDC_CHAN_SUBLCD:			priv->ch[j].enabled = 1 << 2;			priv->ch[j].reg_offs = lcdc_offs_sublcd;			j++;			break;		}	}	if (!j) {		dev_err(&pdev->dev, "no channels defined\n");		error = -EINVAL;		goto err1;	}	error = sh_mobile_lcdc_setup_clocks(pdev, pdata->clock_source, priv);	if (error) {		dev_err(&pdev->dev, "unable to setup clocks\n");		goto err1;	}	priv->base = ioremap_nocache(res->start, (res->end - res->start) + 1);	for (i = 0; i < j; i++) {		info = &priv->ch[i].info;		cfg = &priv->ch[i].cfg;		info->fbops = &sh_mobile_lcdc_ops;		info->var.xres = info->var.xres_virtual = cfg->lcd_cfg.xres;		info->var.yres = info->var.yres_virtual = cfg->lcd_cfg.yres;		info->var.width = cfg->lcd_size_cfg.width;		info->var.height = cfg->lcd_size_cfg.height;		info->var.activate = FB_ACTIVATE_NOW;		error = sh_mobile_lcdc_set_bpp(&info->var, cfg->bpp);		if (error)			break;		info->fix = sh_mobile_lcdc_fix;		info->fix.line_length = cfg->lcd_cfg.xres * (cfg->bpp / 8);		info->fix.smem_len = info->fix.line_length * cfg->lcd_cfg.yres;		buf = dma_alloc_coherent(&pdev->dev, info->fix.smem_len,					 &priv->ch[i].dma_handle, GFP_KERNEL);		if (!buf) {			dev_err(&pdev->dev, "unable to allocate buffer\n");			error = -ENOMEM;			break;		}		info->pseudo_palette = &priv->ch[i].pseudo_palette;		info->flags = FBINFO_FLAG_DEFAULT;		error = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0);		if (error < 0) {			dev_err(&pdev->dev, "unable to allocate cmap\n");			dma_free_coherent(&pdev->dev, info->fix.smem_len,					  buf, priv->ch[i].dma_handle);			break;		}		memset(buf, 0, info->fix.smem_len);		info->fix.smem_start = priv->ch[i].dma_handle;		info->screen_base = buf;		info->device = &pdev->dev;		info->par = &priv->ch[i];	}	if (error)		goto err1;	error = sh_mobile_lcdc_start(priv);	if (error) {		dev_err(&pdev->dev, "unable to start hardware\n");		goto err1;	}	for (i = 0; i < j; i++) {		error = register_framebuffer(&priv->ch[i].info);		if (error < 0)			goto err1;	}	for (i = 0; i < j; i++) {		info = &priv->ch[i].info;		dev_info(info->dev,			 "registered %s/%s as %dx%d %dbpp.\n",			 pdev->name,			 (priv->ch[i].cfg.chan == LCDC_CHAN_MAINLCD) ?			 "mainlcd" : "sublcd",			 (int) priv->ch[i].cfg.lcd_cfg.xres,			 (int) priv->ch[i].cfg.lcd_cfg.yres,			 priv->ch[i].cfg.bpp);		/* deferred io mode: disable clock to save power */		if (info->fbdefio)			sh_mobile_lcdc_clk_off(priv);	}	return 0; err1:	sh_mobile_lcdc_remove(pdev); err0:	return error;}static int sh_mobile_lcdc_remove(struct platform_device *pdev){	struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev);	struct fb_info *info;	int i;	for (i = 0; i < ARRAY_SIZE(priv->ch); i++)		if (priv->ch[i].info.dev)			unregister_framebuffer(&priv->ch[i].info);	sh_mobile_lcdc_stop(priv);	for (i = 0; i < ARRAY_SIZE(priv->ch); i++) {		info = &priv->ch[i].info;		if (!info->device)			continue;		dma_free_coherent(&pdev->dev, info->fix.smem_len,				  info->screen_base, priv->ch[i].dma_handle);		fb_dealloc_cmap(&info->cmap);	}#ifdef CONFIG_HAVE_CLK	if (priv->dot_clk)		clk_put(priv->dot_clk);	clk_put(priv->clk);#endif	if (priv->base)		iounmap(priv->base);	if (priv->irq)		free_irq(priv->irq, priv);	kfree(priv);	return 0;}static struct platform_driver sh_mobile_lcdc_driver = {	.driver		= {		.name		= "sh_mobile_lcdc_fb",		.owner		= THIS_MODULE,	},	.probe		= sh_mobile_lcdc_probe,	.remove		= sh_mobile_lcdc_remove,};static int __init sh_mobile_lcdc_init(void){	return platform_driver_register(&sh_mobile_lcdc_driver);}static void __exit sh_mobile_lcdc_exit(void){	platform_driver_unregister(&sh_mobile_lcdc_driver);}module_init(sh_mobile_lcdc_init);module_exit(sh_mobile_lcdc_exit);MODULE_DESCRIPTION("SuperH Mobile LCDC Framebuffer driver");MODULE_AUTHOR("Magnus Damm <damm@opensource.se>");MODULE_LICENSE("GPL v2");

⌨️ 快捷键说明

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