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