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