1 /*
   2  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
   3  * Use is subject to license terms.
   4  */
   5 /*
   6  * ati_pcigart.h -- ATI PCI GART support -*- linux-c -*-
   7  * Created: Wed Dec 13 21:52:19 2000 by gareth@valinux.com
   8  */
   9 /*
  10  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
  11  * All Rights Reserved.
  12  *
  13  * Permission is hereby granted, free of charge, to any person obtaining a
  14  * copy of this software and associated documentation files (the "Software"),
  15  * to deal in the Software without restriction, including without limitation
  16  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  17  * and/or sell copies of the Software, and to permit persons to whom the
  18  * Software is furnished to do so, subject to the following conditions:
  19  *
  20  * The above copyright notice and this permission notice (including the next
  21  * paragraph) shall be included in all copies or substantial portions of the
  22  * Software.
  23  *
  24  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  25  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  26  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  27  * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  28  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  29  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  30  * DEALINGS IN THE SOFTWARE.
  31  *
  32  * Authors:
  33  *   Gareth Hughes <gareth@valinux.com>
  34  *
  35  */
  36 
  37 #include "drmP.h"
  38 
  39 #define ATI_PCIGART_PAGE_SIZE           4096    /* PCI GART page size */
  40 #define ATI_MAX_PCIGART_PAGES           8192    /* 32 MB aperture, 4K pages */
  41 #define ATI_PCIGART_TABLE_SIZE          32768
  42 
  43 int
  44 drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
  45 {
  46         unsigned long pages;
  47         drm_sg_mem_t *entry;
  48         drm_dma_handle_t *dmah;
  49         u32 *pci_gart = NULL, page_base;
  50         int i, j, k;
  51         int     pagenum;
  52         size_t  bulksize;
  53 
  54         entry = dev->sg;
  55         if (entry == NULL) {
  56                 DRM_ERROR("no scatter/gather memory!\n");
  57                 return (0);
  58         }
  59 
  60         if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) {
  61                 /* GART table in system memory */
  62                 entry->dmah_gart = drm_pci_alloc(dev, ATI_PCIGART_TABLE_SIZE, 0,
  63                     0xfffffffful, 1);
  64                 if (entry->dmah_gart == NULL) {
  65                         DRM_ERROR("cannot allocate PCI GART table!\n");
  66                         return (0);
  67                 }
  68                 gart_info->addr = (void *)entry->dmah_gart->vaddr;
  69                 gart_info->bus_addr = entry->dmah_gart->paddr;
  70                 pci_gart = (u32 *)entry->dmah_gart->vaddr;
  71         } else {
  72                 /* GART table in framebuffer memory */
  73                 pci_gart = gart_info->addr;
  74         }
  75 
  76         pages = DRM_MIN(entry->pages, ATI_MAX_PCIGART_PAGES);
  77         bzero(pci_gart, ATI_PCIGART_TABLE_SIZE);
  78         /*CONSTCOND*/
  79         ASSERT(PAGE_SIZE >= ATI_PCIGART_PAGE_SIZE);
  80 
  81         dmah = entry->dmah_sg;
  82         pagenum = 0;
  83         for (i = 0; i < dmah->cookie_num; i++) {
  84                 bulksize = dmah->cookie.dmac_size;
  85                 for (k = 0; k < bulksize / PAGE_SIZE; k++) {
  86                         entry->busaddr[pagenum] =
  87                             dmah->cookie.dmac_address + k * PAGE_SIZE;
  88                         page_base =  (u32) entry->busaddr[pagenum];
  89                         if (pagenum ++ == pages)
  90                                 goto out;
  91                         for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE);
  92                             j++) {
  93                                 if (gart_info->is_pcie)
  94                                         *pci_gart = (page_base >> 8) | 0xc;
  95                                 else
  96                                         *pci_gart = page_base;
  97                                 pci_gart++;
  98                                 page_base += ATI_PCIGART_PAGE_SIZE;
  99                         }
 100                 }
 101                 ddi_dma_nextcookie(dmah->dma_hdl, &dmah->cookie);
 102         }
 103 
 104 out:
 105         if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) {
 106                 (void) ddi_dma_sync(entry->dmah_gart->dma_hdl, 0,
 107                     entry->dmah_gart->real_sz, DDI_DMA_SYNC_FORDEV);
 108         }
 109 
 110         return (1);
 111 }
 112 
 113 /*ARGSUSED*/
 114 extern int
 115 drm_ati_pcigart_cleanup(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
 116 {
 117         drm_dma_handle_t        *dmah;
 118 
 119         if (dev->sg == NULL) {
 120                 DRM_ERROR("no scatter/gather memory!\n");
 121                 return (0);
 122         }
 123         dmah = dev->sg->dmah_gart;
 124         dev->sg->dmah_gart = NULL;
 125         if (dmah)
 126                 drm_pci_free(dev, dmah);
 127         return (1);
 128 }