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