Hi,

I would like to have the gfxdriver driver I'm writing for the i810/i815
chipset reviewed.  Since there's no official i810 framebuffer driver yet
included in the kernel, I had to write an i810 framebuffer driver as
well. Using a generic gfxdriver in software fallback mode and the i810fb
driver, all the examples, gtk-demo and DFPoint work okay.

Overview:

The i810 does not have it's own memory, so it has to have a collection
of  system RAM pages mapped via agpgart into linear space. Also, the
i810 cannot be programmed via MMIO and if the acceleration engine is to
be used, instructions has to be passed via DMA. The DMA buffer (or
ringbuffer in Intel parlance) is not built in to the chipset, but has to
be similarly mapped to the framebuffer memory via agpgart.

The safest way way I can think of doing this is to have the i810fb
driver provide an interface where clients can request for resources (DMA
buffer, GART memory, etc), and have them mmapped to userland.  To
instruct the engine, a client can pass instructions via the user DMA
buffer, tell the fbdriver that the instructions are ready, at which
point, the fb driver will verify the instructions for correctness before
handling them to the hardware. For now, I'm using the ioctl interface
for communication.

The gfxdriver I have written has accelerated Blit, Blit with
colorkeying, Fill rectangles and Draw rectangles.  Except for df_neo,
(which locks up the accel engine), all examples, gtk-demo and DFBPoint
work. The performance increase cannot be said to be blistering though :)

Anyway, here's the main file.  The complete source for i810fb driver
(i810fb-0.0.14-agpgart) and the gfxdriver patch
(DFB-0.9.8-i810fb-0.0.14) is in
http://www.sourceforge.net/projects.i810fb.

I would appreciate any feedback and I'm receptive for any kind of
assistance, especially pertaining to the coding.

My apologies to all for the long e-mail

Tony

---------Start i810.c------------------------------------------------

/* 
   (c) Copyright 2000  convergence integrated media GmbH.
   All rights reserved.

   Written by Antonino Daplas <[EMAIL PROTECTED]>

   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.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, write to the
   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.
*/
#include <asm/types.h>

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

#include <sys/mman.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <malloc.h>

#include <directfb.h>

#include <core/coredefs.h>
#include <core/coretypes.h>

#include <core/state.h>
#include <core/gfxcard.h>
#include <core/surfaces.h>

/* need fb handle to get accel, MMIO programming in the i810 is useless
*/
#include<core/fbdev.h>
#include <gfx/convert.h>
#include <gfx/util.h>
#include <misc/conf.h>

#include "i810.h"

#define MMIO_SIZE 512 * 1024

#define I810_SUPPORTED_DRAWINGFLAGS \
               (DSDRAW_NOFX)

#define I810_SUPPORTED_DRAWINGFUNCTIONS \
               (DFXL_DRAWRECTANGLE | DFXL_FILLRECTANGLE)

#define I810_SUPPORTED_BLITTINGFLAGS \
               (DSBLIT_SRC_COLORKEY | DSBLIT_DST_COLORKEY)

#define I810_SUPPORTED_BLITTINGFUNCTIONS \
               (DFXL_BLIT)


typedef struct {
        int srcaddr, destaddr, srcpitch, destpitch;
        int color_value, pixeldepth, blit_color;
        int colorkey_bit, colorkey;
} I810DeviceData;

typedef struct {
        int user_key;
        volatile __u8 *mmio_base;
        agp_mem_user dma; 
        agp_mem_user pattern;
        u32 *dma_buffer;
        u32 *pattern_buffer;
        i810_command cmd;
} I810DriverData;

/*
 * MMIO access functions 
 */

static inline volatile u8 i810_readb(volatile __u8 *mmio_base, u32
where)
{
        return  *((volatile u8 *) (mmio_base + where));
}

static inline volatile u16 i810_readw(volatile __u8 *mmio_base, u32
where)
{
       return  *((volatile u16 *) (mmio_base + where));

}

