
int CreatePixmap(pixmap_t *io)
{
    local_pixmap_t *pixmap;

    unsigned pitch;
    size_t size;

    addr_t  mem_local = 0;
    addr_t  mem_dma   = 0;
    void   *mapped;

    if( (io->width == 0) || (io->width > 2048)||
        (io->height == 0)|| (io->height > 2048))
    {
        dbgprintf("Invalid pixmap size w:%d h:%d\n", io->width,io->height);
        return ERR_PARAM;
    };

    pixmap = malloc(sizeof(local_pixmap_t));

    if(!pixmap)
        return ERR_PARAM;

    pitch = ((io->width+15)&~15)*4;
    size = pitch*io->height;

    dbgprintf("pitch = %d\n", pitch);

    if( (io->flags & PX_MEM_MASK) == PX_MEM_LOCAL ) {
        mem_local = rhd_mem_alloc(&rhd,RHD_MEM_FB,size);
        mem_dma = mem_local + rhd.fbLocation;
    }
    else
        mem_local = mem_dma = AllocPages( size >> 12 );

    if ( !mem_local) {
        dbgprintf("Not enough memory for pixmap\n");
        free(pixmap);
        return ERR_PARAM;
    };

    pixmap->pitch_offset = ((pitch/64)<<22)| (mem_dma>>10);
    pixmap->local   = mem_dma;

    size = (size+4095) & ~ 4095;

    if (mapped = UserAlloc(size))
    {
        CommitPages(mapped, mem_dma|7|(1<<9), size);

        io->mapped = mapped;
        io->pitch   = pitch;
        io->handle  = (u32_t)pixmap;

        pixmap->width   = io->width;
        pixmap->height  = io->height;
        pixmap->format  = PICT_a8r8g8b8;
        pixmap->flags   = io->flags;
        pixmap->pitch   = pitch;
        pixmap->mapped  = mapped;

        dbgprintf("pixmap.pitch_offset: %x\n", pixmap->pitch_offset);
        dbgprintf("width: %d height: %d\n",pixmap->width,pixmap->height );
        dbgprintf("map at %x\n", pixmap->mapped);

        return ERR_OK;
    };
    rhd_mem_free(&rhd, RHD_MEM_FB, mem_local);
    free(pixmap);

    return ERR_PARAM;
};


int DestroyPixmap( pixmap_t *io )
{
    local_pixmap_t *pixmap;
    size_t size;

    dbgprintf("Destroy pixmap %x\n", io->handle);

    if(io->handle == -1)
        return ERR_PARAM;
    else
        pixmap = (local_pixmap_t*)io->handle;

    size = (pixmap->pitch*pixmap->height+4095) & ~ 4095;

    UnmapPages(pixmap->mapped, size);
    UserFree(pixmap->mapped);

    if( (io->flags & PX_MEM_MASK) == PX_MEM_LOCAL )
    {
        rhd_mem_free(&rhd,RHD_MEM_FB,pixmap->local-rhd.fbLocation);
    }
    else
    {
        count_t pages = size >> 12;
        addr_t  base  = pixmap->local;

        while( pages--)
        {
            addr_t tmp;
 //           __asm__ __volatile__(
//            "call *__imp__PageFree"
//            :"=eax" (tmp):"a" (base) );
//            base+= 4096;
        };
    }

    free(pixmap);

    io->format  = 0;
    io->pitch   = 0;
    io->mapped  = NULL;
    io->handle  = 0;

    return ERR_OK;
};


# define ATI_PCIGART_PAGE_SIZE      4096    /**< PCI GART page size */
# define ATI_PCIGART_PAGE_MASK		(~(ATI_PCIGART_PAGE_SIZE-1))

#define ATI_PCIE_WRITE  0x4
#define ATI_PCIE_READ   0x8

#define upper_32_bits(n) ((u32_t)(((n) >> 16) >> 16))


