1 /*
2    (c) Copyright 2001-2009  The world wide DirectFB Open Source Community (directfb.org)
3    (c) Copyright 2000-2004  Convergence (integrated media) GmbH
4 
5    All rights reserved.
6 
7    Written by Denis Oliver Kropp <dok@directfb.org>,
8               Andreas Hundt <andi@fischlustig.de>,
9               Sven Neumann <neo@directfb.org>,
10               Ville Syrjälä <syrjala@sci.fi> and
11               Claudio Ciccani <klan@users.sf.net>.
12 
13    This library is free software; you can redistribute it and/or
14    modify it under the terms of the GNU Lesser General Public
15    License as published by the Free Software Foundation; either
16    version 2 of the License, or (at your option) any later version.
17 
18    This library is distributed in the hope that it will be useful,
19    but WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21    Lesser General Public License for more details.
22 
23    You should have received a copy of the GNU Lesser General Public
24    License along with this library; if not, write to the
25    Free Software Foundation, Inc., 59 Temple Place - Suite 330,
26    Boston, MA 02111-1307, USA.
27 */
28 
29 #include <config.h>
30 
31 #include <stdio.h>
32 
33 #include <direct/messages.h>
34 
35 #include <core/coredefs.h>
36 #include <core/layers.h>
37 #include <core/surface.h>
38 
39 #include "regs.h"
40 #include "mmio.h"
41 #include "ati128.h"
42 
43 typedef struct {
44      CoreLayerRegionConfig config;
45 
46      /* overlay registers */
47      struct {
48           u32 H_INC;
49           u32 STEP_BY;
50           u32 Y_X_START;
51           u32 Y_X_END;
52           u32 V_INC;
53           u32 P1_BLANK_LINES_AT_TOP;
54           u32 P23_BLANK_LINES_AT_TOP;
55           u32 VID_BUF_PITCH0_VALUE;
56           u32 VID_BUF_PITCH1_VALUE;
57           u32 P1_X_START_END;
58           u32 P2_X_START_END;
59           u32 P3_X_START_END;
60           u32 VID_BUF0_BASE_ADRS;
61           u32 VID_BUF1_BASE_ADRS;
62           u32 VID_BUF2_BASE_ADRS;
63           u32 P1_V_ACCUM_INIT;
64           u32 P23_V_ACCUM_INIT;
65           u32 P1_H_ACCUM_INIT;
66           u32 P23_H_ACCUM_INIT;
67           u32 SCALE_CNTL;
68      } regs;
69 } ATIOverlayLayerData;
70 
71 static void ov0_set_regs( ATI128DriverData *adrv, ATIOverlayLayerData *aov0 );
72 static void ov0_calc_regs( ATI128DriverData *adrv, ATIOverlayLayerData *aov0,
73                            CoreLayerRegionConfig *config, CoreSurface *surface,
74                            CoreSurfaceBufferLock *lock );
75 
76 #define OV0_SUPPORTED_OPTIONS   (DLOP_NONE)
77 
78 /**********************/
79 
80 static int
ov0LayerDataSize(void)81 ov0LayerDataSize( void )
82 {
83      return sizeof(ATIOverlayLayerData);
84 }
85 
86 static DFBResult
ov0InitLayer(CoreLayer * layer,void * driver_data,void * layer_data,DFBDisplayLayerDescription * description,DFBDisplayLayerConfig * config,DFBColorAdjustment * adjustment)87 ov0InitLayer( CoreLayer                  *layer,
88               void                       *driver_data,
89               void                       *layer_data,
90               DFBDisplayLayerDescription *description,
91               DFBDisplayLayerConfig      *config,
92               DFBColorAdjustment         *adjustment )
93 {
94      ATI128DriverData *adrv = (ATI128DriverData*) driver_data;
95      volatile u8      *mmio = adrv->mmio_base;
96 
97      /* set capabilities and type */
98      description->caps = DLCAPS_SCREEN_LOCATION | DLCAPS_SURFACE;
99      description->type = DLTF_VIDEO | DLTF_STILL_PICTURE;
100 
101      /* set name */
102      snprintf( description->name,
103                DFB_DISPLAY_LAYER_DESC_NAME_LENGTH, "ATI128 Overlay" );
104 
105      /* fill out the default configuration */
106      config->flags       = DLCONF_WIDTH | DLCONF_HEIGHT |
107                            DLCONF_PIXELFORMAT | DLCONF_BUFFERMODE |
108                            DLCONF_OPTIONS;
109      config->width       = 640;
110      config->height      = 480;
111      config->pixelformat = DSPF_YUY2;
112      config->buffermode  = DLBM_FRONTONLY;
113      config->options     = DLOP_NONE;
114 
115      /* fill out default color adjustment,
116         only fields set in flags will be accepted from applications */
117      adjustment->flags = DCAF_NONE;
118 
119      /* reset overlay */
120      ati128_out32( mmio, OV0_SCALE_CNTL, 0x80000000 );
121      ati128_out32( mmio, OV0_EXCLUSIVE_HORZ, 0 );
122      ati128_out32( mmio, OV0_AUTO_FLIP_CNTL, 0 );
123      ati128_out32( mmio, OV0_FILTER_CNTL, 0x0000000f );
124      ati128_out32( mmio, OV0_COLOR_CNTL, 0x00101000 );
125      ati128_out32( mmio, OV0_KEY_CNTL, 0x10 );
126      ati128_out32( mmio, OV0_TEST, 0 );
127 
128      return DFB_OK;
129 }
130 
131 
132 static void
ov0OnOff(ATI128DriverData * adrv,ATIOverlayLayerData * aov0,int on)133 ov0OnOff( ATI128DriverData    *adrv,
134           ATIOverlayLayerData *aov0,
135           int                  on )
136 {
137      /* set/clear enable bit */
138      if (on)
139           aov0->regs.SCALE_CNTL |= R128_SCALER_ENABLE;
140      else
141           aov0->regs.SCALE_CNTL &= ~R128_SCALER_ENABLE;
142 
143      /* write back to card */
144      ati128_out32( adrv->mmio_base, OV0_SCALE_CNTL, aov0->regs.SCALE_CNTL );
145 }
146 
147 static DFBResult
ov0TestRegion(CoreLayer * layer,void * driver_data,void * layer_data,CoreLayerRegionConfig * config,CoreLayerRegionConfigFlags * failed)148 ov0TestRegion( CoreLayer                  *layer,
149                void                       *driver_data,
150                void                       *layer_data,
151                CoreLayerRegionConfig      *config,
152                CoreLayerRegionConfigFlags *failed )
153 {
154      CoreLayerRegionConfigFlags fail = 0;
155 
156      /* check for unsupported options */
157      if (config->options & ~OV0_SUPPORTED_OPTIONS)
158           fail |= CLRCF_OPTIONS;
159 
160      /* check pixel format */
161      switch (config->format) {
162           case DSPF_YUY2:
163           case DSPF_UYVY:
164           case DSPF_I420:
165           case DSPF_YV12:
166                break;
167 
168           default:
169                fail |= CLRCF_FORMAT;
170      }
171 
172      /* check width */
173      if (config->width > 2048 || config->width < 1)
174           fail |= CLRCF_WIDTH;
175 
176      /* check height */
177      if (config->height > 1024 || config->height < 1)
178           fail |= CLRCF_HEIGHT;
179 
180      /* write back failing fields */
181      if (failed)
182           *failed = fail;
183 
184      /* return failure if any field failed */
185      if (fail)
186           return DFB_UNSUPPORTED;
187 
188      return DFB_OK;
189 }
190 
191 static DFBResult
ov0SetRegion(CoreLayer * layer,void * driver_data,void * layer_data,void * region_data,CoreLayerRegionConfig * config,CoreLayerRegionConfigFlags updated,CoreSurface * surface,CorePalette * palette,CoreSurfaceBufferLock * lock)192 ov0SetRegion( CoreLayer                  *layer,
193               void                       *driver_data,
194               void                       *layer_data,
195               void                       *region_data,
196               CoreLayerRegionConfig      *config,
197               CoreLayerRegionConfigFlags  updated,
198               CoreSurface                *surface,
199               CorePalette                *palette,
200               CoreSurfaceBufferLock      *lock )
201 {
202      ATI128DriverData    *adrv = (ATI128DriverData*) driver_data;
203      ATIOverlayLayerData *aov0 = (ATIOverlayLayerData*) layer_data;
204 
205      /* remember configuration */
206      aov0->config = *config;
207 
208      ov0_calc_regs( adrv, aov0, config, surface, lock );
209      ov0_set_regs( adrv, aov0 );
210 
211      /* enable overlay */
212      ov0OnOff( adrv, aov0, 1 );
213 
214      return DFB_OK;
215 }
216 
217 static DFBResult
ov0RemoveRegion(CoreLayer * layer,void * driver_data,void * layer_data,void * region_data)218 ov0RemoveRegion( CoreLayer *layer,
219                  void      *driver_data,
220                  void      *layer_data,
221                  void      *region_data )
222 {
223      ATI128DriverData    *adrv = (ATI128DriverData*) driver_data;
224      ATIOverlayLayerData *aov0 = (ATIOverlayLayerData*) layer_data;
225 
226      /* disable overlay */
227      ov0OnOff( adrv, aov0, 0 );
228 
229      return DFB_OK;
230 }
231 
232 static DFBResult
ov0FlipRegion(CoreLayer * layer,void * driver_data,void * layer_data,void * region_data,CoreSurface * surface,DFBSurfaceFlipFlags flags,CoreSurfaceBufferLock * lock)233 ov0FlipRegion( CoreLayer             *layer,
234                void                  *driver_data,
235                void                  *layer_data,
236                void                  *region_data,
237                CoreSurface           *surface,
238                DFBSurfaceFlipFlags    flags,
239                CoreSurfaceBufferLock *lock )
240 {
241      ATI128DriverData    *adrv = (ATI128DriverData*) driver_data;
242      ATIOverlayLayerData *aov0 = (ATIOverlayLayerData*) layer_data;
243 
244      dfb_surface_flip( surface, false );
245 
246      ov0_calc_regs( adrv, aov0, &aov0->config, surface, lock );
247      ov0_set_regs( adrv, aov0 );
248 
249      return DFB_OK;
250 }
251 
252 
253 DisplayLayerFuncs atiOverlayFuncs = {
254      .LayerDataSize = ov0LayerDataSize,
255      .InitLayer     = ov0InitLayer,
256 
257      .TestRegion    = ov0TestRegion,
258      .SetRegion     = ov0SetRegion,
259      .RemoveRegion  = ov0RemoveRegion,
260      .FlipRegion    = ov0FlipRegion,
261 };
262 
263 /* internal */
264 
ov0_set_regs(ATI128DriverData * adrv,ATIOverlayLayerData * aov0)265 static void ov0_set_regs( ATI128DriverData *adrv, ATIOverlayLayerData *aov0 )
266 {
267      volatile u8 *mmio = adrv->mmio_base;
268 
269      ati128_out32( mmio, OV0_REG_LOAD_CNTL, 1 );
270      while (!(ati128_in32( mmio, OV0_REG_LOAD_CNTL ) & (1 << 3)));
271 
272      ati128_out32( mmio, OV0_H_INC,
273                    aov0->regs.H_INC );
274 
275      ati128_out32( mmio, OV0_STEP_BY,
276                    aov0->regs.STEP_BY );
277 
278      ati128_out32( mmio, OV0_Y_X_START,
279                    aov0->regs.Y_X_START );
280 
281      ati128_out32( mmio, OV0_Y_X_END,
282                    aov0->regs.Y_X_END );
283 
284      ati128_out32( mmio, OV0_V_INC,
285                    aov0->regs.V_INC );
286 
287      ati128_out32( mmio, OV0_P1_BLANK_LINES_AT_TOP,
288                    aov0->regs.P1_BLANK_LINES_AT_TOP );
289 
290      ati128_out32( mmio, OV0_P23_BLANK_LINES_AT_TOP,
291                    aov0->regs.P23_BLANK_LINES_AT_TOP );
292 
293      ati128_out32( mmio, OV0_VID_BUF_PITCH0_VALUE,
294                    aov0->regs.VID_BUF_PITCH0_VALUE );
295 
296      ati128_out32( mmio, OV0_VID_BUF_PITCH1_VALUE,
297                    aov0->regs.VID_BUF_PITCH1_VALUE );
298 
299      ati128_out32( mmio, OV0_P1_X_START_END,
300                    aov0->regs.P1_X_START_END );
301 
302      ati128_out32( mmio, OV0_P2_X_START_END,
303                    aov0->regs.P2_X_START_END );
304 
305      ati128_out32( mmio, OV0_P3_X_START_END,
306                    aov0->regs.P3_X_START_END );
307 
308      ati128_out32( mmio, OV0_VID_BUF0_BASE_ADRS,
309                    aov0->regs.VID_BUF0_BASE_ADRS );
310 
311      ati128_out32( mmio, OV0_VID_BUF1_BASE_ADRS,
312                    aov0->regs.VID_BUF1_BASE_ADRS );
313 
314      ati128_out32( mmio, OV0_VID_BUF2_BASE_ADRS,
315                    aov0->regs.VID_BUF2_BASE_ADRS );
316 
317      ati128_out32( mmio, OV0_P1_V_ACCUM_INIT,
318                    aov0->regs.P1_V_ACCUM_INIT );
319 
320      ati128_out32( mmio, OV0_P23_V_ACCUM_INIT,
321                    aov0->regs.P23_V_ACCUM_INIT );
322 
323      ati128_out32( mmio, OV0_P1_H_ACCUM_INIT,
324                    aov0->regs.P1_H_ACCUM_INIT );
325 
326      ati128_out32( mmio, OV0_P23_H_ACCUM_INIT,
327                    aov0->regs.P23_H_ACCUM_INIT );
328 
329      ati128_out32( mmio, OV0_SCALE_CNTL,
330                    aov0->regs.SCALE_CNTL );
331 
332      ati128_out32( mmio, OV0_REG_LOAD_CNTL, 0 );
333 }
334 
ov0_calc_regs(ATI128DriverData * adrv,ATIOverlayLayerData * aov0,CoreLayerRegionConfig * config,CoreSurface * surface,CoreSurfaceBufferLock * lock)335 static void ov0_calc_regs( ATI128DriverData      *adrv,
336                            ATIOverlayLayerData   *aov0,
337                            CoreLayerRegionConfig *config,
338                            CoreSurface           *surface,
339                            CoreSurfaceBufferLock *lock )
340 {
341      int h_inc, v_inc, step_by, tmp;
342      int p1_h_accum_init, p23_h_accum_init;
343      int p1_v_accum_init, p23_v_accum_init;
344 
345      DFBRegion      dstBox;
346      int            dst_w;
347      int            dst_h;
348      u32            offset_u = 0, offset_v = 0;
349 
350      /* destination box */
351      dstBox.x1 = config->dest.x;
352      dstBox.y1 = config->dest.y;
353      dstBox.x2 = config->dest.x + config->dest.w;
354      dstBox.y2 = config->dest.y + config->dest.h;
355 
356      /* destination size */
357      dst_w = config->dest.w;
358      dst_h = config->dest.h;
359 
360      /* clear everything but the enable bit that may be set*/
361      aov0->regs.SCALE_CNTL &= R128_SCALER_ENABLE;
362 
363 
364      /* calculate incrementors */
365      h_inc   = (surface->config.size.w  << 12) / dst_w;
366      v_inc   = (surface->config.size.h << 20) / dst_h;
367      step_by = 1;
368 
369      while (h_inc >= (2 << 12)) {
370           step_by++;
371           h_inc >>= 1;
372      }
373 
374      /* calculate values for horizontal accumulators */
375      tmp = 0x00028000 + (h_inc << 3);
376      p1_h_accum_init = ((tmp <<  4) & 0x000f8000) | ((tmp << 12) & 0xf0000000);
377 
378      tmp = 0x00028000 + (h_inc << 2);
379      p23_h_accum_init = ((tmp <<  4) & 0x000f8000) | ((tmp << 12) & 0x70000000);
380 
381      /* calculate values for vertical accumulators */
382      tmp = 0x00018000;
383      p1_v_accum_init = ((tmp << 4) & 0x03ff8000) | 0x00000001;
384 
385      tmp = 0x00018000;
386      p23_v_accum_init = ((tmp << 4) & 0x01ff8000) | 0x00000001;
387 
388      /* choose pixel format and calculate buffer offsets for planar modes */
389      switch (surface->config.format) {
390           case DSPF_UYVY:
391                aov0->regs.SCALE_CNTL = R128_SCALER_SOURCE_YVYU422;
392                break;
393 
394           case DSPF_YUY2:
395                aov0->regs.SCALE_CNTL = R128_SCALER_SOURCE_VYUY422;
396                break;
397 
398           case DSPF_I420:
399                aov0->regs.SCALE_CNTL = R128_SCALER_SOURCE_YUV12;
400 
401                offset_u = lock->offset +
402                           surface->config.size.h * lock->pitch;
403                offset_v = offset_u +
404                           (surface->config.size.h >> 1) * (lock->pitch >> 1);
405                break;
406 
407           case DSPF_YV12:
408                aov0->regs.SCALE_CNTL = R128_SCALER_SOURCE_YUV12;
409 
410                offset_v = lock->offset +
411                           surface->config.size.h * lock->pitch;
412                offset_u = offset_v +
413                           (surface->config.size.h >> 1) * (lock->pitch >> 1);
414                break;
415 
416           default:
417                D_BUG("unexpected pixelformat");
418                aov0->regs.SCALE_CNTL = 0;
419                return;
420      }
421 
422      aov0->regs.SCALE_CNTL            |= R128_SCALER_DOUBLE_BUFFER |
423                                          R128_SCALER_BURST_PER_PLANE |
424                                          R128_SCALER_Y2R_TEMP |
425                                          R128_SCALER_PIX_EXPAND;
426 
427      aov0->regs.H_INC                  = h_inc | ((h_inc >> 1) << 16);
428      aov0->regs.V_INC                  = v_inc;
429      aov0->regs.STEP_BY                = step_by | (step_by << 8);
430      aov0->regs.Y_X_START              = dstBox.x1 | (dstBox.y1 << 16);
431      aov0->regs.Y_X_END                = dstBox.x2 | (dstBox.y2 << 16);
432      aov0->regs.P1_BLANK_LINES_AT_TOP  = 0x00000fff | ((surface->config.size.h - 1) << 16);
433      aov0->regs.P23_BLANK_LINES_AT_TOP = 0x000007ff | ((((surface->config.size.h + 1) >> 1) - 1) << 16);
434      aov0->regs.VID_BUF_PITCH0_VALUE   = lock->pitch;
435      aov0->regs.VID_BUF_PITCH1_VALUE   = lock->pitch >> 1;
436      aov0->regs.P1_X_START_END         = surface->config.size.w - 1;
437      aov0->regs.P2_X_START_END         = (surface->config.size.w >> 1) - 1;
438      aov0->regs.P3_X_START_END         = (surface->config.size.w >> 1) - 1;
439      aov0->regs.VID_BUF0_BASE_ADRS     = lock->offset & 0x03fffff0;
440      aov0->regs.VID_BUF1_BASE_ADRS     = (offset_u & 0x03fffff0) | 1;
441      aov0->regs.VID_BUF2_BASE_ADRS     = (offset_v & 0x03fffff0) | 1;
442      aov0->regs.P1_H_ACCUM_INIT        = p1_h_accum_init;
443      aov0->regs.P23_H_ACCUM_INIT       = p23_h_accum_init;
444      aov0->regs.P1_V_ACCUM_INIT        = p1_v_accum_init;
445      aov0->regs.P23_V_ACCUM_INIT       = p23_v_accum_init;
446 }
447 
448