static inline volatile u32 i810_readl(volatile __u8 *mmio_base, u32
where)
{
       return  *((volatile u32 *) (mmio_base + where));
}

static inline void i810_writeb(volatile __u8 *mmio_base, u32 where,
volatile u8 val)
{
        *((volatile u8 *) (mmio_base + where)) = val;
}

static inline void i810_writew(volatile __u8 *mmio_base, u32 where,
volatile u16 val)
{
        *((volatile u16 *) (mmio_base + where)) = val;
}

static inline void i810_writel(volatile __u8 *mmio_base, u32 where,
volatile u32 val)
{
        *((volatile u32 *) (mmio_base + where)) = val;
}

static void i810FlushTextureCache(void *drv, void *dev)
{
        I810DriverData *i810drv = (I810DriverData *) drv;

        i810drv->cmd.command = EMIT_DMA;
        i810drv->cmd.dma_cmd_start = 0;
        i810drv->cmd.dma_cmd_dsize = 1;
        i810drv->dma_buffer[0] = PARSER | FLUSH;
        if (ioctl(fbdev->fd, I810FB_IOC_COMMAND, &i810drv->cmd))
                DEBUGMSG("flush error");
}

static void i810EngineSync(void *drv, void *dev)
{
        I810DriverData *i810drv = (I810DriverData *) drv;
        int count = 0;

        while (i810_readw(i810drv->mmio_base, BLTCNTL) & 1 && count++ <=
20000);
        if (count >= 20000)
                DEBUGMSG("blit engine lockup");
}

/*
 * Set State routines 
 */
static void i810_set_source(I810DriverData *i810drv,
                            I810DeviceData *i810dev,
                            CardState      *state)
{
        CoreSurface   *source = state->source;
        SurfaceBuffer *buffer      = source->front_buffer;

        i810dev->srcaddr = gfxcard_memory_physical(buffer->video.offset);
        i810dev->srcpitch = buffer->video.pitch;
}

static void i810_set_destination(I810DriverData *i810drv,
                                 I810DeviceData *i810dev,
                                 CardState      *state)
{
        CoreSurface   *destination = state->destination;
        SurfaceBuffer *buffer      = destination->back_buffer;
        
        i810dev->destaddr = gfxcard_memory_physical(buffer->video.offset);
        i810dev->destpitch = buffer->video.pitch;
        
}
                                         
static void i810_set_colorkey(I810DriverData *i810drv,
                           I810DeviceData *i810dev,
                           CardState      *state)
{
        if (state->blittingflags & DSBLIT_SRC_COLORKEY) {
                i810dev->colorkey_bit = 1 << 8;
                i810dev->colorkey = state->src_colorkey;
        }
        else {
                i810dev->colorkey_bit = 7 << 8;
                i810dev->colorkey = state->dst_colorkey;
        }

}

static void i810_set_color(I810DriverData *i810drv,
                           I810DeviceData *i810dev,
                           CardState      *state)
{
        switch (state->destination->format) {
        case DSPF_RGB15:
                i810dev->color_value = PIXEL_RGB15(state->color.r,
                                                   state->color.g,
                                                   state->color.b);
                i810dev->pixeldepth = 2;
                i810dev->blit_color = BPP16;
                break;
        case DSPF_RGB16:
                i810dev->color_value = PIXEL_RGB16(state->color.r,
                                                   state->color.g,
                                                   state->color.b);
                i810dev->pixeldepth = 2;
                i810dev->blit_color = BPP16;
                break;
        case DSPF_RGB24:
                i810dev->color_value = PIXEL_RGB24(state->color.r,
                                                   state->color.g,
                                                   state->color.b);
                i810dev->pixeldepth = 3;
                i810dev->blit_color = BPP24;
                break;
        default:
                BUG("unexpected pixelformat~");
        }

}

