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

📄 lcdc.c

📁 Linux环境下视频显示卡设备的驱动程序源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	omap_set_lcd_dma_single_transfer(lcdc.ext_mode);}/* Used only in internal controller mode */static int omap_lcdc_setcolreg(u_int regno, u16 red, u16 green, u16 blue,			       u16 transp, int update_hw_pal){	u16 *palette;	if (lcdc.color_mode != OMAPFB_COLOR_CLUT_8BPP || regno > 255)		return -EINVAL;	palette = (u16 *)lcdc.palette_virt;	palette[regno] &= ~0x0fff;	palette[regno] |= ((red >> 12) << 8) | ((green >> 12) << 4 ) |			   (blue >> 12);	if (update_hw_pal) {		disable_controller();		omap_stop_lcd_dma();		load_palette();		setup_lcd_dma();		set_load_mode(OMAP_LCDC_LOAD_FRAME);		enable_controller();	}	return 0;}static void calc_ck_div(int is_tft, int pck, int *pck_div){	unsigned long lck;	pck = max(1, pck);	lck = clk_get_rate(lcdc.lcd_ck);	*pck_div = (lck + pck - 1) / pck;	if (is_tft)		*pck_div = max(2, *pck_div);	else		*pck_div = max(3, *pck_div);	if (*pck_div > 255) {		/* FIXME: try to adjust logic clock divider as well */		*pck_div = 255;		dev_warn(lcdc.fbdev->dev, "pixclock %d kHz too low.\n",			 pck / 1000);	}}static void inline setup_regs(void){	u32 l;	struct lcd_panel *panel = lcdc.fbdev->panel;	int is_tft = panel->config & OMAP_LCDC_PANEL_TFT;	unsigned long lck;	int pcd;	l = omap_readl(OMAP_LCDC_CONTROL);	l &= ~OMAP_LCDC_CTRL_LCD_TFT;	l |= is_tft ? OMAP_LCDC_CTRL_LCD_TFT : 0;#ifdef CONFIG_MACH_OMAP_PALMTE/* FIXME:if (machine_is_omap_palmte()) { */		/* PalmTE uses alternate TFT setting in 8BPP mode */		l |= (is_tft && panel->bpp == 8) ? 0x810000 : 0;/*	} */#endif	omap_writel(l, OMAP_LCDC_CONTROL);	l = omap_readl(OMAP_LCDC_TIMING2);	l &= ~(((1 << 6) - 1) << 20);	l |= (panel->config & OMAP_LCDC_SIGNAL_MASK) << 20;	omap_writel(l, OMAP_LCDC_TIMING2);	l = panel->x_res - 1;	l |= (panel->hsw - 1) << 10;	l |= (panel->hfp - 1) << 16;	l |= (panel->hbp - 1) << 24;	omap_writel(l, OMAP_LCDC_TIMING0);	l = panel->y_res - 1;	l |= (panel->vsw - 1) << 10;	l |= panel->vfp << 16;	l |= panel->vbp << 24;	omap_writel(l, OMAP_LCDC_TIMING1);	l = omap_readl(OMAP_LCDC_TIMING2);	l &= ~0xff;	lck = clk_get_rate(lcdc.lcd_ck);	if (!panel->pcd)		calc_ck_div(is_tft, panel->pixel_clock * 1000, &pcd);	else {		dev_warn(lcdc.fbdev->dev,		    "Pixel clock divider value is obsolete.\n"		    "Try to set pixel_clock to %lu and pcd to 0 "		    "in drivers/video/omap/lcd_%s.c and submit a patch.\n",			lck / panel->pcd / 1000, panel->name);		pcd = panel->pcd;	}	l |= pcd & 0xff;	l |= panel->acb << 8;	omap_writel(l, OMAP_LCDC_TIMING2);	/* update panel info with the exact clock */	panel->pixel_clock = lck / pcd / 1000;}/* * Configure the LCD controller, download the color palette and start a looped * DMA transfer of the frame image data. Called only in internal * controller mode. */static int omap_lcdc_set_update_mode(enum omapfb_update_mode mode){	int r = 0;	if (mode != lcdc.update_mode) {		switch (mode) {		case OMAPFB_AUTO_UPDATE:			setup_regs();			load_palette();			/* Setup and start LCD DMA */			setup_lcd_dma();			set_load_mode(OMAP_LCDC_LOAD_FRAME);			enable_irqs(OMAP_LCDC_IRQ_DONE);			/* This will start the actual DMA transfer */			enable_controller();			lcdc.update_mode = mode;			break;		case OMAPFB_UPDATE_DISABLED:			disable_controller();			omap_stop_lcd_dma();			lcdc.update_mode = mode;			break;		default:			r = -EINVAL;		}	}	return r;}static enum omapfb_update_mode omap_lcdc_get_update_mode(void){	return lcdc.update_mode;}/* PM code called only in internal controller mode */static void omap_lcdc_suspend(void){	if (lcdc.update_mode == OMAPFB_AUTO_UPDATE) {		disable_controller();		omap_stop_lcd_dma();	}}static void omap_lcdc_resume(void){	if (lcdc.update_mode == OMAPFB_AUTO_UPDATE) {		setup_regs();		load_palette();		setup_lcd_dma();		set_load_mode(OMAP_LCDC_LOAD_FRAME);		enable_irqs(OMAP_LCDC_IRQ_DONE);		enable_controller();	}}static void omap_lcdc_get_caps(int plane, struct omapfb_caps *caps){	return;}int omap_lcdc_set_dma_callback(void (*callback)(void *data), void *data){	BUG_ON(callback == NULL);	if (lcdc.dma_callback)		return -EBUSY;	else {		lcdc.dma_callback = callback;		lcdc.dma_callback_data = data;	}	return 0;}EXPORT_SYMBOL(omap_lcdc_set_dma_callback);void omap_lcdc_free_dma_callback(void){	lcdc.dma_callback = NULL;}EXPORT_SYMBOL(omap_lcdc_free_dma_callback);static void lcdc_dma_handler(u16 status, void *data){	if (lcdc.dma_callback)		lcdc.dma_callback(lcdc.dma_callback_data);}static int mmap_kern(void){	struct vm_struct	*kvma;	struct vm_area_struct	vma;	pgprot_t		pgprot;	unsigned long		vaddr;	kvma = get_vm_area(lcdc.vram_size, VM_IOREMAP);	if (kvma == NULL) {		dev_err(lcdc.fbdev->dev, "can't get kernel vm area\n");		return -ENOMEM;	}	vma.vm_mm = &init_mm;	vaddr = (unsigned long)kvma->addr;	vma.vm_start = vaddr;	vma.vm_end = vaddr + lcdc.vram_size;	pgprot = pgprot_writecombine(pgprot_kernel);	if (io_remap_pfn_range(&vma, vaddr,			   lcdc.vram_phys >> PAGE_SHIFT,			   lcdc.vram_size, pgprot) < 0) {		dev_err(lcdc.fbdev->dev, "kernel mmap for FB memory failed\n");		return -EAGAIN;	}	lcdc.vram_virt = (void *)vaddr;	return 0;}static void unmap_kern(void){	vunmap(lcdc.vram_virt);}static int alloc_palette_ram(void){	lcdc.palette_virt = dma_alloc_writecombine(lcdc.fbdev->dev,		MAX_PALETTE_SIZE, &lcdc.palette_phys, GFP_KERNEL);	if (lcdc.palette_virt == NULL) {		dev_err(lcdc.fbdev->dev, "failed to alloc palette memory\n");		return -ENOMEM;	}	memset(lcdc.palette_virt, 0, MAX_PALETTE_SIZE);	return 0;}static void free_palette_ram(void){	dma_free_writecombine(lcdc.fbdev->dev, MAX_PALETTE_SIZE,			lcdc.palette_virt, lcdc.palette_phys);}static int alloc_fbmem(struct omapfb_mem_region *region){	int bpp;	int frame_size;	struct lcd_panel *panel = lcdc.fbdev->panel;	bpp = panel->bpp;	if (bpp == 12)		bpp = 16;	frame_size = PAGE_ALIGN(panel->x_res * bpp / 8 * panel->y_res);	if (region->size > frame_size)		frame_size = region->size;	lcdc.vram_size = frame_size;	lcdc.vram_virt = dma_alloc_writecombine(lcdc.fbdev->dev,			lcdc.vram_size, &lcdc.vram_phys, GFP_KERNEL);	if (lcdc.vram_virt == NULL) {		dev_err(lcdc.fbdev->dev, "unable to allocate FB DMA memory\n");		return -ENOMEM;	}	region->size = frame_size;	region->paddr = lcdc.vram_phys;	region->vaddr = lcdc.vram_virt;	region->alloc = 1;	memset(lcdc.vram_virt, 0, lcdc.vram_size);	return 0;}static void free_fbmem(void){	dma_free_writecombine(lcdc.fbdev->dev, lcdc.vram_size,			      lcdc.vram_virt, lcdc.vram_phys);}static int setup_fbmem(struct omapfb_mem_desc *req_md){	int r;	if (!req_md->region_cnt) {		dev_err(lcdc.fbdev->dev, "no memory regions defined\n");		return -EINVAL;	}	if (req_md->region_cnt > 1) {		dev_err(lcdc.fbdev->dev, "only one plane is supported\n");		req_md->region_cnt = 1;	}	if (req_md->region[0].paddr == 0) {		lcdc.fbmem_allocated = 1;		if ((r = alloc_fbmem(&req_md->region[0])) < 0)			return r;		return 0;	}	lcdc.vram_phys = req_md->region[0].paddr;	lcdc.vram_size = req_md->region[0].size;	if ((r = mmap_kern()) < 0)		return r;	dev_dbg(lcdc.fbdev->dev, "vram at %08x size %08lx mapped to 0x%p\n",		 lcdc.vram_phys, lcdc.vram_size, lcdc.vram_virt);	return 0;}static void cleanup_fbmem(void){	if (lcdc.fbmem_allocated)		free_fbmem();	else		unmap_kern();}static int omap_lcdc_init(struct omapfb_device *fbdev, int ext_mode,			  struct omapfb_mem_desc *req_vram){	int r;	u32 l;	int rate;	struct clk *tc_ck;	lcdc.irq_mask = 0;	lcdc.fbdev = fbdev;	lcdc.ext_mode = ext_mode;	l = 0;	omap_writel(l, OMAP_LCDC_CONTROL);	/* FIXME:	 * According to errata some platforms have a clock rate limitiation	 */	lcdc.lcd_ck = clk_get(fbdev->dev, "lcd_ck");	if (IS_ERR(lcdc.lcd_ck)) {		dev_err(fbdev->dev, "unable to access LCD clock\n");		r = PTR_ERR(lcdc.lcd_ck);		goto fail0;	}	tc_ck = clk_get(fbdev->dev, "tc_ck");	if (IS_ERR(tc_ck)) {		dev_err(fbdev->dev, "unable to access TC clock\n");		r = PTR_ERR(tc_ck);		goto fail1;	}	rate = clk_get_rate(tc_ck);	clk_put(tc_ck);	if (machine_is_ams_delta())		rate /= 4;	if (machine_is_omap_h3())		rate /= 3;	r = clk_set_rate(lcdc.lcd_ck, rate);	if (r) {		dev_err(fbdev->dev, "failed to adjust LCD rate\n");		goto fail1;	}	clk_enable(lcdc.lcd_ck);	r = request_irq(OMAP_LCDC_IRQ, lcdc_irq_handler, 0, MODULE_NAME, fbdev);	if (r) {		dev_err(fbdev->dev, "unable to get IRQ\n");		goto fail2;	}	r = omap_request_lcd_dma(lcdc_dma_handler, NULL);	if (r) {		dev_err(fbdev->dev, "unable to get LCD DMA\n");		goto fail3;	}	omap_set_lcd_dma_single_transfer(ext_mode);	omap_set_lcd_dma_ext_controller(ext_mode);	if (!ext_mode)		if ((r = alloc_palette_ram()) < 0)			goto fail4;	if ((r = setup_fbmem(req_vram)) < 0)		goto fail5;	pr_info("omapfb: LCDC initialized\n");	return 0;fail5:	if (!ext_mode)		free_palette_ram();fail4:	omap_free_lcd_dma();fail3:	free_irq(OMAP_LCDC_IRQ, lcdc.fbdev);fail2:	clk_disable(lcdc.lcd_ck);fail1:	clk_put(lcdc.lcd_ck);fail0:	return r;}static void omap_lcdc_cleanup(void){	if (!lcdc.ext_mode)		free_palette_ram();	cleanup_fbmem();	omap_free_lcd_dma();	free_irq(OMAP_LCDC_IRQ, lcdc.fbdev);	clk_disable(lcdc.lcd_ck);	clk_put(lcdc.lcd_ck);}const struct lcd_ctrl omap1_int_ctrl = {	.name			= "internal",	.init			= omap_lcdc_init,	.cleanup		= omap_lcdc_cleanup,	.get_caps		= omap_lcdc_get_caps,	.set_update_mode	= omap_lcdc_set_update_mode,	.get_update_mode	= omap_lcdc_get_update_mode,	.update_window		= NULL,	.suspend		= omap_lcdc_suspend,	.resume			= omap_lcdc_resume,	.setup_plane		= omap_lcdc_setup_plane,	.enable_plane		= omap_lcdc_enable_plane,	.setcolreg		= omap_lcdc_setcolreg,};

⌨️ 快捷键说明

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