From 7fe60435bce6595a9c58a9bfd8244d74b5320e96 Mon Sep 17 00:00:00 2001 From: Benjamin Franzke Date: Tue, 15 Jan 2013 08:46:13 +0100 Subject: Import DirectFB141_2k11R3_beta5 --- Source/DirectFB/gfxdrivers/unichrome/unichrome.c | 596 +++++++++++++++++++++++ 1 file changed, 596 insertions(+) create mode 100755 Source/DirectFB/gfxdrivers/unichrome/unichrome.c (limited to 'Source/DirectFB/gfxdrivers/unichrome/unichrome.c') diff --git a/Source/DirectFB/gfxdrivers/unichrome/unichrome.c b/Source/DirectFB/gfxdrivers/unichrome/unichrome.c new file mode 100755 index 0000000..062334e --- /dev/null +++ b/Source/DirectFB/gfxdrivers/unichrome/unichrome.c @@ -0,0 +1,596 @@ +/* + Copyright (c) 2003 Andreas Robinson, All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. +*/ + +// DirectFB headers + +#include + +#include + +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include + +// System headers + +#include +#include +#include +#include +#include +#include + +#include + +// Driver headers + +#include "unichrome.h" +#include "uc_state.h" +#include "uc_accel.h" +#include "uc_fifo.h" +#include "uc_ioctl.h" +#include "mmio.h" +#include "uc_probe.h" + +extern DisplayLayerFuncs ucOverlayFuncs; +extern DisplayLayerFuncs ucPrimaryFuncs; +extern DisplayLayerFuncs ucSubpictureFuncs; + +extern DisplayLayerFuncs ucOldPrimaryFuncs; +extern void *ucOldPrimaryDriverData; + + +DFB_GRAPHICS_DRIVER(unichrome) + +//---------- + +/* PCI probing code is derived from gfxdrivers/matrox/matrox.c */ + +/** Read PCI configuration register 'reg' for device at {bus,slot,func}. */ +static int pci_config_in8( unsigned int bus, + unsigned int slot, + unsigned int func, + u8 reg ) +{ + char filename[512]; + int fd; + int val; + + val = 0; + + snprintf( filename, 512, "/proc/bus/pci/%02x/%02x.%x", bus, slot, func ); + + fd = open( filename, O_RDONLY ); + if (fd < 0) { + D_PERROR( "DirectFB/Unichrome: Error opening `%s'!\n", filename ); + return -1; + } + + if (lseek( fd, reg, SEEK_SET ) == reg) { + if (read( fd, &val, 1 ) == 1) { + close( fd ); + return val; + } + } + + close( fd ); + return -1; +} + +/* Probe for a Unichrome device. +* @returns DFB_OK if successful, with ucdrv->hwid, ucdrv->hwrev, +* and ucdrv->name filled in. +*/ +static DFBResult uc_probe_pci( UcDriverData *ucdrv ) +{ + unsigned int bus, devfn, vendor, device; + char line[512]; + FILE *file; + int i; + + const char* filename = "/proc/bus/pci/devices"; + + file = fopen( filename, "r" ); + if (!file) { + D_PERROR( "DirectFB/Unichrome: Error opening `%s'!\n", filename ); + return errno2result( errno ); + } + + while (fgets( line, 512, file )) { + if (sscanf( line, "%02x%02x\t%04x%04x", + &bus, &devfn, &vendor, &device ) != 4) + continue; + + if (vendor != PCI_VENDOR_ID_VIA) + continue; + + for (i = 0; uc_via_devices[i].id != 0; i++) { + if (device == uc_via_devices[i].id) { + // Found a Unichrome device. + ucdrv->hwid = device; + ucdrv->name = uc_via_devices[i].name; + // Read its revision number from the host bridge. + ucdrv->hwrev = pci_config_in8(0, 0, 0, 0xf6); + if (ucdrv->hwrev == -1 && dfb_config->unichrome_revision == -1) { + ucdrv->hwrev = 0x11; // a fairly arbitrary default + D_ERROR( "DirectFB/Unichrome: Failed to determine hardware revision, assuming %d.\n", + ucdrv->hwrev ); + } + // Because we can only auto-detect if we're superuser, + // allow an override + if (dfb_config->unichrome_revision != -1) + ucdrv->hwrev = dfb_config->unichrome_revision; + fclose( file ); + return DFB_OK; + } + } + } + + D_ERROR( "DirectFB/Unichrome: Can't find a Unichrome device in `%s'!\n", + filename ); + + fclose( file ); + return DFB_INIT; +} + +/** + * Dump beginning of virtual queue. + * Use it to check that the VQ actually is in use. */ +#if 0 +static void uc_dump_vq(UcDeviceData *ucdev) +{ + int i; + u8* vq; + + if (!ucdev->vq_start) return; + vq = dfb_system_video_memory_virtual(ucdev->vq_start); + + for (i = 0; i < 128; i++) { + printf("%02x ", *(vq+i)); + if ((i+1) % 16 == 0) printf("\n"); + } +} +#endif + +/** Allocate memory for the virtual queue. */ + +static DFBResult uc_alloc_vq(CoreGraphicsDevice *device, UcDeviceData *ucdev) +{ + if (ucdev->vq_start) return DFB_OK; + + ucdev->vq_size = 256*1024; // 256kb + ucdev->vq_start = dfb_gfxcard_reserve_memory( device, ucdev->vq_size ); + + if (!ucdev->vq_start) + return DFB_INIT; + + ucdev->vq_end = ucdev->vq_start + ucdev->vq_size - 1; + + // Debug: clear buffer + memset((void *) dfb_system_video_memory_virtual(ucdev->vq_start), + 0xcc, ucdev->vq_size); + + // uc_dump_vq(ucdev); + + return DFB_OK; +} + +/** + * Initialize the hardware. + * @param enable enable VQ if true (else disable it.) + */ + +static DFBResult uc_init_2d_engine(CoreGraphicsDevice *device, UcDeviceData *ucdev, UcDriverData *ucdrv, bool enable) +{ + DFBResult result = DFB_OK; + volatile u8* hwregs = ucdrv->hwregs; + int i; + + // Init 2D engine registers to reset 2D engine + + for ( i = 0x04; i <= 0x40; i += 4 ) + VIA_OUT(hwregs, i, 0x0); + + // Init AGP and VQ registers + + VIA_OUT(hwregs, 0x43c, 0x00100000); + VIA_OUT(hwregs, 0x440, 0x00000000); + VIA_OUT(hwregs, 0x440, 0x00333004); + VIA_OUT(hwregs, 0x440, 0x60000000); + VIA_OUT(hwregs, 0x440, 0x61000000); + VIA_OUT(hwregs, 0x440, 0x62000000); + VIA_OUT(hwregs, 0x440, 0x63000000); + VIA_OUT(hwregs, 0x440, 0x64000000); + VIA_OUT(hwregs, 0x440, 0x7D000000); + + VIA_OUT(hwregs, 0x43c, 0xfe020000); + VIA_OUT(hwregs, 0x440, 0x00000000); + + if (enable) { + result = uc_alloc_vq(device,ucdev); + enable = (result == DFB_OK); + } + + if (enable) { // Enable VQ + + VIA_OUT(hwregs, 0x43c, 0x00fe0000); + VIA_OUT(hwregs, 0x440, 0x080003fe); + VIA_OUT(hwregs, 0x440, 0x0a00027c); + VIA_OUT(hwregs, 0x440, 0x0b000260); + VIA_OUT(hwregs, 0x440, 0x0c000274); + VIA_OUT(hwregs, 0x440, 0x0d000264); + VIA_OUT(hwregs, 0x440, 0x0e000000); + VIA_OUT(hwregs, 0x440, 0x0f000020); + VIA_OUT(hwregs, 0x440, 0x1000027e); + VIA_OUT(hwregs, 0x440, 0x110002fe); + VIA_OUT(hwregs, 0x440, 0x200f0060); + + VIA_OUT(hwregs, 0x440, 0x00000006); + VIA_OUT(hwregs, 0x440, 0x40008c0f); + VIA_OUT(hwregs, 0x440, 0x44000000); + VIA_OUT(hwregs, 0x440, 0x45080c04); + VIA_OUT(hwregs, 0x440, 0x46800408); + + VIA_OUT(hwregs, 0x440, 0x52000000 | + ((ucdev->vq_start & 0xFF000000) >> 24) | + ((ucdev->vq_end & 0xFF000000) >> 16)); + VIA_OUT(hwregs, 0x440, 0x50000000 | (ucdev->vq_start & 0xFFFFFF)); + VIA_OUT(hwregs, 0x440, 0x51000000 | (ucdev->vq_end & 0xFFFFFF)); + VIA_OUT(hwregs, 0x440, 0x53000000 | (ucdev->vq_size >> 3)); + } + else { // Disable VQ + + VIA_OUT(hwregs, 0x43c, 0x00fe0000); + VIA_OUT(hwregs, 0x440, 0x00000004); + VIA_OUT(hwregs, 0x440, 0x40008c0f); + VIA_OUT(hwregs, 0x440, 0x44000000); + VIA_OUT(hwregs, 0x440, 0x45080c04); + VIA_OUT(hwregs, 0x440, 0x46800408); + } + + return result; +} + +static void uc_init_3d_engine(volatile u8* hwregs, int hwrev, bool init_all) +{ + u32 i; + + if (init_all) { + + // Clear NotTex registers + + VIA_OUT(hwregs, 0x43C, 0x00010000); + for (i = 0; i <= 0x7d; i++) + VIA_OUT(hwregs, 0x440, i << 24); + + // Clear texture unit 0 + + VIA_OUT(hwregs, 0x43C, 0x00020000); + for (i = 0; i <= 0x94; i++) + VIA_OUT(hwregs, 0x440, i << 24); + VIA_OUT(hwregs, 0x440, 0x82400000); + + // Clear texture unit 1 + + VIA_OUT(hwregs, 0x43C, 0x01020000); + for (i = 0; i <= 0x94; i++) + VIA_OUT(hwregs, 0x440, i << 24); + VIA_OUT(hwregs, 0x440, 0x82400000); + + // Clear general texture settings + + VIA_OUT(hwregs, 0x43C, 0xfe020000); + for (i = 0; i <= 0x03; i++) + VIA_OUT(hwregs, 0x440, i << 24); + + // Clear palette settings + + VIA_OUT(hwregs, 0x43C, 0x00030000); + for (i = 0; i <= 0xff; i++) + VIA_OUT(hwregs, 0x440, 0); + + VIA_OUT(hwregs, 0x43C, 0x00100000); + VIA_OUT(hwregs, 0x440, 0x00333004); + VIA_OUT(hwregs, 0x440, 0x10000002); + VIA_OUT(hwregs, 0x440, 0x60000000); + VIA_OUT(hwregs, 0x440, 0x61000000); + VIA_OUT(hwregs, 0x440, 0x62000000); + VIA_OUT(hwregs, 0x440, 0x63000000); + VIA_OUT(hwregs, 0x440, 0x64000000); + + VIA_OUT(hwregs, 0x43C, 0x00fe0000); + + if (hwrev >= 3) + VIA_OUT(hwregs, 0x440,0x40008c0f); + else + VIA_OUT(hwregs, 0x440,0x4000800f); + + VIA_OUT(hwregs, 0x440,0x44000000); + VIA_OUT(hwregs, 0x440,0x45080C04); + VIA_OUT(hwregs, 0x440,0x46800408); + VIA_OUT(hwregs, 0x440,0x50000000); + VIA_OUT(hwregs, 0x440,0x51000000); + VIA_OUT(hwregs, 0x440,0x52000000); + VIA_OUT(hwregs, 0x440,0x53000000); + + } + + VIA_OUT(hwregs, 0x43C,0x00fe0000); + VIA_OUT(hwregs, 0x440,0x08000001); + VIA_OUT(hwregs, 0x440,0x0A000183); + VIA_OUT(hwregs, 0x440,0x0B00019F); + VIA_OUT(hwregs, 0x440,0x0C00018B); + VIA_OUT(hwregs, 0x440,0x0D00019B); + VIA_OUT(hwregs, 0x440,0x0E000000); + VIA_OUT(hwregs, 0x440,0x0F000000); + VIA_OUT(hwregs, 0x440,0x10000000); + VIA_OUT(hwregs, 0x440,0x11000000); + VIA_OUT(hwregs, 0x440,0x20000000); +} + +/** */ + +static void uc_after_set_var(void* drv, void* dev) +{ + UcDriverData* ucdrv = (UcDriverData*) drv; + + VGA_OUT8(ucdrv->hwregs, 0x3c4, 0x1a); + // Clear bit 6 in extended VGA register 0x1a to prevent system lockup. + VGA_OUT8(ucdrv->hwregs, 0x3c5, VGA_IN8(ucdrv->hwregs, 0x3c5) & 0xbf); + // Set bit 2, it might make a difference. + VGA_OUT8(ucdrv->hwregs, 0x3c5, VGA_IN8(ucdrv->hwregs, 0x3c5) | 0x4); + + VIA_OUT(ucdrv->hwregs, VIA_REG_CURSOR_MODE, VIA_IN(ucdrv->hwregs, VIA_REG_CURSOR_MODE) & 0xFFFFFFFE); +} + +/** Wait until the engine is idle. */ + +static DFBResult uc_engine_sync(void* drv, void* dev) +{ + UcDriverData* ucdrv = (UcDriverData*) drv; + UcDeviceData* ucdev = (UcDeviceData*) dev; + + int loop = 0; + +/* printf("Entering uc_engine_sync(), status is 0x%08x\n", + VIA_IN(ucdrv->hwregs, VIA_REG_STATUS)); +*/ + + while ((VIA_IN(ucdrv->hwregs, VIA_REG_STATUS) & 0xfffeffff) != 0x00020000) { + if (++loop > MAXLOOP) { + D_ERROR("DirectFB/Unichrome: Timeout waiting for idle engine!\n"); + break; + + /* FIXME: return DFB_TIMEOUT and implement EngineReset! */ + } + } + + /* printf("Leaving uc_engine_sync(), status is 0x%08x, " + "waiting for %d (0x%x) cycles.\n", + VIA_IN(ucdrv->hwregs, VIA_REG_STATUS), loop, loop); + */ + + ucdev->idle_waitcycles += loop; + ucdev->must_wait = 0; + + return DFB_OK; +} + + +// DirectFB interfacing functions -------------------------------------------- + +static int driver_probe(CoreGraphicsDevice *device) +{ + struct stat s; + + switch (dfb_gfxcard_get_accelerator( device )) { + case FB_ACCEL_VIA_UNICHROME: + return 1; + } + + return stat(UNICHROME_DEVICE, &s) + 1; +} + +static void driver_get_info(CoreGraphicsDevice* device, + GraphicsDriverInfo* info) +{ + // Fill in driver info structure. + + snprintf(info->name, + DFB_GRAPHICS_DRIVER_INFO_NAME_LENGTH, + "VIA UniChrome Driver"); + + snprintf(info->vendor, + DFB_GRAPHICS_DRIVER_INFO_VENDOR_LENGTH, + "-"); + + snprintf(info->url, + DFB_GRAPHICS_DRIVER_INFO_URL_LENGTH, + "http://www.directfb.org"); + + snprintf(info->license, + DFB_GRAPHICS_DRIVER_INFO_LICENSE_LENGTH, + "LGPL"); + + info->version.major = 0; + info->version.minor = 4; + + info->driver_data_size = sizeof (UcDriverData); + info->device_data_size = sizeof (UcDeviceData); +} + +static void uc_probe_fbdev(UcDriverData *ucdrv) +{ + struct fb_flip flip; + FBDev *dfb_fbdev = dfb_system_data(); + flip.device = VIAFB_FLIP_NOP; + if (ioctl(dfb_fbdev->fd, FBIO_FLIPONVSYNC, &flip) == 0) + ucdrv->canfliponvsync = true; + else + ucdrv->canfliponvsync = false; +} + +static DFBResult driver_init_driver(CoreGraphicsDevice* device, + GraphicsDeviceFuncs* funcs, + void* driver_data, + void* device_data, + CoreDFB *core) +{ + UcDriverData *ucdrv = (UcDriverData*) driver_data; + + //printf("Entering %s\n", __PRETTY_FUNCTION__); + + ucdrv->file = -1; + ucdrv->pool = dfb_core_shmpool( core ); + + ucdrv->hwregs = dfb_gfxcard_map_mmio( device, 0, 0 ); + if (!ucdrv->hwregs) { + int fd; + + fd = open(UNICHROME_DEVICE, O_RDWR | O_SYNC, 0); + if (fd < 0) { + D_ERROR("DirectFB/Unichrome: Could not access %s. " + "Is the ucio module installed?\n", UNICHROME_DEVICE); + return DFB_IO; + } + + ucdrv->file = fd; + + ucdrv->hwregs = mmap(NULL, 0x1000000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (ucdrv->hwregs == MAP_FAILED) + return DFB_IO; + } + + // Get hardware id and revision. + uc_probe_pci(ucdrv); + + // Check framebuffer device capabilities + uc_probe_fbdev(ucdrv); + + /* FIXME: this belongs to device_data! */ + ucdrv->fifo = uc_fifo_create(ucdrv->pool, UC_FIFO_SIZE); + if (!ucdrv->fifo) + return D_OOSHM(); + + uc_after_set_var(driver_data, device_data); + + // Driver specific initialization + + funcs->CheckState = uc_check_state; + funcs->SetState = uc_set_state; + funcs->EngineSync = uc_engine_sync; + funcs->EmitCommands = uc_emit_commands; + funcs->FlushTextureCache = uc_flush_texture_cache; + funcs->AfterSetVar = uc_after_set_var; + + funcs->FillRectangle = uc_fill_rectangle; + funcs->DrawRectangle = uc_draw_rectangle; + funcs->DrawLine = uc_draw_line; + funcs->FillTriangle = uc_fill_triangle; + funcs->Blit = uc_blit; + funcs->StretchBlit = uc_stretch_blit; + funcs->TextureTriangles = uc_texture_triangles; + + ucdrv->ovl = NULL; + + /* install primary layer hooks */ + dfb_layers_hook_primary( device, driver_data, &ucPrimaryFuncs, + &ucOldPrimaryFuncs, &ucOldPrimaryDriverData ); + + dfb_layers_register( dfb_screens_at(DSCID_PRIMARY), + driver_data, &ucOverlayFuncs ); + dfb_layers_register( dfb_screens_at(DSCID_PRIMARY), + driver_data, &ucSubpictureFuncs ); + + return DFB_OK; +} + +static DFBResult driver_init_device(CoreGraphicsDevice* device, + GraphicsDeviceInfo* device_info, + void* driver_data, + void* device_data) +{ + UcDriverData *ucdrv = (UcDriverData*) driver_data; + UcDeviceData *ucdev = (UcDeviceData*) device_data; + + //printf("Entering %s\n", __PRETTY_FUNCTION__); + + if (ucdrv->name != NULL) { + snprintf(device_info->name, + DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH, "%s", ucdrv->name); + } + else { + snprintf(device_info->name, + DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH, "UniChrome"); + } + snprintf(device_info->vendor, + DFB_GRAPHICS_DEVICE_INFO_VENDOR_LENGTH, "VIA/S3G"); + + device_info->caps.flags = CCF_CLIPPING; + device_info->caps.accel = + UC_DRAWING_FUNCTIONS_2D | UC_DRAWING_FUNCTIONS_3D | + UC_BLITTING_FUNCTIONS_2D | UC_BLITTING_FUNCTIONS_3D; + + device_info->caps.drawing = UC_DRAWING_FLAGS_2D | UC_DRAWING_FLAGS_3D; + device_info->caps.blitting = UC_BLITTING_FLAGS_2D | UC_BLITTING_FLAGS_3D; + + device_info->limits.surface_byteoffset_alignment = 32; + device_info->limits.surface_pixelpitch_alignment = 32; + + ucdev->pitch = 0; + ucdev->draw_rop2d = VIA_ROP_P; + ucdev->draw_rop3d = HC_HROP_P; + ucdev->color = 0; + ucdev->bflags = 0; + + ucdev->must_wait = 0; + ucdev->cmd_waitcycles = 0; + ucdev->idle_waitcycles = 0; + + uc_init_2d_engine(device, ucdev, ucdrv, false); // VQ disabled - can't make it work. + uc_init_3d_engine(ucdrv->hwregs, ucdrv->hwrev, 1); + + return DFB_OK; +} + +static void driver_close_device(CoreGraphicsDevice *device, + void *driver_data, void *device_data) +{ + UcDriverData* ucdrv = (UcDriverData*) driver_data; + UcDeviceData* ucdev = (UcDeviceData*) device_data; + + // uc_dump_vq(ucdev); + + uc_engine_sync(driver_data, device_data); + uc_init_2d_engine(device, ucdev, ucdrv, false); +} + +static void driver_close_driver(CoreGraphicsDevice* device, void* driver_data) +{ + UcDriverData* ucdrv = (UcDriverData*) driver_data; + + if (ucdrv->fifo) + uc_fifo_destroy( ucdrv->pool, ucdrv->fifo ); + + if (ucdrv->file != -1) + close( ucdrv->file ); +} -- cgit