1 /*
2    Copyright (c) 2003 Andreas Robinson, All rights reserved.
3 
4    This library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2 of the License, or (at your option) any later version.
8 */
9 
10 #include <config.h>
11 
12 #include "unichrome.h"
13 #include "uc_overlay.h"
14 #include "vidregs.h"
15 #include "mmio.h"
16 
17 #include <direct/messages.h>
18 
19 #include <core/system.h>
20 
21 #include <misc/conf.h>
22 
23 // Forward declaration
24 static DFBResult
25 uc_ovl_remove(CoreLayer *layer,
26               void      *driver_data,
27               void      *layer_data,
28               void      *region_data);
29 
30 
uc_ovl_datasize(void)31 static int uc_ovl_datasize( void )
32 {
33     return sizeof(UcOverlayData);
34 }
35 
36 
37 static DFBResult
uc_ovl_init_layer(CoreLayer * layer,void * driver_data,void * layer_data,DFBDisplayLayerDescription * description,DFBDisplayLayerConfig * config,DFBColorAdjustment * adjustment)38 uc_ovl_init_layer( CoreLayer                   *layer,
39                    void                        *driver_data,
40                    void                        *layer_data,
41                    DFBDisplayLayerDescription  *description,
42                    DFBDisplayLayerConfig       *config,
43                    DFBColorAdjustment          *adjustment )
44 {
45     UcDriverData* ucdrv = (UcDriverData*) driver_data;
46     UcOverlayData* ucovl = (UcOverlayData*) layer_data;
47 
48     // Set layer type, capabilities and name
49 
50     description->caps = UC_OVL_CAPS;
51     description->type = DLTF_GRAPHICS | DLTF_VIDEO | DLTF_STILL_PICTURE;
52     snprintf(description->name,
53         DFB_DISPLAY_LAYER_DESC_NAME_LENGTH, "VIA CLE266 Video");
54 
55     adjustment->flags = DCAF_NONE;
56 
57     // Fill out the default configuration
58 
59     config->flags  = DLCONF_WIDTH | DLCONF_HEIGHT |
60                      DLCONF_PIXELFORMAT | DLCONF_BUFFERMODE | DLCONF_OPTIONS;
61 
62     ucovl->v1.win.w = 720;
63     ucovl->v1.win.h = 576;
64     ucovl->v1.win.x = 0;
65     ucovl->v1.win.y = 0;
66 
67     config->width  = 720;
68     config->height = 576;
69 
70     config->pixelformat = DSPF_YV12;
71     config->buffermode  = DLBM_FRONTONLY;
72     config->options     = DLOP_NONE;
73 
74     // Reset overlay
75 
76     ucovl->extfifo_on = false;
77     ucovl->hwrev = ucdrv->hwrev;
78     ucovl->scrwidth = ucovl->v1.win.w;
79 
80     ucovl->v1.isenabled = false;
81     ucovl->v1.cfg = *config;
82     ucovl->v1.ox = 0;
83     ucovl->v1.oy = 0;
84 
85 //    adjustment->flags = DCAF_BRIGHTNESS | DCAF_CONTRAST |
86 //        DCAF_HUE | DCAF_SATURATION;
87     adjustment->brightness = 0x8000;
88     adjustment->contrast = 0x8000;
89     adjustment->saturation = 0x8000;
90     adjustment->hue = 0x8000;
91     ucovl->v1.adj = *adjustment;
92 
93     uc_ovl_remove(layer, driver_data, layer_data, NULL);
94 
95     return DFB_OK;
96 }
97 
98 
99 static DFBResult
uc_ovl_set_region(CoreLayer * layer,void * driver_data,void * layer_data,void * region_data,CoreLayerRegionConfig * config,CoreLayerRegionConfigFlags updated,CoreSurface * surface,CorePalette * palette,CoreSurfaceBufferLock * lock)100 uc_ovl_set_region( CoreLayer                  *layer,
101                    void                       *driver_data,
102                    void                       *layer_data,
103                    void                       *region_data,
104                    CoreLayerRegionConfig      *config,
105                    CoreLayerRegionConfigFlags  updated,
106                    CoreSurface                *surface,
107                    CorePalette                *palette,
108                    CoreSurfaceBufferLock      *lock )
109 {
110     UcDriverData*  ucdrv = (UcDriverData*) driver_data;
111     UcOverlayData* ucovl = (UcOverlayData*) layer_data;
112 
113     /* get new destination rectangle */
114     DFBRectangle win = config->dest;;
115 
116     // Bounds checking
117     if ((win.x < -8192) || (win.x > 8192) ||
118         (win.y < -8192) || (win.y > 8192) ||
119         (win.w < 32) || (win.w > 4096) ||
120         (win.h < 32) || (win.h > 4096))
121     {
122         D_DEBUG("Layer size or position is out of bounds.");
123         return DFB_INVAREA;
124     }
125 
126     ucovl->v1.isenabled = true;
127     ucovl->v1.win = win;
128 
129     ucovl->deinterlace = config->options & DLOP_DEINTERLACING;
130     ucovl->surface     = surface;
131     ucovl->lock        = lock;
132 
133     return uc_ovl_update(ucdrv, ucovl, UC_OVL_CHANGE, surface, lock);
134 }
135 
136 
137 static DFBResult
uc_ovl_remove(CoreLayer * layer,void * driver_data,void * layer_data,void * region_data)138 uc_ovl_remove(CoreLayer *layer,
139               void      *driver_data,
140               void      *layer_data,
141               void      *region_data)
142 {
143     UcDriverData*  ucdrv = (UcDriverData*) driver_data;
144     UcOverlayData* ucovl = (UcOverlayData*) layer_data;
145     volatile u8*   vio   = ucdrv->hwregs;
146 
147     ucovl->v1.isenabled = false;
148 
149     uc_ovl_vcmd_wait(vio);
150 
151     VIDEO_OUT(vio, V_FIFO_CONTROL, UC_MAP_V1_FIFO_CONTROL(16,12,8));
152     //  VIDEO_OUT(vio, ALPHA_V3_FIFO_CONTROL, 0x0407181f);
153 
154     if (ucovl->hwrev == 0x10) {
155         VIDEO_OUT(vio, V1_ColorSpaceReg_1, ColorSpaceValue_1_3123C0);
156         VIDEO_OUT(vio, V1_ColorSpaceReg_2, ColorSpaceValue_2_3123C0);
157     }
158     else {
159         VIDEO_OUT(vio, V1_ColorSpaceReg_1, ColorSpaceValue_1);
160         VIDEO_OUT(vio, V1_ColorSpaceReg_2, ColorSpaceValue_2);
161     }
162 
163     VIDEO_OUT(vio, HQV_CONTROL, VIDEO_IN(vio, HQV_CONTROL) & ~HQV_ENABLE);
164     VIDEO_OUT(vio, V1_CONTROL, VIDEO_IN(vio, V1_CONTROL) & ~V1_ENABLE);
165     //  VIDEO_OUT(vio, V3_CONTROL, VIDEO_IN(vio, V3_CONTROL) & ~V3_ENABLE);
166 
167     VIDEO_OUT(vio, V_COMPOSE_MODE,
168         VIDEO_IN(vio, V_COMPOSE_MODE) | V1_COMMAND_FIRE);
169 
170     ucovl->surface = NULL;
171 
172     return DFB_OK;
173 }
174 
175 
176 static DFBResult
uc_ovl_test_region(CoreLayer * layer,void * driver_data,void * layer_data,CoreLayerRegionConfig * config,CoreLayerRegionConfigFlags * failed)177 uc_ovl_test_region(CoreLayer                  *layer,
178                    void                       *driver_data,
179                    void                       *layer_data,
180                    CoreLayerRegionConfig      *config,
181                    CoreLayerRegionConfigFlags *failed)
182 {
183     CoreLayerRegionConfigFlags fail = 0;
184 
185     // Check layer options
186 
187     if (config->options & ~UC_OVL_OPTIONS)
188         fail |= CLRCF_OPTIONS;
189 
190     // Check pixelformats
191 
192     switch (config->format) {
193           case DSPF_YUY2:
194               break;
195           case DSPF_UYVY:
196               fail |= CLRCF_FORMAT;   // Nope...  doesn't work.
197               break;
198           case DSPF_I420:
199           case DSPF_YV12:
200           case DSPF_ARGB1555:
201           case DSPF_RGB16:
202           case DSPF_RGB32:
203           case DSPF_ARGB:
204               break;
205           default:
206               fail |= CLRCF_FORMAT;
207     }
208 
209     // Check width and height
210 
211     if (config->width > 4096 || config->width < 32)
212         fail |= CLRCF_WIDTH;
213 
214     if (config->height > 4096 || config->height < 32)
215         fail |= CLRCF_HEIGHT;
216 
217     if (failed) *failed = fail;
218     if (fail) return DFB_UNSUPPORTED;
219 
220     return DFB_OK;
221 }
222 
223 
224 static DFBResult
uc_ovl_flip_region(CoreLayer * layer,void * driver_data,void * layer_data,void * region_data,CoreSurface * surface,DFBSurfaceFlipFlags flags,CoreSurfaceBufferLock * lock)225 uc_ovl_flip_region( CoreLayer             *layer,
226                     void                  *driver_data,
227                     void                  *layer_data,
228                     void                  *region_data,
229                     CoreSurface           *surface,
230                     DFBSurfaceFlipFlags    flags,
231                     CoreSurfaceBufferLock *lock)
232 {
233     //printf("Entering %s ... \n", __PRETTY_FUNCTION__);
234 
235     UcDriverData*  ucdrv = (UcDriverData*) driver_data;
236     UcOverlayData* ucovl = (UcOverlayData*) layer_data;
237     DFBResult    ret;
238 
239     if (((flags & DSFLIP_WAITFORSYNC) == DSFLIP_WAITFORSYNC) &&
240         !dfb_config->pollvsync_after)
241         dfb_layer_wait_vsync( layer );
242 
243     dfb_surface_flip(surface, false);
244 
245     ucovl->field = 0;
246     ucovl->lock = lock;
247 
248     ret = uc_ovl_update(ucdrv, ucovl, UC_OVL_FLIP, surface, lock);
249     if (ret)
250         return ret;
251 
252     if ((flags & DSFLIP_WAIT) &&
253         (dfb_config->pollvsync_after || !(flags & DSFLIP_ONSYNC)))
254         dfb_layer_wait_vsync(layer);
255 
256     return DFB_OK;
257 }
258 
259 static DFBResult
uc_ovl_get_level(CoreLayer * layer,void * driver_data,void * layer_data,int * level)260 uc_ovl_get_level(CoreLayer    *layer,
261                  void         *driver_data,
262                  void         *layer_data,
263                  int          *level)
264 {
265     UcOverlayData* ucovl = (UcOverlayData*) layer_data;
266     *level = ucovl->v1.level;
267     return DFB_OK;
268 }
269 
270 static DFBResult
uc_ovl_set_level(CoreLayer * layer,void * driver_data,void * layer_data,int level)271 uc_ovl_set_level(CoreLayer    *layer,
272                  void         *driver_data,
273                  void         *layer_data,
274                  int          level)
275 {
276     UcOverlayData* ucovl = (UcOverlayData*) layer_data;
277     UcDriverData*  ucdrv = (UcDriverData*) driver_data;
278 
279     if (level == 0) return DFB_INVARG;
280     if (level > 0) {
281         // Enable underlay mode.
282         VIDEO_OUT(ucdrv->hwregs, V_ALPHA_CONTROL, uc_ovl_map_alpha(-1));
283     }
284     else {
285         // Enable overlay mode (default)
286         VIDEO_OUT(ucdrv->hwregs, V_ALPHA_CONTROL,
287             uc_ovl_map_alpha(ucovl->v1.opacity));
288     }
289 
290     ucovl->v1.level = level;
291     return DFB_OK;
292 }
293 
294 static DFBResult
uc_ovl_set_input_field(CoreLayer * layer,void * driver_data,void * layer_data,void * region_data,int field)295 uc_ovl_set_input_field( CoreLayer *layer,
296                         void      *driver_data,
297                         void      *layer_data,
298                         void      *region_data,
299                         int        field )
300 {
301      UcOverlayData* ucovl = (UcOverlayData*) layer_data;
302      UcDriverData*  ucdrv = (UcDriverData*) driver_data;
303 
304      ucovl->field = field;
305 
306      return uc_ovl_update(ucdrv, ucovl, UC_OVL_FIELD, ucovl->surface, ucovl->lock);
307 }
308 
309 DisplayLayerFuncs ucOverlayFuncs = {
310     .LayerDataSize      = uc_ovl_datasize,
311     .InitLayer          = uc_ovl_init_layer,
312     .SetRegion          = uc_ovl_set_region,
313     .RemoveRegion       = uc_ovl_remove,
314     .TestRegion         = uc_ovl_test_region,
315     .FlipRegion         = uc_ovl_flip_region,
316     .GetLevel           = uc_ovl_get_level,
317     .SetLevel           = uc_ovl_set_level,
318     .SetInputField      = uc_ovl_set_input_field,
319     .SetColorAdjustment = uc_ovl_set_adjustment,
320 };
321