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