static void i810CheckState(void *drv, void *dev,
                            CardState *state, DFBAccelerationMask accel
)
{
        switch (state->destination->format) {
        case DSPF_RGB15:
        case DSPF_RGB16:
        case DSPF_RGB24:
                break;
        default:
                return;
        }

        if (!(accel & ~I810_SUPPORTED_DRAWINGFUNCTIONS) &&
            !(state->drawingflags & ~I810_SUPPORTED_DRAWINGFLAGS))
                state->accel |= I810_SUPPORTED_DRAWINGFUNCTIONS;

        if (!(accel & ~I810_SUPPORTED_BLITTINGFUNCTIONS) &&
            !(state->blittingflags & ~I810_SUPPORTED_BLITTINGFLAGS)) {
                switch (state->source->format) {
                case DSPF_RGB15:
                case DSPF_RGB16:
                case DSPF_RGB24:
                        state->accel |= I810_SUPPORTED_BLITTINGFUNCTIONS;
                default:
                }
        }
}

static void i810SetState( void *drv, void *dev,
                          GraphicsDeviceFuncs *funcs,
                          CardState *state, DFBAccelerationMask accel )
{
        I810DriverData *i810drv = (I810DriverData *) drv;
        I810DeviceData *i810dev = (I810DeviceData *) dev;

        if (state->modified) {
                if ((state->modified & SMF_SOURCE) && state->source)
                        i810_set_source( i810drv, i810dev, state);
                if (state->modified & SMF_DESTINATION)
                        i810_set_destination(i810drv, i810dev, state);
                if (state->modified & SMF_COLOR)
                        i810_set_color(i810drv, i810dev, state);
                if (state->modified & SMF_BLITTING_FLAGS) {
                        i810dev->colorkey_bit = 0;
                        if (state->blittingflags & (DSBLIT_SRC_COLORKEY |
DSBLIT_DST_COLORKEY))  
                                i810_set_colorkey(i810drv, i810dev, state);
                }
        }
}

static void i810FillRectangle( void *drv, void *dev, DFBRectangle *rect
)
{
        I810DriverData *i810drv = (I810DriverData *) drv;
        I810DeviceData *i810dev = (I810DeviceData *) dev;
        int dest;
        
        rect->x *= i810dev->pixeldepth;
        rect->w *= i810dev->pixeldepth;
        dest = i810dev->destaddr + rect->x + (rect->y * i810dev->destpitch);

        i810drv->dma_buffer[0] = BLIT | COLOR_BLT | 3;
        i810drv->dma_buffer[1] = COLOR_COPY_ROP << 16 | i810dev->destpitch |
SOLIDPATTERN;
        i810drv->dma_buffer[2] = rect->h << 16 | rect->w;
        i810drv->dma_buffer[3] = dest;
        i810drv->dma_buffer[4] = i810dev->color_value;

        i810drv->cmd.dma_cmd_start = 0;
        i810drv->cmd.dma_cmd_dsize = 5;
        i810drv->cmd.command = EMIT_DMA;
        if (ioctl(fbdev->fd, I810FB_IOC_COMMAND, &i810drv->cmd))
                DEBUGMSG("fill rectangle error");
}

