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

📄 sm501.c

📁 F:worksip2440a board可启动u-boot-like.tar.gz F:worksip2440a board可启动u-boot-like.tar.gz
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *  linux/drivers/video/sm501.c * * *   Based on pxafb.c Copyright (C) Eric A. Thomas *   Based on sa1100fb.c Copyright (C) Eric A. Thomas *   Based on acornfb.c Copyright (C) Russell King. * * This file is subject to the terms and conditions of the GNU General Public * License.  See the file COPYING in the main directory of this archive for * more details. * *	        Silicon Motion SM501 Frame Buffer Driver*/#include <common.h>#if defined(CONFIG_VIDEO_SM501)#include <video_fb.h>#include <sm501.h>#include <sm501acc.h>#include <s3c2440.h>#define FBTYPE_8BIT_INDEX        0#define FBTYPE_8BIT_332RGB       5#define FBTYPE_15BIT_555RGB      1#define FBTYPE_16BIT_565RGB      2#define FBTYPE_32BIT_X888RGB     3#define FBTYPE_24BIT_888RGB      4#define VSYNCTIMEOUT                       10000//#define SM501_DEBUG int XAACopyROP[16] ={   ROP_0,               /* GXclear */   ROP_DSa,             /* GXand */   ROP_SDna,            /* GXandReverse */   ROP_S,               /* GXcopy */   ROP_DSna,            /* GXandInverted */   ROP_D,               /* GXnoop */   ROP_DSx,             /* GXxor */   ROP_DSo,             /* GXor */   ROP_DSon,            /* GXnor */   ROP_DSxn,            /* GXequiv */   ROP_Dn,              /* GXinvert*/   ROP_SDno,            /* GXorReverse */   ROP_Sn,              /* GXcopyInverted */   ROP_DSno,            /* GXorInverted */   ROP_DSan,            /* GXnand */   ROP_1                /* GXset */};int XAAPatternROP[16]={   ROP_0,   ROP_DPa,   ROP_PDna,   ROP_P,   ROP_DPna,   ROP_D,   ROP_DPx,   ROP_DPo,   ROP_DPon,   ROP_PDxn,   ROP_Dn,   ROP_PDno,   ROP_Pn,   ROP_DPno,   ROP_DPan,   ROP_1};// Format of mode table record.typedef struct _mode_table_t{	// Horizontal timing.	int			horizontal_total;	int			horizontal_display_end;	int			horizontal_sync_start;	int			horizontal_sync_width;	polarity_t	horizontal_sync_polarity;	// Vertical timing.	int 		vertical_total;	int 		vertical_display_end;	int 		vertical_sync_start;	int 		vertical_sync_height;	polarity_t	vertical_sync_polarity;	// Refresh timing.	long		pixel_clock;	long		horizontal_frequency;	long		vertical_frequency;} mode_table_t, *pmode_table_t;// Clock value structure.typedef struct clock_select_t{	long	mclk;	int		divider;	int		shift;} clock_select_t, *pclock_select_t;// Registers necessary to set mode.typedef struct _reg_table_t{	unsigned long	clock;	unsigned long	control;	unsigned long	fb_width;	unsigned long	horizontal_total;	unsigned long	horizontal_sync;	unsigned long	vertical_total;	unsigned long	vertical_sync;	unsigned long	width;	unsigned long	height;	display_t		display;} reg_table_t, *preg_table_t;// Panel On/Off constants to use with panelPowerSequence.typedef enum _panel_state_t{	PANEL_OFF,	PANEL_ON,}panel_state_t;/* Mode table. */mode_table_t mode_table[] ={	//----------------------------------------------------------------------------------------	// H.	H.    H.     H.   H.        V.   V.    V.    V.   V.        Pixel     H.     V.	// tot.	disp. sync   sync sync      tot. disp. sync  sync sinc      clock     freq.  freq.	//      end   start  wdth polarity       end   start hght polarity	//----------------------------------------------------------------------------------------	// 640 x 480	{  800, 640,  656,   96,  NEGATIVE, 525, 480,  490,  2,   NEGATIVE, 25175000, 31469, 60 },	{  832, 640,  664,   40,  NEGATIVE, 520, 480,  489,  3,   NEGATIVE, 31500000, 37861, 72 },	{  840, 640,  656,   64,  NEGATIVE, 500, 480,  481,  3,   NEGATIVE, 31500000, 37500, 75 },	{  832, 640,  696,   56,  NEGATIVE, 509, 480,  481,  3,   NEGATIVE, 36000000, 43269, 85 },	// 800 x 600	{ 1024, 800,  824,   72,  POSITIVE, 625, 600,  601,  2,   POSITIVE, 36000000, 35156, 56 },	{ 1056, 800,  840,  128,  POSITIVE, 628, 600,  601,  4,   POSITIVE, 40000000, 37879, 60 },	{ 1040, 800,  856,  120,  POSITIVE, 666, 600,  637,  6,   POSITIVE, 50000000, 48077, 72 },	{ 1056, 800,  816,   80,  POSITIVE, 625, 600,  601,  3,   POSITIVE, 49500000, 46875, 75 },	{ 1048, 800,  832,   64,  POSITIVE, 631, 600,  601,  3,   POSITIVE, 56250000, 53674, 85 },	// 1024 x 768	{ 1344, 1024, 1048, 136,  NEGATIVE, 806, 768,  771,  6,   NEGATIVE, 65000000, 48363, 60 },	{ 1328, 1024, 1048, 136,  NEGATIVE, 806, 768,  771,  6,   NEGATIVE, 75000000, 56476, 70 },	{ 1312, 1024, 1040,  96,  POSITIVE, 800, 768,  769,  3,   POSITIVE, 78750000, 60023, 75 },	{ 1376, 1024, 1072,  96,  POSITIVE, 808, 768,  769,  3,   POSITIVE, 94500000, 68677, 85 },	// End of table.	{ 0, 0, 0, 0, NEGATIVE, 0, 0, 0, 0, NEGATIVE, 0, 0, 0 },/*	// 320 x 240	{  351, 320, 335, 8, NEGATIVE, 263, 240, 254, 2, NEGATIVE,	   6000000, 16000, 60 },	// 400 x 300	{ 528, 400, 420,  64, NEGATIVE, 314, 300, 301, 2, NEGATIVE,	  10000000, 18940, 60 },	// 640 x 480	{  800, 640, 656, 96, NEGATIVE, 525, 480, 490, 2, NEGATIVE,	   25175000, 31469, 60 },	{  832, 640, 664, 40, NEGATIVE, 520, 480, 489, 3, NEGATIVE,	   31500000, 37861, 72 },	{  840, 640, 656, 64, NEGATIVE, 500, 480, 481, 3, NEGATIVE,	   31500000, 37500, 75 },	{  832, 640, 696, 56, NEGATIVE, 509, 480, 481, 3, NEGATIVE,	   36000000, 43269, 85 },	// 720 x 540	{  900, 720, 740, 96, POSITIVE, 576, 540, 545, 2, POSITIVE,	   31100000, 34560, 60 },	// 800 x 480	{ 1056, 800, 864,  56, POSITIVE, 525, 480, 490, 2, POSITIVE,	  40000000, 31600, 60 },	// 800 x 600	{ 1024, 800, 824,  72, POSITIVE, 625, 600, 601, 2, POSITIVE,	  36000000, 35156, 56 },	{ 1056, 800, 840, 128, POSITIVE, 628, 600, 601, 4, POSITIVE,	  40000000, 37879, 60 },	{ 1040, 800, 856, 120, POSITIVE, 666, 600, 637, 6, POSITIVE,	  50000000, 48077, 72 },	{ 1056, 800, 816,  80, POSITIVE, 625, 600, 601, 3, POSITIVE,	  49500000, 46875, 75 },	{ 1048, 800, 832,  64, POSITIVE, 631, 600, 601, 3, POSITIVE,	  56250000, 53674, 85 },	// 1024 x 600	{ 1344, 1024, 1048, 136, POSITIVE, 628, 600, 601, 4, POSITIVE,	  50600000, 37679, 60 },	// 1024 x 768	{ 1344, 1024, 1048, 136, NEGATIVE, 806, 768, 771, 6, NEGATIVE,	  65000000, 48363, 60 },	{ 1328, 1024, 1048, 136, NEGATIVE, 806, 768, 771, 6, NEGATIVE,	  75000000, 56476, 70 },	{ 1312, 1024, 1040,  96, POSITIVE, 800, 768, 769, 3, POSITIVE,	  78750000, 60023, 75 },	{ 1376, 1024, 1072,  96, POSITIVE, 808, 768, 769, 3, POSITIVE,	  94500000, 68677, 85 },	// 1280 x 960	{ 1688, 1280, 1328, 112, POSITIVE, 1000, 960, 962, 3, POSITIVE,	  101000000, 60000, 60 },	// 1280 x 1024	{ 1688, 1280, 1328, 112, POSITIVE, 1066, 1024, 1025, 3, POSITIVE,	  108000000, 63981, 60 },	// End of table.	{ 0, 0, 0, 0, NEGATIVE, 0, 0, 0, 0, NEGATIVE, 0, 0, 0 },*/};GraphicDevice 			sm501;struct SM501STRU		sm501info;static char 			*sm501Reg;static char 			*sm501Mem;u_long regRead32(u_long nOffset){#ifdef SM501_DEBUG 	u_long ret = *(volatile unsigned long *)(sm501Reg+nOffset);	printf("%s: %#lx --> %#lx\n", __FUNCTION__, sm501Reg+nOffset, ret);	return ret;#else	return *(volatile unsigned long *)(sm501Reg+nOffset);#endif}static int error;void regWrite32(u_long nOffset, u_long nData){	u_long readback;#ifdef SM501_DEBUG   	if (nOffset < 0x00080800)		printf("%s: %#lx <-- %#lx\n", __FUNCTION__, nOffset, nData);	*(volatile unsigned long *)(sm501Reg+nOffset) = nData;	readback = *(volatile unsigned long *)(sm501Reg+nOffset);	if (readback != nData)	{		printf("Warning: read value %#lx != %#lx write value, trying again!\n", readback, nData);		error = 1;	}#else	int i=0;	for(;;)	{		*(volatile unsigned long *)(sm501Reg+nOffset) = nData;		readback = *(volatile unsigned long *)(sm501Reg+nOffset);		if (readback == nData)			break;		else			printf("reg = 0x%lx value = 0x%lx!\n", nOffset, nData);		i++;		if(i > 2)				break;	}#endif}void memWrite32(u_long nOffset, u_long nData){#ifdef SM501_DEBUG 	u_long readback;  		//printf("%s: %#lx <-- %#lx\n", __FUNCTION__, nOffset, nData);		*(volatile unsigned long *)(sm501Mem+nOffset) = nData;	readback = *(volatile unsigned long *)(sm501Mem+nOffset);	if (readback != nData)		printf("Warning: %#lx\n", readback);#else	*(volatile unsigned long *)(sm501Mem+nOffset) = nData;//printf("%s: %#lx <-- %#lx\n", __FUNCTION__, nOffset, nData);#endif}// Perform a rounded division.long roundDiv(long num, long denom){	/* n / d + 1 / 2 = (2n + d) / 2d */	return (2 * num + denom) / (2 * denom);}// Finds clock closest to the requested.long findClock(long requested_clock, clock_select_t *clock, display_t display){	long	mclk;	int		divider, shift;	long	best_diff = 999999999;	// Try 288MHz and 336MHz clocks.	for (mclk = 288000000; mclk <= 336000000; mclk += 48000000)	{		// For CRT, try dividers 1 and 3, for panel, try divider 5 as well.		for (divider = 1; divider <= (display == PANEL ? 5 : 3);			 divider += 2)		{			// Try all 8 shift values.			for (shift = 0; shift < 8; shift++)			{				// Calculate difference with requested clock.				long diff = roundDiv(mclk, divider << shift) - requested_clock;				if (diff < 0)				{					diff = -diff;				}				// If the difference is less than the current, use it.				if (diff < best_diff)				{					// Store best difference.					best_diff = diff;					// Store clock values.					clock->mclk = mclk;					clock->divider = divider;					clock->shift = shift;				}			}		}	}	// Return best clock.	return clock->mclk / (clock->divider << clock->shift);}// Fill the register structure.void setModeRegisters(reg_table_t *register_table, mode_table_t *mode, display_t display, int bpp){	clock_select_t clock;	memset(&clock, 0, sizeof(clock));	// Calculate the clock register values.	findClock(mode->pixel_clock * 2, &clock, display);	if (display == PANEL)	{		// Set clock value for panel.		register_table->clock			= (clock.mclk == 288000000				? FIELD_SET(0, CURRENT_POWER_CLOCK, P2XCLK_SELECT, 288)				: FIELD_SET(0, CURRENT_POWER_CLOCK, P2XCLK_SELECT, 336))			| (clock.divider == 1				? FIELD_SET(0, CURRENT_POWER_CLOCK, P2XCLK_DIVIDER, 1)				: (clock.divider == 3					? FIELD_SET(0, CURRENT_POWER_CLOCK, P2XCLK_DIVIDER, 3)					: FIELD_SET(0, CURRENT_POWER_CLOCK, P2XCLK_DIVIDER, 5)))			| FIELD_VALUE(0, CURRENT_POWER_CLOCK, P2XCLK_SHIFT, clock.shift);		// Set control register value.		register_table->control			= (mode->vertical_sync_polarity == POSITIVE				? FIELD_SET(0, PANEL_DISPLAY_CTRL, VSYNC_PHASE, ACTIVE_HIGH)				: FIELD_SET(0, PANEL_DISPLAY_CTRL, VSYNC_PHASE, ACTIVE_LOW))			| (mode->horizontal_sync_polarity == POSITIVE				? FIELD_SET(0, PANEL_DISPLAY_CTRL, HSYNC_PHASE, ACTIVE_HIGH)				: FIELD_SET(0, PANEL_DISPLAY_CTRL, HSYNC_PHASE, ACTIVE_LOW))			| FIELD_SET(0, PANEL_DISPLAY_CTRL, TIMING, ENABLE)			| FIELD_SET(0, PANEL_DISPLAY_CTRL, PLANE, ENABLE)			| (bpp == 8				? FIELD_SET(0, PANEL_DISPLAY_CTRL, FORMAT, 8)				: (bpp == 16					? FIELD_SET(0, PANEL_DISPLAY_CTRL, FORMAT, 16)					: FIELD_SET(0, PANEL_DISPLAY_CTRL, FORMAT, 32)));		// Set timing registers.		register_table->horizontal_total			= FIELD_VALUE(0, PANEL_HORIZONTAL_TOTAL, TOTAL,						  mode->horizontal_total - 1)			| FIELD_VALUE(0, PANEL_HORIZONTAL_TOTAL, DISPLAY_END, 						  mode->horizontal_display_end - 1);		register_table->horizontal_sync			= FIELD_VALUE(0, PANEL_HORIZONTAL_SYNC, WIDTH,						  mode->horizontal_sync_width)			| FIELD_VALUE(0, PANEL_HORIZONTAL_SYNC, START, 						  mode->horizontal_sync_start - 1);		register_table->vertical_total  			= FIELD_VALUE(0, PANEL_VERTICAL_TOTAL, TOTAL, 						  mode->vertical_total - 1)			| FIELD_VALUE(0, PANEL_VERTICAL_TOTAL, DISPLAY_END, 						  mode->vertical_display_end - 1);		register_table->vertical_sync    			= FIELD_VALUE(0, PANEL_VERTICAL_SYNC, HEIGHT, 						  mode->vertical_sync_height)			| FIELD_VALUE(0, PANEL_VERTICAL_SYNC, START, 						  mode->vertical_sync_start - 1);	}	else	{		// Set clock value for CRT.		register_table->clock			= (clock.mclk == 288000000				? FIELD_SET(0, CURRENT_POWER_CLOCK, V2XCLK_SELECT, 288)				: FIELD_SET(0, CURRENT_POWER_CLOCK, V2XCLK_SELECT, 336))			| (clock.divider == 1				? FIELD_SET(0, CURRENT_POWER_CLOCK, V2XCLK_DIVIDER, 1)				: FIELD_SET(0, CURRENT_POWER_CLOCK, V2XCLK_DIVIDER, 3))			| FIELD_VALUE(0, CURRENT_POWER_CLOCK, V2XCLK_SHIFT, clock.shift);		// Set control register value.		register_table->control 			= (mode->vertical_sync_polarity == POSITIVE				? FIELD_SET(0, CRT_DISPLAY_CTRL, VSYNC_PHASE, ACTIVE_HIGH)				: FIELD_SET(0, CRT_DISPLAY_CTRL, VSYNC_PHASE, ACTIVE_LOW))			| (mode->horizontal_sync_polarity == POSITIVE				? FIELD_SET(0, CRT_DISPLAY_CTRL, HSYNC_PHASE, ACTIVE_HIGH)				: FIELD_SET(0, CRT_DISPLAY_CTRL, HSYNC_PHASE, ACTIVE_LOW))			| FIELD_SET(0, CRT_DISPLAY_CTRL, SELECT, CRT)			| FIELD_SET(0, CRT_DISPLAY_CTRL, TIMING, ENABLE)			| FIELD_SET(0, CRT_DISPLAY_CTRL, PLANE, ENABLE)			| (bpp == 8				? FIELD_SET(0, CRT_DISPLAY_CTRL, FORMAT, 8)				: (bpp == 16					? FIELD_SET(0, CRT_DISPLAY_CTRL, FORMAT, 16)					: FIELD_SET(0, CRT_DISPLAY_CTRL, FORMAT, 32)));		// Set timing registers.		register_table->horizontal_total			= FIELD_VALUE(0, CRT_HORIZONTAL_TOTAL, TOTAL, 						  mode->horizontal_total - 1)			| FIELD_VALUE(0, CRT_HORIZONTAL_TOTAL, DISPLAY_END, 						  mode->horizontal_display_end - 1);		register_table->horizontal_sync  			= FIELD_VALUE(0, CRT_HORIZONTAL_SYNC, WIDTH, 						  mode->horizontal_sync_width)			| FIELD_VALUE(0, CRT_HORIZONTAL_SYNC, START, 						  mode->horizontal_sync_start - 1);		register_table->vertical_total   			= FIELD_VALUE(0, CRT_VERTICAL_TOTAL, TOTAL, 						  mode->vertical_total - 1)			| FIELD_VALUE(0, CRT_VERTICAL_TOTAL, DISPLAY_END, 						  mode->vertical_display_end - 1);		register_table->vertical_sync    			= FIELD_VALUE(0, CRT_VERTICAL_SYNC, HEIGHT, 						  mode->vertical_sync_height)			| FIELD_VALUE(0, CRT_VERTICAL_SYNC, START, 						  mode->vertical_sync_start - 1);	}	// Calculate frame buffer width and height.	register_table->fb_width = mode->horizontal_display_end * (bpp / 8);	register_table->width = mode->horizontal_display_end;	register_table->height = mode->vertical_display_end;	// Save display type.	register_table->display = display;}// Program new power mode.void setPower(unsigned long nGates, unsigned long Clock){	unsigned long gate_reg, clock_reg;	unsigned long control_value;

⌨️ 快捷键说明

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