2 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
25 * Gareth Hughes <gareth@valinux.com>
29 /** @file ati_pcigart.c
30 * Implementation of ATI's PCIGART, which provides an aperture in card virtual
31 * address space with addresses remapped to system memory.
34 #include "dev/drm/drmP.h"
36 #define ATI_PCIGART_PAGE_SIZE 4096 /* PCI GART page size */
37 #define ATI_PCIGART_PAGE_MASK (~(ATI_PCIGART_PAGE_SIZE-1))
39 #define ATI_PCIE_WRITE 0x4
40 #define ATI_PCIE_READ 0x8
43 drm_ati_alloc_pcigart_table_cb(void *arg
, bus_dma_segment_t
*segs
,
46 struct drm_dma_handle
*dmah
= arg
;
52 ("drm_ati_alloc_pcigart_table_cb: bad dma segment count"));
54 dmah
->busaddr
= segs
[0].ds_addr
;
58 drm_ati_alloc_pcigart_table(struct drm_device
*dev
,
59 struct drm_ati_pcigart_info
*gart_info
)
61 struct drm_dma_handle
*dmah
;
64 dmah
= malloc(sizeof(struct drm_dma_handle
), DRM_MEM_DMA
,
70 ret
= bus_dma_tag_create(NULL
, PAGE_SIZE
, 0, /* tag, align, boundary */
71 gart_info
->table_mask
, BUS_SPACE_MAXADDR
, /* lowaddr, highaddr */
72 NULL
, NULL
, /* filtfunc, filtfuncargs */
73 gart_info
->table_size
, 1, /* maxsize, nsegs */
74 gart_info
->table_size
, /* maxsegsize */
78 free(dmah
, DRM_MEM_DMA
);
82 flags
= BUS_DMA_WAITOK
| BUS_DMA_ZERO
;
85 if (gart_info
->gart_reg_if
== DRM_ATI_GART_IGP
)
86 flags
|= BUS_DMA_NOCACHE
;
89 ret
= bus_dmamem_alloc(dmah
->tag
, &dmah
->vaddr
, flags
, &dmah
->map
);
91 bus_dma_tag_destroy(dmah
->tag
);
92 free(dmah
, DRM_MEM_DMA
);
97 ret
= bus_dmamap_load(dmah
->tag
, dmah
->map
, dmah
->vaddr
,
98 gart_info
->table_size
, drm_ati_alloc_pcigart_table_cb
, dmah
,
101 bus_dmamem_free(dmah
->tag
, dmah
->vaddr
, dmah
->map
);
102 bus_dma_tag_destroy(dmah
->tag
);
103 free(dmah
, DRM_MEM_DMA
);
107 gart_info
->dmah
= dmah
;
113 drm_ati_free_pcigart_table(struct drm_device
*dev
,
114 struct drm_ati_pcigart_info
*gart_info
)
116 struct drm_dma_handle
*dmah
= gart_info
->dmah
;
118 bus_dmamem_free(dmah
->tag
, dmah
->vaddr
, dmah
->map
);
119 bus_dma_tag_destroy(dmah
->tag
);
120 free(dmah
, DRM_MEM_DMA
);
121 gart_info
->dmah
= NULL
;
125 drm_ati_pcigart_cleanup(struct drm_device
*dev
,
126 struct drm_ati_pcigart_info
*gart_info
)
128 /* we need to support large memory configurations */
129 if (dev
->sg
== NULL
) {
130 DRM_ERROR("no scatter/gather memory!\n");
134 if (gart_info
->bus_addr
) {
135 if (gart_info
->gart_table_location
== DRM_ATI_GART_MAIN
) {
136 gart_info
->bus_addr
= 0;
138 drm_ati_free_pcigart_table(dev
, gart_info
);
146 drm_ati_pcigart_init(struct drm_device
*dev
,
147 struct drm_ati_pcigart_info
*gart_info
)
149 void *address
= NULL
;
151 u32
*pci_gart
, page_base
;
152 dma_addr_t bus_address
= 0;
153 dma_addr_t entry_addr
;
157 /* we need to support large memory configurations */
158 if (dev
->sg
== NULL
) {
159 DRM_ERROR("no scatter/gather memory!\n");
163 if (gart_info
->gart_table_location
== DRM_ATI_GART_MAIN
) {
164 DRM_DEBUG("PCI: no table in VRAM: using normal RAM\n");
166 ret
= drm_ati_alloc_pcigart_table(dev
, gart_info
);
168 DRM_ERROR("cannot allocate PCI GART page!\n");
172 address
= (void *)gart_info
->dmah
->vaddr
;
173 bus_address
= gart_info
->dmah
->busaddr
;
175 address
= gart_info
->addr
;
176 bus_address
= gart_info
->bus_addr
;
177 DRM_DEBUG("PCI: Gart Table: VRAM %08X mapped at %08lX\n",
178 (unsigned int)bus_address
, (unsigned long)address
);
181 pci_gart
= (u32
*) address
;
183 max_pages
= (gart_info
->table_size
/ sizeof(u32
));
184 pages
= (dev
->sg
->pages
<= max_pages
)
185 ? dev
->sg
->pages
: max_pages
;
187 memset(pci_gart
, 0, max_pages
* sizeof(u32
));
189 KASSERT(PAGE_SIZE
>= ATI_PCIGART_PAGE_SIZE
, ("page size too small"));
191 for (i
= 0; i
< pages
; i
++) {
192 entry_addr
= dev
->sg
->busaddr
[i
];
193 for (j
= 0; j
< (PAGE_SIZE
/ ATI_PCIGART_PAGE_SIZE
); j
++) {
194 page_base
= (u32
) entry_addr
& ATI_PCIGART_PAGE_MASK
;
195 switch(gart_info
->gart_reg_if
) {
196 case DRM_ATI_GART_IGP
:
198 (upper_32_bits(entry_addr
) & 0xff) << 4;
201 case DRM_ATI_GART_PCIE
:
204 (upper_32_bits(entry_addr
) & 0xff) << 24;
205 page_base
|= ATI_PCIE_READ
| ATI_PCIE_WRITE
;
208 case DRM_ATI_GART_PCI
:
211 *pci_gart
= cpu_to_le32(page_base
);
213 entry_addr
+= ATI_PCIGART_PAGE_SIZE
;
220 gart_info
->addr
= address
;
221 gart_info
->bus_addr
= bus_address
;