| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
 | 2 |  *  linux/drivers/video/kyro/STG4000OverlayDevice.c | 
 | 3 |  * | 
 | 4 |  *  Copyright (C) 2000 Imagination Technologies Ltd | 
 | 5 |  *  Copyright (C) 2002 STMicroelectronics | 
 | 6 |  * | 
 | 7 |  * This file is subject to the terms and conditions of the GNU General Public | 
 | 8 |  * License.  See the file COPYING in the main directory of this archive | 
 | 9 |  * 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" | 
| Adrian Bunk | a0aa7d0 | 2006-01-09 20:54:04 -0800 | [diff] [blame] | 17 | #include "STG4000Interface.h" | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 18 |  | 
 | 19 | /* HW Defines */ | 
 | 20 |  | 
 | 21 | #define STG4000_NO_SCALING    0x800 | 
 | 22 | #define STG4000_NO_DECIMATION 0xFFFFFFFF | 
 | 23 |  | 
 | 24 | /* Primary surface */ | 
 | 25 | #define STG4000_PRIM_NUM_PIX   5 | 
 | 26 | #define STG4000_PRIM_ALIGN     4 | 
 | 27 | #define STG4000_PRIM_ADDR_BITS 20 | 
 | 28 |  | 
 | 29 | #define STG4000_PRIM_MIN_WIDTH  640 | 
 | 30 | #define STG4000_PRIM_MAX_WIDTH  1600 | 
 | 31 | #define STG4000_PRIM_MIN_HEIGHT 480 | 
 | 32 | #define STG4000_PRIM_MAX_HEIGHT 1200 | 
 | 33 |  | 
 | 34 | /* Overlay surface */ | 
 | 35 | #define STG4000_OVRL_NUM_PIX   4 | 
 | 36 | #define STG4000_OVRL_ALIGN     2 | 
 | 37 | #define STG4000_OVRL_ADDR_BITS 20 | 
 | 38 | #define STG4000_OVRL_NUM_MODES 5 | 
 | 39 |  | 
 | 40 | #define STG4000_OVRL_MIN_WIDTH  0 | 
 | 41 | #define STG4000_OVRL_MAX_WIDTH  720 | 
 | 42 | #define STG4000_OVRL_MIN_HEIGHT 0 | 
 | 43 | #define STG4000_OVRL_MAX_HEIGHT 576 | 
 | 44 |  | 
 | 45 | /* Decimation and Scaling */ | 
 | 46 | static 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, 0x00000000 | 
 | 54 | }; | 
 | 55 |  | 
 | 56 | typedef 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 |  | 
 | 76 | static u32 ovlWidth, ovlHeight, ovlStride; | 
 | 77 | static int ovlLinear; | 
 | 78 |  | 
 | 79 | void 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 overwrite | 
 | 132 | 	 */ | 
 | 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 |  | 
 | 140 | int 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 format | 
 | 226 | 	 * 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 |  | 
 | 242 | int 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 |  | 
 | 288 | void 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 |  | 
 | 302 | static 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 |  | 
 | 317 | int 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, ulScaleRight; | 
 | 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 the | 
 | 374 | 	 * source of the buffer | 
 | 375 | 	 */ | 
 | 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 | 	/* | 
| Lucas De Marchi | 25985ed | 2011-03-30 22:57:33 -0300 | [diff] [blame] | 420 | 	 * Now we handle the horizontal case, this is a simplified version of | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 421 | 	 * the vertical case in that we decimate by factors of 2.  as we are | 
 | 422 | 	 * working in words we should always be able to decimate by these | 
 | 423 | 	 * factors.  as we always have to have a buffer which is aligned to a | 
 | 424 | 	 * whole number of 128 bit words, we must align the left side to the | 
 | 425 | 	 * lowest to the next lowest 128 bit boundary, and the right hand edge | 
 | 426 | 	 * to the next largets boundary, (in a similar way to how we didi it in | 
 | 427 | 	 * PMX1) as the left and right hand edges are aligned to these | 
 | 428 | 	 * boundaries normally this only becomes an issue when we are chopping | 
 | 429 | 	 * of one of the sides We shall work out vertical stuff first | 
 | 430 | 	 */ | 
 | 431 | 	ulSrc = srcDest.ulSrcX2 - srcDest.ulSrcX1; | 
 | 432 | 	ulDest = srcDest.lDstX2 - srcDest.lDstX1; | 
 | 433 | #ifdef _OLDCODE | 
 | 434 | 	ulLeft = srcDest.ulDstX1; | 
 | 435 | 	ulRight = srcDest.ulDstX2; | 
 | 436 | #else | 
 | 437 | 	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 | #endif | 
 | 445 | 	/* 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 shall | 
 | 470 | 		 * round down the pixel pos to the nearest 8 pixels. | 
 | 471 | 		 */ | 
 | 472 | 		ulScaleLeft = ulSrcLeft; | 
 | 473 | 		ulScaleRight = ulSrcRight; | 
 | 474 |  | 
 | 475 | 		/* shift fxscale until it is in the range of the scaler */ | 
 | 476 | 		ulhDecim = 0; | 
 | 477 | 		ulScale = (((ulSrcRight - ulSrcLeft) - 1) << (11 - ulhDecim)) / (ulRight - ulLeft + 2); | 
 | 478 |  | 
 | 479 | 		while (ulScale > 0x800) { | 
 | 480 | 			ulhDecim++; | 
 | 481 | 			ulScale = (((ulSrcRight - ulSrcLeft) - 1) << (11 - ulhDecim)) / (ulRight - ulLeft + 2); | 
 | 482 | 		} | 
 | 483 |  | 
 | 484 | 		/* | 
 | 485 | 		 * to try and get the best values We first try and use | 
 | 486 | 		 * src/dwdest for the scale factor, then we move onto src-1 | 
 | 487 | 		 * | 
 | 488 | 		 * we want to check to see if we will need to clip data, if so | 
 | 489 | 		 * then we should clip our source so that we don't need to | 
 | 490 | 		 */ | 
 | 491 | 		if (!ovlLinear) { | 
 | 492 | 			ulSrcLeft &= ~0x1f; | 
 | 493 |  | 
 | 494 | 			/* | 
 | 495 | 			 * we must align the right hand edge to the next 32 | 
 | 496 | 			 * pixel` boundary, must be on a 256 boundary so u, and | 
 | 497 | 			 * v are 128 bit aligned | 
 | 498 | 			 */ | 
 | 499 | 			ulSrcRight = (ulSrcRight + 0x1f) & ~0x1f; | 
 | 500 | 		} else { | 
 | 501 | 			ulSrcLeft &= ~0x7; | 
 | 502 |  | 
 | 503 | 			/* | 
 | 504 | 			 * we must align the right hand edge to the next | 
 | 505 | 			 * 8pixel` boundary | 
 | 506 | 			 */ | 
 | 507 | 			ulSrcRight = (ulSrcRight + 0x7) & ~0x7; | 
 | 508 | 		} | 
 | 509 |  | 
 | 510 | 		/* this is the input size line store needs to cope with */ | 
 | 511 | 		ulWidth = ulSrcRight - ulSrcLeft; | 
 | 512 |  | 
 | 513 | 		/* | 
 | 514 | 		 * use unclipped value to work out scale factror this is the | 
 | 515 | 		 * scale factor we want we shall now work out the horizonal | 
 | 516 | 		 * decimation and scaling | 
 | 517 | 		 */ | 
 | 518 | 		ulsVal = ((ulWidth / 8) >> ulhDecim); | 
 | 519 |  | 
 | 520 | 		if ((ulWidth != (ulsVal << ulhDecim) * 8)) | 
 | 521 | 			ulsAdd = 1; | 
 | 522 |  | 
 | 523 | 		/* input pixels to scaler; */ | 
 | 524 | 		ulSrc = ulWidth >> ulhDecim; | 
 | 525 |  | 
 | 526 | 		if (ulSrc <= 2) | 
 | 527 | 			return -EINVAL; | 
 | 528 |  | 
 | 529 | 		ulExcessPixels = ((((ulScaleLeft - ulSrcLeft)) << (11 - ulhDecim)) / ulScale); | 
 | 530 |  | 
 | 531 | 		ulClip = (ulSrc << 11) / ulScale; | 
 | 532 | 		ulClip -= (ulRight - ulLeft); | 
 | 533 | 		ulClip += ulExcessPixels; | 
 | 534 |  | 
 | 535 | 		if (ulClip) | 
 | 536 | 			ulClip--; | 
 | 537 |  | 
 | 538 | 		/* We may need to do more here if we really have a HW rev < 5 */ | 
 | 539 | 	} while (!bResult); | 
 | 540 |  | 
 | 541 | 	ulExtraLines = (1 << ulhDecim) * ulVertDecFactor; | 
 | 542 | 	ulExtraLines += 64; | 
 | 543 | 	ulHeight += ulExtraLines; | 
 | 544 |  | 
 | 545 | 	ulDacXScale = ulScale; | 
 | 546 |  | 
 | 547 |  | 
 | 548 | 	tmp = STG_READ_REG(DACVerticalScal); | 
 | 549 | 	CLEAR_BITS_FRM_TO(0, 11); | 
 | 550 | 	CLEAR_BITS_FRM_TO(16, 22);	/* Vertical Scaling */ | 
 | 551 |  | 
 | 552 | 	/* Calculate new output line stride, this is always the number of 422 | 
 | 553 | 	   words in the line buffer, so it doesn't matter if the | 
 | 554 | 	   mode is 420. Then set the vertical scale register. | 
 | 555 | 	 */ | 
 | 556 | 	ulStride = (ulWidth >> (ulhDecim + 3)) + ulsAdd; | 
 | 557 | 	tmp |= ((ulStride << 16) | (ulDacYScale));	/* DAC_LS_CTRL = stride */ | 
 | 558 | 	STG_WRITE_REG(DACVerticalScal, tmp); | 
 | 559 |  | 
 | 560 | 	/* Now set up the overlay size using the modified width and height | 
 | 561 | 	   from decimate and scaling calculations | 
 | 562 | 	 */ | 
 | 563 | 	tmp = STG_READ_REG(DACOverlaySize); | 
 | 564 | 	CLEAR_BITS_FRM_TO(0, 10); | 
 | 565 | 	CLEAR_BITS_FRM_TO(12, 31); | 
 | 566 |  | 
 | 567 | 	if (ovlLinear) { | 
 | 568 | 		tmp |= | 
 | 569 | 		    (ovlStride | ((ulHeight + 1) << 12) | | 
 | 570 | 		     (((ulWidth / 8) - 1) << 23)); | 
 | 571 | 	} else { | 
 | 572 | 		tmp |= | 
 | 573 | 		    (ovlStride | ((ulHeight + 1) << 12) | | 
 | 574 | 		     (((ulWidth / 32) - 1) << 23)); | 
 | 575 | 	} | 
 | 576 |  | 
 | 577 | 	STG_WRITE_REG(DACOverlaySize, tmp); | 
 | 578 |  | 
 | 579 | 	/* Set Video Window Start */ | 
 | 580 | 	tmp = ((ulLeft << 16)) | (srcDest.ulDstY1); | 
 | 581 | 	STG_WRITE_REG(DACVidWinStart, tmp); | 
 | 582 |  | 
 | 583 | 	/* Set Video Window End */ | 
 | 584 | 	tmp = ((ulRight) << 16) | (srcDest.ulDstY2); | 
 | 585 | 	STG_WRITE_REG(DACVidWinEnd, tmp); | 
 | 586 |  | 
 | 587 | 	/* Finally set up the rest of the overlay regs in the order | 
 | 588 | 	   done in the IMG driver | 
 | 589 | 	 */ | 
 | 590 | 	tmp = STG_READ_REG(DACPixelFormat); | 
 | 591 | 	tmp = ((ulExcessPixels << 16) | tmp) & 0x7fffffff; | 
 | 592 | 	STG_WRITE_REG(DACPixelFormat, tmp); | 
 | 593 |  | 
 | 594 | 	tmp = STG_READ_REG(DACHorizontalScal); | 
 | 595 | 	CLEAR_BITS_FRM_TO(0, 11); | 
 | 596 | 	CLEAR_BITS_FRM_TO(16, 17); | 
 | 597 | 	tmp |= ((ulhDecim << 16) | (ulDacXScale)); | 
 | 598 | 	STG_WRITE_REG(DACHorizontalScal, tmp); | 
 | 599 |  | 
 | 600 | 	return 0; | 
 | 601 | } |