1 #ifdef SH7722_DEBUG_DRIVER
2 #define DIRECT_ENABLE_DEBUG
3 #endif
4 
5 #include <stdio.h>
6 
7 #undef HAVE_STDLIB_H
8 
9 #include <config.h>
10 #include <stdio.h>
11 #include <unistd.h>
12 #include <stdlib.h>
13 #include <errno.h>
14 #include <string.h>
15 
16 #include <sys/mman.h>
17 #include <fcntl.h>
18 
19 #include <asm/types.h>
20 
21 #include <directfb.h>
22 #include <directfb_util.h>
23 
24 #include <direct/debug.h>
25 #include <direct/messages.h>
26 #include <direct/system.h>
27 
28 #include <misc/conf.h>
29 
30 #include <core/core.h>
31 #include <core/gfxcard.h>
32 #include <core/layers.h>
33 #include <core/screens.h>
34 #include <core/system.h>
35 
36 #include <core/graphics_driver.h>
37 
38 DFB_GRAPHICS_DRIVER( sh7722 )
39 
40 
41 #include "sh7722.h"
42 #include "sh7722_blt.h"
43 #include "sh7722_layer.h"
44 #include "sh7722_lcd.h"
45 #include "sh7722_multi.h"
46 #include "sh7722_screen.h"
47 
48 #include "sh7723_blt.h"
49 
50 #ifdef SH772X_FBDEV_SUPPORT
51 #include <linux/fb.h>
52 #include <sys/mman.h>
53 #endif
54 
55 /* libshbeu */
56 #include <shbeu/shbeu.h>
57 #include <uiomux/uiomux.h>
58 
59 D_DEBUG_DOMAIN( SH7722_Driver, "SH772x/Driver", "Renesas SH7722 Driver" );
60 
61 /**********************************************************************************************************************/
62 
63 static int
driver_probe(CoreGraphicsDevice * device)64 driver_probe( CoreGraphicsDevice *device )
65 {
66      D_DEBUG_AT( SH7722_Driver, "%s()\n", __FUNCTION__ );
67 
68      return dfb_gfxcard_get_accelerator( device ) == 0x2D47;
69 }
70 
71 static void
driver_get_info(CoreGraphicsDevice * device,GraphicsDriverInfo * info)72 driver_get_info( CoreGraphicsDevice *device,
73                  GraphicsDriverInfo *info )
74 {
75      D_DEBUG_AT( SH7722_Driver, "%s()\n", __FUNCTION__ );
76 
77      /* fill driver info structure */
78      snprintf( info->name,
79                DFB_GRAPHICS_DRIVER_INFO_NAME_LENGTH,
80                "Renesas SH772x Driver" );
81 
82      snprintf( info->vendor,
83                DFB_GRAPHICS_DRIVER_INFO_VENDOR_LENGTH,
84                "Denis & Janine Kropp" );
85 
86      info->version.major = 0;
87      info->version.minor = 9;
88 
89      info->driver_data_size = sizeof(SH7722DriverData);
90      info->device_data_size = sizeof(SH7722DeviceData);
91 }
92 
93 static DFBResult
driver_init_driver(CoreGraphicsDevice * device,GraphicsDeviceFuncs * funcs,void * driver_data,void * device_data,CoreDFB * core)94 driver_init_driver( CoreGraphicsDevice  *device,
95                     GraphicsDeviceFuncs *funcs,
96                     void                *driver_data,
97                     void                *device_data,
98                     CoreDFB             *core )
99 {
100      DFBResult         ret;
101      SH7722DriverData *sdrv = driver_data;
102      SH7722DeviceData *sdev = device_data;
103 
104      D_DEBUG_AT( SH7722_Driver, "%s()\n", __FUNCTION__ );
105 
106      /* Keep pointer to shared device data. */
107      sdrv->dev = device_data;
108 
109      /* Keep core and device pointer. */
110      sdrv->core   = core;
111      sdrv->device = device;
112 
113      /* Open the drawing engine device. */
114      sdrv->gfx_fd = direct_try_open( "/dev/sh772x_gfx", "/dev/misc/sh772x_gfx", O_RDWR, true );
115      if (sdrv->gfx_fd < 0)
116           return DFB_INIT;
117 
118      /* Map its shared data. */
119      sdrv->gfx_shared = mmap( NULL, direct_page_align( sizeof(SH772xGfxSharedArea) ),
120                               PROT_READ | PROT_WRITE,
121                               MAP_SHARED, sdrv->gfx_fd, 0 );
122      if (sdrv->gfx_shared == MAP_FAILED) {
123           D_PERROR( "SH772x/Driver: Could not map shared area!\n" );
124           close( sdrv->gfx_fd );
125           return DFB_INIT;
126      }
127 
128      sdrv->mmio_base = dfb_gfxcard_map_mmio( device, 0, -1 );
129      if (!sdrv->mmio_base) {
130           D_PERROR( "SH772x/Driver: Could not map MMIO area!\n" );
131           munmap( (void*) sdrv->gfx_shared, direct_page_align( sizeof(SH772xGfxSharedArea) ) );
132           close( sdrv->gfx_fd );
133           return DFB_INIT;
134      }
135      /* libshbeu */
136      sdrv->shbeu = shbeu_open();
137      if (!sdrv->shbeu) {
138           D_PERROR( "SH772x/Driver: Could not initialize libshbeu" );
139           munmap( (void*) sdrv->gfx_shared, direct_page_align( sizeof(SH772xGfxSharedArea) ) );
140           close( sdrv->gfx_fd );
141           return DFB_INIT;
142      }
143 
144      /* Check the magic value. */
145      switch (sdrv->gfx_shared->magic) {
146           case SH7722GFX_SHARED_MAGIC:
147                sdev->sh772x = 7722;
148 
149                /* Initialize function table. */
150                funcs->EngineReset       = sh7722EngineReset;
151                funcs->EngineSync        = sh7722EngineSync;
152                funcs->EmitCommands      = sh7722EmitCommands;
153                funcs->CheckState        = sh7722CheckState;
154                funcs->SetState          = sh7722SetState;
155                funcs->FillTriangle      = sh7722FillTriangle;
156                funcs->Blit              = sh7722Blit;
157                funcs->StretchBlit       = sh7722StretchBlit;
158                funcs->FlushTextureCache = sh7722FlushTextureCache;
159                break;
160 
161           case SH7723GFX_SHARED_MAGIC:
162                sdev->sh772x = 7723;
163 
164                /* Initialize function table. */
165                funcs->EngineReset       = sh7723EngineReset;
166                funcs->EngineSync        = sh7723EngineSync;
167                funcs->EmitCommands      = sh7723EmitCommands;
168                funcs->CheckState        = sh7723CheckState;
169                funcs->SetState          = sh7723SetState;
170                funcs->FillRectangle     = sh7723FillRectangle;
171                funcs->FillTriangle      = sh7723FillTriangle;
172                funcs->DrawRectangle     = sh7723DrawRectangle;
173                funcs->DrawLine          = sh7723DrawLine;
174                funcs->Blit              = sh7723Blit;
175                break;
176 
177           default:
178                D_ERROR( "SH772x/Driver: Magic value 0x%08x doesn't match 0x%08x or 0x%08x!\n",
179                         sdrv->gfx_shared->magic, SH7722GFX_SHARED_MAGIC, SH7723GFX_SHARED_MAGIC );
180                dfb_gfxcard_unmap_mmio( device, sdrv->mmio_base, -1 );
181                munmap( (void*) sdrv->gfx_shared, direct_page_align( sizeof(SH772xGfxSharedArea) ) );
182                close( sdrv->gfx_fd );
183                return DFB_INIT;
184      }
185 
186 
187      /* Get virtual address for the LCD buffer in slaves here,
188         master does it in driver_init_device(). */
189 #ifndef SH772X_FBDEV_SUPPORT
190      if (!dfb_core_is_master( core ))
191           sdrv->lcd_virt = dfb_gfxcard_memory_virtual( device, sdev->lcd_offset );
192 #endif
193 
194 
195      /* Register primary screen. */
196      sdrv->screen = dfb_screens_register( device, driver_data, &sh7722ScreenFuncs );
197 
198      /* Register three input system layers. */
199      sdrv->input1 = dfb_layers_register( sdrv->screen, driver_data, &sh7722LayerFuncs );
200      sdrv->input2 = dfb_layers_register( sdrv->screen, driver_data, &sh7722LayerFuncs );
201      sdrv->input3 = dfb_layers_register( sdrv->screen, driver_data, &sh7722LayerFuncs );
202 
203      /* Register multi window layer. */
204      sdrv->multi = dfb_layers_register( sdrv->screen, driver_data, &sh7722MultiLayerFuncs );
205 
206      return DFB_OK;
207 }
208 
209 static DFBResult
driver_init_device(CoreGraphicsDevice * device,GraphicsDeviceInfo * device_info,void * driver_data,void * device_data)210 driver_init_device( CoreGraphicsDevice *device,
211                     GraphicsDeviceInfo *device_info,
212                     void               *driver_data,
213                     void               *device_data )
214 {
215      SH7722DriverData *sdrv = driver_data;
216      SH7722DeviceData *sdev = device_data;
217 
218      D_DEBUG_AT( SH7722_Driver, "%s()\n", __FUNCTION__ );
219 
220      /* FIXME: Add a runtime option / config file. */
221      sdev->lcd_format = DSPF_RGB16;
222 
223      /* Check format of LCD buffer. */
224      switch (sdev->lcd_format) {
225           case DSPF_RGB16:
226           case DSPF_NV16:
227                break;
228 
229           default:
230                return DFB_UNSUPPORTED;
231      }
232 
233      if (sdev->sh772x == 7723)
234           memset( dfb_gfxcard_memory_virtual(device,0), 0, dfb_gfxcard_memory_length() );
235 
236      /*
237       * Setup LCD buffer.
238       */
239 #ifdef SH772X_FBDEV_SUPPORT
240      {
241             struct fb_fix_screeninfo fsi;
242             struct fb_var_screeninfo vsi;
243             int fbdev;
244 
245             if ((fbdev = open("/dev/fb0", O_RDWR)) < 0) {
246                   D_ERROR( "SH772x/Driver: Can't open fbdev to get LCDC info!\n" );
247                   return DFB_FAILURE;
248             }
249 
250             if (ioctl(fbdev, FBIOGET_FSCREENINFO, &fsi) < 0) {
251                   D_ERROR( "SH772x/Driver: FBIOGET_FSCREEINFO failed.\n" );
252                   close(fbdev);
253                   return DFB_FAILURE;
254             }
255 
256             if (ioctl(fbdev, FBIOGET_VSCREENINFO, &vsi) < 0) {
257                   D_ERROR( "SH772x/Driver: FBIOGET_VSCREEINFO failed.\n" );
258                   close(fbdev);
259                   return DFB_FAILURE;
260             }
261 
262             sdev->lcd_width  = vsi.xres;
263             sdev->lcd_height = vsi.yres;
264             sdev->lcd_pitch  = fsi.line_length;
265             sdev->lcd_size   = fsi.smem_len;
266             sdev->lcd_offset = 0;
267             sdev->lcd_phys   = fsi.smem_start;
268             sdrv->lcd_virt   = mmap(NULL, fsi.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED,
269                                             fbdev, 0);
270             if (sdrv->lcd_virt == MAP_FAILED) {
271                   D_PERROR( "SH772x/Driver: mapping fbdev failed.\n" );
272                   close(fbdev);
273                   return DFB_FAILURE;
274             }
275 
276 
277           /* Clear LCD buffer. */
278           switch (sdev->lcd_format) {
279                case DSPF_RGB16:
280                     memset( (void*) sdrv->lcd_virt, 0x00, sdev->lcd_height * sdev->lcd_pitch );
281                     break;
282 
283                case DSPF_NV16:
284                     memset( (void*) sdrv->lcd_virt, 0x10, sdev->lcd_height * sdev->lcd_pitch );
285                     memset( (void*) sdrv->lcd_virt + sdev->lcd_height * sdev->lcd_pitch, 0x80, sdev->lcd_height * sdev->lcd_pitch );
286                     break;
287 
288                default:
289                     D_BUG( "unsupported format" );
290                     return DFB_BUG;
291           }
292 
293           /* Register the framebuffer with UIOMux */
294           uiomux_register (sdrv->lcd_virt, sdev->lcd_phys, sdev->lcd_size);
295 
296           close(fbdev);
297      }
298 #else
299      sdev->lcd_width  = SH7722_LCD_WIDTH;
300      sdev->lcd_height = SH7722_LCD_HEIGHT;
301      sdev->lcd_pitch  = (DFB_BYTES_PER_LINE( sdev->lcd_format, sdev->lcd_width ) + 0xf) & ~0xf;
302      sdev->lcd_size   = DFB_PLANE_MULTIPLY( sdev->lcd_format, sdev->lcd_height ) * sdev->lcd_pitch;
303      sdev->lcd_offset = dfb_gfxcard_reserve_memory( device, sdev->lcd_size );
304 
305      if (sdev->lcd_offset < 0) {
306           D_ERROR( "SH772x/Driver: Allocating %d bytes for the LCD buffer failed!\n", sdev->lcd_size );
307           return DFB_FAILURE;
308      }
309 
310      sdev->lcd_phys = dfb_gfxcard_memory_physical( device, sdev->lcd_offset );
311 
312      /* Get virtual addresses for LCD buffer in master here,
313         slaves do it in driver_init_driver(). */
314      sdrv->lcd_virt = dfb_gfxcard_memory_virtual( device, sdev->lcd_offset );
315 #endif
316 
317      D_INFO( "SH772x/LCD: Allocated %dx%d %s Buffer (%d bytes) at 0x%08lx (%p)\n",
318              sdev->lcd_width, sdev->lcd_height, dfb_pixelformat_name(sdev->lcd_format),
319              sdev->lcd_size, sdev->lcd_phys, sdrv->lcd_virt );
320 
321      D_ASSERT( ! (sdev->lcd_pitch & 0xf) );
322      D_ASSERT( ! (sdev->lcd_phys & 0xf) );
323 
324      /*
325       * Initialize hardware.
326       */
327 
328      switch (sdev->sh772x) {
329           case 7722:
330                /* Reset the drawing engine. */
331                sh7722EngineReset( sdrv, sdev );
332 
333                /* Fill in the device info. */
334                snprintf( device_info->name,   DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH,   "SH7722" );
335                snprintf( device_info->vendor, DFB_GRAPHICS_DEVICE_INFO_VENDOR_LENGTH, "Renesas" );
336 
337                /* Set device limitations. */
338                device_info->limits.surface_byteoffset_alignment = 16;
339                device_info->limits.surface_bytepitch_alignment  = 8;
340 
341                /* Set device capabilities. */
342                device_info->caps.flags    = CCF_CLIPPING | CCF_RENDEROPTS;
343                device_info->caps.accel    = SH7722_SUPPORTED_DRAWINGFUNCTIONS |
344                                             SH7722_SUPPORTED_BLITTINGFUNCTIONS;
345                device_info->caps.drawing  = SH7722_SUPPORTED_DRAWINGFLAGS;
346                device_info->caps.blitting = SH7722_SUPPORTED_BLITTINGFLAGS;
347 
348                /* Change font format for acceleration. */
349                if (!dfb_config->software_only) {
350                     dfb_config->font_format  = DSPF_ARGB;
351                     dfb_config->font_premult = false;
352                }
353                break;
354 
355           case 7723:
356                /* Reset the drawing engine. */
357                sh7723EngineReset( sdrv, sdev );
358 
359                /* Fill in the device info. */
360                snprintf( device_info->name,   DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH,   "SH7723" );
361                snprintf( device_info->vendor, DFB_GRAPHICS_DEVICE_INFO_VENDOR_LENGTH, "Renesas" );
362 
363                /* Set device limitations. */
364                device_info->limits.surface_byteoffset_alignment = 512;
365                device_info->limits.surface_bytepitch_alignment  = 64;
366 
367                /* Set device capabilities. */
368                device_info->caps.flags    = CCF_CLIPPING | CCF_RENDEROPTS;
369                device_info->caps.accel    = SH7723_SUPPORTED_DRAWINGFUNCTIONS | \
370                                             SH7723_SUPPORTED_BLITTINGFUNCTIONS;
371                device_info->caps.drawing  = SH7723_SUPPORTED_DRAWINGFLAGS;
372                device_info->caps.blitting = SH7723_SUPPORTED_BLITTINGFLAGS;
373 
374                break;
375 
376           default:
377                D_BUG( "unexpected device" );
378                return DFB_BUG;
379      }
380 
381 #ifndef SH772X_FBDEV_SUPPORT
382      /* Clear LCD buffer. */
383      switch (sdev->lcd_format) {
384           case DSPF_RGB16:
385                memset( (void*) sdrv->lcd_virt, 0x00, sdev->lcd_height * sdev->lcd_pitch );
386                break;
387 
388           case DSPF_NV16:
389                memset( (void*) sdrv->lcd_virt, 0x10, sdev->lcd_height * sdev->lcd_pitch );
390                memset( (void*) sdrv->lcd_virt + sdev->lcd_height * sdev->lcd_pitch, 0x80, sdev->lcd_height * sdev->lcd_pitch );
391                break;
392 
393           default:
394                D_BUG( "unsupported format" );
395                return DFB_BUG;
396      }
397 #endif
398 
399      /*
400       * TODO: Make LCD Buffer format and primary BEU format runtime configurable.
401       */
402 
403      /* Set output pixel format of the BEU. */
404      switch (sdev->lcd_format) {
405           case DSPF_RGB16:
406                sdev->shbeu_dest.s.pc = NULL;
407                sdev->shbeu_dest.s.pa = NULL;
408                sdev->shbeu_dest.s.format = REN_RGB565;
409                break;
410 
411           case DSPF_NV16:
412                sdev->shbeu_dest.s.pc = sdrv->lcd_virt + sdev->lcd_height * sdev->lcd_pitch;
413                sdev->shbeu_dest.s.pa = NULL;
414                sdev->shbeu_dest.s.format = REN_NV16;
415                break;
416 
417           default:
418                D_BUG( "unsupported format" );
419                return DFB_BUG;
420      }
421 
422 #ifndef SH772X_FBDEV_SUPPORT
423      /* Setup LCD controller to show the buffer. */
424      sh7722_lcd_setup( sdrv, sdev->lcd_width, sdev->lcd_height,
425                        sdev->lcd_phys, sdev->lcd_pitch, sdev->lcd_format, false );
426 #endif
427 
428      /* Initialize BEU lock. */
429      fusion_skirmish_init( &sdev->beu_lock, "BEU", dfb_core_world(sdrv->core) );
430 
431      /* libshbeu */
432      sdev->shbeu_dest.s.py = sdrv->lcd_virt;
433      sdev->shbeu_dest.s.w = sdev->lcd_width;
434      sdev->shbeu_dest.s.h =sdev->lcd_height;
435      sdev->shbeu_dest.s.pitch = sdev->lcd_pitch/DFB_BYTES_PER_PIXEL(sdev->lcd_format);
436      sdev->shbeu_dest.alpha = 0xff;
437      sdev->shbeu_dest.x = 0;
438      sdev->shbeu_dest.y = 0;
439 
440      return DFB_OK;
441 }
442 
443 static void
driver_close_device(CoreGraphicsDevice * device,void * driver_data,void * device_data)444 driver_close_device( CoreGraphicsDevice *device,
445                      void               *driver_data,
446                      void               *device_data )
447 {
448      SH7722DeviceData *sdev = device_data;
449 
450      D_DEBUG_AT( SH7722_Driver, "%s()\n", __FUNCTION__ );
451 
452      /* Destroy BEU lock. */
453      fusion_skirmish_destroy( &sdev->beu_lock );
454 }
455 
456 static void
driver_close_driver(CoreGraphicsDevice * device,void * driver_data)457 driver_close_driver( CoreGraphicsDevice *device,
458                      void               *driver_data )
459 {
460      SH7722DriverData    *sdrv   = driver_data;
461      SH772xGfxSharedArea *shared = sdrv->gfx_shared;
462 
463      (void) shared;
464 
465      D_DEBUG_AT( SH7722_Driver, "%s()\n", __FUNCTION__ );
466 
467      D_INFO( "SH772x/BLT: %u starts, %u done, %u interrupts, %u wait_idle, %u wait_next, %u idle\n",
468              shared->num_starts, shared->num_done, shared->num_interrupts,
469              shared->num_wait_idle, shared->num_wait_next, shared->num_idle );
470 
471      D_INFO( "SH772x/BLT: %u words, %u words/start, %u words/idle, %u starts/idle\n",
472              shared->num_words,
473              shared->num_words  / shared->num_starts,
474              shared->num_words  / shared->num_idle,
475              shared->num_starts / shared->num_idle );
476 
477      /* Unmap shared area. */
478      munmap( (void*) sdrv->gfx_shared, direct_page_align( sizeof(SH772xGfxSharedArea) ) );
479 
480      /* Close Drawing Engine device. */
481      close( sdrv->gfx_fd );
482 
483      /* libshbeu */
484      shbeu_close(sdrv->shbeu);
485 }
486 
487