static void bind_pcie(u32_t *gart, addr_t base, count_t pages)
{
    addr_t page_base;

    while(pages--)
    {
        page_base = base & ATI_PCIGART_PAGE_MASK;

        page_base >>= 8;
        page_base |= (upper_32_bits(base) & 0xff) << 24;
        page_base |= ATI_PCIE_READ | ATI_PCIE_WRITE;

        *gart = page_base;
        base+= 4096;
        gart++;
    }
    __asm__ __volatile("sfence":::"memory");

    RADEON_WRITE_PCIE(RADEON_PCIE_TX_GART_CNTL,
                      RADEON_PCIE_TX_GART_EN
                     | RADEON_PCIE_TX_GART_INVALIDATE_TLB);
}

static void bind_pci(u32_t *gart, addr_t base, count_t pages)
{
    u32_t tmp;

    tmp = INREG(RADEON_AIC_CNTL);
    OUTREG(RADEON_AIC_CNTL, tmp & ~RADEON_PCIGART_TRANSLATE_EN);

    while(pages--)
    {
        *gart = base & ATI_PCIGART_PAGE_MASK;
         base+= 4096;
         gart++;
    }
    __asm__ __volatile("sfence":::"memory");

    OUTREG(RADEON_AIC_CNTL, tmp | RADEON_PCIGART_TRANSLATE_EN);
    OUTREG(RADEON_AIC_PT_BASE, rhd.gart_table_dma);
}

static addr_t bind_pixmap(local_pixmap_t *pixmap)
{
    u32_t   *gart = rhd.gart_table;
    count_t  pages = ((pixmap->height * pixmap->pitch+4095)&~4095)>>12;
    addr_t   base = pixmap->local;

    if( rhd.gart_type == RADEON_IS_PCIE)
        bind_pcie(gart, base, pages);
    else
        bind_pci(gart, base, pages);

    return ((pixmap->pitch / 64) << 22) | (rhd.gart_vm_start >> 10);
}

#if 0

int LockPixmap(userpixmap_t *io)
{
   pixmap_t *pixmap;
   size_t    size;
   void     *usermap;

   dbgprintf("Lock pixmap %x\n", io->pixmap);

   if(io->pixmap == (pixmap_t*)-1)
     return ERR_PARAM;
   else
     pixmap = io->pixmap;

   if( (pixmap->flags & 1) == PX_LOCK )
     return ERR_PARAM;

   size = (pixmap->pitch*pixmap->width+4095) & ~ 4095;
   if (usermap = UserAlloc(size))
   {
     CommitPages(usermap, ((u32_t)pixmap->raw+rhd.PhisBase)|7|(1<<9), size);
     pixmap->flags |= PX_LOCK;
     pixmap->usermap = usermap;
     io->usermap = usermap;
     io->pitch   = pixmap->pitch;
     dbgprintf("map at %x\n", io->usermap);

     return ERR_OK;
   }
   else
     return ERR_PARAM;
};

int UnlockPixmap(userpixmap_t *io)
{
  pixmap_t *pixmap;
  size_t    size;

  dbgprintf("Unlock pixmap %x\n", io->pixmap);

  if(io->pixmap == (pixmap_t*)-1)
    return ERR_PARAM;
  else
    pixmap = io->pixmap;

  if( (pixmap->flags & 1) != PX_LOCK )
    return ERR_PARAM;

/*   Sanity checks  */

  if( (pixmap->usermap == 0)||
      ((u32_t)pixmap->usermap >= 0x80000000) ||
      ((u32_t)pixmap->usermap & 4095)
    )
    return ERR_PARAM;

  size = (pixmap->pitch*pixmap->width+4095) & ~ 4095;

  UnmapPages(pixmap->usermap, size);
  UserFree(pixmap->usermap);
  pixmap->usermap =  NULL;
  pixmap->flags  &= ~PX_LOCK;
  io->usermap     =  NULL;
  io->pitch       =  0;

  return ERR_OK;
};

#endif

