18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci *  linux/drivers/video/kyro/STG4000OverlayDevice.c
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci *  Copyright (C) 2000 Imagination Technologies Ltd
58c2ecf20Sopenharmony_ci *  Copyright (C) 2002 STMicroelectronics
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
88c2ecf20Sopenharmony_ci * License.  See the file COPYING in the main directory of this archive
98c2ecf20Sopenharmony_ci * for more details.
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <linux/kernel.h>
138c2ecf20Sopenharmony_ci#include <linux/errno.h>
148c2ecf20Sopenharmony_ci#include <linux/types.h>
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#include "STG4000Reg.h"
178c2ecf20Sopenharmony_ci#include "STG4000Interface.h"
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci/* HW Defines */
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#define STG4000_NO_SCALING    0x800
228c2ecf20Sopenharmony_ci#define STG4000_NO_DECIMATION 0xFFFFFFFF
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci/* Primary surface */
258c2ecf20Sopenharmony_ci#define STG4000_PRIM_NUM_PIX   5
268c2ecf20Sopenharmony_ci#define STG4000_PRIM_ALIGN     4
278c2ecf20Sopenharmony_ci#define STG4000_PRIM_ADDR_BITS 20
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#define STG4000_PRIM_MIN_WIDTH  640
308c2ecf20Sopenharmony_ci#define STG4000_PRIM_MAX_WIDTH  1600
318c2ecf20Sopenharmony_ci#define STG4000_PRIM_MIN_HEIGHT 480
328c2ecf20Sopenharmony_ci#define STG4000_PRIM_MAX_HEIGHT 1200
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci/* Overlay surface */
358c2ecf20Sopenharmony_ci#define STG4000_OVRL_NUM_PIX   4
368c2ecf20Sopenharmony_ci#define STG4000_OVRL_ALIGN     2
378c2ecf20Sopenharmony_ci#define STG4000_OVRL_ADDR_BITS 20
388c2ecf20Sopenharmony_ci#define STG4000_OVRL_NUM_MODES 5
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci#define STG4000_OVRL_MIN_WIDTH  0
418c2ecf20Sopenharmony_ci#define STG4000_OVRL_MAX_WIDTH  720
428c2ecf20Sopenharmony_ci#define STG4000_OVRL_MIN_HEIGHT 0
438c2ecf20Sopenharmony_ci#define STG4000_OVRL_MAX_HEIGHT 576
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci/* Decimation and Scaling */
468c2ecf20Sopenharmony_cistatic u32 adwDecim8[33] = {
478c2ecf20Sopenharmony_ci	    0xffffffff, 0xfffeffff, 0xffdffbff, 0xfefefeff, 0xfdf7efbf,
488c2ecf20Sopenharmony_ci	    0xfbdf7bdf, 0xf7bbddef, 0xeeeeeeef, 0xeeddbb77, 0xedb76db7,
498c2ecf20Sopenharmony_ci	    0xdb6db6db, 0xdb5b5b5b, 0xdab5ad6b, 0xd5ab55ab, 0xd555aaab,
508c2ecf20Sopenharmony_ci	    0xaaaaaaab, 0xaaaa5555, 0xaa952a55, 0xa94a5295, 0xa5252525,
518c2ecf20Sopenharmony_ci	    0xa4924925, 0x92491249, 0x91224489, 0x91111111, 0x90884211,
528c2ecf20Sopenharmony_ci	    0x88410821, 0x88102041, 0x81010101, 0x80800801, 0x80010001,
538c2ecf20Sopenharmony_ci	    0x80000001, 0x00000001, 0x00000000
548c2ecf20Sopenharmony_ci};
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_citypedef struct _OVRL_SRC_DEST {
578c2ecf20Sopenharmony_ci	/*clipped on-screen pixel position of overlay */
588c2ecf20Sopenharmony_ci	u32 ulDstX1;
598c2ecf20Sopenharmony_ci	u32 ulDstY1;
608c2ecf20Sopenharmony_ci	u32 ulDstX2;
618c2ecf20Sopenharmony_ci	u32 ulDstY2;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	/*clipped pixel pos of source data within buffer thses need to be 128 bit word aligned */
648c2ecf20Sopenharmony_ci	u32 ulSrcX1;
658c2ecf20Sopenharmony_ci	u32 ulSrcY1;
668c2ecf20Sopenharmony_ci	u32 ulSrcX2;
678c2ecf20Sopenharmony_ci	u32 ulSrcY2;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	/* on-screen pixel position of overlay */
708c2ecf20Sopenharmony_ci	s32 lDstX1;
718c2ecf20Sopenharmony_ci	s32 lDstY1;
728c2ecf20Sopenharmony_ci	s32 lDstX2;
738c2ecf20Sopenharmony_ci	s32 lDstY2;
748c2ecf20Sopenharmony_ci} OVRL_SRC_DEST;
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_cistatic u32 ovlWidth, ovlHeight, ovlStride;
778c2ecf20Sopenharmony_cistatic int ovlLinear;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_civoid ResetOverlayRegisters(volatile STG4000REG __iomem *pSTGReg)
808c2ecf20Sopenharmony_ci{
818c2ecf20Sopenharmony_ci	u32 tmp;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	/* Set Overlay address to default */
848c2ecf20Sopenharmony_ci	tmp = STG_READ_REG(DACOverlayAddr);
858c2ecf20Sopenharmony_ci	CLEAR_BITS_FRM_TO(0, 20);
868c2ecf20Sopenharmony_ci	CLEAR_BIT(31);
878c2ecf20Sopenharmony_ci	STG_WRITE_REG(DACOverlayAddr, tmp);
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	/* Set Overlay U address */
908c2ecf20Sopenharmony_ci	tmp = STG_READ_REG(DACOverlayUAddr);
918c2ecf20Sopenharmony_ci	CLEAR_BITS_FRM_TO(0, 20);
928c2ecf20Sopenharmony_ci	STG_WRITE_REG(DACOverlayUAddr, tmp);
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	/* Set Overlay V address */
958c2ecf20Sopenharmony_ci	tmp = STG_READ_REG(DACOverlayVAddr);
968c2ecf20Sopenharmony_ci	CLEAR_BITS_FRM_TO(0, 20);
978c2ecf20Sopenharmony_ci	STG_WRITE_REG(DACOverlayVAddr, tmp);
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	/* Set Overlay Size */
1008c2ecf20Sopenharmony_ci	tmp = STG_READ_REG(DACOverlaySize);
1018c2ecf20Sopenharmony_ci	CLEAR_BITS_FRM_TO(0, 10);
1028c2ecf20Sopenharmony_ci	CLEAR_BITS_FRM_TO(12, 31);
1038c2ecf20Sopenharmony_ci	STG_WRITE_REG(DACOverlaySize, tmp);
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	/* Set Overlay Vt Decimation */
1068c2ecf20Sopenharmony_ci	tmp = STG4000_NO_DECIMATION;
1078c2ecf20Sopenharmony_ci	STG_WRITE_REG(DACOverlayVtDec, tmp);
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	/* Set Overlay format to default value */
1108c2ecf20Sopenharmony_ci	tmp = STG_READ_REG(DACPixelFormat);
1118c2ecf20Sopenharmony_ci	CLEAR_BITS_FRM_TO(4, 7);
1128c2ecf20Sopenharmony_ci	CLEAR_BITS_FRM_TO(16, 22);
1138c2ecf20Sopenharmony_ci	STG_WRITE_REG(DACPixelFormat, tmp);
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	/* Set Vertical scaling to default */
1168c2ecf20Sopenharmony_ci	tmp = STG_READ_REG(DACVerticalScal);
1178c2ecf20Sopenharmony_ci	CLEAR_BITS_FRM_TO(0, 11);
1188c2ecf20Sopenharmony_ci	CLEAR_BITS_FRM_TO(16, 22);
1198c2ecf20Sopenharmony_ci	tmp |= STG4000_NO_SCALING;	/* Set to no scaling */
1208c2ecf20Sopenharmony_ci	STG_WRITE_REG(DACVerticalScal, tmp);
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	/* Set Horizontal Scaling to default */
1238c2ecf20Sopenharmony_ci	tmp = STG_READ_REG(DACHorizontalScal);
1248c2ecf20Sopenharmony_ci	CLEAR_BITS_FRM_TO(0, 11);
1258c2ecf20Sopenharmony_ci	CLEAR_BITS_FRM_TO(16, 17);
1268c2ecf20Sopenharmony_ci	tmp |= STG4000_NO_SCALING;	/* Set to no scaling */
1278c2ecf20Sopenharmony_ci	STG_WRITE_REG(DACHorizontalScal, tmp);
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	/* Set Blend mode to Alpha Blend */
1308c2ecf20Sopenharmony_ci	/* ????? SG 08/11/2001 Surely this isn't the alpha blend mode,
1318c2ecf20Sopenharmony_ci	   hopefully its overwrite
1328c2ecf20Sopenharmony_ci	 */
1338c2ecf20Sopenharmony_ci	tmp = STG_READ_REG(DACBlendCtrl);
1348c2ecf20Sopenharmony_ci	CLEAR_BITS_FRM_TO(0, 30);
1358c2ecf20Sopenharmony_ci	tmp = (GRAPHICS_MODE << 28);
1368c2ecf20Sopenharmony_ci	STG_WRITE_REG(DACBlendCtrl, tmp);
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci}
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ciint CreateOverlaySurface(volatile STG4000REG __iomem *pSTGReg,
1418c2ecf20Sopenharmony_ci			 u32 inWidth,
1428c2ecf20Sopenharmony_ci			 u32 inHeight,
1438c2ecf20Sopenharmony_ci			 int bLinear,
1448c2ecf20Sopenharmony_ci			 u32 ulOverlayOffset,
1458c2ecf20Sopenharmony_ci			 u32 * retStride, u32 * retUVStride)
1468c2ecf20Sopenharmony_ci{
1478c2ecf20Sopenharmony_ci	u32 tmp;
1488c2ecf20Sopenharmony_ci	u32 ulStride;
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	if (inWidth > STG4000_OVRL_MAX_WIDTH ||
1518c2ecf20Sopenharmony_ci	    inHeight > STG4000_OVRL_MAX_HEIGHT) {
1528c2ecf20Sopenharmony_ci		return -EINVAL;
1538c2ecf20Sopenharmony_ci	}
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	/* Stride in 16 byte words - 16Bpp */
1568c2ecf20Sopenharmony_ci	if (bLinear) {
1578c2ecf20Sopenharmony_ci		/* Format is 16bits so num 16 byte words is width/8 */
1588c2ecf20Sopenharmony_ci		if ((inWidth & 0x7) == 0) {	/* inWidth % 8 */
1598c2ecf20Sopenharmony_ci			ulStride = (inWidth / 8);
1608c2ecf20Sopenharmony_ci		} else {
1618c2ecf20Sopenharmony_ci			/* Round up to next 16byte boundary */
1628c2ecf20Sopenharmony_ci			ulStride = ((inWidth + 8) / 8);
1638c2ecf20Sopenharmony_ci		}
1648c2ecf20Sopenharmony_ci	} else {
1658c2ecf20Sopenharmony_ci		/* Y component is 8bits so num 16 byte words is width/16 */
1668c2ecf20Sopenharmony_ci		if ((inWidth & 0xf) == 0) {	/* inWidth % 16 */
1678c2ecf20Sopenharmony_ci			ulStride = (inWidth / 16);
1688c2ecf20Sopenharmony_ci		} else {
1698c2ecf20Sopenharmony_ci			/* Round up to next 16byte boundary */
1708c2ecf20Sopenharmony_ci			ulStride = ((inWidth + 16) / 16);
1718c2ecf20Sopenharmony_ci		}
1728c2ecf20Sopenharmony_ci	}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	/* Set Overlay address and Format mode */
1768c2ecf20Sopenharmony_ci	tmp = STG_READ_REG(DACOverlayAddr);
1778c2ecf20Sopenharmony_ci	CLEAR_BITS_FRM_TO(0, 20);
1788c2ecf20Sopenharmony_ci	if (bLinear) {
1798c2ecf20Sopenharmony_ci		CLEAR_BIT(31);	/* Overlay format to Linear */
1808c2ecf20Sopenharmony_ci	} else {
1818c2ecf20Sopenharmony_ci		tmp |= SET_BIT(31);	/* Overlay format to Planer */
1828c2ecf20Sopenharmony_ci	}
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	/* Only bits 24:4 of the Overlay address */
1858c2ecf20Sopenharmony_ci	tmp |= (ulOverlayOffset >> 4);
1868c2ecf20Sopenharmony_ci	STG_WRITE_REG(DACOverlayAddr, tmp);
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	if (!bLinear) {
1898c2ecf20Sopenharmony_ci		u32 uvSize =
1908c2ecf20Sopenharmony_ci		    (inWidth & 0x1) ? (inWidth + 1 / 2) : (inWidth / 2);
1918c2ecf20Sopenharmony_ci		u32 uvStride;
1928c2ecf20Sopenharmony_ci		u32 ulOffset;
1938c2ecf20Sopenharmony_ci		/* Y component is 8bits so num 32 byte words is width/32 */
1948c2ecf20Sopenharmony_ci		if ((uvSize & 0xf) == 0) {	/* inWidth % 16 */
1958c2ecf20Sopenharmony_ci			uvStride = (uvSize / 16);
1968c2ecf20Sopenharmony_ci		} else {
1978c2ecf20Sopenharmony_ci			/* Round up to next 32byte boundary */
1988c2ecf20Sopenharmony_ci			uvStride = ((uvSize + 16) / 16);
1998c2ecf20Sopenharmony_ci		}
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci		ulOffset = ulOverlayOffset + (inHeight * (ulStride * 16));
2028c2ecf20Sopenharmony_ci		/* Align U,V data to 32byte boundary */
2038c2ecf20Sopenharmony_ci		if ((ulOffset & 0x1f) != 0)
2048c2ecf20Sopenharmony_ci			ulOffset = (ulOffset + 32L) & 0xffffffE0L;
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci		tmp = STG_READ_REG(DACOverlayUAddr);
2078c2ecf20Sopenharmony_ci		CLEAR_BITS_FRM_TO(0, 20);
2088c2ecf20Sopenharmony_ci		tmp |= (ulOffset >> 4);
2098c2ecf20Sopenharmony_ci		STG_WRITE_REG(DACOverlayUAddr, tmp);
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci		ulOffset += (inHeight / 2) * (uvStride * 16);
2128c2ecf20Sopenharmony_ci		/* Align U,V data to 32byte boundary */
2138c2ecf20Sopenharmony_ci		if ((ulOffset & 0x1f) != 0)
2148c2ecf20Sopenharmony_ci			ulOffset = (ulOffset + 32L) & 0xffffffE0L;
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci		tmp = STG_READ_REG(DACOverlayVAddr);
2178c2ecf20Sopenharmony_ci		CLEAR_BITS_FRM_TO(0, 20);
2188c2ecf20Sopenharmony_ci		tmp |= (ulOffset >> 4);
2198c2ecf20Sopenharmony_ci		STG_WRITE_REG(DACOverlayVAddr, tmp);
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci		*retUVStride = uvStride * 16;
2228c2ecf20Sopenharmony_ci	}
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	/* Set Overlay YUV pixel format
2268c2ecf20Sopenharmony_ci	 * Make sure that LUT not used - ??????
2278c2ecf20Sopenharmony_ci	 */
2288c2ecf20Sopenharmony_ci	tmp = STG_READ_REG(DACPixelFormat);
2298c2ecf20Sopenharmony_ci	/* Only support Planer or UYVY linear formats */
2308c2ecf20Sopenharmony_ci	CLEAR_BITS_FRM_TO(4, 9);
2318c2ecf20Sopenharmony_ci	STG_WRITE_REG(DACPixelFormat, tmp);
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	ovlWidth = inWidth;
2348c2ecf20Sopenharmony_ci	ovlHeight = inHeight;
2358c2ecf20Sopenharmony_ci	ovlStride = ulStride;
2368c2ecf20Sopenharmony_ci	ovlLinear = bLinear;
2378c2ecf20Sopenharmony_ci	*retStride = ulStride << 4;	/* In bytes */
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	return 0;
2408c2ecf20Sopenharmony_ci}
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ciint SetOverlayBlendMode(volatile STG4000REG __iomem *pSTGReg,
2438c2ecf20Sopenharmony_ci			OVRL_BLEND_MODE mode,
2448c2ecf20Sopenharmony_ci			u32 ulAlpha, u32 ulColorKey)
2458c2ecf20Sopenharmony_ci{
2468c2ecf20Sopenharmony_ci	u32 tmp;
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	tmp = STG_READ_REG(DACBlendCtrl);
2498c2ecf20Sopenharmony_ci	CLEAR_BITS_FRM_TO(28, 30);
2508c2ecf20Sopenharmony_ci	tmp |= (mode << 28);
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	switch (mode) {
2538c2ecf20Sopenharmony_ci	case COLOR_KEY:
2548c2ecf20Sopenharmony_ci		CLEAR_BITS_FRM_TO(0, 23);
2558c2ecf20Sopenharmony_ci		tmp |= (ulColorKey & 0x00FFFFFF);
2568c2ecf20Sopenharmony_ci		break;
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	case GLOBAL_ALPHA:
2598c2ecf20Sopenharmony_ci		CLEAR_BITS_FRM_TO(24, 27);
2608c2ecf20Sopenharmony_ci		tmp |= ((ulAlpha & 0xF) << 24);
2618c2ecf20Sopenharmony_ci		break;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	case CK_PIXEL_ALPHA:
2648c2ecf20Sopenharmony_ci		CLEAR_BITS_FRM_TO(0, 23);
2658c2ecf20Sopenharmony_ci		tmp |= (ulColorKey & 0x00FFFFFF);
2668c2ecf20Sopenharmony_ci		break;
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	case CK_GLOBAL_ALPHA:
2698c2ecf20Sopenharmony_ci		CLEAR_BITS_FRM_TO(0, 23);
2708c2ecf20Sopenharmony_ci		tmp |= (ulColorKey & 0x00FFFFFF);
2718c2ecf20Sopenharmony_ci		CLEAR_BITS_FRM_TO(24, 27);
2728c2ecf20Sopenharmony_ci		tmp |= ((ulAlpha & 0xF) << 24);
2738c2ecf20Sopenharmony_ci		break;
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	case GRAPHICS_MODE:
2768c2ecf20Sopenharmony_ci	case PER_PIXEL_ALPHA:
2778c2ecf20Sopenharmony_ci		break;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	default:
2808c2ecf20Sopenharmony_ci		return -EINVAL;
2818c2ecf20Sopenharmony_ci	}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	STG_WRITE_REG(DACBlendCtrl, tmp);
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	return 0;
2868c2ecf20Sopenharmony_ci}
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_civoid EnableOverlayPlane(volatile STG4000REG __iomem *pSTGReg)
2898c2ecf20Sopenharmony_ci{
2908c2ecf20Sopenharmony_ci	u32 tmp;
2918c2ecf20Sopenharmony_ci	/* Enable Overlay */
2928c2ecf20Sopenharmony_ci	tmp = STG_READ_REG(DACPixelFormat);
2938c2ecf20Sopenharmony_ci	tmp |= SET_BIT(7);
2948c2ecf20Sopenharmony_ci	STG_WRITE_REG(DACPixelFormat, tmp);
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	/* Set video stream control */
2978c2ecf20Sopenharmony_ci	tmp = STG_READ_REG(DACStreamCtrl);
2988c2ecf20Sopenharmony_ci	tmp |= SET_BIT(1);	/* video stream */
2998c2ecf20Sopenharmony_ci	STG_WRITE_REG(DACStreamCtrl, tmp);
3008c2ecf20Sopenharmony_ci}
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_cistatic u32 Overlap(u32 ulBits, u32 ulPattern)
3038c2ecf20Sopenharmony_ci{
3048c2ecf20Sopenharmony_ci	u32 ulCount = 0;
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	while (ulBits) {
3078c2ecf20Sopenharmony_ci		if (!(ulPattern & 1))
3088c2ecf20Sopenharmony_ci			ulCount++;
3098c2ecf20Sopenharmony_ci		ulBits--;
3108c2ecf20Sopenharmony_ci		ulPattern = ulPattern >> 1;
3118c2ecf20Sopenharmony_ci	}
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	return ulCount;
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci}
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ciint SetOverlayViewPort(volatile STG4000REG __iomem *pSTGReg,
3188c2ecf20Sopenharmony_ci		       u32 left, u32 top,
3198c2ecf20Sopenharmony_ci		       u32 right, u32 bottom)
3208c2ecf20Sopenharmony_ci{
3218c2ecf20Sopenharmony_ci	OVRL_SRC_DEST srcDest;
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	u32 ulSrcTop, ulSrcBottom;
3248c2ecf20Sopenharmony_ci	u32 ulSrc, ulDest;
3258c2ecf20Sopenharmony_ci	u32 ulFxScale, ulFxOffset;
3268c2ecf20Sopenharmony_ci	u32 ulHeight, ulWidth;
3278c2ecf20Sopenharmony_ci	u32 ulPattern;
3288c2ecf20Sopenharmony_ci	u32 ulDecimate, ulDecimated;
3298c2ecf20Sopenharmony_ci	u32 ulApplied;
3308c2ecf20Sopenharmony_ci	u32 ulDacXScale, ulDacYScale;
3318c2ecf20Sopenharmony_ci	u32 ulScale;
3328c2ecf20Sopenharmony_ci	u32 ulLeft, ulRight;
3338c2ecf20Sopenharmony_ci	u32 ulSrcLeft, ulSrcRight;
3348c2ecf20Sopenharmony_ci	u32 ulScaleLeft;
3358c2ecf20Sopenharmony_ci	u32 ulhDecim;
3368c2ecf20Sopenharmony_ci	u32 ulsVal;
3378c2ecf20Sopenharmony_ci	u32 ulVertDecFactor;
3388c2ecf20Sopenharmony_ci	int bResult;
3398c2ecf20Sopenharmony_ci	u32 ulClipOff = 0;
3408c2ecf20Sopenharmony_ci	u32 ulBits = 0;
3418c2ecf20Sopenharmony_ci	u32 ulsAdd = 0;
3428c2ecf20Sopenharmony_ci	u32 tmp, ulStride;
3438c2ecf20Sopenharmony_ci	u32 ulExcessPixels, ulClip, ulExtraLines;
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	srcDest.ulSrcX1 = 0;
3478c2ecf20Sopenharmony_ci	srcDest.ulSrcY1 = 0;
3488c2ecf20Sopenharmony_ci	srcDest.ulSrcX2 = ovlWidth - 1;
3498c2ecf20Sopenharmony_ci	srcDest.ulSrcY2 = ovlHeight - 1;
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	srcDest.ulDstX1 = left;
3528c2ecf20Sopenharmony_ci	srcDest.ulDstY1 = top;
3538c2ecf20Sopenharmony_ci	srcDest.ulDstX2 = right;
3548c2ecf20Sopenharmony_ci	srcDest.ulDstY2 = bottom;
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	srcDest.lDstX1 = srcDest.ulDstX1;
3578c2ecf20Sopenharmony_ci	srcDest.lDstY1 = srcDest.ulDstY1;
3588c2ecf20Sopenharmony_ci	srcDest.lDstX2 = srcDest.ulDstX2;
3598c2ecf20Sopenharmony_ci	srcDest.lDstY2 = srcDest.ulDstY2;
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci    /************* Vertical decimation/scaling ******************/
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	/* Get Src Top and Bottom */
3648c2ecf20Sopenharmony_ci	ulSrcTop = srcDest.ulSrcY1;
3658c2ecf20Sopenharmony_ci	ulSrcBottom = srcDest.ulSrcY2;
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	ulSrc = ulSrcBottom - ulSrcTop;
3688c2ecf20Sopenharmony_ci	ulDest = srcDest.lDstY2 - srcDest.lDstY1;	/* on-screen overlay */
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	if (ulSrc <= 1)
3718c2ecf20Sopenharmony_ci		return -EINVAL;
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	/* First work out the position we are to display as offset from the
3748c2ecf20Sopenharmony_ci	 * source of the buffer
3758c2ecf20Sopenharmony_ci	 */
3768c2ecf20Sopenharmony_ci	ulFxScale = (ulDest << 11) / ulSrc;	/* fixed point scale factor */
3778c2ecf20Sopenharmony_ci	ulFxOffset = (srcDest.lDstY2 - srcDest.ulDstY2) << 11;
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	ulSrcBottom = ulSrcBottom - (ulFxOffset / ulFxScale);
3808c2ecf20Sopenharmony_ci	ulSrc = ulSrcBottom - ulSrcTop;
3818c2ecf20Sopenharmony_ci	ulHeight = ulSrc;
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	ulDest = srcDest.ulDstY2 - (srcDest.ulDstY1 - 1);
3848c2ecf20Sopenharmony_ci	ulPattern = adwDecim8[ulBits];
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	/* At this point ulSrc represents the input decimator */
3878c2ecf20Sopenharmony_ci	if (ulSrc > ulDest) {
3888c2ecf20Sopenharmony_ci		ulDecimate = ulSrc - ulDest;
3898c2ecf20Sopenharmony_ci		ulBits = 0;
3908c2ecf20Sopenharmony_ci		ulApplied = ulSrc / 32;
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci		while (((ulBits * ulApplied) +
3938c2ecf20Sopenharmony_ci			Overlap((ulSrc % 32),
3948c2ecf20Sopenharmony_ci				adwDecim8[ulBits])) < ulDecimate)
3958c2ecf20Sopenharmony_ci			ulBits++;
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci		ulPattern = adwDecim8[ulBits];
3988c2ecf20Sopenharmony_ci		ulDecimated =
3998c2ecf20Sopenharmony_ci		    (ulBits * ulApplied) + Overlap((ulSrc % 32),
4008c2ecf20Sopenharmony_ci						   ulPattern);
4018c2ecf20Sopenharmony_ci		ulSrc = ulSrc - ulDecimated;	/* the number number of lines that will go into the scaler */
4028c2ecf20Sopenharmony_ci	}
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	if (ulBits && (ulBits != 32)) {
4058c2ecf20Sopenharmony_ci		ulVertDecFactor = (63 - ulBits) / (32 - ulBits);	/* vertical decimation factor scaled up to nearest integer */
4068c2ecf20Sopenharmony_ci	} else {
4078c2ecf20Sopenharmony_ci		ulVertDecFactor = 1;
4088c2ecf20Sopenharmony_ci	}
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	ulDacYScale = ((ulSrc - 1) * 2048) / (ulDest + 1);
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	tmp = STG_READ_REG(DACOverlayVtDec);	/* Decimation */
4138c2ecf20Sopenharmony_ci	CLEAR_BITS_FRM_TO(0, 31);
4148c2ecf20Sopenharmony_ci	tmp = ulPattern;
4158c2ecf20Sopenharmony_ci	STG_WRITE_REG(DACOverlayVtDec, tmp);
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci	/***************** Horizontal decimation/scaling ***************************/
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	/*
4208c2ecf20Sopenharmony_ci	 * Now we handle the horizontal case, this is a simplified version of
4218c2ecf20Sopenharmony_ci	 * the vertical case in that we decimate by factors of 2.  as we are
4228c2ecf20Sopenharmony_ci	 * working in words we should always be able to decimate by these
4238c2ecf20Sopenharmony_ci	 * factors.  as we always have to have a buffer which is aligned to a
4248c2ecf20Sopenharmony_ci	 * whole number of 128 bit words, we must align the left side to the
4258c2ecf20Sopenharmony_ci	 * lowest to the next lowest 128 bit boundary, and the right hand edge
4268c2ecf20Sopenharmony_ci	 * to the next largets boundary, (in a similar way to how we didi it in
4278c2ecf20Sopenharmony_ci	 * PMX1) as the left and right hand edges are aligned to these
4288c2ecf20Sopenharmony_ci	 * boundaries normally this only becomes an issue when we are chopping
4298c2ecf20Sopenharmony_ci	 * of one of the sides We shall work out vertical stuff first
4308c2ecf20Sopenharmony_ci	 */
4318c2ecf20Sopenharmony_ci	ulSrc = srcDest.ulSrcX2 - srcDest.ulSrcX1;
4328c2ecf20Sopenharmony_ci	ulDest = srcDest.lDstX2 - srcDest.lDstX1;
4338c2ecf20Sopenharmony_ci#ifdef _OLDCODE
4348c2ecf20Sopenharmony_ci	ulLeft = srcDest.ulDstX1;
4358c2ecf20Sopenharmony_ci	ulRight = srcDest.ulDstX2;
4368c2ecf20Sopenharmony_ci#else
4378c2ecf20Sopenharmony_ci	if (srcDest.ulDstX1 > 2) {
4388c2ecf20Sopenharmony_ci		ulLeft = srcDest.ulDstX1 + 2;
4398c2ecf20Sopenharmony_ci		ulRight = srcDest.ulDstX2 + 1;
4408c2ecf20Sopenharmony_ci	} else {
4418c2ecf20Sopenharmony_ci		ulLeft = srcDest.ulDstX1;
4428c2ecf20Sopenharmony_ci		ulRight = srcDest.ulDstX2 + 1;
4438c2ecf20Sopenharmony_ci	}
4448c2ecf20Sopenharmony_ci#endif
4458c2ecf20Sopenharmony_ci	/* first work out the position we are to display as offset from the source of the buffer */
4468c2ecf20Sopenharmony_ci	bResult = 1;
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	do {
4498c2ecf20Sopenharmony_ci		if (ulDest == 0)
4508c2ecf20Sopenharmony_ci			return -EINVAL;
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci		/* source pixels per dest pixel <<11 */
4538c2ecf20Sopenharmony_ci		ulFxScale = ((ulSrc - 1) << 11) / (ulDest);
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci		/* then number of destination pixels out we are */
4568c2ecf20Sopenharmony_ci		ulFxOffset = ulFxScale * ((srcDest.ulDstX1 - srcDest.lDstX1) + ulClipOff);
4578c2ecf20Sopenharmony_ci		ulFxOffset >>= 11;
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci		/* this replaces the code which was making a decision as to use either ulFxOffset or ulSrcX1 */
4608c2ecf20Sopenharmony_ci		ulSrcLeft = srcDest.ulSrcX1 + ulFxOffset;
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci		/* then number of destination pixels out we are */
4638c2ecf20Sopenharmony_ci		ulFxOffset = ulFxScale * (srcDest.lDstX2 - srcDest.ulDstX2);
4648c2ecf20Sopenharmony_ci		ulFxOffset >>= 11;
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci		ulSrcRight = srcDest.ulSrcX2 - ulFxOffset;
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci		/*
4698c2ecf20Sopenharmony_ci		 * we must align these to our 128 bit boundaries. we shall
4708c2ecf20Sopenharmony_ci		 * round down the pixel pos to the nearest 8 pixels.
4718c2ecf20Sopenharmony_ci		 */
4728c2ecf20Sopenharmony_ci		ulScaleLeft = ulSrcLeft;
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci		/* shift fxscale until it is in the range of the scaler */
4758c2ecf20Sopenharmony_ci		ulhDecim = 0;
4768c2ecf20Sopenharmony_ci		ulScale = (((ulSrcRight - ulSrcLeft) - 1) << (11 - ulhDecim)) / (ulRight - ulLeft + 2);
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci		while (ulScale > 0x800) {
4798c2ecf20Sopenharmony_ci			ulhDecim++;
4808c2ecf20Sopenharmony_ci			ulScale = (((ulSrcRight - ulSrcLeft) - 1) << (11 - ulhDecim)) / (ulRight - ulLeft + 2);
4818c2ecf20Sopenharmony_ci		}
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci		/*
4848c2ecf20Sopenharmony_ci		 * to try and get the best values We first try and use
4858c2ecf20Sopenharmony_ci		 * src/dwdest for the scale factor, then we move onto src-1
4868c2ecf20Sopenharmony_ci		 *
4878c2ecf20Sopenharmony_ci		 * we want to check to see if we will need to clip data, if so
4888c2ecf20Sopenharmony_ci		 * then we should clip our source so that we don't need to
4898c2ecf20Sopenharmony_ci		 */
4908c2ecf20Sopenharmony_ci		if (!ovlLinear) {
4918c2ecf20Sopenharmony_ci			ulSrcLeft &= ~0x1f;
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci			/*
4948c2ecf20Sopenharmony_ci			 * we must align the right hand edge to the next 32
4958c2ecf20Sopenharmony_ci			 * pixel` boundary, must be on a 256 boundary so u, and
4968c2ecf20Sopenharmony_ci			 * v are 128 bit aligned
4978c2ecf20Sopenharmony_ci			 */
4988c2ecf20Sopenharmony_ci			ulSrcRight = (ulSrcRight + 0x1f) & ~0x1f;
4998c2ecf20Sopenharmony_ci		} else {
5008c2ecf20Sopenharmony_ci			ulSrcLeft &= ~0x7;
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci			/*
5038c2ecf20Sopenharmony_ci			 * we must align the right hand edge to the next
5048c2ecf20Sopenharmony_ci			 * 8pixel` boundary
5058c2ecf20Sopenharmony_ci			 */
5068c2ecf20Sopenharmony_ci			ulSrcRight = (ulSrcRight + 0x7) & ~0x7;
5078c2ecf20Sopenharmony_ci		}
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci		/* this is the input size line store needs to cope with */
5108c2ecf20Sopenharmony_ci		ulWidth = ulSrcRight - ulSrcLeft;
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci		/*
5138c2ecf20Sopenharmony_ci		 * use unclipped value to work out scale factror this is the
5148c2ecf20Sopenharmony_ci		 * scale factor we want we shall now work out the horizonal
5158c2ecf20Sopenharmony_ci		 * decimation and scaling
5168c2ecf20Sopenharmony_ci		 */
5178c2ecf20Sopenharmony_ci		ulsVal = ((ulWidth / 8) >> ulhDecim);
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci		if ((ulWidth != (ulsVal << ulhDecim) * 8))
5208c2ecf20Sopenharmony_ci			ulsAdd = 1;
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci		/* input pixels to scaler; */
5238c2ecf20Sopenharmony_ci		ulSrc = ulWidth >> ulhDecim;
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci		if (ulSrc <= 2)
5268c2ecf20Sopenharmony_ci			return -EINVAL;
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci		ulExcessPixels = ((((ulScaleLeft - ulSrcLeft)) << (11 - ulhDecim)) / ulScale);
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci		ulClip = (ulSrc << 11) / ulScale;
5318c2ecf20Sopenharmony_ci		ulClip -= (ulRight - ulLeft);
5328c2ecf20Sopenharmony_ci		ulClip += ulExcessPixels;
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci		if (ulClip)
5358c2ecf20Sopenharmony_ci			ulClip--;
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci		/* We may need to do more here if we really have a HW rev < 5 */
5388c2ecf20Sopenharmony_ci	} while (!bResult);
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	ulExtraLines = (1 << ulhDecim) * ulVertDecFactor;
5418c2ecf20Sopenharmony_ci	ulExtraLines += 64;
5428c2ecf20Sopenharmony_ci	ulHeight += ulExtraLines;
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci	ulDacXScale = ulScale;
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci	tmp = STG_READ_REG(DACVerticalScal);
5488c2ecf20Sopenharmony_ci	CLEAR_BITS_FRM_TO(0, 11);
5498c2ecf20Sopenharmony_ci	CLEAR_BITS_FRM_TO(16, 22);	/* Vertical Scaling */
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci	/* Calculate new output line stride, this is always the number of 422
5528c2ecf20Sopenharmony_ci	   words in the line buffer, so it doesn't matter if the
5538c2ecf20Sopenharmony_ci	   mode is 420. Then set the vertical scale register.
5548c2ecf20Sopenharmony_ci	 */
5558c2ecf20Sopenharmony_ci	ulStride = (ulWidth >> (ulhDecim + 3)) + ulsAdd;
5568c2ecf20Sopenharmony_ci	tmp |= ((ulStride << 16) | (ulDacYScale));	/* DAC_LS_CTRL = stride */
5578c2ecf20Sopenharmony_ci	STG_WRITE_REG(DACVerticalScal, tmp);
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	/* Now set up the overlay size using the modified width and height
5608c2ecf20Sopenharmony_ci	   from decimate and scaling calculations
5618c2ecf20Sopenharmony_ci	 */
5628c2ecf20Sopenharmony_ci	tmp = STG_READ_REG(DACOverlaySize);
5638c2ecf20Sopenharmony_ci	CLEAR_BITS_FRM_TO(0, 10);
5648c2ecf20Sopenharmony_ci	CLEAR_BITS_FRM_TO(12, 31);
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci	if (ovlLinear) {
5678c2ecf20Sopenharmony_ci		tmp |=
5688c2ecf20Sopenharmony_ci		    (ovlStride | ((ulHeight + 1) << 12) |
5698c2ecf20Sopenharmony_ci		     (((ulWidth / 8) - 1) << 23));
5708c2ecf20Sopenharmony_ci	} else {
5718c2ecf20Sopenharmony_ci		tmp |=
5728c2ecf20Sopenharmony_ci		    (ovlStride | ((ulHeight + 1) << 12) |
5738c2ecf20Sopenharmony_ci		     (((ulWidth / 32) - 1) << 23));
5748c2ecf20Sopenharmony_ci	}
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	STG_WRITE_REG(DACOverlaySize, tmp);
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	/* Set Video Window Start */
5798c2ecf20Sopenharmony_ci	tmp = ((ulLeft << 16)) | (srcDest.ulDstY1);
5808c2ecf20Sopenharmony_ci	STG_WRITE_REG(DACVidWinStart, tmp);
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	/* Set Video Window End */
5838c2ecf20Sopenharmony_ci	tmp = ((ulRight) << 16) | (srcDest.ulDstY2);
5848c2ecf20Sopenharmony_ci	STG_WRITE_REG(DACVidWinEnd, tmp);
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci	/* Finally set up the rest of the overlay regs in the order
5878c2ecf20Sopenharmony_ci	   done in the IMG driver
5888c2ecf20Sopenharmony_ci	 */
5898c2ecf20Sopenharmony_ci	tmp = STG_READ_REG(DACPixelFormat);
5908c2ecf20Sopenharmony_ci	tmp = ((ulExcessPixels << 16) | tmp) & 0x7fffffff;
5918c2ecf20Sopenharmony_ci	STG_WRITE_REG(DACPixelFormat, tmp);
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci	tmp = STG_READ_REG(DACHorizontalScal);
5948c2ecf20Sopenharmony_ci	CLEAR_BITS_FRM_TO(0, 11);
5958c2ecf20Sopenharmony_ci	CLEAR_BITS_FRM_TO(16, 17);
5968c2ecf20Sopenharmony_ci	tmp |= ((ulhDecim << 16) | (ulDacXScale));
5978c2ecf20Sopenharmony_ci	STG_WRITE_REG(DACHorizontalScal, tmp);
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci	return 0;
6008c2ecf20Sopenharmony_ci}
601