brintos

brintos / linux-shallow public Read only

0
0
Text · 15.2 KiB · 9fde0e3 Raw
601 lines · c
1/*2 *  linux/drivers/video/kyro/STG4000OverlayDevice.c3 *4 *  Copyright (C) 2000 Imagination Technologies Ltd5 *  Copyright (C) 2002 STMicroelectronics6 *7 * This file is subject to the terms and conditions of the GNU General Public8 * License.  See the file COPYING in the main directory of this archive9 * for more details.10 */11 12#include <linux/kernel.h>13#include <linux/errno.h>14#include <linux/types.h>15 16#include "STG4000Reg.h"17#include "STG4000Interface.h"18 19/* HW Defines */20 21#define STG4000_NO_SCALING    0x80022#define STG4000_NO_DECIMATION 0xFFFFFFFF23 24/* Primary surface */25#define STG4000_PRIM_NUM_PIX   526#define STG4000_PRIM_ALIGN     427#define STG4000_PRIM_ADDR_BITS 2028 29#define STG4000_PRIM_MIN_WIDTH  64030#define STG4000_PRIM_MAX_WIDTH  160031#define STG4000_PRIM_MIN_HEIGHT 48032#define STG4000_PRIM_MAX_HEIGHT 120033 34/* Overlay surface */35#define STG4000_OVRL_NUM_PIX   436#define STG4000_OVRL_ALIGN     237#define STG4000_OVRL_ADDR_BITS 2038#define STG4000_OVRL_NUM_MODES 539 40#define STG4000_OVRL_MIN_WIDTH  041#define STG4000_OVRL_MAX_WIDTH  72042#define STG4000_OVRL_MIN_HEIGHT 043#define STG4000_OVRL_MAX_HEIGHT 57644 45/* Decimation and Scaling */46static u32 adwDecim8[33] = {47	    0xffffffff, 0xfffeffff, 0xffdffbff, 0xfefefeff, 0xfdf7efbf,48	    0xfbdf7bdf, 0xf7bbddef, 0xeeeeeeef, 0xeeddbb77, 0xedb76db7,49	    0xdb6db6db, 0xdb5b5b5b, 0xdab5ad6b, 0xd5ab55ab, 0xd555aaab,50	    0xaaaaaaab, 0xaaaa5555, 0xaa952a55, 0xa94a5295, 0xa5252525,51	    0xa4924925, 0x92491249, 0x91224489, 0x91111111, 0x90884211,52	    0x88410821, 0x88102041, 0x81010101, 0x80800801, 0x80010001,53	    0x80000001, 0x00000001, 0x0000000054};55 56typedef struct _OVRL_SRC_DEST {57	/*clipped on-screen pixel position of overlay */58	u32 ulDstX1;59	u32 ulDstY1;60	u32 ulDstX2;61	u32 ulDstY2;62 63	/*clipped pixel pos of source data within buffer thses need to be 128 bit word aligned */64	u32 ulSrcX1;65	u32 ulSrcY1;66	u32 ulSrcX2;67	u32 ulSrcY2;68 69	/* on-screen pixel position of overlay */70	s32 lDstX1;71	s32 lDstY1;72	s32 lDstX2;73	s32 lDstY2;74} OVRL_SRC_DEST;75 76static u32 ovlWidth, ovlHeight, ovlStride;77static int ovlLinear;78 79void ResetOverlayRegisters(volatile STG4000REG __iomem *pSTGReg)80{81	u32 tmp;82 83	/* Set Overlay address to default */84	tmp = STG_READ_REG(DACOverlayAddr);85	CLEAR_BITS_FRM_TO(0, 20);86	CLEAR_BIT(31);87	STG_WRITE_REG(DACOverlayAddr, tmp);88 89	/* Set Overlay U address */90	tmp = STG_READ_REG(DACOverlayUAddr);91	CLEAR_BITS_FRM_TO(0, 20);92	STG_WRITE_REG(DACOverlayUAddr, tmp);93 94	/* Set Overlay V address */95	tmp = STG_READ_REG(DACOverlayVAddr);96	CLEAR_BITS_FRM_TO(0, 20);97	STG_WRITE_REG(DACOverlayVAddr, tmp);98 99	/* Set Overlay Size */100	tmp = STG_READ_REG(DACOverlaySize);101	CLEAR_BITS_FRM_TO(0, 10);102	CLEAR_BITS_FRM_TO(12, 31);103	STG_WRITE_REG(DACOverlaySize, tmp);104 105	/* Set Overlay Vt Decimation */106	tmp = STG4000_NO_DECIMATION;107	STG_WRITE_REG(DACOverlayVtDec, tmp);108 109	/* Set Overlay format to default value */110	tmp = STG_READ_REG(DACPixelFormat);111	CLEAR_BITS_FRM_TO(4, 7);112	CLEAR_BITS_FRM_TO(16, 22);113	STG_WRITE_REG(DACPixelFormat, tmp);114 115	/* Set Vertical scaling to default */116	tmp = STG_READ_REG(DACVerticalScal);117	CLEAR_BITS_FRM_TO(0, 11);118	CLEAR_BITS_FRM_TO(16, 22);119	tmp |= STG4000_NO_SCALING;	/* Set to no scaling */120	STG_WRITE_REG(DACVerticalScal, tmp);121 122	/* Set Horizontal Scaling to default */123	tmp = STG_READ_REG(DACHorizontalScal);124	CLEAR_BITS_FRM_TO(0, 11);125	CLEAR_BITS_FRM_TO(16, 17);126	tmp |= STG4000_NO_SCALING;	/* Set to no scaling */127	STG_WRITE_REG(DACHorizontalScal, tmp);128 129	/* Set Blend mode to Alpha Blend */130	/* ????? SG 08/11/2001 Surely this isn't the alpha blend mode,131	   hopefully its overwrite132	 */133	tmp = STG_READ_REG(DACBlendCtrl);134	CLEAR_BITS_FRM_TO(0, 30);135	tmp = (GRAPHICS_MODE << 28);136	STG_WRITE_REG(DACBlendCtrl, tmp);137 138}139 140int CreateOverlaySurface(volatile STG4000REG __iomem *pSTGReg,141			 u32 inWidth,142			 u32 inHeight,143			 int bLinear,144			 u32 ulOverlayOffset,145			 u32 * retStride, u32 * retUVStride)146{147	u32 tmp;148	u32 ulStride;149 150	if (inWidth > STG4000_OVRL_MAX_WIDTH ||151	    inHeight > STG4000_OVRL_MAX_HEIGHT) {152		return -EINVAL;153	}154 155	/* Stride in 16 byte words - 16Bpp */156	if (bLinear) {157		/* Format is 16bits so num 16 byte words is width/8 */158		if ((inWidth & 0x7) == 0) {	/* inWidth % 8 */159			ulStride = (inWidth / 8);160		} else {161			/* Round up to next 16byte boundary */162			ulStride = ((inWidth + 8) / 8);163		}164	} else {165		/* Y component is 8bits so num 16 byte words is width/16 */166		if ((inWidth & 0xf) == 0) {	/* inWidth % 16 */167			ulStride = (inWidth / 16);168		} else {169			/* Round up to next 16byte boundary */170			ulStride = ((inWidth + 16) / 16);171		}172	}173 174 175	/* Set Overlay address and Format mode */176	tmp = STG_READ_REG(DACOverlayAddr);177	CLEAR_BITS_FRM_TO(0, 20);178	if (bLinear) {179		CLEAR_BIT(31);	/* Overlay format to Linear */180	} else {181		tmp |= SET_BIT(31);	/* Overlay format to Planer */182	}183 184	/* Only bits 24:4 of the Overlay address */185	tmp |= (ulOverlayOffset >> 4);186	STG_WRITE_REG(DACOverlayAddr, tmp);187 188	if (!bLinear) {189		u32 uvSize =190		    (inWidth & 0x1) ? (inWidth + 1 / 2) : (inWidth / 2);191		u32 uvStride;192		u32 ulOffset;193		/* Y component is 8bits so num 32 byte words is width/32 */194		if ((uvSize & 0xf) == 0) {	/* inWidth % 16 */195			uvStride = (uvSize / 16);196		} else {197			/* Round up to next 32byte boundary */198			uvStride = ((uvSize + 16) / 16);199		}200 201		ulOffset = ulOverlayOffset + (inHeight * (ulStride * 16));202		/* Align U,V data to 32byte boundary */203		if ((ulOffset & 0x1f) != 0)204			ulOffset = (ulOffset + 32L) & 0xffffffE0L;205 206		tmp = STG_READ_REG(DACOverlayUAddr);207		CLEAR_BITS_FRM_TO(0, 20);208		tmp |= (ulOffset >> 4);209		STG_WRITE_REG(DACOverlayUAddr, tmp);210 211		ulOffset += (inHeight / 2) * (uvStride * 16);212		/* Align U,V data to 32byte boundary */213		if ((ulOffset & 0x1f) != 0)214			ulOffset = (ulOffset + 32L) & 0xffffffE0L;215 216		tmp = STG_READ_REG(DACOverlayVAddr);217		CLEAR_BITS_FRM_TO(0, 20);218		tmp |= (ulOffset >> 4);219		STG_WRITE_REG(DACOverlayVAddr, tmp);220 221		*retUVStride = uvStride * 16;222	}223 224 225	/* Set Overlay YUV pixel format226	 * Make sure that LUT not used - ??????227	 */228	tmp = STG_READ_REG(DACPixelFormat);229	/* Only support Planer or UYVY linear formats */230	CLEAR_BITS_FRM_TO(4, 9);231	STG_WRITE_REG(DACPixelFormat, tmp);232 233	ovlWidth = inWidth;234	ovlHeight = inHeight;235	ovlStride = ulStride;236	ovlLinear = bLinear;237	*retStride = ulStride << 4;	/* In bytes */238 239	return 0;240}241 242int SetOverlayBlendMode(volatile STG4000REG __iomem *pSTGReg,243			OVRL_BLEND_MODE mode,244			u32 ulAlpha, u32 ulColorKey)245{246	u32 tmp;247 248	tmp = STG_READ_REG(DACBlendCtrl);249	CLEAR_BITS_FRM_TO(28, 30);250	tmp |= (mode << 28);251 252	switch (mode) {253	case COLOR_KEY:254		CLEAR_BITS_FRM_TO(0, 23);255		tmp |= (ulColorKey & 0x00FFFFFF);256		break;257 258	case GLOBAL_ALPHA:259		CLEAR_BITS_FRM_TO(24, 27);260		tmp |= ((ulAlpha & 0xF) << 24);261		break;262 263	case CK_PIXEL_ALPHA:264		CLEAR_BITS_FRM_TO(0, 23);265		tmp |= (ulColorKey & 0x00FFFFFF);266		break;267 268	case CK_GLOBAL_ALPHA:269		CLEAR_BITS_FRM_TO(0, 23);270		tmp |= (ulColorKey & 0x00FFFFFF);271		CLEAR_BITS_FRM_TO(24, 27);272		tmp |= ((ulAlpha & 0xF) << 24);273		break;274 275	case GRAPHICS_MODE:276	case PER_PIXEL_ALPHA:277		break;278 279	default:280		return -EINVAL;281	}282 283	STG_WRITE_REG(DACBlendCtrl, tmp);284 285	return 0;286}287 288void EnableOverlayPlane(volatile STG4000REG __iomem *pSTGReg)289{290	u32 tmp;291	/* Enable Overlay */292	tmp = STG_READ_REG(DACPixelFormat);293	tmp |= SET_BIT(7);294	STG_WRITE_REG(DACPixelFormat, tmp);295 296	/* Set video stream control */297	tmp = STG_READ_REG(DACStreamCtrl);298	tmp |= SET_BIT(1);	/* video stream */299	STG_WRITE_REG(DACStreamCtrl, tmp);300}301 302static u32 Overlap(u32 ulBits, u32 ulPattern)303{304	u32 ulCount = 0;305 306	while (ulBits) {307		if (!(ulPattern & 1))308			ulCount++;309		ulBits--;310		ulPattern = ulPattern >> 1;311	}312 313	return ulCount;314 315}316 317int SetOverlayViewPort(volatile STG4000REG __iomem *pSTGReg,318		       u32 left, u32 top,319		       u32 right, u32 bottom)320{321	OVRL_SRC_DEST srcDest;322 323	u32 ulSrcTop, ulSrcBottom;324	u32 ulSrc, ulDest;325	u32 ulFxScale, ulFxOffset;326	u32 ulHeight, ulWidth;327	u32 ulPattern;328	u32 ulDecimate, ulDecimated;329	u32 ulApplied;330	u32 ulDacXScale, ulDacYScale;331	u32 ulScale;332	u32 ulLeft, ulRight;333	u32 ulSrcLeft, ulSrcRight;334	u32 ulScaleLeft;335	u32 ulhDecim;336	u32 ulsVal;337	u32 ulVertDecFactor;338	int bResult;339	u32 ulClipOff = 0;340	u32 ulBits = 0;341	u32 ulsAdd = 0;342	u32 tmp, ulStride;343	u32 ulExcessPixels, ulClip, ulExtraLines;344 345 346	srcDest.ulSrcX1 = 0;347	srcDest.ulSrcY1 = 0;348	srcDest.ulSrcX2 = ovlWidth - 1;349	srcDest.ulSrcY2 = ovlHeight - 1;350 351	srcDest.ulDstX1 = left;352	srcDest.ulDstY1 = top;353	srcDest.ulDstX2 = right;354	srcDest.ulDstY2 = bottom;355 356	srcDest.lDstX1 = srcDest.ulDstX1;357	srcDest.lDstY1 = srcDest.ulDstY1;358	srcDest.lDstX2 = srcDest.ulDstX2;359	srcDest.lDstY2 = srcDest.ulDstY2;360 361    /************* Vertical decimation/scaling ******************/362 363	/* Get Src Top and Bottom */364	ulSrcTop = srcDest.ulSrcY1;365	ulSrcBottom = srcDest.ulSrcY2;366 367	ulSrc = ulSrcBottom - ulSrcTop;368	ulDest = srcDest.lDstY2 - srcDest.lDstY1;	/* on-screen overlay */369 370	if (ulSrc <= 1)371		return -EINVAL;372 373	/* First work out the position we are to display as offset from the374	 * source of the buffer375	 */376	ulFxScale = (ulDest << 11) / ulSrc;	/* fixed point scale factor */377	ulFxOffset = (srcDest.lDstY2 - srcDest.ulDstY2) << 11;378 379	ulSrcBottom = ulSrcBottom - (ulFxOffset / ulFxScale);380	ulSrc = ulSrcBottom - ulSrcTop;381	ulHeight = ulSrc;382 383	ulDest = srcDest.ulDstY2 - (srcDest.ulDstY1 - 1);384	ulPattern = adwDecim8[ulBits];385 386	/* At this point ulSrc represents the input decimator */387	if (ulSrc > ulDest) {388		ulDecimate = ulSrc - ulDest;389		ulBits = 0;390		ulApplied = ulSrc / 32;391 392		while (((ulBits * ulApplied) +393			Overlap((ulSrc % 32),394				adwDecim8[ulBits])) < ulDecimate)395			ulBits++;396 397		ulPattern = adwDecim8[ulBits];398		ulDecimated =399		    (ulBits * ulApplied) + Overlap((ulSrc % 32),400						   ulPattern);401		ulSrc = ulSrc - ulDecimated;	/* the number number of lines that will go into the scaler */402	}403 404	if (ulBits && (ulBits != 32)) {405		ulVertDecFactor = (63 - ulBits) / (32 - ulBits);	/* vertical decimation factor scaled up to nearest integer */406	} else {407		ulVertDecFactor = 1;408	}409 410	ulDacYScale = ((ulSrc - 1) * 2048) / (ulDest + 1);411 412	tmp = STG_READ_REG(DACOverlayVtDec);	/* Decimation */413	CLEAR_BITS_FRM_TO(0, 31);414	tmp = ulPattern;415	STG_WRITE_REG(DACOverlayVtDec, tmp);416 417	/***************** Horizontal decimation/scaling ***************************/418 419	/*420	 * Now we handle the horizontal case, this is a simplified version of421	 * the vertical case in that we decimate by factors of 2.  as we are422	 * working in words we should always be able to decimate by these423	 * factors.  as we always have to have a buffer which is aligned to a424	 * whole number of 128 bit words, we must align the left side to the425	 * lowest to the next lowest 128 bit boundary, and the right hand edge426	 * to the next largets boundary, (in a similar way to how we didi it in427	 * PMX1) as the left and right hand edges are aligned to these428	 * boundaries normally this only becomes an issue when we are chopping429	 * of one of the sides We shall work out vertical stuff first430	 */431	ulSrc = srcDest.ulSrcX2 - srcDest.ulSrcX1;432	ulDest = srcDest.lDstX2 - srcDest.lDstX1;433#ifdef _OLDCODE434	ulLeft = srcDest.ulDstX1;435	ulRight = srcDest.ulDstX2;436#else437	if (srcDest.ulDstX1 > 2) {438		ulLeft = srcDest.ulDstX1 + 2;439		ulRight = srcDest.ulDstX2 + 1;440	} else {441		ulLeft = srcDest.ulDstX1;442		ulRight = srcDest.ulDstX2 + 1;443	}444#endif445	/* first work out the position we are to display as offset from the source of the buffer */446	bResult = 1;447 448	do {449		if (ulDest == 0)450			return -EINVAL;451 452		/* source pixels per dest pixel <<11 */453		ulFxScale = ((ulSrc - 1) << 11) / (ulDest);454 455		/* then number of destination pixels out we are */456		ulFxOffset = ulFxScale * ((srcDest.ulDstX1 - srcDest.lDstX1) + ulClipOff);457		ulFxOffset >>= 11;458 459		/* this replaces the code which was making a decision as to use either ulFxOffset or ulSrcX1 */460		ulSrcLeft = srcDest.ulSrcX1 + ulFxOffset;461 462		/* then number of destination pixels out we are */463		ulFxOffset = ulFxScale * (srcDest.lDstX2 - srcDest.ulDstX2);464		ulFxOffset >>= 11;465 466		ulSrcRight = srcDest.ulSrcX2 - ulFxOffset;467 468		/*469		 * we must align these to our 128 bit boundaries. we shall470		 * round down the pixel pos to the nearest 8 pixels.471		 */472		ulScaleLeft = ulSrcLeft;473 474		/* shift fxscale until it is in the range of the scaler */475		ulhDecim = 0;476		ulScale = (((ulSrcRight - ulSrcLeft) - 1) << (11 - ulhDecim)) / (ulRight - ulLeft + 2);477 478		while (ulScale > 0x800) {479			ulhDecim++;480			ulScale = (((ulSrcRight - ulSrcLeft) - 1) << (11 - ulhDecim)) / (ulRight - ulLeft + 2);481		}482 483		/*484		 * to try and get the best values We first try and use485		 * src/dwdest for the scale factor, then we move onto src-1486		 *487		 * we want to check to see if we will need to clip data, if so488		 * then we should clip our source so that we don't need to489		 */490		if (!ovlLinear) {491			ulSrcLeft &= ~0x1f;492 493			/*494			 * we must align the right hand edge to the next 32495			 * pixel` boundary, must be on a 256 boundary so u, and496			 * v are 128 bit aligned497			 */498			ulSrcRight = (ulSrcRight + 0x1f) & ~0x1f;499		} else {500			ulSrcLeft &= ~0x7;501 502			/*503			 * we must align the right hand edge to the next504			 * 8pixel` boundary505			 */506			ulSrcRight = (ulSrcRight + 0x7) & ~0x7;507		}508 509		/* this is the input size line store needs to cope with */510		ulWidth = ulSrcRight - ulSrcLeft;511 512		/*513		 * use unclipped value to work out scale factror this is the514		 * scale factor we want we shall now work out the horizonal515		 * decimation and scaling516		 */517		ulsVal = ((ulWidth / 8) >> ulhDecim);518 519		if ((ulWidth != (ulsVal << ulhDecim) * 8))520			ulsAdd = 1;521 522		/* input pixels to scaler; */523		ulSrc = ulWidth >> ulhDecim;524 525		if (ulSrc <= 2)526			return -EINVAL;527 528		ulExcessPixels = ((((ulScaleLeft - ulSrcLeft)) << (11 - ulhDecim)) / ulScale);529 530		ulClip = (ulSrc << 11) / ulScale;531		ulClip -= (ulRight - ulLeft);532		ulClip += ulExcessPixels;533 534		if (ulClip)535			ulClip--;536 537		/* We may need to do more here if we really have a HW rev < 5 */538	} while (!bResult);539 540	ulExtraLines = (1 << ulhDecim) * ulVertDecFactor;541	ulExtraLines += 64;542	ulHeight += ulExtraLines;543 544	ulDacXScale = ulScale;545 546 547	tmp = STG_READ_REG(DACVerticalScal);548	CLEAR_BITS_FRM_TO(0, 11);549	CLEAR_BITS_FRM_TO(16, 22);	/* Vertical Scaling */550 551	/* Calculate new output line stride, this is always the number of 422552	   words in the line buffer, so it doesn't matter if the553	   mode is 420. Then set the vertical scale register.554	 */555	ulStride = (ulWidth >> (ulhDecim + 3)) + ulsAdd;556	tmp |= ((ulStride << 16) | (ulDacYScale));	/* DAC_LS_CTRL = stride */557	STG_WRITE_REG(DACVerticalScal, tmp);558 559	/* Now set up the overlay size using the modified width and height560	   from decimate and scaling calculations561	 */562	tmp = STG_READ_REG(DACOverlaySize);563	CLEAR_BITS_FRM_TO(0, 10);564	CLEAR_BITS_FRM_TO(12, 31);565 566	if (ovlLinear) {567		tmp |=568		    (ovlStride | ((ulHeight + 1) << 12) |569		     (((ulWidth / 8) - 1) << 23));570	} else {571		tmp |=572		    (ovlStride | ((ulHeight + 1) << 12) |573		     (((ulWidth / 32) - 1) << 23));574	}575 576	STG_WRITE_REG(DACOverlaySize, tmp);577 578	/* Set Video Window Start */579	tmp = ((ulLeft << 16)) | (srcDest.ulDstY1);580	STG_WRITE_REG(DACVidWinStart, tmp);581 582	/* Set Video Window End */583	tmp = ((ulRight) << 16) | (srcDest.ulDstY2);584	STG_WRITE_REG(DACVidWinEnd, tmp);585 586	/* Finally set up the rest of the overlay regs in the order587	   done in the IMG driver588	 */589	tmp = STG_READ_REG(DACPixelFormat);590	tmp = ((ulExcessPixels << 16) | tmp) & 0x7fffffff;591	STG_WRITE_REG(DACPixelFormat, tmp);592 593	tmp = STG_READ_REG(DACHorizontalScal);594	CLEAR_BITS_FRM_TO(0, 11);595	CLEAR_BITS_FRM_TO(16, 17);596	tmp |= ((ulhDecim << 16) | (ulDacXScale));597	STG_WRITE_REG(DACHorizontalScal, tmp);598 599	return 0;600}601