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

📄 sm501fb.c

📁 Linux环境下视频显示卡设备的驱动程序源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
		return ret;	}	sm501fb_pan_crt(var, info);	sm501fb_set_par_geometry(info, var);	control |= SM501_FIFO_3;	/* fill if >3 free slots */	switch(var->bits_per_pixel) {	case 8:		control |= SM501_DC_CRT_CONTROL_8BPP;		break;	case 16:		control |= SM501_DC_CRT_CONTROL_16BPP;		sm501fb_setup_gamma(fbi, SM501_DC_CRT_PALETTE);		break;	case 32:		control |= SM501_DC_CRT_CONTROL_32BPP;		sm501fb_setup_gamma(fbi, SM501_DC_CRT_PALETTE);		break;	default:		BUG();	}	control |= SM501_DC_CRT_CONTROL_SEL;	/* CRT displays CRT data */	control |= SM501_DC_CRT_CONTROL_TE;	/* enable CRT timing */	control |= SM501_DC_CRT_CONTROL_ENABLE;	/* enable CRT plane */ out_update:	dev_dbg(fbi->dev, "new control is %08lx\n", control);	writel(control, fbi->regs + SM501_DC_CRT_CONTROL);	sm501fb_sync_regs(fbi);	return 0;}static void sm501fb_panel_power(struct sm501fb_info *fbi, int to){	unsigned long control;	void __iomem *ctrl_reg = fbi->regs + SM501_DC_PANEL_CONTROL;	struct sm501_platdata_fbsub *pd = fbi->pdata->fb_pnl;	control = readl(ctrl_reg);	if (to && (control & SM501_DC_PANEL_CONTROL_VDD) == 0) {		/* enable panel power */		control |= SM501_DC_PANEL_CONTROL_VDD;	/* FPVDDEN */		writel(control, ctrl_reg);		sm501fb_sync_regs(fbi);		mdelay(10);		control |= SM501_DC_PANEL_CONTROL_DATA;	/* DATA */		writel(control, ctrl_reg);		sm501fb_sync_regs(fbi);		mdelay(10);		/* VBIASEN */		if (!(pd->flags & SM501FB_FLAG_PANEL_NO_VBIASEN)) {			if (pd->flags & SM501FB_FLAG_PANEL_INV_VBIASEN)				control &= ~SM501_DC_PANEL_CONTROL_BIAS;			else				control |= SM501_DC_PANEL_CONTROL_BIAS;			writel(control, ctrl_reg);			sm501fb_sync_regs(fbi);			mdelay(10);		}		if (!(pd->flags & SM501FB_FLAG_PANEL_NO_FPEN)) {			if (pd->flags & SM501FB_FLAG_PANEL_INV_FPEN)				control &= ~SM501_DC_PANEL_CONTROL_FPEN;			else				control |= SM501_DC_PANEL_CONTROL_FPEN;			writel(control, ctrl_reg);			sm501fb_sync_regs(fbi);			mdelay(10);		}	} else if (!to && (control & SM501_DC_PANEL_CONTROL_VDD) != 0) {		/* disable panel power */		if (!(pd->flags & SM501FB_FLAG_PANEL_NO_FPEN)) {			if (pd->flags & SM501FB_FLAG_PANEL_INV_FPEN)				control |= SM501_DC_PANEL_CONTROL_FPEN;			else				control &= ~SM501_DC_PANEL_CONTROL_FPEN;			writel(control, ctrl_reg);			sm501fb_sync_regs(fbi);			mdelay(10);		}		if (!(pd->flags & SM501FB_FLAG_PANEL_NO_VBIASEN)) {			if (pd->flags & SM501FB_FLAG_PANEL_INV_VBIASEN)				control |= SM501_DC_PANEL_CONTROL_BIAS;			else				control &= ~SM501_DC_PANEL_CONTROL_BIAS;			writel(control, ctrl_reg);			sm501fb_sync_regs(fbi);			mdelay(10);		}		control &= ~SM501_DC_PANEL_CONTROL_DATA;		writel(control, ctrl_reg);		sm501fb_sync_regs(fbi);		mdelay(10);		control &= ~SM501_DC_PANEL_CONTROL_VDD;		writel(control, ctrl_reg);		sm501fb_sync_regs(fbi);		mdelay(10);	}	sm501fb_sync_regs(fbi);}/* sm501fb_set_par_pnl * * Set the panel video mode from the fb_info structure*/static int sm501fb_set_par_pnl(struct fb_info *info){	struct sm501fb_par  *par = info->par;	struct sm501fb_info *fbi = par->info;	struct fb_var_screeninfo *var = &info->var;	unsigned long control;	unsigned long reg;	int ret;	dev_dbg(fbi->dev, "%s(%p)\n", __func__, info);	/* activate this new configuration */	ret = sm501fb_set_par_common(info, var);	if (ret)		return ret;	sm501fb_pan_pnl(var, info);	sm501fb_set_par_geometry(info, var);	/* update control register */	control = readl(fbi->regs + SM501_DC_PANEL_CONTROL);	control &= (SM501_DC_PANEL_CONTROL_GAMMA |		    SM501_DC_PANEL_CONTROL_VDD  |		    SM501_DC_PANEL_CONTROL_DATA |		    SM501_DC_PANEL_CONTROL_BIAS |		    SM501_DC_PANEL_CONTROL_FPEN |		    SM501_DC_PANEL_CONTROL_CP |		    SM501_DC_PANEL_CONTROL_CK |		    SM501_DC_PANEL_CONTROL_HP |		    SM501_DC_PANEL_CONTROL_VP |		    SM501_DC_PANEL_CONTROL_HPD |		    SM501_DC_PANEL_CONTROL_VPD);	control |= SM501_FIFO_3;	/* fill if >3 free slots */	switch(var->bits_per_pixel) {	case 8:		control |= SM501_DC_PANEL_CONTROL_8BPP;		break;	case 16:		control |= SM501_DC_PANEL_CONTROL_16BPP;		sm501fb_setup_gamma(fbi, SM501_DC_PANEL_PALETTE);		break;	case 32:		control |= SM501_DC_PANEL_CONTROL_32BPP;		sm501fb_setup_gamma(fbi, SM501_DC_PANEL_PALETTE);		break;	default:		BUG();	}	writel(0x0, fbi->regs + SM501_DC_PANEL_PANNING_CONTROL);	/* panel plane top left and bottom right location */	writel(0x00, fbi->regs + SM501_DC_PANEL_TL_LOC);	reg  = var->xres - 1;	reg |= (var->yres - 1) << 16;	writel(reg, fbi->regs + SM501_DC_PANEL_BR_LOC);	/* program panel control register */	control |= SM501_DC_PANEL_CONTROL_TE;	/* enable PANEL timing */	control |= SM501_DC_PANEL_CONTROL_EN;	/* enable PANEL gfx plane */	if ((var->sync & FB_SYNC_HOR_HIGH_ACT) == 0)		control |= SM501_DC_PANEL_CONTROL_HSP;	if ((var->sync & FB_SYNC_VERT_HIGH_ACT) == 0)		control |= SM501_DC_PANEL_CONTROL_VSP;	writel(control, fbi->regs + SM501_DC_PANEL_CONTROL);	sm501fb_sync_regs(fbi);	/* ensure the panel interface is not tristated at this point */	sm501_modify_reg(fbi->dev->parent, SM501_SYSTEM_CONTROL,			 0, SM501_SYSCTRL_PANEL_TRISTATE);	/* power the panel up */	sm501fb_panel_power(fbi, 1);	return 0;}/* chan_to_field * * convert a colour value into a field position * * from pxafb.c*/static inline unsigned int chan_to_field(unsigned int chan,					 struct fb_bitfield *bf){	chan &= 0xffff;	chan >>= 16 - bf->length;	return chan << bf->offset;}/* sm501fb_setcolreg * * set the colour mapping for modes that support palettised data*/static int sm501fb_setcolreg(unsigned regno,			     unsigned red, unsigned green, unsigned blue,			     unsigned transp, struct fb_info *info){	struct sm501fb_par  *par = info->par;	struct sm501fb_info *fbi = par->info;	void __iomem *base = fbi->regs;	unsigned int val;	if (par->head == HEAD_CRT)		base += SM501_DC_CRT_PALETTE;	else		base += SM501_DC_PANEL_PALETTE;	switch (info->fix.visual) {	case FB_VISUAL_TRUECOLOR:		/* true-colour, use pseuo-palette */		if (regno < 16) {			u32 *pal = par->pseudo_palette;			val  = chan_to_field(red,   &info->var.red);			val |= chan_to_field(green, &info->var.green);			val |= chan_to_field(blue,  &info->var.blue);			pal[regno] = val;		}		break;	case FB_VISUAL_PSEUDOCOLOR:		if (regno < 256) {			val = (red >> 8) << 16;			val |= (green >> 8) << 8;			val |= blue >> 8;			writel(val, base + (regno * 4));		}		break;	default:		return 1;   /* unknown type */	}	return 0;}/* sm501fb_blank_pnl * * Blank or un-blank the panel interface*/static int sm501fb_blank_pnl(int blank_mode, struct fb_info *info){	struct sm501fb_par  *par = info->par;	struct sm501fb_info *fbi = par->info;	dev_dbg(fbi->dev, "%s(mode=%d, %p)\n", __func__, blank_mode, info);	switch (blank_mode) {	case FB_BLANK_POWERDOWN:		sm501fb_panel_power(fbi, 0);		break;	case FB_BLANK_UNBLANK:		sm501fb_panel_power(fbi, 1);		break;	case FB_BLANK_NORMAL:	case FB_BLANK_VSYNC_SUSPEND:	case FB_BLANK_HSYNC_SUSPEND:	default:		return 1;	}	return 0;}/* sm501fb_blank_crt * * Blank or un-blank the crt interface*/static int sm501fb_blank_crt(int blank_mode, struct fb_info *info){	struct sm501fb_par  *par = info->par;	struct sm501fb_info *fbi = par->info;	unsigned long ctrl;	dev_dbg(fbi->dev, "%s(mode=%d, %p)\n", __func__, blank_mode, info);	ctrl = readl(fbi->regs + SM501_DC_CRT_CONTROL);	switch (blank_mode) {	case FB_BLANK_POWERDOWN:		ctrl &= ~SM501_DC_CRT_CONTROL_ENABLE;		sm501_misc_control(fbi->dev->parent, SM501_MISC_DAC_POWER, 0);	case FB_BLANK_NORMAL:		ctrl |= SM501_DC_CRT_CONTROL_BLANK;		break;	case FB_BLANK_UNBLANK:		ctrl &= ~SM501_DC_CRT_CONTROL_BLANK;		ctrl |=  SM501_DC_CRT_CONTROL_ENABLE;		sm501_misc_control(fbi->dev->parent, 0, SM501_MISC_DAC_POWER);		break;	case FB_BLANK_VSYNC_SUSPEND:	case FB_BLANK_HSYNC_SUSPEND:	default:		return 1;	}	writel(ctrl, fbi->regs + SM501_DC_CRT_CONTROL);	sm501fb_sync_regs(fbi);	return 0;}/* sm501fb_cursor * * set or change the hardware cursor parameters*/static int sm501fb_cursor(struct fb_info *info, struct fb_cursor *cursor){	struct sm501fb_par  *par = info->par;	struct sm501fb_info *fbi = par->info;	void __iomem *base = fbi->regs;	unsigned long hwc_addr;	unsigned long fg, bg;	dev_dbg(fbi->dev, "%s(%p,%p)\n", __func__, info, cursor);	if (par->head == HEAD_CRT)		base += SM501_DC_CRT_HWC_BASE;	else		base += SM501_DC_PANEL_HWC_BASE;	/* check not being asked to exceed capabilities */	if (cursor->image.width > 64)		return -EINVAL;	if (cursor->image.height > 64)		return -EINVAL;	if (cursor->image.depth > 1)		return -EINVAL;	hwc_addr = readl(base + SM501_OFF_HWC_ADDR);	if (cursor->enable)		writel(hwc_addr | SM501_HWC_EN, base + SM501_OFF_HWC_ADDR);	else		writel(hwc_addr & ~SM501_HWC_EN, base + SM501_OFF_HWC_ADDR);	/* set data */	if (cursor->set & FB_CUR_SETPOS) {		unsigned int x = cursor->image.dx;		unsigned int y = cursor->image.dy;		if (x >= 2048 || y >= 2048 )			return -EINVAL;		dev_dbg(fbi->dev, "set position %d,%d\n", x, y);		//y += cursor->image.height;		writel(x | (y << 16), base + SM501_OFF_HWC_LOC);	}	if (cursor->set & FB_CUR_SETCMAP) {		unsigned int bg_col = cursor->image.bg_color;		unsigned int fg_col = cursor->image.fg_color;		dev_dbg(fbi->dev, "%s: update cmap (%08x,%08x)\n",			__func__, bg_col, fg_col);		bg = ((info->cmap.red[bg_col] & 0xF8) << 8) |			((info->cmap.green[bg_col] & 0xFC) << 3) |			((info->cmap.blue[bg_col] & 0xF8) >> 3);		fg = ((info->cmap.red[fg_col] & 0xF8) << 8) |			((info->cmap.green[fg_col] & 0xFC) << 3) |			((info->cmap.blue[fg_col] & 0xF8) >> 3);		dev_dbg(fbi->dev, "fgcol %08lx, bgcol %08lx\n", fg, bg);		writel(bg, base + SM501_OFF_HWC_COLOR_1_2);		writel(fg, base + SM501_OFF_HWC_COLOR_3);	}	if (cursor->set & FB_CUR_SETSIZE ||	    cursor->set & (FB_CUR_SETIMAGE | FB_CUR_SETSHAPE)) {		/* SM501 cursor is a two bpp 64x64 bitmap this routine		 * clears it to transparent then combines the cursor		 * shape plane with the colour plane to set the		 * cursor */		int x, y;		const unsigned char *pcol = cursor->image.data;		const unsigned char *pmsk = cursor->mask;		void __iomem   *dst = par->cursor.k_addr;		unsigned char  dcol = 0;		unsigned char  dmsk = 0;		unsigned int   op;		dev_dbg(fbi->dev, "%s: setting shape (%d,%d)\n",			__func__, cursor->image.width, cursor->image.height);		for (op = 0; op < (64*64*2)/8; op+=4)			writel(0x0, dst + op);		for (y = 0; y < cursor->image.height; y++) {			for (x = 0; x < cursor->image.width; x++) {				if ((x % 8) == 0) {					dcol = *pcol++;					dmsk = *pmsk++;				} else {					dcol >>= 1;					dmsk >>= 1;				}				if (dmsk & 1) {					op = (dcol & 1) ? 1 : 3;					op <<= ((x % 4) * 2);					op |= readb(dst + (x / 4));					writeb(op, dst + (x / 4));				}			}			dst += (64*2)/8;		}	}	sm501fb_sync_regs(fbi);	/* ensure cursor data flushed */	return 0;}/* sm501fb_crtsrc_show * * device attribute code to show where the crt output is sourced from*/static ssize_t sm501fb_crtsrc_show(struct device *dev,			       struct device_attribute *attr, char *buf){	struct sm501fb_info *info = dev_get_drvdata(dev);	unsigned long ctrl;	ctrl = readl(info->regs + SM501_DC_CRT_CONTROL);	ctrl &= SM501_DC_CRT_CONTROL_SEL;	return snprintf(buf, PAGE_SIZE, "%s\n", ctrl ? "crt" : "panel");}/* sm501fb_crtsrc_show * * device attribute code to set where the crt output is sourced from*/static ssize_t sm501fb_crtsrc_store(struct device *dev,				struct device_attribute *attr,				const char *buf, size_t len){	struct sm501fb_info *info = dev_get_drvdata(dev);	enum sm501_controller head;	unsigned long ctrl;	if (len < 1)		return -EINVAL;	if (strnicmp(buf, "crt", 3) == 0)		head = HEAD_CRT;	else if (strnicmp(buf, "panel", 5) == 0)		head = HEAD_PANEL;	else		return -EINVAL;	dev_info(dev, "setting crt source to head %d\n", head);	ctrl = readl(info->regs + SM501_DC_CRT_CONTROL);	if (head == HEAD_CRT) {		ctrl |= SM501_DC_CRT_CONTROL_SEL;		ctrl |= SM501_DC_CRT_CONTROL_ENABLE;		ctrl |= SM501_DC_CRT_CONTROL_TE;	} else {		ctrl &= ~SM501_DC_CRT_CONTROL_SEL;		ctrl &= ~SM501_DC_CRT_CONTROL_ENABLE;		ctrl &= ~SM501_DC_CRT_CONTROL_TE;	}	writel(ctrl, info->regs + SM501_DC_CRT_CONTROL);	sm501fb_sync_regs(info);	return len;}/* Prepare the device_attr for registration with sysfs later */static DEVICE_ATTR(crt_src, 0666, sm501fb_crtsrc_show, sm501fb_crtsrc_store);/* sm501fb_show_regs * * show the primary sm501 registers*/static int sm501fb_show_regs(struct sm501fb_info *info, char *ptr,			     unsigned int start, unsigned int len){	void __iomem *mem = info->regs;	char *buf = ptr;	unsigned int reg;	for (reg = start; reg < (len + start); reg += 4)		ptr += sprintf(ptr, "%08x = %08x\n", reg, readl(mem + reg));	return ptr - buf;}/* sm501fb_debug_show_crt * * show the crt control and cursor registers*/static ssize_t sm501fb_debug_show_crt(struct device *dev,				  struct device_attribute *attr, char *buf){	struct sm501fb_info *info = dev_get_drvdata(dev);	char *ptr = buf;	ptr += sm501fb_show_regs(info, ptr, SM501_DC_CRT_CONTROL, 0x40);	ptr += sm501fb_show_regs(info, ptr, SM501_DC_CRT_HWC_BASE, 0x10);	return ptr - buf;}static DEVICE_ATTR(fbregs_crt, 0444, sm501fb_debug_show_crt, NULL);/* sm501fb_debug_show_pnl * * show the panel control and cursor registers*/static ssize_t sm501fb_debug_show_pnl(struct device *dev,				  struct device_attribute *attr, char *buf){	struct sm501fb_info *info = dev_get_drvdata(dev);	char *ptr = buf;	ptr += sm501fb_show_regs(info, ptr, 0x0, 0x40);	ptr += sm501fb_show_regs(info, ptr, SM501_DC_PANEL_HWC_BASE, 0x10);	return ptr - buf;}static DEVICE_ATTR(fbregs_pnl, 0444, sm501fb_debug_show_pnl, NULL);/* framebuffer ops */static struct fb_ops sm501fb_ops_crt = {	.owner		= THIS_MODULE,	.fb_check_var	= sm501fb_check_var_crt,	.fb_set_par	= sm501fb_set_par_crt,	.fb_blank	= sm501fb_blank_crt,	.fb_setcolreg	= sm501fb_setcolreg,	.fb_pan_display	= sm501fb_pan_crt,	.fb_cursor	= sm501fb_cursor,	.fb_fillrect	= cfb_fillrect,	.fb_copyarea	= cfb_copyarea,	.fb_imageblit	= cfb_imageblit,};static struct fb_ops sm501fb_ops_pnl = {	.owner		= THIS_MODULE,	.fb_check_var	= sm501fb_check_var_pnl,	.fb_set_par	= sm501fb_set_par_pnl,	.fb_pan_display	= sm501fb_pan_pnl,	.fb_blank	= sm501fb_blank_pnl,	.fb_setcolreg	= sm501fb_setcolreg,	.fb_cursor	= sm501fb_cursor,	.fb_fillrect	= cfb_fillrect,	.fb_copyarea	= cfb_copyarea,	.fb_imageblit	= cfb_imageblit,};/* sm501_init_cursor * * initialise hw cursor parameters*/static int sm501_init_cursor(struct fb_info *fbi, unsigned int reg_base){	struct sm501fb_par *par;	struct sm501fb_info *info;	int ret;	if (fbi == NULL)		return 0;	par = fbi->par;	info = par->info;	par->cursor_regs = info->regs + reg_base;	ret = sm501_alloc_mem(info, &par->cursor, SM501_MEMF_CURSOR, 1024);

⌨️ 快捷键说明

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