1 /*
2    TI Davinci driver - Video Layer
3 
4    (c) Copyright 2007  Telio AG
5 
6    Written by Denis Oliver Kropp <dok@directfb.org>
7 
8    Code is derived from VMWare driver.
9 
10    (c) Copyright 2001-2009  The world wide DirectFB Open Source Community (directfb.org)
11    (c) Copyright 2000-2004  Convergence (integrated media) GmbH
12 
13    All rights reserved.
14 
15    This library is free software; you can redistribute it and/or
16    modify it under the terms of the GNU Lesser General Public
17    License as published by the Free Software Foundation; either
18    version 2 of the License, or (at your option) any later version.
19 
20    This library is distributed in the hope that it will be useful,
21    but WITHOUT ANY WARRANTY; without even the implied warranty of
22    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23    Lesser General Public License for more details.
24 
25    You should have received a copy of the GNU Lesser General Public
26    License along with this library; if not, write to the
27    Free Software Foundation, Inc., 59 Temple Place - Suite 330,
28    Boston, MA 02111-1307, USA.
29 */
30 
31 //#define DIRECT_ENABLE_DEBUG
32 
33 #include <config.h>
34 
35 #include <asm/types.h>
36 
37 #include <stdio.h>
38 #include <sys/ioctl.h>
39 
40 #include <directfb.h>
41 #include <directfb_util.h>
42 
43 #include <core/layers.h>
44 #include <core/surface.h>
45 #include <core/surface_buffer.h>
46 
47 #include <gfx/convert.h>
48 
49 #include <direct/memcpy.h>
50 #include <direct/messages.h>
51 
52 #include "davincifb.h"
53 
54 #include "davinci_gfxdriver.h"
55 #include "davinci_video.h"
56 
57 
58 #define D_VIDERROR(x...) do {} while (0)
59 
60 
61 D_DEBUG_DOMAIN( Davinci_Video, "Davinci/Video", "TI Davinci Video" );
62 
63 /**********************************************************************************************************************/
64 
65 static DFBResult ShowBuffer( DavinciDriverData     *ddrv,
66                              DavinciVideoLayerData *dvid,
67                              CoreSurfaceBufferLock *lock,
68                              const DFBRectangle    *area,
69                              DFBSurfaceFlipFlags    flags );
70 
71 static void SetupResizerParams( vpfe_resizer_params_t *params,
72                                 int srcWidth, int srcHeight,
73                                 int outWidth, int outHeight,
74                                 int *ret_outWidth,
75                                 int *ret_outHeight );
76 
77 /**********************************************************************************************************************/
78 
79 static int
videoLayerDataSize(void)80 videoLayerDataSize( void )
81 {
82      return sizeof(DavinciVideoLayerData);
83 }
84 
85 static DFBResult
videoInitLayer(CoreLayer * layer,void * driver_data,void * layer_data,DFBDisplayLayerDescription * description,DFBDisplayLayerConfig * config,DFBColorAdjustment * adjustment)86 videoInitLayer( CoreLayer                  *layer,
87                 void                       *driver_data,
88                 void                       *layer_data,
89                 DFBDisplayLayerDescription *description,
90                 DFBDisplayLayerConfig      *config,
91                 DFBColorAdjustment         *adjustment )
92 {
93      int                    ret;
94      DavinciDriverData     *ddrv = driver_data;
95      DavinciVideoLayerData *dvid = layer_data;
96 
97      D_DEBUG_AT( Davinci_Video, "%s()\n", __FUNCTION__ );
98 
99      /* Initialize with configuration from VID0 to start with a fullscreen (unscaled) layer */
100      ret = ioctl( ddrv->fb[VID0].fd, FBIOGET_VSCREENINFO, &dvid->var );
101      if (ret) {
102           D_PERROR( "Davinci/Video: FBIOGET_VSCREENINFO (fb%d) failed!\n", VID0 );
103           return DFB_INIT;
104      }
105 
106      /* Disable VID0 (unused) */
107      ret = ioctl( ddrv->fb[VID0].fd, FBIO_ENABLE_DISABLE_WIN, 0 );
108      if (ret)
109           D_VIDERROR( "Davinci/Video: FBIO_ENABLE_DISABLE_WIN (fb%d - %d)!\n", VID0, 0 );
110 
111      /* Disable VID1 (our layer) */
112      ret = ioctl( ddrv->fb[VID1].fd, FBIO_ENABLE_DISABLE_WIN, 0 );
113      if (ret)
114           D_VIDERROR( "Davinci/Video: FBIO_ENABLE_DISABLE_WIN (fb%d - %d)!\n", VID1, 0 );
115 
116      /* set capabilities and type */
117      description->caps = DLCAPS_SURFACE | DLCAPS_SCREEN_LOCATION;
118      description->type = DLTF_VIDEO | DLTF_STILL_PICTURE;
119 
120      /* set name */
121      snprintf( description->name, DFB_DISPLAY_LAYER_DESC_NAME_LENGTH, "TI Davinci Video" );
122 
123      /* fill out the default configuration */
124      config->flags       = DLCONF_WIDTH       | DLCONF_HEIGHT |
125                            DLCONF_PIXELFORMAT | DLCONF_BUFFERMODE | DLCONF_OPTIONS;
126      config->width       = dvid->var.xres;
127      config->height      = dvid->var.yres;
128      config->pixelformat = DSPF_UYVY;
129      config->buffermode  = DLBM_FRONTONLY;
130      config->options     = DLOP_NONE;
131 
132      return DFB_OK;
133 }
134 
135 static DFBResult
videoTestRegion(CoreLayer * layer,void * driver_data,void * layer_data,CoreLayerRegionConfig * config,CoreLayerRegionConfigFlags * failed)136 videoTestRegion( CoreLayer                  *layer,
137                  void                       *driver_data,
138                  void                       *layer_data,
139                  CoreLayerRegionConfig      *config,
140                  CoreLayerRegionConfigFlags *failed )
141 {
142      CoreLayerRegionConfigFlags fail = 0;
143 
144      D_DEBUG_AT( Davinci_Video, "%s()\n", __FUNCTION__ );
145 
146      DFB_CORE_LAYER_REGION_CONFIG_DEBUG_AT( Davinci_Video, config );
147 
148      if (config->options & ~DAVINCI_VIDEO_SUPPORTED_OPTIONS)
149           fail |= CLRCF_OPTIONS;
150 
151      switch (config->format) {
152           case DSPF_UYVY:
153                break;
154 
155           default:
156                fail |= CLRCF_FORMAT;
157      }
158 
159      if (config->width  < 8 || config->width  > 1920)
160           fail |= CLRCF_WIDTH;
161 
162      if (config->height < 8 || config->height > 1080)
163           fail |= CLRCF_HEIGHT;
164 
165      if (config->dest.x < 0 || config->dest.y < 0)
166           fail |= CLRCF_DEST;
167 
168      if (config->dest.x + config->dest.w > 1920)
169           fail |= CLRCF_DEST;
170 
171      if (config->dest.y + config->dest.h > 1080)
172           fail |= CLRCF_DEST;
173 
174      if (failed)
175           *failed = fail;
176 
177      if (fail) {
178           D_DEBUG_AT( Davinci_Video, "  -> FAILED (0x%08x)\n", fail );
179           return DFB_UNSUPPORTED;
180      }
181 
182      D_DEBUG_AT( Davinci_Video, "  -> OK\n" );
183 
184      return DFB_OK;
185 }
186 
187 static DFBResult
videoSetRegion(CoreLayer * layer,void * driver_data,void * layer_data,void * region_data,CoreLayerRegionConfig * config,CoreLayerRegionConfigFlags updated,CoreSurface * surface,CorePalette * palette,CoreSurfaceBufferLock * lock)188 videoSetRegion( CoreLayer                  *layer,
189                 void                       *driver_data,
190                 void                       *layer_data,
191                 void                       *region_data,
192                 CoreLayerRegionConfig      *config,
193                 CoreLayerRegionConfigFlags  updated,
194                 CoreSurface                *surface,
195                 CorePalette                *palette,
196                 CoreSurfaceBufferLock      *lock )
197 {
198      int                    ret;
199      DavinciDriverData     *ddrv = driver_data;
200      DavinciDeviceData     *ddev = ddrv->ddev;
201      DavinciVideoLayerData *dvid = layer_data;
202      CoreLayerRegionConfig *old  = &dvid->config;
203 
204      D_DEBUG_AT( Davinci_Video, "%s( updated 0x%08x, surface %p )\n", __FUNCTION__, updated, surface );
205 
206      DFB_CORE_LAYER_REGION_CONFIG_DEBUG_AT( Davinci_Video, config );
207 
208      D_ASSERT( ddrv != NULL );
209      D_ASSERT( ddev != NULL );
210      D_ASSERT( dvid != NULL );
211 
212      /* Update output size? */
213      if ((updated & CLRCF_DEST) && (config->dest.w != old->dest.w || config->dest.h != old->dest.h)) {
214           vpbe_window_position_t win_pos;
215 
216           D_DEBUG_AT( Davinci_Video, "  => dest    %4dx%4d\n", config->dest.w, config->dest.h );
217 
218           ret = ioctl( ddrv->fb[VID1].fd, FBIO_ENABLE_DISABLE_WIN, 0 );
219           if (ret)
220                D_VIDERROR( "Davinci/Video: FBIO_ENABLE_DISABLE_WIN (fb%d - %d)!\n", VID1, 0 );
221 
222           dvid->enabled = false;
223 
224 /*********************************** Start workaround ***********************************/
225           win_pos.xpos = 0;
226           win_pos.ypos = 0;
227 
228           ret = ioctl( ddrv->fb[VID1].fd, FBIO_SETPOS, &win_pos );
229           if (ret)
230                D_VIDERROR( "Davinci/Video: FBIO_SETPOS (fb%d - %d,%d) failed!\n", VID1, win_pos.xpos, win_pos.ypos );
231 
232           dvid->var.yoffset = 0;
233 /*********************************** End workaround ***********************************/
234 
235           /* Set output width and height. */
236           dvid->var.xres = config->dest.w;
237           dvid->var.yres = config->dest.h;
238 
239           dvid->var.yres_virtual = ddrv->fb[VID1].size / lock->pitch;
240 
241           ret = ioctl( ddrv->fb[VID1].fd, FBIOPUT_VSCREENINFO, &dvid->var );
242           if (ret)
243                D_PERROR( "Davinci/Video: FBIOPUT_VSCREENINFO (fb%d) failed!\n", VID1 );
244 
245           /* Read back new pitch etc. */
246           ret = ioctl( ddrv->fb[VID1].fd, FBIOGET_FSCREENINFO, &ddev->fix[VID1] );
247           if (ret)
248                D_PERROR( "Davinci/Video: FBIOGET_FSCREENINFO (fb%d) failed!\n", VID1 );
249      }
250 
251      /* Update output position? */
252      if (updated & CLRCF_DEST) {
253           vpbe_window_position_t win_pos;
254 
255           D_DEBUG_AT( Davinci_Video, "  => dest    %4d,%4d\n", config->dest.x, config->dest.y );
256 
257           if (dvid->enabled)
258                ioctl( ddrv->fb[VID1].fd, FBIO_WAITFORVSYNC );
259 
260           /* Set horizontal and vertical offset. */
261           win_pos.xpos = config->dest.x;
262           win_pos.ypos = config->dest.y;
263 
264           ret = ioctl( ddrv->fb[VID1].fd, FBIO_SETPOS, &win_pos );
265           if (ret)
266                D_VIDERROR( "Davinci/Video: FBIO_SETPOS (fb%d - %d,%d) failed!\n", VID1, config->dest.x, config->dest.y );
267      }
268 
269      /* Update format? */
270      if (updated & CLRCF_FORMAT) {
271           vpbe_video_config_params_t params;
272 
273           params.cb_cr_order = (config->format == DSPF_YUY2) ? 1 : 0;
274 
275           params.exp_info.horizontal = VPBE_DISABLE;
276           params.exp_info.vertical   = VPBE_DISABLE;
277 
278           ret = ioctl( ddrv->fb[VID1].fd, FBIO_SET_VIDEO_CONFIG_PARAMS, &params );
279           if (ret)
280                D_VIDERROR( "Davinci/Video: FBIO_SET_VIDEO_CONFIG_PARAMS (fb%d - %s) failed!\n",
281                          VID1, params.cb_cr_order ? "CrCb" : "CbCr" );
282      }
283 
284      /* Update scaling parameters? */
285      if ((updated & (CLRCF_SOURCE | CLRCF_DEST)) &&
286          (config->source.w != old->source.w || config->source.h != old->source.h ||
287           config->dest.w   != old->dest.w   || config->dest.h   != old->dest.h) &&
288          (config->dest.w != config->source.w || config->dest.h != config->source.h))
289      {
290           D_DEBUG_AT( Davinci_Video, "  => scaling %4dx%4d -> %4dx%4d\n",
291                       config->source.w, config->source.h, config->dest.w, config->dest.h );
292 
293           SetupResizerParams( &dvid->resizer, config->source.w, config->source.h,
294                               config->dest.w, config->dest.h, &dvid->resized.w, &dvid->resized.h );
295 
296           dvid->offset.x = (config->dest.w - dvid->resized.w) / 2;
297           dvid->offset.y = (config->dest.h - dvid->resized.h) / 2;
298 
299           D_DEBUG_AT( Davinci_Video, "  => resized %4dx%4d, centered %d,%d\n",
300                       dvid->resized.w, dvid->resized.h, dvid->offset.x, dvid->offset.y );
301 
302           dvid->offset.x += dvid->offset.x & 1; /* Round up to multiple of two */
303 
304           D_DEBUG_AT( Davinci_Video, "  => offset  %4d,%4d\n", dvid->offset.x, dvid->offset.y );
305 
306           davincifb_pan_display( &ddrv->fb[VID1], &dvid->var, NULL, DSFLIP_NONE, 0, 0 );
307      }
308 
309      dvid->enable = true;
310      dvid->config = *config;
311 
312      return DFB_OK;
313 }
314 
315 static DFBResult
videoRemoveRegion(CoreLayer * layer,void * driver_data,void * layer_data,void * region_data)316 videoRemoveRegion( CoreLayer *layer,
317                    void      *driver_data,
318                    void      *layer_data,
319                    void      *region_data )
320 {
321      int                    ret;
322      DavinciDriverData     *ddrv = driver_data;
323      DavinciVideoLayerData *dvid = layer_data;
324 
325      D_DEBUG_AT( Davinci_Video, "%s()\n", __FUNCTION__ );
326 
327      D_ASSERT( ddrv != NULL );
328 
329      ret = ioctl( ddrv->fb[VID1].fd, FBIO_ENABLE_DISABLE_WIN, 0 );
330      if (ret)
331           D_VIDERROR( "Davinci/Video: FBIO_ENABLE_DISABLE_WIN (fb%d - %d)!\n", VID1, 0 );
332 
333      dvid->enabled = false;
334      dvid->enable  = false;
335 
336      return DFB_OK;
337 }
338 
339 static DFBResult
videoFlipRegion(CoreLayer * layer,void * driver_data,void * layer_data,void * region_data,CoreSurface * surface,DFBSurfaceFlipFlags flags,CoreSurfaceBufferLock * lock)340 videoFlipRegion( CoreLayer             *layer,
341                  void                  *driver_data,
342                  void                  *layer_data,
343                  void                  *region_data,
344                  CoreSurface           *surface,
345                  DFBSurfaceFlipFlags    flags,
346                  CoreSurfaceBufferLock *lock )
347 {
348      DFBResult              ret;
349      DavinciDriverData     *ddrv = driver_data;
350      DavinciVideoLayerData *dvid = layer_data;
351 
352      D_ASSERT( surface != NULL );
353      D_ASSERT( lock != NULL );
354      D_ASSERT( ddrv != NULL );
355      D_ASSERT( dvid != NULL );
356 
357      D_DEBUG_AT( Davinci_Video, "%s( 0x%08lx [%d] 0x%04x [%4dx%4d] )\n", __FUNCTION__,
358                  lock->phys, lock->pitch, flags, dvid->config.width, dvid->config.height );
359 
360      ret = ShowBuffer( ddrv, dvid, lock, NULL, flags );
361      if (ret)
362           return ret;
363 
364      dfb_surface_flip( surface, false );
365 
366      return DFB_OK;
367 }
368 
369 static DFBResult
videoUpdateRegion(CoreLayer * layer,void * driver_data,void * layer_data,void * region_data,CoreSurface * surface,const DFBRegion * update,CoreSurfaceBufferLock * lock)370 videoUpdateRegion( CoreLayer             *layer,
371                    void                  *driver_data,
372                    void                  *layer_data,
373                    void                  *region_data,
374                    CoreSurface           *surface,
375                    const DFBRegion       *update,
376                    CoreSurfaceBufferLock *lock )
377 {
378      DavinciDriverData     *ddrv = driver_data;
379      DavinciVideoLayerData *dvid = layer_data;
380 
381      D_ASSERT( surface != NULL );
382      D_ASSERT( lock != NULL );
383      D_ASSERT( ddrv != NULL );
384      D_ASSERT( dvid != NULL );
385 
386      if (update) {
387           DFBRectangle area = DFB_RECTANGLE_INIT_FROM_REGION( update );
388 
389           D_DEBUG_AT( Davinci_Video, "%s( 0x%08lx [%d], %4d,%4d-%4dx%4d )\n", __FUNCTION__,
390                       lock->phys, lock->pitch, DFB_RECTANGLE_VALS( &area ) );
391 
392           if (!dfb_rectangle_intersect( &area, &dvid->config.source )) {
393                D_DEBUG_AT( Davinci_Video, "  -> NO INTERSECTION with %4d,%4d-%4dx%4d\n",
394                            DFB_RECTANGLE_VALS( &dvid->config.source ) );
395 
396                return DFB_OK;
397           }
398 
399           if (!DFB_RECTANGLE_EQUAL( area, dvid->config.source ))
400                return ShowBuffer( ddrv, dvid, lock, &area, DSFLIP_NONE );
401      }
402      else
403           D_DEBUG_AT( Davinci_Video, "%s( 0x%08lx [%d], %4dx%4d )\n", __FUNCTION__,
404                       lock->phys, lock->pitch, dvid->config.width, dvid->config.height );
405 
406      return ShowBuffer( ddrv, dvid, lock, NULL, DSFLIP_NONE );
407 }
408 
409 const DisplayLayerFuncs davinciVideoLayerFuncs = {
410      .LayerDataSize = videoLayerDataSize,
411      .InitLayer     = videoInitLayer,
412 
413      .TestRegion    = videoTestRegion,
414      .SetRegion     = videoSetRegion,
415      .RemoveRegion  = videoRemoveRegion,
416      .FlipRegion    = videoFlipRegion,
417      .UpdateRegion  = videoUpdateRegion,
418 };
419 
420 /***********************************************************************************************************************
421 ** Frame Output
422 */
423 
424 static void
enable_video(DavinciDriverData * ddrv,DavinciVideoLayerData * dvid)425 enable_video( DavinciDriverData     *ddrv,
426               DavinciVideoLayerData *dvid )
427 {
428      if (dvid->enable && !dvid->enabled) {
429           ioctl( ddrv->fb[VID1].fd, FBIO_WAITFORVSYNC );
430 
431           if (ioctl( ddrv->fb[VID1].fd, FBIO_ENABLE_DISABLE_WIN, 1 ))
432                D_VIDERROR( "Davinci/Video: FBIO_ENABLE_DISABLE_WIN (fb%d - %d)!\n", VID1, 1 );
433 
434           dvid->enabled = true;
435      }
436 }
437 
438 static DFBResult
ShowBuffer(DavinciDriverData * ddrv,DavinciVideoLayerData * dvid,CoreSurfaceBufferLock * lock,const DFBRectangle * area,DFBSurfaceFlipFlags flags)439 ShowBuffer( DavinciDriverData     *ddrv,
440             DavinciVideoLayerData *dvid,
441             CoreSurfaceBufferLock *lock,
442             const DFBRectangle    *area,
443             DFBSurfaceFlipFlags    flags )
444 {
445      const CoreLayerRegionConfig *config = &dvid->config;
446 
447      if (area)
448           D_DEBUG_AT( Davinci_Video, "%s( 0x%08lx [%d], %4d,%4d-%4dx%4d )\n", __FUNCTION__,
449                       lock->phys, lock->pitch, DFB_RECTANGLE_VALS( area ) );
450      else
451           D_DEBUG_AT( Davinci_Video, "%s( 0x%08lx [%d] )\n", __FUNCTION__, lock->phys, lock->pitch );
452 
453      if (config->dest.w == config->source.w && config->dest.h == config->source.h) {
454           /*
455            * Unscaled video, buffer displayed directly
456            */
457           D_DEBUG_AT( Davinci_Video, "  -> unscaled %4dx%4d <- %4d,%4d [%4dx%4d]\n",
458                       config->source.w, config->source.h, config->source.x, config->source.y,
459                       config->width, config->height );
460 
461           /* Partial update, assuming proper buffer is shown, saving system calls */
462           if (area && dvid->enabled)
463                return DFB_OK;
464 
465           davincifb_pan_display( &ddrv->fb[VID1], &dvid->var, lock, flags, config->source.x, config->source.y );
466      }
467      else {
468           int                    ret;
469           DavinciDeviceData     *ddev   = ddrv->ddev;
470           CoreSurfaceBuffer     *buffer = lock->buffer;
471           vpfe_resizer_params_t *params = &dvid->resizer;
472 
473           /*
474            * Scaled video, buffer scaled to output buffer by resizer
475            */
476           D_DEBUG_AT( Davinci_Video, "  -> scaled %4dx%4d -> %4dx%4d <- %4d,%4d [%4dx%4d]\n",
477                       config->source.w, config->source.h, config->dest.w, config->dest.h,
478                       config->source.x, config->source.y, config->width, config->height );
479 
480           /* FIXME: Implement scaled partial updates! */
481           if (area)
482                D_UNIMPLEMENTED();
483 
484           params->sdr_inoff = lock->pitch;
485           params->sdr_inadd = lock->phys + DFB_BYTES_PER_LINE( buffer->format, config->source.x )
486                                          + config->source.y * params->sdr_inoff;
487 
488           params->sdr_outoff = ddev->fix[VID1].line_length;
489           params->sdr_outadd = ddev->fix[VID1].smem_start + dvid->offset.x * 2
490                                                           + dvid->offset.y * params->sdr_outoff;
491 
492           params->in_start    = (params->sdr_outadd & 0x1f) / 2;
493           params->sdr_outadd &= ~0x1f;
494 
495           D_DEBUG_AT( Davinci_Video, "  -> FBIO_RESIZER running...\n" );
496 
497           ret = ioctl( ddrv->fb[VID1].fd, FBIO_RESIZER, params );
498           if (ret)
499                D_VIDERROR( "Davinci/Video: FBIO_RESIZER (fb%d)!\n", VID1 );
500 
501           D_DEBUG_AT( Davinci_Video, "  => FBIO_RESIZER returned %d\n", ret );
502      }
503 
504      enable_video( ddrv, dvid );
505 
506      return DFB_OK;
507 }
508 
509 /***********************************************************************************************************************
510 ** Scaling Setup
511 */
512 
513 static int
limitInput(int rsz,int inSize,int outSize,int * pInSize)514 limitInput(int rsz,int inSize,int outSize,int* pInSize)
515 {
516      int phases;
517      int phaseShift;
518      int taps;
519      int phaseMask;
520      int coarseShift;
521      int halfCoarse;
522      int tmp;
523 
524      do {
525           if (rsz<=512) {
526                //1/2x to 4x resize uses 8 phase, 4 taps
527                phaseShift = 3;
528                taps = 4;
529           }
530           else {
531                //4-phase, 7 taps
532                phaseShift = 2;
533                taps = 7;
534           }
535           phases = 1<<phaseShift;
536           phaseMask = phases-1;
537           coarseShift = (8-phaseShift);
538           halfCoarse = (1<<(coarseShift-1));
539           tmp = (((outSize-1)* rsz + halfCoarse)>>8) + taps;
540           if (tmp <= inSize) break;
541           rsz--;
542      } while (1);
543 
544      *pInSize = tmp;
545 
546      return rsz;
547 }
548 
549 static void
SetupCoef(unsigned int * pCoef,int rsz)550 SetupCoef(unsigned int* pCoef,int rsz)
551 {
552      int startCoef;
553      int highCoef;
554      int c;
555      int phases;
556      int taps;
557      if (rsz<=512) {
558           //1/2x to 4x resize uses 8 phase, 4 taps
559           highCoef = 0x100;
560           c=1;
561           phases=8;
562           taps=4;
563      }
564      else {
565           //4-phase, 7 taps
566           if (rsz<=(256*3)) {
567                highCoef = 0x100/2; c=2;
568           }
569           else {
570                highCoef = 0x100/4; c=1;
571           }
572           phases=4;
573           taps=7;
574      }
575      startCoef = highCoef>>1;
576      while (phases) {
577           int prev = startCoef;
578           int tapNum=0;
579           int rem=256 - startCoef;
580           while ( tapNum < (c-1)) {
581                *pCoef++ = 0;
582                tapNum+=2;
583           }
584           if (c&1) {
585                *pCoef++ = prev<<16;
586                tapNum+=2;
587           }
588           else {
589                tapNum++;
590           }
591           while ( tapNum < taps) {
592                int min = (rem<highCoef)? rem : highCoef;
593                if (tapNum&1) *pCoef++ = (min<<16)+prev;
594                else prev = min;
595                rem -= min;
596                tapNum++;
597           }
598           if (tapNum&1) {
599                *pCoef++ = prev;
600                tapNum++;
601           }
602           while ( tapNum < taps) {
603                *pCoef++ = 0;
604                tapNum+=2;
605           }
606           if (startCoef > (highCoef>>3)) startCoef -= (highCoef>>3);
607           else {
608                startCoef = highCoef; c++;
609           }
610           phases--;
611      }
612 }
613 
614 #define SDRAM_SRC (1<<28)
615 #define BILINEAR (1<<29)
616 
617 static void
SetupResizerParams(vpfe_resizer_params_t * params,int srcWidth,int srcHeight,int outWidth,int outHeight,int * ret_outWidth,int * ret_outHeight)618 SetupResizerParams( vpfe_resizer_params_t *params,
619                     int srcWidth, int srcHeight,
620                     int outWidth, int outHeight,
621                     int *ret_outWidth,
622                     int *ret_outHeight )
623 {
624      int rsz;
625      int hrsz;
626      int vrsz;
627      int tmp;
628 
629      D_DEBUG_AT( Davinci_Video, "%s( %4dx%4d->%4dx%4d )\n", __FUNCTION__, srcWidth, srcHeight, outWidth, outHeight );
630 
631      params->sdr_inadd = 0;
632      params->sdr_inoff = 0;
633 
634      params->sdr_outadd = 0;
635      params->sdr_outoff = 0;
636 
637      params->in_start = (0<<16)|(0);
638      params->yenh = 0;
639 
640      params->rsz_cnt = SDRAM_SRC;
641 
642 
643 
644 
645      //find scale factor
646      rsz = (srcWidth<<8)/outWidth;
647      if (rsz<64) {
648           //too much upscaling, reduce destination size
649           rsz = 64;
650      }
651      else if (rsz>1024) {
652           //too much down scaling, reduce source size
653           rsz=1024;
654           srcWidth  = (outWidth * rsz)>>8;
655      }
656 
657      tmp = ((srcWidth<<8)+255)/rsz;
658      if (tmp > outWidth) tmp = outWidth;
659      tmp &= ~1;  //force even
660      if (rsz>256) {
661           //upsize in vertical direction requires a multiple of 16 bytes (8 pixels)
662           tmp &= ~0x7;
663      }
664      do {
665           int t;
666           hrsz = limitInput(rsz,srcWidth,tmp,&t);
667           if (hrsz>=64) {
668                srcWidth = t;
669                break;
670           }
671           tmp-=2;
672      } while (1);
673      outWidth = tmp;
674 
675      if (srcWidth==outWidth) {
676           int i=0;
677           params->rsz_cnt |= ((256-1)<<0);    //1 to 1
678           params->in_size = (srcWidth+3);  //4 taps
679           while (i<16) {
680                params->hfilt[i] = i? 0 : 0x100; //2 coefficient written at a time
681                i++;
682           }
683      }
684      else {
685           SetupCoef(&params->hfilt[0],hrsz);
686           params->rsz_cnt |= ((hrsz-1)<<0) | ((hrsz<256)? BILINEAR : 0);
687           params->in_size = (srcWidth);
688      }
689 
690 
691 
692 
693      //find scale factor
694      rsz = (srcHeight<<8)/outHeight;
695      if (rsz<64) {
696           //too much upscaling, reduce destination size
697           rsz = 64;
698      }
699      else if (rsz>1024) {
700           //too much down scaling, reduce source size
701           rsz=1024;
702           srcHeight = (outHeight * rsz)>>8;
703      }
704 
705      tmp = ((srcHeight<<8)+255)/rsz;
706      if (tmp > outHeight) tmp = outHeight;
707      do {
708           int t;
709           vrsz = limitInput(rsz,srcHeight,tmp,&t);
710           if (vrsz>=64) {
711                srcHeight = t;
712                break;
713           }
714           tmp--;
715      } while (1);
716      outHeight = tmp;
717 
718      if (srcHeight==outHeight) {
719           int i=0;
720           params->rsz_cnt |= ((256-1)<<10);   //1 to 1
721           params->in_size |= ((srcHeight+3)<<16);   //4 taps
722           while (i<16) {
723                params->vfilt[i] = i? 0 : 0x100; //2 coefficient written at a time
724                i++;
725           }
726      }
727      else {
728           SetupCoef(&params->vfilt[0],vrsz);
729           params->rsz_cnt |= ((vrsz-1)<<10);
730           params->in_size |= (srcHeight<<16);
731      }
732 
733 
734      params->out_size = (outHeight<<16)|(outWidth);
735 
736      D_DEBUG_AT( Davinci_Video, "  => %4dx%4d->%4dx%4d\n", srcWidth, srcHeight, outWidth, outHeight );
737 
738      if (ret_outWidth)
739           *ret_outWidth = outWidth;
740 
741      if (ret_outHeight)
742           *ret_outHeight = outHeight;
743 }
744 
745