162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci *  linux/drivers/video/kyro/STG4000OverlayDevice.c
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci *  Copyright (C) 2000 Imagination Technologies Ltd
562306a36Sopenharmony_ci *  Copyright (C) 2002 STMicroelectronics
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
862306a36Sopenharmony_ci * License.  See the file COPYING in the main directory of this archive
962306a36Sopenharmony_ci * for more details.
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <linux/kernel.h>
1362306a36Sopenharmony_ci#include <linux/errno.h>
1462306a36Sopenharmony_ci#include <linux/types.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include "STG4000Reg.h"
1762306a36Sopenharmony_ci#include "STG4000Interface.h"
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci/* HW Defines */
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#define STG4000_NO_SCALING    0x800
2262306a36Sopenharmony_ci#define STG4000_NO_DECIMATION 0xFFFFFFFF
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci/* Primary surface */
2562306a36Sopenharmony_ci#define STG4000_PRIM_NUM_PIX   5
2662306a36Sopenharmony_ci#define STG4000_PRIM_ALIGN     4
2762306a36Sopenharmony_ci#define STG4000_PRIM_ADDR_BITS 20
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#define STG4000_PRIM_MIN_WIDTH  640
3062306a36Sopenharmony_ci#define STG4000_PRIM_MAX_WIDTH  1600
3162306a36Sopenharmony_ci#define STG4000_PRIM_MIN_HEIGHT 480
3262306a36Sopenharmony_ci#define STG4000_PRIM_MAX_HEIGHT 1200
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci/* Overlay surface */
3562306a36Sopenharmony_ci#define STG4000_OVRL_NUM_PIX   4
3662306a36Sopenharmony_ci#define STG4000_OVRL_ALIGN     2
3762306a36Sopenharmony_ci#define STG4000_OVRL_ADDR_BITS 20
3862306a36Sopenharmony_ci#define STG4000_OVRL_NUM_MODES 5
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#define STG4000_OVRL_MIN_WIDTH  0
4162306a36Sopenharmony_ci#define STG4000_OVRL_MAX_WIDTH  720
4262306a36Sopenharmony_ci#define STG4000_OVRL_MIN_HEIGHT 0
4362306a36Sopenharmony_ci#define STG4000_OVRL_MAX_HEIGHT 576
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci/* Decimation and Scaling */
4662306a36Sopenharmony_cistatic u32 adwDecim8[33] = {
4762306a36Sopenharmony_ci	    0xffffffff, 0xfffeffff, 0xffdffbff, 0xfefefeff, 0xfdf7efbf,
4862306a36Sopenharmony_ci	    0xfbdf7bdf, 0xf7bbddef, 0xeeeeeeef, 0xeeddbb77, 0xedb76db7,
4962306a36Sopenharmony_ci	    0xdb6db6db, 0xdb5b5b5b, 0xdab5ad6b, 0xd5ab55ab, 0xd555aaab,
5062306a36Sopenharmony_ci	    0xaaaaaaab, 0xaaaa5555, 0xaa952a55, 0xa94a5295, 0xa5252525,
5162306a36Sopenharmony_ci	    0xa4924925, 0x92491249, 0x91224489, 0x91111111, 0x90884211,
5262306a36Sopenharmony_ci	    0x88410821, 0x88102041, 0x81010101, 0x80800801, 0x80010001,
5362306a36Sopenharmony_ci	    0x80000001, 0x00000001, 0x00000000
5462306a36Sopenharmony_ci};
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_citypedef struct _OVRL_SRC_DEST {
5762306a36Sopenharmony_ci	/*clipped on-screen pixel position of overlay */
5862306a36Sopenharmony_ci	u32 ulDstX1;
5962306a36Sopenharmony_ci	u32 ulDstY1;
6062306a36Sopenharmony_ci	u32 ulDstX2;
6162306a36Sopenharmony_ci	u32 ulDstY2;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	/*clipped pixel pos of source data within buffer thses need to be 128 bit word aligned */
6462306a36Sopenharmony_ci	u32 ulSrcX1;
6562306a36Sopenharmony_ci	u32 ulSrcY1;
6662306a36Sopenharmony_ci	u32 ulSrcX2;
6762306a36Sopenharmony_ci	u32 ulSrcY2;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	/* on-screen pixel position of overlay */
7062306a36Sopenharmony_ci	s32 lDstX1;
7162306a36Sopenharmony_ci	s32 lDstY1;
7262306a36Sopenharmony_ci	s32 lDstX2;
7362306a36Sopenharmony_ci	s32 lDstY2;
7462306a36Sopenharmony_ci} OVRL_SRC_DEST;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_cistatic u32 ovlWidth, ovlHeight, ovlStride;
7762306a36Sopenharmony_cistatic int ovlLinear;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_civoid ResetOverlayRegisters(volatile STG4000REG __iomem *pSTGReg)
8062306a36Sopenharmony_ci{
8162306a36Sopenharmony_ci	u32 tmp;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	/* Set Overlay address to default */
8462306a36Sopenharmony_ci	tmp = STG_READ_REG(DACOverlayAddr);
8562306a36Sopenharmony_ci	CLEAR_BITS_FRM_TO(0, 20);
8662306a36Sopenharmony_ci	CLEAR_BIT(31);
8762306a36Sopenharmony_ci	STG_WRITE_REG(DACOverlayAddr, tmp);
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	/* Set Overlay U address */
9062306a36Sopenharmony_ci	tmp = STG_READ_REG(DACOverlayUAddr);
9162306a36Sopenharmony_ci	CLEAR_BITS_FRM_TO(0, 20);
9262306a36Sopenharmony_ci	STG_WRITE_REG(DACOverlayUAddr, tmp);
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	/* Set Overlay V address */
9562306a36Sopenharmony_ci	tmp = STG_READ_REG(DACOverlayVAddr);
9662306a36Sopenharmony_ci	CLEAR_BITS_FRM_TO(0, 20);
9762306a36Sopenharmony_ci	STG_WRITE_REG(DACOverlayVAddr, tmp);
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	/* Set Overlay Size */
10062306a36Sopenharmony_ci	tmp = STG_READ_REG(DACOverlaySize);
10162306a36Sopenharmony_ci	CLEAR_BITS_FRM_TO(0, 10);
10262306a36Sopenharmony_ci	CLEAR_BITS_FRM_TO(12, 31);
10362306a36Sopenharmony_ci	STG_WRITE_REG(DACOverlaySize, tmp);
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	/* Set Overlay Vt Decimation */
10662306a36Sopenharmony_ci	tmp = STG4000_NO_DECIMATION;
10762306a36Sopenharmony_ci	STG_WRITE_REG(DACOverlayVtDec, tmp);
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	/* Set Overlay format to default value */
11062306a36Sopenharmony_ci	tmp = STG_READ_REG(DACPixelFormat);
11162306a36Sopenharmony_ci	CLEAR_BITS_FRM_TO(4, 7);
11262306a36Sopenharmony_ci	CLEAR_BITS_FRM_TO(16, 22);
11362306a36Sopenharmony_ci	STG_WRITE_REG(DACPixelFormat, tmp);
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	/* Set Vertical scaling to default */
11662306a36Sopenharmony_ci	tmp = STG_READ_REG(DACVerticalScal);
11762306a36Sopenharmony_ci	CLEAR_BITS_FRM_TO(0, 11);
11862306a36Sopenharmony_ci	CLEAR_BITS_FRM_TO(16, 22);
11962306a36Sopenharmony_ci	tmp |= STG4000_NO_SCALING;	/* Set to no scaling */
12062306a36Sopenharmony_ci	STG_WRITE_REG(DACVerticalScal, tmp);
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	/* Set Horizontal Scaling to default */
12362306a36Sopenharmony_ci	tmp = STG_READ_REG(DACHorizontalScal);
12462306a36Sopenharmony_ci	CLEAR_BITS_FRM_TO(0, 11);
12562306a36Sopenharmony_ci	CLEAR_BITS_FRM_TO(16, 17);
12662306a36Sopenharmony_ci	tmp |= STG4000_NO_SCALING;	/* Set to no scaling */
12762306a36Sopenharmony_ci	STG_WRITE_REG(DACHorizontalScal, tmp);
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	/* Set Blend mode to Alpha Blend */
13062306a36Sopenharmony_ci	/* ????? SG 08/11/2001 Surely this isn't the alpha blend mode,
13162306a36Sopenharmony_ci	   hopefully its overwrite
13262306a36Sopenharmony_ci	 */
13362306a36Sopenharmony_ci	tmp = STG_READ_REG(DACBlendCtrl);
13462306a36Sopenharmony_ci	CLEAR_BITS_FRM_TO(0, 30);
13562306a36Sopenharmony_ci	tmp = (GRAPHICS_MODE << 28);
13662306a36Sopenharmony_ci	STG_WRITE_REG(DACBlendCtrl, tmp);
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ciint CreateOverlaySurface(volatile STG4000REG __iomem *pSTGReg,
14162306a36Sopenharmony_ci			 u32 inWidth,
14262306a36Sopenharmony_ci			 u32 inHeight,
14362306a36Sopenharmony_ci			 int bLinear,
14462306a36Sopenharmony_ci			 u32 ulOverlayOffset,
14562306a36Sopenharmony_ci			 u32 * retStride, u32 * retUVStride)
14662306a36Sopenharmony_ci{
14762306a36Sopenharmony_ci	u32 tmp;
14862306a36Sopenharmony_ci	u32 ulStride;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	if (inWidth > STG4000_OVRL_MAX_WIDTH ||
15162306a36Sopenharmony_ci	    inHeight > STG4000_OVRL_MAX_HEIGHT) {
15262306a36Sopenharmony_ci		return -EINVAL;
15362306a36Sopenharmony_ci	}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	/* Stride in 16 byte words - 16Bpp */
15662306a36Sopenharmony_ci	if (bLinear) {
15762306a36Sopenharmony_ci		/* Format is 16bits so num 16 byte words is width/8 */
15862306a36Sopenharmony_ci		if ((inWidth & 0x7) == 0) {	/* inWidth % 8 */
15962306a36Sopenharmony_ci			ulStride = (inWidth / 8);
16062306a36Sopenharmony_ci		} else {
16162306a36Sopenharmony_ci			/* Round up to next 16byte boundary */
16262306a36Sopenharmony_ci			ulStride = ((inWidth + 8) / 8);
16362306a36Sopenharmony_ci		}
16462306a36Sopenharmony_ci	} else {
16562306a36Sopenharmony_ci		/* Y component is 8bits so num 16 byte words is width/16 */
16662306a36Sopenharmony_ci		if ((inWidth & 0xf) == 0) {	/* inWidth % 16 */
16762306a36Sopenharmony_ci			ulStride = (inWidth / 16);
16862306a36Sopenharmony_ci		} else {
16962306a36Sopenharmony_ci			/* Round up to next 16byte boundary */
17062306a36Sopenharmony_ci			ulStride = ((inWidth + 16) / 16);
17162306a36Sopenharmony_ci		}
17262306a36Sopenharmony_ci	}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	/* Set Overlay address and Format mode */
17662306a36Sopenharmony_ci	tmp = STG_READ_REG(DACOverlayAddr);
17762306a36Sopenharmony_ci	CLEAR_BITS_FRM_TO(0, 20);
17862306a36Sopenharmony_ci	if (bLinear) {
17962306a36Sopenharmony_ci		CLEAR_BIT(31);	/* Overlay format to Linear */
18062306a36Sopenharmony_ci	} else {
18162306a36Sopenharmony_ci		tmp |= SET_BIT(31);	/* Overlay format to Planer */
18262306a36Sopenharmony_ci	}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	/* Only bits 24:4 of the Overlay address */
18562306a36Sopenharmony_ci	tmp |= (ulOverlayOffset >> 4);
18662306a36Sopenharmony_ci	STG_WRITE_REG(DACOverlayAddr, tmp);
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	if (!bLinear) {
18962306a36Sopenharmony_ci		u32 uvSize =
19062306a36Sopenharmony_ci		    (inWidth & 0x1) ? (inWidth + 1 / 2) : (inWidth / 2);
19162306a36Sopenharmony_ci		u32 uvStride;
19262306a36Sopenharmony_ci		u32 ulOffset;
19362306a36Sopenharmony_ci		/* Y component is 8bits so num 32 byte words is width/32 */
19462306a36Sopenharmony_ci		if ((uvSize & 0xf) == 0) {	/* inWidth % 16 */
19562306a36Sopenharmony_ci			uvStride = (uvSize / 16);
19662306a36Sopenharmony_ci		} else {
19762306a36Sopenharmony_ci			/* Round up to next 32byte boundary */
19862306a36Sopenharmony_ci			uvStride = ((uvSize + 16) / 16);
19962306a36Sopenharmony_ci		}
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci		ulOffset = ulOverlayOffset + (inHeight * (ulStride * 16));
20262306a36Sopenharmony_ci		/* Align U,V data to 32byte boundary */
20362306a36Sopenharmony_ci		if ((ulOffset & 0x1f) != 0)
20462306a36Sopenharmony_ci			ulOffset = (ulOffset + 32L) & 0xffffffE0L;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci		tmp = STG_READ_REG(DACOverlayUAddr);
20762306a36Sopenharmony_ci		CLEAR_BITS_FRM_TO(0, 20);
20862306a36Sopenharmony_ci		tmp |= (ulOffset >> 4);
20962306a36Sopenharmony_ci		STG_WRITE_REG(DACOverlayUAddr, tmp);
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci		ulOffset += (inHeight / 2) * (uvStride * 16);
21262306a36Sopenharmony_ci		/* Align U,V data to 32byte boundary */
21362306a36Sopenharmony_ci		if ((ulOffset & 0x1f) != 0)
21462306a36Sopenharmony_ci			ulOffset = (ulOffset + 32L) & 0xffffffE0L;
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci		tmp = STG_READ_REG(DACOverlayVAddr);
21762306a36Sopenharmony_ci		CLEAR_BITS_FRM_TO(0, 20);
21862306a36Sopenharmony_ci		tmp |= (ulOffset >> 4);
21962306a36Sopenharmony_ci		STG_WRITE_REG(DACOverlayVAddr, tmp);
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci		*retUVStride = uvStride * 16;
22262306a36Sopenharmony_ci	}
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	/* Set Overlay YUV pixel format
22662306a36Sopenharmony_ci	 * Make sure that LUT not used - ??????
22762306a36Sopenharmony_ci	 */
22862306a36Sopenharmony_ci	tmp = STG_READ_REG(DACPixelFormat);
22962306a36Sopenharmony_ci	/* Only support Planer or UYVY linear formats */
23062306a36Sopenharmony_ci	CLEAR_BITS_FRM_TO(4, 9);
23162306a36Sopenharmony_ci	STG_WRITE_REG(DACPixelFormat, tmp);
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	ovlWidth = inWidth;
23462306a36Sopenharmony_ci	ovlHeight = inHeight;
23562306a36Sopenharmony_ci	ovlStride = ulStride;
23662306a36Sopenharmony_ci	ovlLinear = bLinear;
23762306a36Sopenharmony_ci	*retStride = ulStride << 4;	/* In bytes */
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	return 0;
24062306a36Sopenharmony_ci}
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ciint SetOverlayBlendMode(volatile STG4000REG __iomem *pSTGReg,
24362306a36Sopenharmony_ci			OVRL_BLEND_MODE mode,
24462306a36Sopenharmony_ci			u32 ulAlpha, u32 ulColorKey)
24562306a36Sopenharmony_ci{
24662306a36Sopenharmony_ci	u32 tmp;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	tmp = STG_READ_REG(DACBlendCtrl);
24962306a36Sopenharmony_ci	CLEAR_BITS_FRM_TO(28, 30);
25062306a36Sopenharmony_ci	tmp |= (mode << 28);
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	switch (mode) {
25362306a36Sopenharmony_ci	case COLOR_KEY:
25462306a36Sopenharmony_ci		CLEAR_BITS_FRM_TO(0, 23);
25562306a36Sopenharmony_ci		tmp |= (ulColorKey & 0x00FFFFFF);
25662306a36Sopenharmony_ci		break;
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	case GLOBAL_ALPHA:
25962306a36Sopenharmony_ci		CLEAR_BITS_FRM_TO(24, 27);
26062306a36Sopenharmony_ci		tmp |= ((ulAlpha & 0xF) << 24);
26162306a36Sopenharmony_ci		break;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	case CK_PIXEL_ALPHA:
26462306a36Sopenharmony_ci		CLEAR_BITS_FRM_TO(0, 23);
26562306a36Sopenharmony_ci		tmp |= (ulColorKey & 0x00FFFFFF);
26662306a36Sopenharmony_ci		break;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	case CK_GLOBAL_ALPHA:
26962306a36Sopenharmony_ci		CLEAR_BITS_FRM_TO(0, 23);
27062306a36Sopenharmony_ci		tmp |= (ulColorKey & 0x00FFFFFF);
27162306a36Sopenharmony_ci		CLEAR_BITS_FRM_TO(24, 27);
27262306a36Sopenharmony_ci		tmp |= ((ulAlpha & 0xF) << 24);
27362306a36Sopenharmony_ci		break;
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	case GRAPHICS_MODE:
27662306a36Sopenharmony_ci	case PER_PIXEL_ALPHA:
27762306a36Sopenharmony_ci		break;
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	default:
28062306a36Sopenharmony_ci		return -EINVAL;
28162306a36Sopenharmony_ci	}
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	STG_WRITE_REG(DACBlendCtrl, tmp);
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	return 0;
28662306a36Sopenharmony_ci}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_civoid EnableOverlayPlane(volatile STG4000REG __iomem *pSTGReg)
28962306a36Sopenharmony_ci{
29062306a36Sopenharmony_ci	u32 tmp;
29162306a36Sopenharmony_ci	/* Enable Overlay */
29262306a36Sopenharmony_ci	tmp = STG_READ_REG(DACPixelFormat);
29362306a36Sopenharmony_ci	tmp |= SET_BIT(7);
29462306a36Sopenharmony_ci	STG_WRITE_REG(DACPixelFormat, tmp);
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	/* Set video stream control */
29762306a36Sopenharmony_ci	tmp = STG_READ_REG(DACStreamCtrl);
29862306a36Sopenharmony_ci	tmp |= SET_BIT(1);	/* video stream */
29962306a36Sopenharmony_ci	STG_WRITE_REG(DACStreamCtrl, tmp);
30062306a36Sopenharmony_ci}
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_cistatic u32 Overlap(u32 ulBits, u32 ulPattern)
30362306a36Sopenharmony_ci{
30462306a36Sopenharmony_ci	u32 ulCount = 0;
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	while (ulBits) {
30762306a36Sopenharmony_ci		if (!(ulPattern & 1))
30862306a36Sopenharmony_ci			ulCount++;
30962306a36Sopenharmony_ci		ulBits--;
31062306a36Sopenharmony_ci		ulPattern = ulPattern >> 1;
31162306a36Sopenharmony_ci	}
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	return ulCount;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci}
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ciint SetOverlayViewPort(volatile STG4000REG __iomem *pSTGReg,
31862306a36Sopenharmony_ci		       u32 left, u32 top,
31962306a36Sopenharmony_ci		       u32 right, u32 bottom)
32062306a36Sopenharmony_ci{
32162306a36Sopenharmony_ci	OVRL_SRC_DEST srcDest;
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	u32 ulSrcTop, ulSrcBottom;
32462306a36Sopenharmony_ci	u32 ulSrc, ulDest;
32562306a36Sopenharmony_ci	u32 ulFxScale, ulFxOffset;
32662306a36Sopenharmony_ci	u32 ulHeight, ulWidth;
32762306a36Sopenharmony_ci	u32 ulPattern;
32862306a36Sopenharmony_ci	u32 ulDecimate, ulDecimated;
32962306a36Sopenharmony_ci	u32 ulApplied;
33062306a36Sopenharmony_ci	u32 ulDacXScale, ulDacYScale;
33162306a36Sopenharmony_ci	u32 ulScale;
33262306a36Sopenharmony_ci	u32 ulLeft, ulRight;
33362306a36Sopenharmony_ci	u32 ulSrcLeft, ulSrcRight;
33462306a36Sopenharmony_ci	u32 ulScaleLeft;
33562306a36Sopenharmony_ci	u32 ulhDecim;
33662306a36Sopenharmony_ci	u32 ulsVal;
33762306a36Sopenharmony_ci	u32 ulVertDecFactor;
33862306a36Sopenharmony_ci	int bResult;
33962306a36Sopenharmony_ci	u32 ulClipOff = 0;
34062306a36Sopenharmony_ci	u32 ulBits = 0;
34162306a36Sopenharmony_ci	u32 ulsAdd = 0;
34262306a36Sopenharmony_ci	u32 tmp, ulStride;
34362306a36Sopenharmony_ci	u32 ulExcessPixels, ulClip, ulExtraLines;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	srcDest.ulSrcX1 = 0;
34762306a36Sopenharmony_ci	srcDest.ulSrcY1 = 0;
34862306a36Sopenharmony_ci	srcDest.ulSrcX2 = ovlWidth - 1;
34962306a36Sopenharmony_ci	srcDest.ulSrcY2 = ovlHeight - 1;
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	srcDest.ulDstX1 = left;
35262306a36Sopenharmony_ci	srcDest.ulDstY1 = top;
35362306a36Sopenharmony_ci	srcDest.ulDstX2 = right;
35462306a36Sopenharmony_ci	srcDest.ulDstY2 = bottom;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	srcDest.lDstX1 = srcDest.ulDstX1;
35762306a36Sopenharmony_ci	srcDest.lDstY1 = srcDest.ulDstY1;
35862306a36Sopenharmony_ci	srcDest.lDstX2 = srcDest.ulDstX2;
35962306a36Sopenharmony_ci	srcDest.lDstY2 = srcDest.ulDstY2;
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci    /************* Vertical decimation/scaling ******************/
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	/* Get Src Top and Bottom */
36462306a36Sopenharmony_ci	ulSrcTop = srcDest.ulSrcY1;
36562306a36Sopenharmony_ci	ulSrcBottom = srcDest.ulSrcY2;
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	ulSrc = ulSrcBottom - ulSrcTop;
36862306a36Sopenharmony_ci	ulDest = srcDest.lDstY2 - srcDest.lDstY1;	/* on-screen overlay */
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	if (ulSrc <= 1)
37162306a36Sopenharmony_ci		return -EINVAL;
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	/* First work out the position we are to display as offset from the
37462306a36Sopenharmony_ci	 * source of the buffer
37562306a36Sopenharmony_ci	 */
37662306a36Sopenharmony_ci	ulFxScale = (ulDest << 11) / ulSrc;	/* fixed point scale factor */
37762306a36Sopenharmony_ci	ulFxOffset = (srcDest.lDstY2 - srcDest.ulDstY2) << 11;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	ulSrcBottom = ulSrcBottom - (ulFxOffset / ulFxScale);
38062306a36Sopenharmony_ci	ulSrc = ulSrcBottom - ulSrcTop;
38162306a36Sopenharmony_ci	ulHeight = ulSrc;
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	ulDest = srcDest.ulDstY2 - (srcDest.ulDstY1 - 1);
38462306a36Sopenharmony_ci	ulPattern = adwDecim8[ulBits];
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	/* At this point ulSrc represents the input decimator */
38762306a36Sopenharmony_ci	if (ulSrc > ulDest) {
38862306a36Sopenharmony_ci		ulDecimate = ulSrc - ulDest;
38962306a36Sopenharmony_ci		ulBits = 0;
39062306a36Sopenharmony_ci		ulApplied = ulSrc / 32;
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci		while (((ulBits * ulApplied) +
39362306a36Sopenharmony_ci			Overlap((ulSrc % 32),
39462306a36Sopenharmony_ci				adwDecim8[ulBits])) < ulDecimate)
39562306a36Sopenharmony_ci			ulBits++;
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci		ulPattern = adwDecim8[ulBits];
39862306a36Sopenharmony_ci		ulDecimated =
39962306a36Sopenharmony_ci		    (ulBits * ulApplied) + Overlap((ulSrc % 32),
40062306a36Sopenharmony_ci						   ulPattern);
40162306a36Sopenharmony_ci		ulSrc = ulSrc - ulDecimated;	/* the number number of lines that will go into the scaler */
40262306a36Sopenharmony_ci	}
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	if (ulBits && (ulBits != 32)) {
40562306a36Sopenharmony_ci		ulVertDecFactor = (63 - ulBits) / (32 - ulBits);	/* vertical decimation factor scaled up to nearest integer */
40662306a36Sopenharmony_ci	} else {
40762306a36Sopenharmony_ci		ulVertDecFactor = 1;
40862306a36Sopenharmony_ci	}
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	ulDacYScale = ((ulSrc - 1) * 2048) / (ulDest + 1);
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	tmp = STG_READ_REG(DACOverlayVtDec);	/* Decimation */
41362306a36Sopenharmony_ci	CLEAR_BITS_FRM_TO(0, 31);
41462306a36Sopenharmony_ci	tmp = ulPattern;
41562306a36Sopenharmony_ci	STG_WRITE_REG(DACOverlayVtDec, tmp);
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	/***************** Horizontal decimation/scaling ***************************/
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	/*
42062306a36Sopenharmony_ci	 * Now we handle the horizontal case, this is a simplified version of
42162306a36Sopenharmony_ci	 * the vertical case in that we decimate by factors of 2.  as we are
42262306a36Sopenharmony_ci	 * working in words we should always be able to decimate by these
42362306a36Sopenharmony_ci	 * factors.  as we always have to have a buffer which is aligned to a
42462306a36Sopenharmony_ci	 * whole number of 128 bit words, we must align the left side to the
42562306a36Sopenharmony_ci	 * lowest to the next lowest 128 bit boundary, and the right hand edge
42662306a36Sopenharmony_ci	 * to the next largets boundary, (in a similar way to how we didi it in
42762306a36Sopenharmony_ci	 * PMX1) as the left and right hand edges are aligned to these
42862306a36Sopenharmony_ci	 * boundaries normally this only becomes an issue when we are chopping
42962306a36Sopenharmony_ci	 * of one of the sides We shall work out vertical stuff first
43062306a36Sopenharmony_ci	 */
43162306a36Sopenharmony_ci	ulSrc = srcDest.ulSrcX2 - srcDest.ulSrcX1;
43262306a36Sopenharmony_ci	ulDest = srcDest.lDstX2 - srcDest.lDstX1;
43362306a36Sopenharmony_ci#ifdef _OLDCODE
43462306a36Sopenharmony_ci	ulLeft = srcDest.ulDstX1;
43562306a36Sopenharmony_ci	ulRight = srcDest.ulDstX2;
43662306a36Sopenharmony_ci#else
43762306a36Sopenharmony_ci	if (srcDest.ulDstX1 > 2) {
43862306a36Sopenharmony_ci		ulLeft = srcDest.ulDstX1 + 2;
43962306a36Sopenharmony_ci		ulRight = srcDest.ulDstX2 + 1;
44062306a36Sopenharmony_ci	} else {
44162306a36Sopenharmony_ci		ulLeft = srcDest.ulDstX1;
44262306a36Sopenharmony_ci		ulRight = srcDest.ulDstX2 + 1;
44362306a36Sopenharmony_ci	}
44462306a36Sopenharmony_ci#endif
44562306a36Sopenharmony_ci	/* first work out the position we are to display as offset from the source of the buffer */
44662306a36Sopenharmony_ci	bResult = 1;
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	do {
44962306a36Sopenharmony_ci		if (ulDest == 0)
45062306a36Sopenharmony_ci			return -EINVAL;
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci		/* source pixels per dest pixel <<11 */
45362306a36Sopenharmony_ci		ulFxScale = ((ulSrc - 1) << 11) / (ulDest);
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci		/* then number of destination pixels out we are */
45662306a36Sopenharmony_ci		ulFxOffset = ulFxScale * ((srcDest.ulDstX1 - srcDest.lDstX1) + ulClipOff);
45762306a36Sopenharmony_ci		ulFxOffset >>= 11;
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci		/* this replaces the code which was making a decision as to use either ulFxOffset or ulSrcX1 */
46062306a36Sopenharmony_ci		ulSrcLeft = srcDest.ulSrcX1 + ulFxOffset;
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci		/* then number of destination pixels out we are */
46362306a36Sopenharmony_ci		ulFxOffset = ulFxScale * (srcDest.lDstX2 - srcDest.ulDstX2);
46462306a36Sopenharmony_ci		ulFxOffset >>= 11;
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci		ulSrcRight = srcDest.ulSrcX2 - ulFxOffset;
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci		/*
46962306a36Sopenharmony_ci		 * we must align these to our 128 bit boundaries. we shall
47062306a36Sopenharmony_ci		 * round down the pixel pos to the nearest 8 pixels.
47162306a36Sopenharmony_ci		 */
47262306a36Sopenharmony_ci		ulScaleLeft = ulSrcLeft;
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci		/* shift fxscale until it is in the range of the scaler */
47562306a36Sopenharmony_ci		ulhDecim = 0;
47662306a36Sopenharmony_ci		ulScale = (((ulSrcRight - ulSrcLeft) - 1) << (11 - ulhDecim)) / (ulRight - ulLeft + 2);
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci		while (ulScale > 0x800) {
47962306a36Sopenharmony_ci			ulhDecim++;
48062306a36Sopenharmony_ci			ulScale = (((ulSrcRight - ulSrcLeft) - 1) << (11 - ulhDecim)) / (ulRight - ulLeft + 2);
48162306a36Sopenharmony_ci		}
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci		/*
48462306a36Sopenharmony_ci		 * to try and get the best values We first try and use
48562306a36Sopenharmony_ci		 * src/dwdest for the scale factor, then we move onto src-1
48662306a36Sopenharmony_ci		 *
48762306a36Sopenharmony_ci		 * we want to check to see if we will need to clip data, if so
48862306a36Sopenharmony_ci		 * then we should clip our source so that we don't need to
48962306a36Sopenharmony_ci		 */
49062306a36Sopenharmony_ci		if (!ovlLinear) {
49162306a36Sopenharmony_ci			ulSrcLeft &= ~0x1f;
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci			/*
49462306a36Sopenharmony_ci			 * we must align the right hand edge to the next 32
49562306a36Sopenharmony_ci			 * pixel` boundary, must be on a 256 boundary so u, and
49662306a36Sopenharmony_ci			 * v are 128 bit aligned
49762306a36Sopenharmony_ci			 */
49862306a36Sopenharmony_ci			ulSrcRight = (ulSrcRight + 0x1f) & ~0x1f;
49962306a36Sopenharmony_ci		} else {
50062306a36Sopenharmony_ci			ulSrcLeft &= ~0x7;
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci			/*
50362306a36Sopenharmony_ci			 * we must align the right hand edge to the next
50462306a36Sopenharmony_ci			 * 8pixel` boundary
50562306a36Sopenharmony_ci			 */
50662306a36Sopenharmony_ci			ulSrcRight = (ulSrcRight + 0x7) & ~0x7;
50762306a36Sopenharmony_ci		}
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci		/* this is the input size line store needs to cope with */
51062306a36Sopenharmony_ci		ulWidth = ulSrcRight - ulSrcLeft;
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci		/*
51362306a36Sopenharmony_ci		 * use unclipped value to work out scale factror this is the
51462306a36Sopenharmony_ci		 * scale factor we want we shall now work out the horizonal
51562306a36Sopenharmony_ci		 * decimation and scaling
51662306a36Sopenharmony_ci		 */
51762306a36Sopenharmony_ci		ulsVal = ((ulWidth / 8) >> ulhDecim);
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci		if ((ulWidth != (ulsVal << ulhDecim) * 8))
52062306a36Sopenharmony_ci			ulsAdd = 1;
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci		/* input pixels to scaler; */
52362306a36Sopenharmony_ci		ulSrc = ulWidth >> ulhDecim;
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci		if (ulSrc <= 2)
52662306a36Sopenharmony_ci			return -EINVAL;
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci		ulExcessPixels = ((((ulScaleLeft - ulSrcLeft)) << (11 - ulhDecim)) / ulScale);
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci		ulClip = (ulSrc << 11) / ulScale;
53162306a36Sopenharmony_ci		ulClip -= (ulRight - ulLeft);
53262306a36Sopenharmony_ci		ulClip += ulExcessPixels;
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci		if (ulClip)
53562306a36Sopenharmony_ci			ulClip--;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci		/* We may need to do more here if we really have a HW rev < 5 */
53862306a36Sopenharmony_ci	} while (!bResult);
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	ulExtraLines = (1 << ulhDecim) * ulVertDecFactor;
54162306a36Sopenharmony_ci	ulExtraLines += 64;
54262306a36Sopenharmony_ci	ulHeight += ulExtraLines;
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	ulDacXScale = ulScale;
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	tmp = STG_READ_REG(DACVerticalScal);
54862306a36Sopenharmony_ci	CLEAR_BITS_FRM_TO(0, 11);
54962306a36Sopenharmony_ci	CLEAR_BITS_FRM_TO(16, 22);	/* Vertical Scaling */
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	/* Calculate new output line stride, this is always the number of 422
55262306a36Sopenharmony_ci	   words in the line buffer, so it doesn't matter if the
55362306a36Sopenharmony_ci	   mode is 420. Then set the vertical scale register.
55462306a36Sopenharmony_ci	 */
55562306a36Sopenharmony_ci	ulStride = (ulWidth >> (ulhDecim + 3)) + ulsAdd;
55662306a36Sopenharmony_ci	tmp |= ((ulStride << 16) | (ulDacYScale));	/* DAC_LS_CTRL = stride */
55762306a36Sopenharmony_ci	STG_WRITE_REG(DACVerticalScal, tmp);
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	/* Now set up the overlay size using the modified width and height
56062306a36Sopenharmony_ci	   from decimate and scaling calculations
56162306a36Sopenharmony_ci	 */
56262306a36Sopenharmony_ci	tmp = STG_READ_REG(DACOverlaySize);
56362306a36Sopenharmony_ci	CLEAR_BITS_FRM_TO(0, 10);
56462306a36Sopenharmony_ci	CLEAR_BITS_FRM_TO(12, 31);
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	if (ovlLinear) {
56762306a36Sopenharmony_ci		tmp |=
56862306a36Sopenharmony_ci		    (ovlStride | ((ulHeight + 1) << 12) |
56962306a36Sopenharmony_ci		     (((ulWidth / 8) - 1) << 23));
57062306a36Sopenharmony_ci	} else {
57162306a36Sopenharmony_ci		tmp |=
57262306a36Sopenharmony_ci		    (ovlStride | ((ulHeight + 1) << 12) |
57362306a36Sopenharmony_ci		     (((ulWidth / 32) - 1) << 23));
57462306a36Sopenharmony_ci	}
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	STG_WRITE_REG(DACOverlaySize, tmp);
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	/* Set Video Window Start */
57962306a36Sopenharmony_ci	tmp = ((ulLeft << 16)) | (srcDest.ulDstY1);
58062306a36Sopenharmony_ci	STG_WRITE_REG(DACVidWinStart, tmp);
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	/* Set Video Window End */
58362306a36Sopenharmony_ci	tmp = ((ulRight) << 16) | (srcDest.ulDstY2);
58462306a36Sopenharmony_ci	STG_WRITE_REG(DACVidWinEnd, tmp);
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	/* Finally set up the rest of the overlay regs in the order
58762306a36Sopenharmony_ci	   done in the IMG driver
58862306a36Sopenharmony_ci	 */
58962306a36Sopenharmony_ci	tmp = STG_READ_REG(DACPixelFormat);
59062306a36Sopenharmony_ci	tmp = ((ulExcessPixels << 16) | tmp) & 0x7fffffff;
59162306a36Sopenharmony_ci	STG_WRITE_REG(DACPixelFormat, tmp);
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	tmp = STG_READ_REG(DACHorizontalScal);
59462306a36Sopenharmony_ci	CLEAR_BITS_FRM_TO(0, 11);
59562306a36Sopenharmony_ci	CLEAR_BITS_FRM_TO(16, 17);
59662306a36Sopenharmony_ci	tmp |= ((ulhDecim << 16) | (ulDacXScale));
59762306a36Sopenharmony_ci	STG_WRITE_REG(DACHorizontalScal, tmp);
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	return 0;
60062306a36Sopenharmony_ci}
601