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