static void i810DrawRectangle( void *drv, void *dev, DFBRectangle *rect
)
{
        I810DriverData *i810drv = (I810DriverData *) drv;
        I810DeviceData *i810dev = (I810DeviceData *) dev;
        u32 dest;

        rect->x *= i810dev->pixeldepth;
        rect->w *= i810dev->pixeldepth;

        /* horizontal line 1 */
        dest = i810dev->destaddr + rect->x + (rect->y * i810dev->destpitch);
        i810drv->dma_buffer[0] = BLIT | COLOR_BLT | 3;
        i810drv->dma_buffer[1] = COLOR_COPY_ROP << 16 | i810dev->destpitch |
SOLIDPATTERN;
        i810drv->dma_buffer[2] = 1 << 16 | rect->w;
        i810drv->dma_buffer[3] = dest;
        i810drv->dma_buffer[4] = i810dev->color_value;

        /* vertical line 2 */
        dest += rect->w;
        i810drv->dma_buffer[5] = BLIT | COLOR_BLT | 3;
        i810drv->dma_buffer[6] = COLOR_COPY_ROP << 16 | i810dev->destpitch |
SOLIDPATTERN;
        i810drv->dma_buffer[7] = rect->h << 16 | i810dev->pixeldepth;
        i810drv->dma_buffer[8] = dest;
        i810drv->dma_buffer[9] = i810dev->color_value;

        /* vertical line 1 */
        dest -= rect->w;
        i810drv->dma_buffer[10] = BLIT | COLOR_BLT | 3;
        i810drv->dma_buffer[11] = COLOR_COPY_ROP << 16 | i810dev->destpitch |
SOLIDPATTERN;
        i810drv->dma_buffer[12] = rect->h << 16 | i810dev->pixeldepth;
        i810drv->dma_buffer[13] = dest;
        i810drv->dma_buffer[14] = i810dev->color_value;
        
        /* horizontal line 2 */
        dest += rect->h * i810dev->destpitch;
        i810drv->dma_buffer[15] = BLIT | COLOR_BLT | 3;
        i810drv->dma_buffer[16] = COLOR_COPY_ROP << 16 | i810dev->destpitch |
SOLIDPATTERN;
        i810drv->dma_buffer[17] = 1 << 16 | rect->w;
        i810drv->dma_buffer[18] = dest;
        i810drv->dma_buffer[19] = i810dev->color_value;
        
        i810drv->cmd.dma_cmd_start = 0;
        i810drv->cmd.dma_cmd_dsize = 20;
        i810drv->cmd.command = EMIT_DMA;
        if (ioctl(fbdev->fd, I810FB_IOC_COMMAND, &i810drv->cmd))
                DEBUGMSG("draw rectangle error");
}

static void i810Blit( void *drv, void *dev, DFBRectangle *rect, int dx,
int dy )
{
        I810DriverData *i810drv = (I810DriverData *) drv;
        I810DeviceData *i810dev = (I810DeviceData *) dev;
        int xdir = INCREMENT, spitch = 0, dpitch = 0, src, dest;

        rect->x *= i810dev->pixeldepth;
        dx *= i810dev->pixeldepth;
        rect->w *= i810dev->pixeldepth;

        src = i810dev->srcaddr + rect->x + (rect->y * i810dev->srcpitch);
        dest = i810dev->destaddr + dx + (dy * i810dev->destpitch);

        if (i810dev->srcaddr == i810dev->destaddr) {
                spitch = i810dev->srcpitch;
                dpitch = i810dev->destpitch;
                if (dx > rect->x && dx < rect->x + rect->w) {
                        xdir = DECREMENT;
                        rect->x += rect->w - 1;
                        dx += rect->w - 1;
                }
                if (dy > rect->y && dy < rect->y + rect->h) {
                        i810dev->srcpitch = (-(i810dev->srcpitch)) & 0xFFFF;
                        i810dev->destpitch = (-(i810dev->destpitch)) & 0xFFFF;
                        rect->y += rect->h - 1;
                        dy += rect->h - 1;
                }
                src = i810dev->srcaddr + rect->x + (rect->y * spitch);
                dest = i810dev->destaddr + dx + (dy * dpitch);
        }

        i810drv->dma_buffer[0] = BLIT | FULL_BLIT | 0x6 |
i810dev->colorkey_bit;
        i810drv->dma_buffer[1] = xdir | PAT_COPY_ROP << 16 | i810dev->destpitch
| DYN_COLOR_EN | i810dev->blit_color;
        i810drv->dma_buffer[2] = (rect->h << 16) | rect->w;
        i810drv->dma_buffer[3] = dest;
        i810drv->dma_buffer[4] = i810dev->srcpitch;
        i810drv->dma_buffer[5] = src;
        i810drv->dma_buffer[6] = i810dev->colorkey;
        i810drv->dma_buffer[7] = i810drv->pattern.offset << 12;

        i810drv->cmd.dma_cmd_start = 0;
        i810drv->cmd.dma_cmd_dsize = 8;
        i810drv->cmd.command = EMIT_DMA;

        if (ioctl(fbdev->fd, I810FB_IOC_COMMAND, &i810drv->cmd))
                DEBUGMSG("blit error");
}


