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

📄 dispc.c

📁 Linux环境下视频显示卡设备的驱动程序源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
				int orig_width, int orig_height,				int out_width, int out_height){	const u32 at_reg[]  = { 0, DISPC_VID1_BASE + DISPC_VID_ATTRIBUTES,				DISPC_VID2_BASE + DISPC_VID_ATTRIBUTES };	const u32 vs_reg[]  = { 0, DISPC_VID1_BASE + DISPC_VID_SIZE,				DISPC_VID2_BASE + DISPC_VID_SIZE };	const u32 fir_reg[] = { 0, DISPC_VID1_BASE + DISPC_VID_FIR,				DISPC_VID2_BASE + DISPC_VID_FIR };	u32 l;	int fir_hinc;	int fir_vinc;	if ((unsigned)plane > OMAPFB_PLANE_NUM)		return -ENODEV;	if (plane == OMAPFB_PLANE_GFX &&	    (out_width != orig_width || out_height != orig_height))		return -EINVAL;	enable_lcd_clocks(1);	if (orig_width < out_width) {		/*		 * Upsampling.		 * Currently you can only scale both dimensions in one way.		 */		if (orig_height > out_height ||		    orig_width * 8 < out_width ||		    orig_height * 8 < out_height) {			enable_lcd_clocks(0);			return -EINVAL;		}		set_upsampling_coef_table(plane);	} else if (orig_width > out_width) {		/* Downsampling not yet supported		*/		enable_lcd_clocks(0);		return -EINVAL;	}	if (!orig_width || orig_width == out_width)		fir_hinc = 0;	else		fir_hinc = 1024 * orig_width / out_width;	if (!orig_height || orig_height == out_height)		fir_vinc = 0;	else		fir_vinc = 1024 * orig_height / out_height;	dispc.fir_hinc[plane] = fir_hinc;	dispc.fir_vinc[plane] = fir_vinc;	MOD_REG_FLD(fir_reg[plane],		    FLD_MASK(16, 12) | FLD_MASK(0, 12),		    ((fir_vinc & 4095) << 16) |		    (fir_hinc & 4095));	dev_dbg(dispc.fbdev->dev, "out_width %d out_height %d orig_width %d "		"orig_height %d fir_hinc  %d fir_vinc %d\n",		out_width, out_height, orig_width, orig_height,		fir_hinc, fir_vinc);	MOD_REG_FLD(vs_reg[plane],		    FLD_MASK(16, 11) | FLD_MASK(0, 11),		    ((out_height - 1) << 16) | (out_width - 1));	l = dispc_read_reg(at_reg[plane]);	l &= ~(0x03 << 5);	l |= fir_hinc ? (1 << 5) : 0;	l |= fir_vinc ? (1 << 6) : 0;	dispc_write_reg(at_reg[plane], l);	enable_lcd_clocks(0);	return 0;}static int omap_dispc_enable_plane(int plane, int enable){	const u32 at_reg[] = { DISPC_GFX_ATTRIBUTES,				DISPC_VID1_BASE + DISPC_VID_ATTRIBUTES,				DISPC_VID2_BASE + DISPC_VID_ATTRIBUTES };	if ((unsigned int)plane > dispc.mem_desc.region_cnt)		return -EINVAL;	enable_lcd_clocks(1);	MOD_REG_FLD(at_reg[plane], 1, enable ? 1 : 0);	enable_lcd_clocks(0);	return 0;}static int omap_dispc_set_color_key(struct omapfb_color_key *ck){	u32 df_reg, tr_reg;	int shift, val;	switch (ck->channel_out) {	case OMAPFB_CHANNEL_OUT_LCD:		df_reg = DISPC_DEFAULT_COLOR0;		tr_reg = DISPC_TRANS_COLOR0;		shift = 10;		break;	case OMAPFB_CHANNEL_OUT_DIGIT:		df_reg = DISPC_DEFAULT_COLOR1;		tr_reg = DISPC_TRANS_COLOR1;		shift = 12;		break;	default:		return -EINVAL;	}	switch (ck->key_type) {	case OMAPFB_COLOR_KEY_DISABLED:		val = 0;		break;	case OMAPFB_COLOR_KEY_GFX_DST:		val = 1;		break;	case OMAPFB_COLOR_KEY_VID_SRC:		val = 3;		break;	default:		return -EINVAL;	}	enable_lcd_clocks(1);	MOD_REG_FLD(DISPC_CONFIG, FLD_MASK(shift, 2), val << shift);	if (val != 0)		dispc_write_reg(tr_reg, ck->trans_key);	dispc_write_reg(df_reg, ck->background);	enable_lcd_clocks(0);	dispc.color_key = *ck;	return 0;}static int omap_dispc_get_color_key(struct omapfb_color_key *ck){	*ck = dispc.color_key;	return 0;}static void load_palette(void){}static int omap_dispc_set_update_mode(enum omapfb_update_mode mode){	int r = 0;	if (mode != dispc.update_mode) {		switch (mode) {		case OMAPFB_AUTO_UPDATE:		case OMAPFB_MANUAL_UPDATE:			enable_lcd_clocks(1);			omap_dispc_enable_lcd_out(1);			dispc.update_mode = mode;			break;		case OMAPFB_UPDATE_DISABLED:			init_completion(&dispc.frame_done);			omap_dispc_enable_lcd_out(0);			if (!wait_for_completion_timeout(&dispc.frame_done,					msecs_to_jiffies(500))) {				dev_err(dispc.fbdev->dev,					 "timeout waiting for FRAME DONE\n");			}			dispc.update_mode = mode;			enable_lcd_clocks(0);			break;		default:			r = -EINVAL;		}	}	return r;}static void omap_dispc_get_caps(int plane, struct omapfb_caps *caps){	caps->ctrl |= OMAPFB_CAPS_PLANE_RELOCATE_MEM;	if (plane > 0)		caps->ctrl |= OMAPFB_CAPS_PLANE_SCALE;	caps->plane_color |= (1 << OMAPFB_COLOR_RGB565) |			     (1 << OMAPFB_COLOR_YUV422) |			     (1 << OMAPFB_COLOR_YUY422);	if (plane == 0)		caps->plane_color |= (1 << OMAPFB_COLOR_CLUT_8BPP) |				     (1 << OMAPFB_COLOR_CLUT_4BPP) |				     (1 << OMAPFB_COLOR_CLUT_2BPP) |				     (1 << OMAPFB_COLOR_CLUT_1BPP) |				     (1 << OMAPFB_COLOR_RGB444);}static enum omapfb_update_mode omap_dispc_get_update_mode(void){	return dispc.update_mode;}static void setup_color_conv_coef(void){	u32 mask = FLD_MASK(16, 11) | FLD_MASK(0, 11);	int cf1_reg = DISPC_VID1_BASE + DISPC_VID_CONV_COEF0;	int cf2_reg = DISPC_VID2_BASE + DISPC_VID_CONV_COEF0;	int at1_reg = DISPC_VID1_BASE + DISPC_VID_ATTRIBUTES;	int at2_reg = DISPC_VID2_BASE + DISPC_VID_ATTRIBUTES;	const struct color_conv_coef {		int  ry,  rcr,  rcb,   gy,  gcr,  gcb,   by,  bcr,  bcb;		int  full_range;	}  ctbl_bt601_5 = {		    298,  409,    0,  298, -208, -100,  298,    0,  517, 0,	};	const struct color_conv_coef *ct;#define CVAL(x, y)	(((x & 2047) << 16) | (y & 2047))	ct = &ctbl_bt601_5;	MOD_REG_FLD(cf1_reg,		mask,	CVAL(ct->rcr, ct->ry));	MOD_REG_FLD(cf1_reg + 4,	mask,	CVAL(ct->gy,  ct->rcb));	MOD_REG_FLD(cf1_reg + 8,	mask,	CVAL(ct->gcb, ct->gcr));	MOD_REG_FLD(cf1_reg + 12,	mask,	CVAL(ct->bcr, ct->by));	MOD_REG_FLD(cf1_reg + 16,	mask,	CVAL(0,	      ct->bcb));	MOD_REG_FLD(cf2_reg,		mask,	CVAL(ct->rcr, ct->ry));	MOD_REG_FLD(cf2_reg + 4,	mask,	CVAL(ct->gy,  ct->rcb));	MOD_REG_FLD(cf2_reg + 8,	mask,	CVAL(ct->gcb, ct->gcr));	MOD_REG_FLD(cf2_reg + 12,	mask,	CVAL(ct->bcr, ct->by));	MOD_REG_FLD(cf2_reg + 16,	mask,	CVAL(0,	      ct->bcb));#undef CVAL	MOD_REG_FLD(at1_reg, (1 << 11), ct->full_range);	MOD_REG_FLD(at2_reg, (1 << 11), ct->full_range);}static void calc_ck_div(int is_tft, int pck, int *lck_div, int *pck_div){	unsigned long fck, lck;	*lck_div = 1;	pck = max(1, pck);	fck = clk_get_rate(dispc.dss1_fck);	lck = fck;	*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) {		*pck_div = 255;		lck = pck * *pck_div;		*lck_div = fck / lck;		BUG_ON(*lck_div < 1);		if (*lck_div > 255) {			*lck_div = 255;			dev_warn(dispc.fbdev->dev, "pixclock %d kHz too low.\n",				 pck / 1000);		}	}}static void set_lcd_tft_mode(int enable){	u32 mask;	mask = 1 << 3;	MOD_REG_FLD(DISPC_CONTROL, mask, enable ? mask : 0);}static void set_lcd_timings(void){	u32 l;	int lck_div, pck_div;	struct lcd_panel *panel = dispc.fbdev->panel;	int is_tft = panel->config & OMAP_LCDC_PANEL_TFT;	unsigned long fck;	l = dispc_read_reg(DISPC_TIMING_H);	l &= ~(FLD_MASK(0, 6) | FLD_MASK(8, 8) | FLD_MASK(20, 8));	l |= ( max(1, (min(64,  panel->hsw))) - 1 ) << 0;	l |= ( max(1, (min(256, panel->hfp))) - 1 ) << 8;	l |= ( max(1, (min(256, panel->hbp))) - 1 ) << 20;	dispc_write_reg(DISPC_TIMING_H, l);	l = dispc_read_reg(DISPC_TIMING_V);	l &= ~(FLD_MASK(0, 6) | FLD_MASK(8, 8) | FLD_MASK(20, 8));	l |= ( max(1, (min(64,  panel->vsw))) - 1 ) << 0;	l |= ( max(0, (min(255, panel->vfp))) - 0 ) << 8;	l |= ( max(0, (min(255, panel->vbp))) - 0 ) << 20;	dispc_write_reg(DISPC_TIMING_V, l);	l = dispc_read_reg(DISPC_POL_FREQ);	l &= ~FLD_MASK(12, 6);	l |= (panel->config & OMAP_LCDC_SIGNAL_MASK) << 12;	l |= panel->acb & 0xff;	dispc_write_reg(DISPC_POL_FREQ, l);	calc_ck_div(is_tft, panel->pixel_clock * 1000, &lck_div, &pck_div);	l = dispc_read_reg(DISPC_DIVISOR);	l &= ~(FLD_MASK(16, 8) | FLD_MASK(0, 8));	l |= (lck_div << 16) | (pck_div << 0);	dispc_write_reg(DISPC_DIVISOR, l);	/* update panel info with the exact clock */	fck = clk_get_rate(dispc.dss1_fck);	panel->pixel_clock = fck / lck_div / pck_div / 1000;}int omap_dispc_request_irq(void (*callback)(void *data), void *data){	int r = 0;	BUG_ON(callback == NULL);	if (dispc.irq_callback)		r = -EBUSY;	else {		dispc.irq_callback = callback;		dispc.irq_callback_data = data;	}	return r;}EXPORT_SYMBOL(omap_dispc_request_irq);void omap_dispc_enable_irqs(int irq_mask){	enable_lcd_clocks(1);	dispc.enabled_irqs = irq_mask;	irq_mask |= DISPC_IRQ_MASK_ERROR;	MOD_REG_FLD(DISPC_IRQENABLE, 0x7fff, irq_mask);	enable_lcd_clocks(0);}EXPORT_SYMBOL(omap_dispc_enable_irqs);void omap_dispc_disable_irqs(int irq_mask){	enable_lcd_clocks(1);	dispc.enabled_irqs &= ~irq_mask;	irq_mask &= ~DISPC_IRQ_MASK_ERROR;	MOD_REG_FLD(DISPC_IRQENABLE, 0x7fff, irq_mask);	enable_lcd_clocks(0);}EXPORT_SYMBOL(omap_dispc_disable_irqs);void omap_dispc_free_irq(void){	enable_lcd_clocks(1);	omap_dispc_disable_irqs(DISPC_IRQ_MASK_ALL);	dispc.irq_callback = NULL;	dispc.irq_callback_data = NULL;	enable_lcd_clocks(0);}EXPORT_SYMBOL(omap_dispc_free_irq);static irqreturn_t omap_dispc_irq_handler(int irq, void *dev){	u32 stat = dispc_read_reg(DISPC_IRQSTATUS);	if (stat & DISPC_IRQ_FRAMEMASK)		complete(&dispc.frame_done);	if (stat & DISPC_IRQ_MASK_ERROR) {		if (printk_ratelimit()) {			dev_err(dispc.fbdev->dev, "irq error status %04x\n",				stat & 0x7fff);		}	}	if ((stat & dispc.enabled_irqs) && dispc.irq_callback)		dispc.irq_callback(dispc.irq_callback_data);	dispc_write_reg(DISPC_IRQSTATUS, stat);	return IRQ_HANDLED;}static int get_dss_clocks(void){	if (IS_ERR((dispc.dss_ick = clk_get(dispc.fbdev->dev, "dss_ick")))) {		dev_err(dispc.fbdev->dev, "can't get dss_ick\n");		return PTR_ERR(dispc.dss_ick);	}	if (IS_ERR((dispc.dss1_fck = clk_get(dispc.fbdev->dev, "dss1_fck")))) {		dev_err(dispc.fbdev->dev, "can't get dss1_fck\n");		clk_put(dispc.dss_ick);		return PTR_ERR(dispc.dss1_fck);	}	if (IS_ERR((dispc.dss_54m_fck =				clk_get(dispc.fbdev->dev, "dss_54m_fck")))) {		dev_err(dispc.fbdev->dev, "can't get dss_54m_fck\n");		clk_put(dispc.dss_ick);		clk_put(dispc.dss1_fck);		return PTR_ERR(dispc.dss_54m_fck);	}	return 0;}static void put_dss_clocks(void){	clk_put(dispc.dss_54m_fck);	clk_put(dispc.dss1_fck);	clk_put(dispc.dss_ick);}static void enable_lcd_clocks(int enable){	if (enable)		clk_enable(dispc.dss1_fck);	else		clk_disable(dispc.dss1_fck);}static void enable_interface_clocks(int enable){	if (enable)		clk_enable(dispc.dss_ick);	else		clk_disable(dispc.dss_ick);}static void enable_digit_clocks(int enable){	if (enable)		clk_enable(dispc.dss_54m_fck);	else		clk_disable(dispc.dss_54m_fck);}static void omap_dispc_suspend(void){	if (dispc.update_mode == OMAPFB_AUTO_UPDATE) {		init_completion(&dispc.frame_done);		omap_dispc_enable_lcd_out(0);		if (!wait_for_completion_timeout(&dispc.frame_done,				msecs_to_jiffies(500))) {			dev_err(dispc.fbdev->dev,				"timeout waiting for FRAME DONE\n");		}		enable_lcd_clocks(0);	}}static void omap_dispc_resume(void){	if (dispc.update_mode == OMAPFB_AUTO_UPDATE) {		enable_lcd_clocks(1);		if (!dispc.ext_mode) {			set_lcd_timings();			load_palette();		}		omap_dispc_enable_lcd_out(1);	}}static int omap_dispc_update_window(struct fb_info *fbi,				 struct omapfb_update_window *win,				 void (*complete_callback)(void *arg),				 void *complete_callback_data){	return dispc.update_mode == OMAPFB_UPDATE_DISABLED ? -ENODEV : 0;}static int mmap_kern(struct omapfb_mem_region *region){	struct vm_struct	*kvma;	struct vm_area_struct	vma;	pgprot_t		pgprot;	unsigned long		vaddr;	kvma = get_vm_area(region->size, VM_IOREMAP);	if (kvma == NULL) {		dev_err(dispc.fbdev->dev, "can't get kernel vm area\n");		return -ENOMEM;	}	vma.vm_mm = &init_mm;	vaddr = (unsigned long)kvma->addr;	pgprot = pgprot_writecombine(pgprot_kernel);	vma.vm_start = vaddr;	vma.vm_end = vaddr + region->size;	if (io_remap_pfn_range(&vma, vaddr, region->paddr >> PAGE_SHIFT,			   region->size, pgprot) < 0) {		dev_err(dispc.fbdev->dev, "kernel mmap for FBMEM failed\n");		return -EAGAIN;	}	region->vaddr = (void *)vaddr;	return 0;}static void mmap_user_open(struct vm_area_struct *vma){	int plane = (int)vma->vm_private_data;	atomic_inc(&dispc.map_count[plane]);}static void mmap_user_close(struct vm_area_struct *vma){

⌨️ 快捷键说明

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