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

📄 hwa742.c

📁 Linux环境下视频显示卡设备的驱动程序源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Epson HWA742 LCD controller driver * * Copyright (C) 2004-2005 Nokia Corporation * Authors:     Juha Yrjölä   <juha.yrjola@nokia.com> *	        Imre Deak     <imre.deak@nokia.com> * YUV support: Jussi Laako   <jussi.laako@nokia.com> * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. */#include <linux/module.h>#include <linux/mm.h>#include <linux/fb.h>#include <linux/delay.h>#include <linux/clk.h>#include <mach/dma.h>#include <mach/omapfb.h>#include <mach/hwa742.h>#define HWA742_REV_CODE_REG       0x0#define HWA742_CONFIG_REG         0x2#define HWA742_PLL_DIV_REG        0x4#define HWA742_PLL_0_REG          0x6#define HWA742_PLL_1_REG          0x8#define HWA742_PLL_2_REG          0xa#define HWA742_PLL_3_REG          0xc#define HWA742_PLL_4_REG          0xe#define HWA742_CLK_SRC_REG        0x12#define HWA742_PANEL_TYPE_REG     0x14#define HWA742_H_DISP_REG         0x16#define HWA742_H_NDP_REG          0x18#define HWA742_V_DISP_1_REG       0x1a#define HWA742_V_DISP_2_REG       0x1c#define HWA742_V_NDP_REG          0x1e#define HWA742_HS_W_REG           0x20#define HWA742_HP_S_REG           0x22#define HWA742_VS_W_REG           0x24#define HWA742_VP_S_REG           0x26#define HWA742_PCLK_POL_REG       0x28#define HWA742_INPUT_MODE_REG     0x2a#define HWA742_TRANSL_MODE_REG1   0x2e#define HWA742_DISP_MODE_REG      0x34#define HWA742_WINDOW_TYPE        0x36#define HWA742_WINDOW_X_START_0   0x38#define HWA742_WINDOW_X_START_1   0x3a#define HWA742_WINDOW_Y_START_0   0x3c#define HWA742_WINDOW_Y_START_1   0x3e#define HWA742_WINDOW_X_END_0     0x40#define HWA742_WINDOW_X_END_1     0x42#define HWA742_WINDOW_Y_END_0     0x44#define HWA742_WINDOW_Y_END_1     0x46#define HWA742_MEMORY_WRITE_LSB   0x48#define HWA742_MEMORY_WRITE_MSB   0x49#define HWA742_MEMORY_READ_0      0x4a#define HWA742_MEMORY_READ_1      0x4c#define HWA742_MEMORY_READ_2      0x4e#define HWA742_POWER_SAVE         0x56#define HWA742_NDP_CTRL           0x58#define HWA742_AUTO_UPDATE_TIME		(HZ / 20)/* Reserve 4 request slots for requests in irq context */#define REQ_POOL_SIZE			24#define IRQ_REQ_POOL_SIZE		4#define REQ_FROM_IRQ_POOL 0x01#define REQ_COMPLETE	0#define REQ_PENDING	1struct update_param {	int	x, y, width, height;	int	color_mode;	int	flags;};struct hwa742_request {	struct list_head entry;	unsigned int	 flags;	int		 (*handler)(struct hwa742_request *req);	void		 (*complete)(void *data);	void		 *complete_data;	union {		struct update_param	update;		struct completion	*sync;	} par;};struct {	enum omapfb_update_mode	update_mode;	enum omapfb_update_mode	update_mode_before_suspend;	struct timer_list	auto_update_timer;	int			stop_auto_update;	struct omapfb_update_window	auto_update_window;	unsigned		te_connected:1;	unsigned		vsync_only:1;	struct hwa742_request	req_pool[REQ_POOL_SIZE];	struct list_head	pending_req_list;	struct list_head	free_req_list;	struct semaphore	req_sema;	spinlock_t		req_lock;	struct extif_timings	reg_timings, lut_timings;	int			prev_color_mode;	int			prev_flags;	int			window_type;	u32			max_transmit_size;	u32			extif_clk_period;	unsigned long		pix_tx_time;	unsigned long		line_upd_time;	struct omapfb_device	*fbdev;	struct lcd_ctrl_extif	*extif;	struct lcd_ctrl		*int_ctrl;	void			(*power_up)(struct device *dev);	void			(*power_down)(struct device *dev);} hwa742;struct lcd_ctrl hwa742_ctrl;static u8 hwa742_read_reg(u8 reg){	u8 data;	hwa742.extif->set_bits_per_cycle(8);	hwa742.extif->write_command(&reg, 1);	hwa742.extif->read_data(&data, 1);	return data;}static void hwa742_write_reg(u8 reg, u8 data){	hwa742.extif->set_bits_per_cycle(8);	hwa742.extif->write_command(&reg, 1);	hwa742.extif->write_data(&data, 1);}static void set_window_regs(int x_start, int y_start, int x_end, int y_end){	u8 tmp[8];	u8 cmd;	x_end--;	y_end--;	tmp[0] = x_start;	tmp[1] = x_start >> 8;	tmp[2] = y_start;	tmp[3] = y_start >> 8;	tmp[4] = x_end;	tmp[5] = x_end >> 8;	tmp[6] = y_end;	tmp[7] = y_end >> 8;	hwa742.extif->set_bits_per_cycle(8);	cmd = HWA742_WINDOW_X_START_0;	hwa742.extif->write_command(&cmd, 1);	hwa742.extif->write_data(tmp, 8);}static void set_format_regs(int conv, int transl, int flags){	if (flags & OMAPFB_FORMAT_FLAG_DOUBLE) {		hwa742.window_type = ((hwa742.window_type & 0xfc) | 0x01);#ifdef VERBOSE		dev_dbg(hwa742.fbdev->dev, "hwa742: enabled pixel doubling\n");#endif	} else {		hwa742.window_type = (hwa742.window_type & 0xfc);#ifdef VERBOSE		dev_dbg(hwa742.fbdev->dev, "hwa742: disabled pixel doubling\n");#endif	}	hwa742_write_reg(HWA742_INPUT_MODE_REG, conv);	hwa742_write_reg(HWA742_TRANSL_MODE_REG1, transl);	hwa742_write_reg(HWA742_WINDOW_TYPE, hwa742.window_type);}static void enable_tearsync(int y, int width, int height, int screen_height,			    int force_vsync){	u8 b;	b = hwa742_read_reg(HWA742_NDP_CTRL);	b |= 1 << 2;	hwa742_write_reg(HWA742_NDP_CTRL, b);	if (likely(hwa742.vsync_only || force_vsync)) {		hwa742.extif->enable_tearsync(1, 0);		return;	}	if (width * hwa742.pix_tx_time < hwa742.line_upd_time) {		hwa742.extif->enable_tearsync(1, 0);		return;	}	if ((width * hwa742.pix_tx_time / 1000) * height <	    (y + height) * (hwa742.line_upd_time / 1000)) {		hwa742.extif->enable_tearsync(1, 0);		return;	}	hwa742.extif->enable_tearsync(1, y + 1);}static void disable_tearsync(void){	u8 b;	hwa742.extif->enable_tearsync(0, 0);	b = hwa742_read_reg(HWA742_NDP_CTRL);	b &= ~(1 << 2);	hwa742_write_reg(HWA742_NDP_CTRL, b);}static inline struct hwa742_request *alloc_req(void){	unsigned long flags;	struct hwa742_request *req;	int req_flags = 0;	if (!in_interrupt())		down(&hwa742.req_sema);	else		req_flags = REQ_FROM_IRQ_POOL;	spin_lock_irqsave(&hwa742.req_lock, flags);	BUG_ON(list_empty(&hwa742.free_req_list));	req = list_entry(hwa742.free_req_list.next,			 struct hwa742_request, entry);	list_del(&req->entry);	spin_unlock_irqrestore(&hwa742.req_lock, flags);	INIT_LIST_HEAD(&req->entry);	req->flags = req_flags;	return req;}static inline void free_req(struct hwa742_request *req){	unsigned long flags;	spin_lock_irqsave(&hwa742.req_lock, flags);	list_del(&req->entry);	list_add(&req->entry, &hwa742.free_req_list);	if (!(req->flags & REQ_FROM_IRQ_POOL))		up(&hwa742.req_sema);	spin_unlock_irqrestore(&hwa742.req_lock, flags);}static void process_pending_requests(void){	unsigned long flags;	spin_lock_irqsave(&hwa742.req_lock, flags);	while (!list_empty(&hwa742.pending_req_list)) {		struct hwa742_request *req;		void (*complete)(void *);		void *complete_data;		req = list_entry(hwa742.pending_req_list.next,				 struct hwa742_request, entry);		spin_unlock_irqrestore(&hwa742.req_lock, flags);		if (req->handler(req) == REQ_PENDING)			return;		complete = req->complete;		complete_data = req->complete_data;		free_req(req);		if (complete)			complete(complete_data);		spin_lock_irqsave(&hwa742.req_lock, flags);	}	spin_unlock_irqrestore(&hwa742.req_lock, flags);}static void submit_req_list(struct list_head *head){	unsigned long flags;	int process = 1;	spin_lock_irqsave(&hwa742.req_lock, flags);	if (likely(!list_empty(&hwa742.pending_req_list)))		process = 0;	list_splice_init(head, hwa742.pending_req_list.prev);	spin_unlock_irqrestore(&hwa742.req_lock, flags);	if (process)		process_pending_requests();}static void request_complete(void *data){	struct hwa742_request	*req = (struct hwa742_request *)data;	void			(*complete)(void *);	void			*complete_data;	complete = req->complete;	complete_data = req->complete_data;	free_req(req);	if (complete)		complete(complete_data);	process_pending_requests();}static int send_frame_handler(struct hwa742_request *req){	struct update_param *par = &req->par.update;	int x = par->x;	int y = par->y;	int w = par->width;	int h = par->height;	int bpp;	int conv, transl;	unsigned long offset;	int color_mode = par->color_mode;	int flags = par->flags;	int scr_width = hwa742.fbdev->panel->x_res;	int scr_height = hwa742.fbdev->panel->y_res;#ifdef VERBOSE	dev_dbg(hwa742.fbdev->dev, "x %d y %d w %d h %d scr_width %d "		"color_mode %d flags %d\n",		x, y, w, h, scr_width, color_mode, flags);#endif	switch (color_mode) {	case OMAPFB_COLOR_YUV422:		bpp = 16;		conv = 0x08;		transl = 0x25;		break;	case OMAPFB_COLOR_YUV420:		bpp = 12;		conv = 0x09;		transl = 0x25;		break;	case OMAPFB_COLOR_RGB565:		bpp = 16;		conv = 0x01;		transl = 0x05;		break;	default:		return -EINVAL;	}	if (hwa742.prev_flags != flags ||	    hwa742.prev_color_mode != color_mode) {		set_format_regs(conv, transl, flags);		hwa742.prev_color_mode = color_mode;		hwa742.prev_flags = flags;	}	flags = req->par.update.flags;	if (flags & OMAPFB_FORMAT_FLAG_TEARSYNC)		enable_tearsync(y, scr_width, h, scr_height,				flags & OMAPFB_FORMAT_FLAG_FORCE_VSYNC);	else		disable_tearsync();	set_window_regs(x, y, x + w, y + h);	offset = (scr_width * y + x) * bpp / 8;	hwa742.int_ctrl->setup_plane(OMAPFB_PLANE_GFX,			OMAPFB_CHANNEL_OUT_LCD, offset, scr_width, 0, 0, w, h,			color_mode);	hwa742.extif->set_bits_per_cycle(16);	hwa742.int_ctrl->enable_plane(OMAPFB_PLANE_GFX, 1);	hwa742.extif->transfer_area(w, h, request_complete, req);	return REQ_PENDING;}static void send_frame_complete(void *data){	hwa742.int_ctrl->enable_plane(OMAPFB_PLANE_GFX, 0);}#define ADD_PREQ(_x, _y, _w, _h) do {		\	req = alloc_req();			\	req->handler	= send_frame_handler;	\	req->complete	= send_frame_complete;	\	req->par.update.x = _x;			\	req->par.update.y = _y;			\	req->par.update.width  = _w;		\	req->par.update.height = _h;		\	req->par.update.color_mode = color_mode;\	req->par.update.flags	  = flags;	\	list_add_tail(&req->entry, req_head);	\} while(0)static void create_req_list(struct omapfb_update_window *win,			    struct list_head *req_head){	struct hwa742_request *req;	int x = win->x;	int y = win->y;	int width = win->width;	int height = win->height;	int color_mode;	int flags;	flags = win->format & ~OMAPFB_FORMAT_MASK;	color_mode = win->format & OMAPFB_FORMAT_MASK;	if (x & 1) {		ADD_PREQ(x, y, 1, height);		width--;		x++;		flags &= ~OMAPFB_FORMAT_FLAG_TEARSYNC;	}	if (width & ~1) {		unsigned int xspan = width & ~1;		unsigned int ystart = y;		unsigned int yspan = height;		if (xspan * height * 2 > hwa742.max_transmit_size) {			yspan = hwa742.max_transmit_size / (xspan * 2);			ADD_PREQ(x, ystart, xspan, yspan);			ystart += yspan;			yspan = height - yspan;			flags &= ~OMAPFB_FORMAT_FLAG_TEARSYNC;		}		ADD_PREQ(x, ystart, xspan, yspan);		x += xspan;		width -= xspan;		flags &= ~OMAPFB_FORMAT_FLAG_TEARSYNC;	}	if (width)		ADD_PREQ(x, y, 1, height);}static void auto_update_complete(void *data){	if (!hwa742.stop_auto_update)		mod_timer(&hwa742.auto_update_timer,			  jiffies + HWA742_AUTO_UPDATE_TIME);}static void hwa742_update_window_auto(unsigned long arg){	LIST_HEAD(req_list);	struct hwa742_request *last;	create_req_list(&hwa742.auto_update_window, &req_list);	last = list_entry(req_list.prev, struct hwa742_request, entry);	last->complete = auto_update_complete;	last->complete_data = NULL;	submit_req_list(&req_list);}int hwa742_update_window_async(struct fb_info *fbi,				 struct omapfb_update_window *win,				 void (*complete_callback)(void *arg),				 void *complete_callback_data){	LIST_HEAD(req_list);	struct hwa742_request *last;	int r = 0;	if (hwa742.update_mode != OMAPFB_MANUAL_UPDATE) {		dev_dbg(hwa742.fbdev->dev, "invalid update mode\n");		r = -EINVAL;		goto out;	}	if (unlikely(win->format &	    ~(0x03 | OMAPFB_FORMAT_FLAG_DOUBLE |	    OMAPFB_FORMAT_FLAG_TEARSYNC | OMAPFB_FORMAT_FLAG_FORCE_VSYNC))) {		dev_dbg(hwa742.fbdev->dev, "invalid window flag\n");		r = -EINVAL;		goto out;	}	create_req_list(win, &req_list);	last = list_entry(req_list.prev, struct hwa742_request, entry);	last->complete = complete_callback;	last->complete_data = (void *)complete_callback_data;	submit_req_list(&req_list);out:	return r;}EXPORT_SYMBOL(hwa742_update_window_async);static int hwa742_setup_plane(int plane, int channel_out,				  unsigned long offset, int screen_width,				  int pos_x, int pos_y, int width, int height,				  int color_mode){	if (plane != OMAPFB_PLANE_GFX ||	    channel_out != OMAPFB_CHANNEL_OUT_LCD)		return -EINVAL;	return 0;}

⌨️ 快捷键说明

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