int
driver_get_abi_version()
{
     return DFB_GRAPHICS_DRIVER_ABI_VERSION;
}

int
driver_probe( GraphicsDevice *device )
{
#ifdef FB_ACCEL_I810
     switch (gfxcard_get_accelerator( device )) {
          case FB_ACCEL_I810:          /* Intel 810 */
                  if (!ioctl(fbdev->fd, I810FB_IOC_AREYOUTHERE, 0))
                          return 1;
     }
#endif
     return 0;
}


void
driver_get_info( GraphicsDevice     *device,
                 GraphicsDriverInfo *info )
{
     /* fill driver info structure */
     snprintf( info->name,
               DFB_GRAPHICS_DRIVER_INFO_NAME_LENGTH,
               "Intel 810/810E/810-DC100/815 Driver" );

     snprintf( info->vendor,
               DFB_GRAPHICS_DRIVER_INFO_VENDOR_LENGTH,
               "convergence integrated media GmbH" );

     info->version.major = 0;
     info->version.minor = 1;

     info->driver_data_size = sizeof (I810DriverData);
     info->device_data_size = sizeof (I810DeviceData);
}

DFBResult
driver_init_driver( GraphicsDevice      *device,
                    GraphicsDeviceFuncs *funcs,
                    void                *driver_data )
{
     I810DriverData *i810drv = (I810DriverData *) driver_data;

     i810drv->mmio_base = (volatile __u8*) gfxcard_map_mmio( device, 0,
-1 );
     if (!i810drv->mmio_base)
          return DFB_IO;

     /* Acquire the framebuffer */
     if (ioctl(fbdev->fd, I810FB_IOC_ACQUIREFB, &i810drv->user_key))
             return DFB_IO;

     i810drv->cmd.user_key = i810drv->user_key;
     i810drv->dma.user_key = i810drv->user_key;

     /* request for a DMA buffer */
     i810drv->dma.type = AGP_DMA;
     if (ioctl(fbdev->fd, I810FB_IOC_REQUESTAGPMEM, &i810drv->dma)) {
             i810drv->cmd.command = RELEASE_FB;
             ioctl(fbdev->fd, I810FB_IOC_COMMAND, &i810drv->cmd);
             return DFB_IO;
     }
     i810drv->cmd.surface_key = i810drv->dma.surface_key;
     
     /* mmap the DMA buffer */
     i810drv->dma_buffer = (u32 *) mmap(NULL, i810drv->dma.pgsize << 12,
                                        PROT_READ | PROT_WRITE,
                                        MAP_SHARED, fbdev->fd, 
                                        gfxcard_memory_length() + MMIO_SIZE +
                                        (i810drv->dma.offset << 12));
     
     if ((long) i810drv->dma_buffer == -1L) {
             i810drv->cmd.command = RELEASE_FB;
             ioctl(fbdev->fd, I810FB_IOC_COMMAND, &i810drv->cmd);
             return DFB_IO;
     }
             
     /* make requested DMA buffer current */
     i810drv->cmd.command = UPDATE_DMA;
     if (ioctl(fbdev->fd, I810FB_IOC_COMMAND, &i810drv->cmd)) {
             i810drv->cmd.command = RELEASE_FB;
             ioctl(fbdev->fd, I810FB_IOC_COMMAND, &i810drv->cmd);
             return DFB_IO;
     }

     /* request for a pattern buffer  - may need this as the third
operand for some BLIT operations */
     i810drv->pattern.type = AGP_SURFACE;
     i810drv->pattern.pgsize = 1;
     if (ioctl(fbdev->fd, I810FB_IOC_REQUESTAGPMEM, &i810drv->pattern))
{
             i810drv->cmd.command = RELEASE_FB;
             ioctl(fbdev->fd, I810FB_IOC_COMMAND, &i810drv->cmd);
             return DFB_IO;
     }

     /* mmap the pattern buffer */
     i810drv->pattern_buffer = (u32 *) mmap(NULL,
i810drv->pattern.pgsize << 12, 
                                            PROT_READ | PROT_WRITE,
                                            MAP_SHARED, fbdev->fd, 
                                            gfxcard_memory_length() + MMIO_SIZE +
                                            (i810drv->pattern.offset << 12));
     
     if ((long) i810drv->pattern_buffer == -1L) {
             i810drv->cmd.command = RELEASE_FB;
             ioctl(fbdev->fd, I810FB_IOC_COMMAND, &i810drv->cmd);
             return DFB_IO;
     }
     memset((void *) i810drv->pattern_buffer, 0xFF,
i810drv->pattern.pgsize << 12); 
     

     funcs->CheckState         = i810CheckState;
     funcs->SetState           = i810SetState;
     funcs->FlushTextureCache  = i810FlushTextureCache;
     funcs->DrawRectangle      = i810DrawRectangle;
     funcs->FillRectangle      = i810FillRectangle;
     funcs->Blit               = i810Blit;
     funcs->EngineSync         = i810EngineSync;
     return DFB_OK;
}

