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 
11 /*
12 
13 EPIA-M benchmarks (df_dok)
14 
15                               SW    v0.0.1  v0.1.0 v0.2.0     v0.3
16 
17 Anti-aliased Text            98.97    -       -       -     280.80  KChars/sec
18 Anti-aliased Text (blend)    28.85    -       -       -     280.61  KChars/sec
19 Fill Rectangles              25.21  443.46  437.05  432.39  435.60  Mpixel/sec
20 Fill Rectangles (blend)       5.54    -     130.12  128.42  127.82  MPixel/sec
21 Fill Triangles               24.84  173.44  129.76  127.86  128.63  MPixel/sec
22 Fill Triangles (blend)        5.46    -     129.81  127.86  128.67  MPixel/sec
23 Draw Rectangles              11.82  58.98    59.07   52.48   55.10  KRects/sec
24 Draw Rectangles (blend)       1.98    -      32.13   22.76   23.50  KRects/sec
25 Draw Lines                   42.67  283.81  292.33  193.87  203.20  KLines/sec
26 Draw Lines (blend)            8.54    -     142.62  101.23  102.80  KLines/sec
27 Blit                         21.48    -     117.38  114.26  114.41  MPixel/sec
28 Blit colorkeyed              22.54    -     117.34  114.26  114.41  MPixel/sec
29 Blit w/ format conversion    16.22    -       -     103.41  103.00  MPixel/sec
30 Blit from 32bit (blend)       4.19    -       -      87.72   87.32  MPixel/sec
31 Blit from 8bit palette       11.02    -       -     110.13  113.37  MPixel/sec
32 Blit from 8bit pal. (blend)   3.78    -       -     110.20  113.40  MPixel/sec
33 Stretch Blit                 23.19    -       -      99.53   99.32  MPixel/sec
34 Stretch Blit colorkeyed      25.04    -       -       5.00   38.00  MPixel/sec
35 
36 
37 Comparing M9000 and M10000
38 
39 v0.2.0                         M9000  M10000
40 
41 Anti-aliased Text               -       -     KChars/sec
42 Anti-aliased Text (blend)       -       -     KChars/sec
43 Fill Rectangles               401.82  432.39  Mpixel/sec
44 Fill Rectangles (blend)       129.05  128.42  MPixel/sec
45 Fill Triangles                128.46  127.86  MPixel/sec
46 Fill Triangles (blend)        128.46  127.86  MPixel/sec
47 Draw Rectangles                55.51   52.48  KRects/sec
48 Draw Rectangles (blend)        26.90   22.76  KRects/sec
49 Draw Lines                    225.00  193.87  KLines/sec
50 Draw Lines (blend)            121.29  101.23  KLines/sec
51 Blit                          112.36  114.26  MPixel/sec
52 Blit colorkeyed               112.28  114.26  MPixel/sec
53 Blit w/ format conversion     103.92  103.41  MPixel/sec
54 Blit from 32bit (blend)        87.89   87.72  MPixel/sec
55 Blit from 8bit palette        110.56  110.13  MPixel/sec
56 Blit from 8bit pal. (blend)   110.56  110.20  MPixel/sec
57 Stretch Blit                  108.67   99.53  MPixel/sec
58 Stretch Blit colorkeyed         4.79    5.00  MPixel/sec
59 
60 
61 v0.0.1 and v0.1.0 are tested on an EPIA-M9000,
62 later versions on an EPIA-M10000.
63 
64 */
65 
66 // DirectFB headers
67 
68 #include <config.h>
69 
70 #include <directfb.h>
71 
72 #include <fusion/shmalloc.h>
73 
74 #include <direct/messages.h>
75 
76 #include <core/coretypes.h>
77 #include <core/core.h>
78 #include <core/gfxcard.h>
79 #include <core/graphics_driver.h>
80 #include <core/system.h>
81 #include <core/screens.h>
82 
83 #include <fbdev/fb.h>
84 
85 // System headers
86 
87 #include <sys/types.h>
88 #include <sys/stat.h>
89 #include <fcntl.h>
90 #include <sys/mman.h>
91 #include <stdlib.h>
92 #include <unistd.h>
93 #include <stdio.h>
94 
95 #include <string.h>
96 
97 // Driver headers
98 
99 #include "unichrome.h"
100 #include "uc_state.h"
101 #include "uc_accel.h"
102 #include "uc_fifo.h"
103 #include "mmio.h"
104 
105 #ifndef FB_ACCEL_VIA_UNICHROME
106 #define FB_ACCEL_VIA_UNICHROME 77
107 #endif
108 
109 extern DisplayLayerFuncs ucOverlayFuncs;
110 extern DisplayLayerFuncs ucPrimaryFuncs;
111 
112 extern DisplayLayerFuncs  ucOldPrimaryFuncs;
113 extern void              *ucOldPrimaryDriverData;
114 
DFB_GRAPHICS_DRIVER(cle266)115 DFB_GRAPHICS_DRIVER(cle266)
116 
117 //----------
118 
119 
120 /**
121  * Dump beginning of virtual queue.
122  * Use it to check that the VQ actually is in use. */
123 #if 0
124 static void uc_dump_vq(UcDeviceData *ucdev)
125 {
126      int i;
127      u8* vq;
128 
129      if (!ucdev->vq_start) return;
130      vq = dfb_system_video_memory_virtual(ucdev->vq_start);
131 
132      for (i = 0; i < 128; i++) {
133           printf("%02x ", *(vq+i));
134           if ((i+1) % 16 == 0) printf("\n");
135      }
136 }
137 #endif
138 
139 /** Allocate memory for the virtual queue. */
140 
141 static DFBResult uc_alloc_vq(CoreGraphicsDevice *device, UcDeviceData *ucdev)
142 {
143      if (ucdev->vq_start) return DFB_OK;
144 
145      ucdev->vq_size = 256*1024; // 256kb
146      ucdev->vq_start = dfb_gfxcard_reserve_memory( device, ucdev->vq_size );
147 
148      if (!ucdev->vq_start)
149           return DFB_INIT;
150 
151      ucdev->vq_end = ucdev->vq_start + ucdev->vq_size - 1;
152 
153      // Debug: clear buffer
154      memset((void *) dfb_system_video_memory_virtual(ucdev->vq_start),
155             0xcc, ucdev->vq_size);
156 
157      // uc_dump_vq(ucdev);
158 
159      return DFB_OK;
160 }
161 
162 /**
163  * Initialize the hardware.
164  * @param enable    enable VQ if true (else disable it.)
165  */
166 
uc_init_2d_engine(CoreGraphicsDevice * device,UcDeviceData * ucdev,UcDriverData * ucdrv,bool enable)167 static DFBResult uc_init_2d_engine(CoreGraphicsDevice *device, UcDeviceData *ucdev, UcDriverData *ucdrv, bool enable)
168 {
169      DFBResult result = DFB_OK;
170      volatile u8* hwregs = ucdrv->hwregs;
171 
172      // Init 2D engine registers to reset 2D engine
173 
174      VIA_OUT(hwregs, 0x04, 0x0);
175      VIA_OUT(hwregs, 0x08, 0x0);
176      VIA_OUT(hwregs, 0x0c, 0x0);
177      VIA_OUT(hwregs, 0x10, 0x0);
178      VIA_OUT(hwregs, 0x14, 0x0);
179      VIA_OUT(hwregs, 0x18, 0x0);
180      VIA_OUT(hwregs, 0x1c, 0x0);
181      VIA_OUT(hwregs, 0x20, 0x0);
182      VIA_OUT(hwregs, 0x24, 0x0);
183      VIA_OUT(hwregs, 0x28, 0x0);
184      VIA_OUT(hwregs, 0x2c, 0x0);
185      VIA_OUT(hwregs, 0x30, 0x0);
186      VIA_OUT(hwregs, 0x34, 0x0);
187      VIA_OUT(hwregs, 0x38, 0x0);
188      VIA_OUT(hwregs, 0x3c, 0x0);
189      VIA_OUT(hwregs, 0x40, 0x0);
190 
191      // Init AGP and VQ registers
192 
193      VIA_OUT(hwregs, 0x43c, 0x00100000);
194      VIA_OUT(hwregs, 0x440, 0x00000000);
195      VIA_OUT(hwregs, 0x440, 0x00333004);
196      VIA_OUT(hwregs, 0x440, 0x60000000);
197      VIA_OUT(hwregs, 0x440, 0x61000000);
198      VIA_OUT(hwregs, 0x440, 0x62000000);
199      VIA_OUT(hwregs, 0x440, 0x63000000);
200      VIA_OUT(hwregs, 0x440, 0x64000000);
201      VIA_OUT(hwregs, 0x440, 0x7D000000);
202 
203      VIA_OUT(hwregs, 0x43c, 0xfe020000);
204      VIA_OUT(hwregs, 0x440, 0x00000000);
205 
206      if (enable) {
207           result = uc_alloc_vq(device,ucdev);
208           enable = (result == DFB_OK);
209      }
210 
211      if (enable) { // Enable VQ
212 
213           VIA_OUT(hwregs, 0x43c, 0x00fe0000);
214           VIA_OUT(hwregs, 0x440, 0x080003fe);
215           VIA_OUT(hwregs, 0x440, 0x0a00027c);
216           VIA_OUT(hwregs, 0x440, 0x0b000260);
217           VIA_OUT(hwregs, 0x440, 0x0c000274);
218           VIA_OUT(hwregs, 0x440, 0x0d000264);
219           VIA_OUT(hwregs, 0x440, 0x0e000000);
220           VIA_OUT(hwregs, 0x440, 0x0f000020);
221           VIA_OUT(hwregs, 0x440, 0x1000027e);
222           VIA_OUT(hwregs, 0x440, 0x110002fe);
223           VIA_OUT(hwregs, 0x440, 0x200f0060);
224 
225           VIA_OUT(hwregs, 0x440, 0x00000006);
226           VIA_OUT(hwregs, 0x440, 0x40008c0f);
227           VIA_OUT(hwregs, 0x440, 0x44000000);
228           VIA_OUT(hwregs, 0x440, 0x45080c04);
229           VIA_OUT(hwregs, 0x440, 0x46800408);
230 
231           VIA_OUT(hwregs, 0x440, 0x52000000 |
232                   ((ucdev->vq_start & 0xFF000000) >> 24) |
233                   ((ucdev->vq_end & 0xFF000000) >> 16));
234           VIA_OUT(hwregs, 0x440, 0x50000000 | (ucdev->vq_start & 0xFFFFFF));
235           VIA_OUT(hwregs, 0x440, 0x51000000 | (ucdev->vq_end & 0xFFFFFF));
236           VIA_OUT(hwregs, 0x440, 0x53000000 | (ucdev->vq_size >> 3));
237      }
238      else { // Disable VQ
239 
240           VIA_OUT(hwregs, 0x43c, 0x00fe0000);
241           VIA_OUT(hwregs, 0x440, 0x00000004);
242           VIA_OUT(hwregs, 0x440, 0x40008c0f);
243           VIA_OUT(hwregs, 0x440, 0x44000000);
244           VIA_OUT(hwregs, 0x440, 0x45080c04);
245           VIA_OUT(hwregs, 0x440, 0x46800408);
246      }
247 
248      return result;
249 }
250 
uc_init_3d_engine(volatile u8 * hwregs,int hwrev,bool init_all)251 static void uc_init_3d_engine(volatile u8* hwregs, int hwrev, bool init_all)
252 {
253      u32 i;
254 
255      if (init_all) {
256 
257           // Clear NotTex registers (?)
258 
259           VIA_OUT(hwregs, 0x43C, 0x00010000);
260           for (i = 0; i <= 0x7d; i++)
261                VIA_OUT(hwregs, 0x440, i << 24);
262 
263           // Clear texture unit 0 (?)
264 
265           VIA_OUT(hwregs, 0x43C, 0x00020000);
266           for (i = 0; i <= 0x94; i++)
267                VIA_OUT(hwregs, 0x440, i << 24);
268           VIA_OUT(hwregs, 0x440, 0x82400000);
269 
270           // Clear texture unit 1 (?)
271 
272           VIA_OUT(hwregs, 0x43C, 0x01020000);
273           for (i = 0; i <= 0x94; i++)
274                VIA_OUT(hwregs, 0x440, i << 24);
275           VIA_OUT(hwregs, 0x440, 0x82400000);
276 
277           // Clear general texture settings (?)
278 
279           VIA_OUT(hwregs, 0x43C, 0xfe020000);
280           for (i = 0; i <= 0x03; i++)
281                VIA_OUT(hwregs, 0x440, i << 24);
282 
283           // Clear palette settings (?)
284 
285           VIA_OUT(hwregs, 0x43C, 0x00030000);
286           for (i = 0; i <= 0xff; i++)
287                VIA_OUT(hwregs, 0x440, 0);
288 
289           VIA_OUT(hwregs, 0x43C, 0x00100000);
290           VIA_OUT(hwregs, 0x440, 0x00333004);
291           VIA_OUT(hwregs, 0x440, 0x10000002);
292           VIA_OUT(hwregs, 0x440, 0x60000000);
293           VIA_OUT(hwregs, 0x440, 0x61000000);
294           VIA_OUT(hwregs, 0x440, 0x62000000);
295           VIA_OUT(hwregs, 0x440, 0x63000000);
296           VIA_OUT(hwregs, 0x440, 0x64000000);
297 
298           VIA_OUT(hwregs, 0x43C, 0x00fe0000);
299 
300           if (hwrev >= 3)
301                VIA_OUT(hwregs, 0x440,0x40008c0f);
302           else
303                VIA_OUT(hwregs, 0x440,0x4000800f);
304 
305           VIA_OUT(hwregs, 0x440,0x44000000);
306           VIA_OUT(hwregs, 0x440,0x45080C04);
307           VIA_OUT(hwregs, 0x440,0x46800408);
308           VIA_OUT(hwregs, 0x440,0x50000000);
309           VIA_OUT(hwregs, 0x440,0x51000000);
310           VIA_OUT(hwregs, 0x440,0x52000000);
311           VIA_OUT(hwregs, 0x440,0x53000000);
312 
313      }
314 
315      VIA_OUT(hwregs, 0x43C,0x00fe0000);
316      VIA_OUT(hwregs, 0x440,0x08000001);
317      VIA_OUT(hwregs, 0x440,0x0A000183);
318      VIA_OUT(hwregs, 0x440,0x0B00019F);
319      VIA_OUT(hwregs, 0x440,0x0C00018B);
320      VIA_OUT(hwregs, 0x440,0x0D00019B);
321      VIA_OUT(hwregs, 0x440,0x0E000000);
322      VIA_OUT(hwregs, 0x440,0x0F000000);
323      VIA_OUT(hwregs, 0x440,0x10000000);
324      VIA_OUT(hwregs, 0x440,0x11000000);
325      VIA_OUT(hwregs, 0x440,0x20000000);
326 }
327 
328 /** */
329 
uc_after_set_var(void * drv,void * dev)330 static void uc_after_set_var(void* drv, void* dev)
331 {
332      UcDriverData* ucdrv = (UcDriverData*) drv;
333 
334      VGA_OUT8(ucdrv->hwregs, 0x3c4, 0x1a);
335      // Clear bit 6 in extended VGA register 0x1a to prevent system lockup.
336      VGA_OUT8(ucdrv->hwregs, 0x3c5, VGA_IN8(ucdrv->hwregs, 0x3c5) & 0xbf);
337      // Set bit 2, it might make a difference.
338      VGA_OUT8(ucdrv->hwregs, 0x3c5, VGA_IN8(ucdrv->hwregs, 0x3c5) | 0x4);
339 }
340 
341 /** Wait until the engine is idle. */
342 
uc_engine_sync(void * drv,void * dev)343 static DFBResult uc_engine_sync(void* drv, void* dev)
344 {
345      UcDriverData* ucdrv = (UcDriverData*) drv;
346      UcDeviceData* ucdev = (UcDeviceData*) dev;
347 
348      int loop = 0;
349 
350 /*    printf("Entering uc_engine_sync(), status is 0x%08x\n",
351         VIA_IN(ucdrv->hwregs, VIA_REG_STATUS));
352 */
353 
354      while ((VIA_IN(ucdrv->hwregs, VIA_REG_STATUS) & 0xfffeffff) != 0x00020000) {
355           if (++loop > MAXLOOP) {
356                D_ERROR("DirectFB/VIA: Timeout waiting for idle engine!\n");
357                break;
358           }
359      }
360 
361      /* printf("Leaving uc_engine_sync(), status is 0x%08x, "
362          "waiting for %d (0x%x) cycles.\n",
363          VIA_IN(ucdrv->hwregs, VIA_REG_STATUS), loop, loop);
364       */
365 
366      ucdev->idle_waitcycles += loop;
367      ucdev->must_wait = 0;
368 
369      return DFB_OK;
370 }
371 
372 
373 // DirectFB interfacing functions --------------------------------------------
374 
driver_probe(CoreGraphicsDevice * device)375 static int driver_probe(CoreGraphicsDevice *device)
376 {
377      struct stat s;
378 
379      switch (dfb_gfxcard_get_accelerator( device )) {
380           case FB_ACCEL_VIA_UNICHROME:
381                return 1;
382      }
383 
384      return stat(UNICHROME_DEVICE, &s) + 1;
385 }
386 
driver_get_info(CoreGraphicsDevice * device,GraphicsDriverInfo * info)387 static void driver_get_info(CoreGraphicsDevice* device,
388                             GraphicsDriverInfo* info)
389 {
390      // Fill in driver info structure.
391 
392      snprintf(info->name,
393               DFB_GRAPHICS_DRIVER_INFO_NAME_LENGTH,
394               "VIA UniChrome Driver");
395 
396      snprintf(info->vendor,
397               DFB_GRAPHICS_DRIVER_INFO_VENDOR_LENGTH,
398               "-");
399 
400      snprintf(info->url,
401               DFB_GRAPHICS_DRIVER_INFO_URL_LENGTH,
402               "http://www.directfb.org");
403 
404      snprintf(info->license,
405               DFB_GRAPHICS_DRIVER_INFO_LICENSE_LENGTH,
406               "LGPL");
407 
408      info->version.major = 0;
409      info->version.minor = 3;
410 
411      info->driver_data_size = sizeof (UcDriverData);
412      info->device_data_size = sizeof (UcDeviceData);
413 }
414 
415 
driver_init_driver(CoreGraphicsDevice * device,GraphicsDeviceFuncs * funcs,void * driver_data,void * device_data,CoreDFB * core)416 static DFBResult driver_init_driver(CoreGraphicsDevice* device,
417                                     GraphicsDeviceFuncs* funcs,
418                                     void* driver_data,
419                                     void* device_data,
420                                     CoreDFB *core)
421 {
422      UcDriverData *ucdrv = (UcDriverData*) driver_data;
423 
424      //printf("Entering %s\n", __PRETTY_FUNCTION__);
425 
426      ucdrv->file = -1;
427      ucdrv->pool = dfb_core_shmpool( core );
428 
429      ucdrv->hwregs = dfb_gfxcard_map_mmio( device, 0, 0 );
430      if (!ucdrv->hwregs) {
431           int fd;
432 
433           fd = open(UNICHROME_DEVICE, O_RDWR | O_SYNC, 0);
434           if (fd < 0) {
435                D_ERROR("Could not access %s. "
436                         "Is the cle266vgaio module installed?\n", UNICHROME_DEVICE);
437                return DFB_IO;
438           }
439 
440           ucdrv->file = fd;
441 
442           ucdrv->hwregs = mmap(NULL, 0x1000000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
443           if (ucdrv->hwregs == MAP_FAILED)
444                return DFB_IO;
445      }
446 
447      /* FIXME: this belongs to device_data! */
448      ucdrv->fifo = uc_fifo_create(ucdrv->pool, UC_FIFO_SIZE);
449      if (!ucdrv->fifo)
450           return D_OOSHM();
451 
452      uc_after_set_var(driver_data, device_data);
453 
454      ucdrv->hwrev = 3;   // FIXME: Get the real hardware revision number!!!
455 
456      // Driver specific initialization
457 
458      funcs->CheckState        = uc_check_state;
459      funcs->SetState          = uc_set_state;
460      funcs->EngineSync        = uc_engine_sync;
461      funcs->EmitCommands      = uc_emit_commands;
462      funcs->FlushTextureCache = uc_flush_texture_cache;
463      funcs->AfterSetVar       = uc_after_set_var;
464 
465      funcs->FillRectangle     = uc_fill_rectangle;
466      funcs->DrawRectangle     = uc_draw_rectangle;
467      funcs->DrawLine          = uc_draw_line;
468      funcs->FillTriangle      = uc_fill_triangle;
469      funcs->Blit              = uc_blit;
470      funcs->StretchBlit       = uc_stretch_blit;
471      funcs->TextureTriangles  = uc_texture_triangles;
472 
473 
474      /* install primary layer hooks */
475      if ( getenv("DFB_CLE266_UNDERLAY"))
476           dfb_layers_hook_primary( device, driver_data, &ucPrimaryFuncs,
477                                     &ucOldPrimaryFuncs, &ucOldPrimaryDriverData );
478 
479      dfb_layers_register( dfb_screens_at(DSCID_PRIMARY),
480                           driver_data, &ucOverlayFuncs );
481 
482      return DFB_OK;
483 }
484 
driver_init_device(CoreGraphicsDevice * device,GraphicsDeviceInfo * device_info,void * driver_data,void * device_data)485 static DFBResult driver_init_device(CoreGraphicsDevice* device,
486                                     GraphicsDeviceInfo* device_info,
487                                     void* driver_data,
488                                     void* device_data)
489 {
490      UcDriverData *ucdrv = (UcDriverData*) driver_data;
491      UcDeviceData *ucdev = (UcDeviceData*) device_data;
492 
493      //printf("Entering %s\n", __PRETTY_FUNCTION__);
494 
495      snprintf(device_info->name,
496               DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH, "UniChrome");
497      snprintf(device_info->vendor,
498               DFB_GRAPHICS_DEVICE_INFO_VENDOR_LENGTH, "VIA/S3G");
499 
500      device_info->caps.flags = CCF_CLIPPING;
501      device_info->caps.accel =
502      UC_DRAWING_FUNCTIONS_2D | UC_DRAWING_FUNCTIONS_3D |
503      UC_BLITTING_FUNCTIONS_2D | UC_BLITTING_FUNCTIONS_3D;
504 
505      device_info->caps.drawing  = UC_DRAWING_FLAGS_2D | UC_DRAWING_FLAGS_3D;
506      device_info->caps.blitting = UC_BLITTING_FLAGS_2D | UC_BLITTING_FLAGS_3D;
507 
508      device_info->limits.surface_byteoffset_alignment = 32;
509      device_info->limits.surface_pixelpitch_alignment = 32;
510 
511      ucdev->pitch = 0;
512      ucdev->draw_rop2d = VIA_ROP_P;
513      ucdev->draw_rop3d = HC_HROP_P;
514      ucdev->color = 0;
515      ucdev->bflags = 0;
516 
517      ucdev->must_wait = 0;
518      ucdev->cmd_waitcycles = 0;
519      ucdev->idle_waitcycles = 0;
520 
521      uc_init_2d_engine(device, ucdev, ucdrv, false); // VQ disabled - can't make it work.
522      uc_init_3d_engine(ucdrv->hwregs, ucdrv->hwrev, 1);
523 
524      return DFB_OK;
525 }
526 
driver_close_device(CoreGraphicsDevice * device,void * driver_data,void * device_data)527 static void driver_close_device(CoreGraphicsDevice *device,
528                                 void *driver_data, void *device_data)
529 {
530      UcDriverData* ucdrv = (UcDriverData*) driver_data;
531      UcDeviceData* ucdev = (UcDeviceData*) device_data;
532 
533      // uc_dump_vq(ucdev);
534 
535      uc_engine_sync(driver_data, device_data);
536      uc_init_2d_engine(device, ucdev, ucdrv, false);
537 }
538 
driver_close_driver(CoreGraphicsDevice * device,void * driver_data)539 static void driver_close_driver(CoreGraphicsDevice* device, void* driver_data)
540 {
541      UcDriverData* ucdrv = (UcDriverData*) driver_data;
542 
543      if (ucdrv->fifo)
544           uc_fifo_destroy( ucdrv->pool, ucdrv->fifo );
545 
546      if (ucdrv->file != -1)
547           close( ucdrv->file );
548 }
549