aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/radeon/rs400.c
diff options
context:
space:
mode:
authorJerome Glisse <jglisse@redhat.com>2009-06-05 08:42:42 -0400
committerDave Airlie <airlied@redhat.com>2009-06-14 22:01:53 -0400
commit771fe6b912fca54f03e8a72eb63058b582775362 (patch)
tree58aa5469ba8058c2b564d50807395ad6cd7bd7e4 /drivers/gpu/drm/radeon/rs400.c
parentba4e7d973dd09b66912ac4c0856add8b0703a997 (diff)
drm/radeon: introduce kernel modesetting for radeon hardware
Add kernel modesetting support to radeon driver, use the ttm memory manager to manage memory and DRM/GEM to provide userspace API. In order to avoid backward compatibility issue and to allow clean design and code the radeon kernel modesetting use different code path than old radeon/drm driver. When kernel modesetting is enabled the IOCTL of radeon/drm driver are considered as invalid and an error message is printed in the log and they return failure. KMS enabled userspace will use new API to talk with the radeon/drm driver. The new API provide functions to create/destroy/share/mmap buffer object which are then managed by the kernel memory manager (here TTM). In order to submit command to the GPU the userspace provide a buffer holding the command stream, along this buffer userspace have to provide a list of buffer object used by the command stream. The kernel radeon driver will then place buffer in GPU accessible memory and will update command stream to reflect the position of the different buffers. The kernel will also perform security check on command stream provided by the user, we want to catch and forbid any illegal use of the GPU such as DMA into random system memory or into memory not owned by the process supplying the command stream. This part of the code is still incomplete and this why we propose that patch as a staging driver addition, future security might forbid current experimental userspace to run. This code support the following hardware : R1XX,R2XX,R3XX,R4XX,R5XX (radeon up to X1950). Works is underway to provide support for R6XX, R7XX and newer hardware (radeon from HD2XXX to HD4XXX). Authors: Jerome Glisse <jglisse@redhat.com> Dave Airlie <airlied@redhat.com> Alex Deucher <alexdeucher@gmail.com> Signed-off-by: Jerome Glisse <jglisse@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com> Signed-off-by: Alex Deucher <alexdeucher@gmail.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/radeon/rs400.c')
-rw-r--r--drivers/gpu/drm/radeon/rs400.c411
1 files changed, 411 insertions, 0 deletions
diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c
new file mode 100644
index 000000000000..cc074b5a8f74
--- /dev/null
+++ b/drivers/gpu/drm/radeon/rs400.c
@@ -0,0 +1,411 @@
1/*
2 * Copyright 2008 Advanced Micro Devices, Inc.
3 * Copyright 2008 Red Hat Inc.
4 * Copyright 2009 Jerome Glisse.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
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 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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
22 * OTHER DEALINGS IN THE SOFTWARE.
23 *
24 * Authors: Dave Airlie
25 * Alex Deucher
26 * Jerome Glisse
27 */
28#include <linux/seq_file.h>
29#include <drm/drmP.h>
30#include "radeon_reg.h"
31#include "radeon.h"
32
33/* rs400,rs480 depends on : */
34void r100_hdp_reset(struct radeon_device *rdev);
35void r100_mc_disable_clients(struct radeon_device *rdev);
36int r300_mc_wait_for_idle(struct radeon_device *rdev);
37void r420_pipes_init(struct radeon_device *rdev);
38
39/* This files gather functions specifics to :
40 * rs400,rs480
41 *
42 * Some of these functions might be used by newer ASICs.
43 */
44void rs400_gpu_init(struct radeon_device *rdev);
45int rs400_debugfs_pcie_gart_info_init(struct radeon_device *rdev);
46
47
48/*
49 * GART functions.
50 */
51void rs400_gart_adjust_size(struct radeon_device *rdev)
52{
53 /* Check gart size */
54 switch (rdev->mc.gtt_size/(1024*1024)) {
55 case 32:
56 case 64:
57 case 128:
58 case 256:
59 case 512:
60 case 1024:
61 case 2048:
62 break;
63 default:
64 DRM_ERROR("Unable to use IGP GART size %uM\n",
65 rdev->mc.gtt_size >> 20);
66 DRM_ERROR("Valid GART size for IGP are 32M,64M,128M,256M,512M,1G,2G\n");
67 DRM_ERROR("Forcing to 32M GART size\n");
68 rdev->mc.gtt_size = 32 * 1024 * 1024;
69 return;
70 }
71 if (rdev->family == CHIP_RS400 || rdev->family == CHIP_RS480) {
72 /* FIXME: RS400 & RS480 seems to have issue with GART size
73 * if 4G of system memory (needs more testing) */
74 rdev->mc.gtt_size = 32 * 1024 * 1024;
75 DRM_ERROR("Forcing to 32M GART size (because of ASIC bug ?)\n");
76 }
77}
78
79void rs400_gart_tlb_flush(struct radeon_device *rdev)
80{
81 uint32_t tmp;
82 unsigned int timeout = rdev->usec_timeout;
83
84 WREG32_MC(RS480_GART_CACHE_CNTRL, RS480_GART_CACHE_INVALIDATE);
85 do {
86 tmp = RREG32_MC(RS480_GART_CACHE_CNTRL);
87 if ((tmp & RS480_GART_CACHE_INVALIDATE) == 0)
88 break;
89 DRM_UDELAY(1);
90 timeout--;
91 } while (timeout > 0);
92 WREG32_MC(RS480_GART_CACHE_CNTRL, 0);
93}
94
95int rs400_gart_enable(struct radeon_device *rdev)
96{
97 uint32_t size_reg;
98 uint32_t tmp;
99 int r;
100
101 /* Initialize common gart structure */
102 r = radeon_gart_init(rdev);
103 if (r) {
104 return r;
105 }
106 if (rs400_debugfs_pcie_gart_info_init(rdev)) {
107 DRM_ERROR("Failed to register debugfs file for RS400 GART !\n");
108 }
109
110 tmp = RREG32_MC(RS690_AIC_CTRL_SCRATCH);
111 tmp |= RS690_DIS_OUT_OF_PCI_GART_ACCESS;
112 WREG32_MC(RS690_AIC_CTRL_SCRATCH, tmp);
113 /* Check gart size */
114 switch(rdev->mc.gtt_size / (1024 * 1024)) {
115 case 32:
116 size_reg = RS480_VA_SIZE_32MB;
117 break;
118 case 64:
119 size_reg = RS480_VA_SIZE_64MB;
120 break;
121 case 128:
122 size_reg = RS480_VA_SIZE_128MB;
123 break;
124 case 256:
125 size_reg = RS480_VA_SIZE_256MB;
126 break;
127 case 512:
128 size_reg = RS480_VA_SIZE_512MB;
129 break;
130 case 1024:
131 size_reg = RS480_VA_SIZE_1GB;
132 break;
133 case 2048:
134 size_reg = RS480_VA_SIZE_2GB;
135 break;
136 default:
137 return -EINVAL;
138 }
139 if (rdev->gart.table.ram.ptr == NULL) {
140 rdev->gart.table_size = rdev->gart.num_gpu_pages * 4;
141 r = radeon_gart_table_ram_alloc(rdev);
142 if (r) {
143 return r;
144 }
145 }
146 /* It should be fine to program it to max value */
147 if (rdev->family == CHIP_RS690 || (rdev->family == CHIP_RS740)) {
148 WREG32_MC(RS690_MCCFG_AGP_BASE, 0xFFFFFFFF);
149 WREG32_MC(RS690_MCCFG_AGP_BASE_2, 0);
150 } else {
151 WREG32(RADEON_AGP_BASE, 0xFFFFFFFF);
152 WREG32(RS480_AGP_BASE_2, 0);
153 }
154 tmp = rdev->mc.gtt_location + rdev->mc.gtt_size - 1;
155 tmp = REG_SET(RS690_MC_AGP_TOP, tmp >> 16);
156 tmp |= REG_SET(RS690_MC_AGP_START, rdev->mc.gtt_location >> 16);
157 if ((rdev->family == CHIP_RS690) || (rdev->family == CHIP_RS740)) {
158 WREG32_MC(RS690_MCCFG_AGP_LOCATION, tmp);
159 tmp = RREG32(RADEON_BUS_CNTL) & ~RS600_BUS_MASTER_DIS;
160 WREG32(RADEON_BUS_CNTL, tmp);
161 } else {
162 WREG32(RADEON_MC_AGP_LOCATION, tmp);
163 tmp = RREG32(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS;
164 WREG32(RADEON_BUS_CNTL, tmp);
165 }
166 /* Table should be in 32bits address space so ignore bits above. */
167 tmp = rdev->gart.table_addr & 0xfffff000;
168 WREG32_MC(RS480_GART_BASE, tmp);
169 /* TODO: more tweaking here */
170 WREG32_MC(RS480_GART_FEATURE_ID,
171 (RS480_TLB_ENABLE |
172 RS480_GTW_LAC_EN | RS480_1LEVEL_GART));
173 /* Disable snooping */
174 WREG32_MC(RS480_AGP_MODE_CNTL,
175 (1 << RS480_REQ_TYPE_SNOOP_SHIFT) | RS480_REQ_TYPE_SNOOP_DIS);
176 /* Disable AGP mode */
177 /* FIXME: according to doc we should set HIDE_MMCFG_BAR=0,
178 * AGPMODE30=0 & AGP30ENHANCED=0 in NB_CNTL */
179 if ((rdev->family == CHIP_RS690) || (rdev->family == CHIP_RS740)) {
180 WREG32_MC(RS480_MC_MISC_CNTL,
181 (RS480_GART_INDEX_REG_EN | RS690_BLOCK_GFX_D3_EN));
182 } else {
183 WREG32_MC(RS480_MC_MISC_CNTL, RS480_GART_INDEX_REG_EN);
184 }
185 /* Enable gart */
186 WREG32_MC(RS480_AGP_ADDRESS_SPACE_SIZE, (RS480_GART_EN | size_reg));
187 rs400_gart_tlb_flush(rdev);
188 rdev->gart.ready = true;
189 return 0;
190}
191
192void rs400_gart_disable(struct radeon_device *rdev)
193{
194 uint32_t tmp;
195
196 tmp = RREG32_MC(RS690_AIC_CTRL_SCRATCH);
197 tmp |= RS690_DIS_OUT_OF_PCI_GART_ACCESS;
198 WREG32_MC(RS690_AIC_CTRL_SCRATCH, tmp);
199 WREG32_MC(RS480_AGP_ADDRESS_SPACE_SIZE, 0);
200}
201
202int rs400_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr)
203{
204 if (i < 0 || i > rdev->gart.num_gpu_pages) {
205 return -EINVAL;
206 }
207 rdev->gart.table.ram.ptr[i] = cpu_to_le32(((uint32_t)addr) | 0xC);
208 return 0;
209}
210
211
212/*
213 * MC functions.
214 */
215int rs400_mc_init(struct radeon_device *rdev)
216{
217 uint32_t tmp;
218 int r;
219
220 if (r100_debugfs_rbbm_init(rdev)) {
221 DRM_ERROR("Failed to register debugfs file for RBBM !\n");
222 }
223
224 rs400_gpu_init(rdev);
225 rs400_gart_disable(rdev);
226 rdev->mc.gtt_location = rdev->mc.vram_size;
227 rdev->mc.gtt_location += (rdev->mc.gtt_size - 1);
228 rdev->mc.gtt_location &= ~(rdev->mc.gtt_size - 1);
229 rdev->mc.vram_location = 0xFFFFFFFFUL;
230 r = radeon_mc_setup(rdev);
231 if (r) {
232 return r;
233 }
234
235 r100_mc_disable_clients(rdev);
236 if (r300_mc_wait_for_idle(rdev)) {
237 printk(KERN_WARNING "Failed to wait MC idle while "
238 "programming pipes. Bad things might happen.\n");
239 }
240
241 tmp = rdev->mc.vram_location + rdev->mc.vram_size - 1;
242 tmp = REG_SET(RADEON_MC_FB_TOP, tmp >> 16);
243 tmp |= REG_SET(RADEON_MC_FB_START, rdev->mc.vram_location >> 16);
244 WREG32(RADEON_MC_FB_LOCATION, tmp);
245 tmp = RREG32(RADEON_HOST_PATH_CNTL) | RADEON_HP_LIN_RD_CACHE_DIS;
246 WREG32(RADEON_HOST_PATH_CNTL, tmp | RADEON_HDP_SOFT_RESET | RADEON_HDP_READ_BUFFER_INVALIDATE);
247 (void)RREG32(RADEON_HOST_PATH_CNTL);
248 WREG32(RADEON_HOST_PATH_CNTL, tmp);
249 (void)RREG32(RADEON_HOST_PATH_CNTL);
250 return 0;
251}
252
253void rs400_mc_fini(struct radeon_device *rdev)
254{
255 rs400_gart_disable(rdev);
256 radeon_gart_table_ram_free(rdev);
257 radeon_gart_fini(rdev);
258}
259
260
261/*
262 * Global GPU functions
263 */
264void rs400_errata(struct radeon_device *rdev)
265{
266 rdev->pll_errata = 0;
267}
268
269void rs400_gpu_init(struct radeon_device *rdev)
270{
271 /* FIXME: HDP same place on rs400 ? */
272 r100_hdp_reset(rdev);
273 /* FIXME: is this correct ? */
274 r420_pipes_init(rdev);
275 if (r300_mc_wait_for_idle(rdev)) {
276 printk(KERN_WARNING "Failed to wait MC idle while "
277 "programming pipes. Bad things might happen.\n");
278 }
279}
280
281
282/*
283 * VRAM info.
284 */
285void rs400_vram_info(struct radeon_device *rdev)
286{
287 uint32_t tom;
288
289 rs400_gart_adjust_size(rdev);
290 /* DDR for all card after R300 & IGP */
291 rdev->mc.vram_is_ddr = true;
292 rdev->mc.vram_width = 128;
293
294 /* read NB_TOM to get the amount of ram stolen for the GPU */
295 tom = RREG32(RADEON_NB_TOM);
296 rdev->mc.vram_size = (((tom >> 16) - (tom & 0xffff) + 1) << 16);
297 WREG32(RADEON_CONFIG_MEMSIZE, rdev->mc.vram_size);
298
299 /* Could aper size report 0 ? */
300 rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0);
301 rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0);
302}
303
304
305/*
306 * Indirect registers accessor
307 */
308uint32_t rs400_mc_rreg(struct radeon_device *rdev, uint32_t reg)
309{
310 uint32_t r;
311
312 WREG32(RS480_NB_MC_INDEX, reg & 0xff);
313 r = RREG32(RS480_NB_MC_DATA);
314 WREG32(RS480_NB_MC_INDEX, 0xff);
315 return r;
316}
317
318void rs400_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v)
319{
320 WREG32(RS480_NB_MC_INDEX, ((reg) & 0xff) | RS480_NB_MC_IND_WR_EN);
321 WREG32(RS480_NB_MC_DATA, (v));
322 WREG32(RS480_NB_MC_INDEX, 0xff);
323}
324
325
326/*
327 * Debugfs info
328 */
329#if defined(CONFIG_DEBUG_FS)
330static int rs400_debugfs_gart_info(struct seq_file *m, void *data)
331{
332 struct drm_info_node *node = (struct drm_info_node *) m->private;
333 struct drm_device *dev = node->minor->dev;
334 struct radeon_device *rdev = dev->dev_private;
335 uint32_t tmp;
336
337 tmp = RREG32(RADEON_HOST_PATH_CNTL);
338 seq_printf(m, "HOST_PATH_CNTL 0x%08x\n", tmp);
339 tmp = RREG32(RADEON_BUS_CNTL);
340 seq_printf(m, "BUS_CNTL 0x%08x\n", tmp);
341 tmp = RREG32_MC(RS690_AIC_CTRL_SCRATCH);
342 seq_printf(m, "AIC_CTRL_SCRATCH 0x%08x\n", tmp);
343 if (rdev->family == CHIP_RS690 || (rdev->family == CHIP_RS740)) {
344 tmp = RREG32_MC(RS690_MCCFG_AGP_BASE);
345 seq_printf(m, "MCCFG_AGP_BASE 0x%08x\n", tmp);
346 tmp = RREG32_MC(RS690_MCCFG_AGP_BASE_2);
347 seq_printf(m, "MCCFG_AGP_BASE_2 0x%08x\n", tmp);
348 tmp = RREG32_MC(RS690_MCCFG_AGP_LOCATION);
349 seq_printf(m, "MCCFG_AGP_LOCATION 0x%08x\n", tmp);
350 tmp = RREG32_MC(0x100);
351 seq_printf(m, "MCCFG_FB_LOCATION 0x%08x\n", tmp);
352 tmp = RREG32(0x134);
353 seq_printf(m, "HDP_FB_LOCATION 0x%08x\n", tmp);
354 } else {
355 tmp = RREG32(RADEON_AGP_BASE);
356 seq_printf(m, "AGP_BASE 0x%08x\n", tmp);
357 tmp = RREG32(RS480_AGP_BASE_2);
358 seq_printf(m, "AGP_BASE_2 0x%08x\n", tmp);
359 tmp = RREG32(RADEON_MC_AGP_LOCATION);
360 seq_printf(m, "MC_AGP_LOCATION 0x%08x\n", tmp);
361 }
362 tmp = RREG32_MC(RS480_GART_BASE);
363 seq_printf(m, "GART_BASE 0x%08x\n", tmp);
364 tmp = RREG32_MC(RS480_GART_FEATURE_ID);
365 seq_printf(m, "GART_FEATURE_ID 0x%08x\n", tmp);
366 tmp = RREG32_MC(RS480_AGP_MODE_CNTL);
367 seq_printf(m, "AGP_MODE_CONTROL 0x%08x\n", tmp);
368 tmp = RREG32_MC(RS480_MC_MISC_CNTL);
369 seq_printf(m, "MC_MISC_CNTL 0x%08x\n", tmp);
370 tmp = RREG32_MC(0x5F);
371 seq_printf(m, "MC_MISC_UMA_CNTL 0x%08x\n", tmp);
372 tmp = RREG32_MC(RS480_AGP_ADDRESS_SPACE_SIZE);
373 seq_printf(m, "AGP_ADDRESS_SPACE_SIZE 0x%08x\n", tmp);
374 tmp = RREG32_MC(RS480_GART_CACHE_CNTRL);
375 seq_printf(m, "GART_CACHE_CNTRL 0x%08x\n", tmp);
376 tmp = RREG32_MC(0x3B);
377 seq_printf(m, "MC_GART_ERROR_ADDRESS 0x%08x\n", tmp);
378 tmp = RREG32_MC(0x3C);
379 seq_printf(m, "MC_GART_ERROR_ADDRESS_HI 0x%08x\n", tmp);
380 tmp = RREG32_MC(0x30);
381 seq_printf(m, "GART_ERROR_0 0x%08x\n", tmp);
382 tmp = RREG32_MC(0x31);
383 seq_printf(m, "GART_ERROR_1 0x%08x\n", tmp);
384 tmp = RREG32_MC(0x32);
385 seq_printf(m, "GART_ERROR_2 0x%08x\n", tmp);
386 tmp = RREG32_MC(0x33);
387 seq_printf(m, "GART_ERROR_3 0x%08x\n", tmp);
388 tmp = RREG32_MC(0x34);
389 seq_printf(m, "GART_ERROR_4 0x%08x\n", tmp);
390 tmp = RREG32_MC(0x35);
391 seq_printf(m, "GART_ERROR_5 0x%08x\n", tmp);
392 tmp = RREG32_MC(0x36);
393 seq_printf(m, "GART_ERROR_6 0x%08x\n", tmp);
394 tmp = RREG32_MC(0x37);
395 seq_printf(m, "GART_ERROR_7 0x%08x\n", tmp);
396 return 0;
397}
398
399static struct drm_info_list rs400_gart_info_list[] = {
400 {"rs400_gart_info", rs400_debugfs_gart_info, 0, NULL},
401};
402#endif
403
404int rs400_debugfs_pcie_gart_info_init(struct radeon_device *rdev)
405{
406#if defined(CONFIG_DEBUG_FS)
407 return radeon_debugfs_add_files(rdev, rs400_gart_info_list, 1);
408#else
409 return 0;
410#endif
411}