DFBResult
driver_init_device( GraphicsDevice     *device,
                    GraphicsDeviceInfo *device_info,
                    void               *driver_data,
                    void               *device_data )
{

     /* fill device info */
     snprintf( device_info->name,
               DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH,
"810/810E/810-DC100/815" );

     snprintf( device_info->vendor,
               DFB_GRAPHICS_DEVICE_INFO_VENDOR_LENGTH, "Intel" );

     device_info->caps.flags    = CCF_CLIPPING;
     device_info->caps.accel    = I810_SUPPORTED_DRAWINGFUNCTIONS |
                                  I810_SUPPORTED_BLITTINGFUNCTIONS;
     device_info->caps.drawing  = I810_SUPPORTED_DRAWINGFLAGS;
     device_info->caps.blitting = I810_SUPPORTED_BLITTINGFLAGS;

     device_info->limits.surface_byteoffset_alignment = 32 * 4;
     device_info->limits.surface_pixelpitch_alignment = 32;

     return DFB_OK;
}

void
driver_init_layers()
{
}

void
driver_close_device( GraphicsDevice *device,
                     void           *driver_data,
                     void           *device_data )
{
        I810DeviceData *i810dev = (I810DeviceData *) device_data;
        I810DriverData *i810drv = (I810DriverData *) driver_data;

        (void) i810dev;
        (void) i810drv;

        /* Cannot accurately determine performance, so I'll leave it out */
}

void
driver_close_driver( GraphicsDevice *device,
                     void           *driver_data )
{
        I810DriverData *i810drv = (I810DriverData *) driver_data;

        /* unmap all requested buffers */
        munmap(i810drv->pattern_buffer, i810drv->pattern.pgsize << 12);
        munmap(i810drv->dma_buffer, i810drv->dma.pgsize << 12);

        /* release fb which automatically releases all acquired resources */
        i810drv->cmd.command = RELEASE_FB;
        ioctl(fbdev->fd, I810FB_IOC_COMMAND, &i810drv->cmd);

        /* unmap mmio */
        gfxcard_unmap_mmio( device, i810drv->mmio_base, -1);
}






-- 
Info:  To unsubscribe send a mail to [EMAIL PROTECTED] with 
"unsubscribe directfb-dev" as subject.

Reply via email to