diff options
Diffstat (limited to 'drivers/gpu/drm/radeon/rs600.c')
-rw-r--r-- | drivers/gpu/drm/radeon/rs600.c | 324 |
1 files changed, 324 insertions, 0 deletions
diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c new file mode 100644 index 000000000000..ab0c967553e6 --- /dev/null +++ b/drivers/gpu/drm/radeon/rs600.c | |||
@@ -0,0 +1,324 @@ | |||
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 "drmP.h" | ||
29 | #include "radeon_reg.h" | ||
30 | #include "radeon.h" | ||
31 | |||
32 | /* rs600 depends on : */ | ||
33 | void r100_hdp_reset(struct radeon_device *rdev); | ||
34 | int r100_gui_wait_for_idle(struct radeon_device *rdev); | ||
35 | int r300_mc_wait_for_idle(struct radeon_device *rdev); | ||
36 | void r420_pipes_init(struct radeon_device *rdev); | ||
37 | |||
38 | /* This files gather functions specifics to : | ||
39 | * rs600 | ||
40 | * | ||
41 | * Some of these functions might be used by newer ASICs. | ||
42 | */ | ||
43 | void rs600_gpu_init(struct radeon_device *rdev); | ||
44 | int rs600_mc_wait_for_idle(struct radeon_device *rdev); | ||
45 | void rs600_disable_vga(struct radeon_device *rdev); | ||
46 | |||
47 | |||
48 | /* | ||
49 | * GART. | ||
50 | */ | ||
51 | void rs600_gart_tlb_flush(struct radeon_device *rdev) | ||
52 | { | ||
53 | uint32_t tmp; | ||
54 | |||
55 | tmp = RREG32_MC(RS600_MC_PT0_CNTL); | ||
56 | tmp &= ~(RS600_INVALIDATE_ALL_L1_TLBS | RS600_INVALIDATE_L2_CACHE); | ||
57 | WREG32_MC(RS600_MC_PT0_CNTL, tmp); | ||
58 | |||
59 | tmp = RREG32_MC(RS600_MC_PT0_CNTL); | ||
60 | tmp |= RS600_INVALIDATE_ALL_L1_TLBS | RS600_INVALIDATE_L2_CACHE; | ||
61 | WREG32_MC(RS600_MC_PT0_CNTL, tmp); | ||
62 | |||
63 | tmp = RREG32_MC(RS600_MC_PT0_CNTL); | ||
64 | tmp &= ~(RS600_INVALIDATE_ALL_L1_TLBS | RS600_INVALIDATE_L2_CACHE); | ||
65 | WREG32_MC(RS600_MC_PT0_CNTL, tmp); | ||
66 | tmp = RREG32_MC(RS600_MC_PT0_CNTL); | ||
67 | } | ||
68 | |||
69 | int rs600_gart_enable(struct radeon_device *rdev) | ||
70 | { | ||
71 | uint32_t tmp; | ||
72 | int i; | ||
73 | int r; | ||
74 | |||
75 | /* Initialize common gart structure */ | ||
76 | r = radeon_gart_init(rdev); | ||
77 | if (r) { | ||
78 | return r; | ||
79 | } | ||
80 | rdev->gart.table_size = rdev->gart.num_gpu_pages * 8; | ||
81 | r = radeon_gart_table_vram_alloc(rdev); | ||
82 | if (r) { | ||
83 | return r; | ||
84 | } | ||
85 | /* FIXME: setup default page */ | ||
86 | WREG32_MC(RS600_MC_PT0_CNTL, | ||
87 | (RS600_EFFECTIVE_L2_CACHE_SIZE(6) | | ||
88 | RS600_EFFECTIVE_L2_QUEUE_SIZE(6))); | ||
89 | for (i = 0; i < 19; i++) { | ||
90 | WREG32_MC(RS600_MC_PT0_CLIENT0_CNTL + i, | ||
91 | (RS600_ENABLE_TRANSLATION_MODE_OVERRIDE | | ||
92 | RS600_SYSTEM_ACCESS_MODE_IN_SYS | | ||
93 | RS600_SYSTEM_APERTURE_UNMAPPED_ACCESS_DEFAULT_PAGE | | ||
94 | RS600_EFFECTIVE_L1_CACHE_SIZE(3) | | ||
95 | RS600_ENABLE_FRAGMENT_PROCESSING | | ||
96 | RS600_EFFECTIVE_L1_QUEUE_SIZE(3))); | ||
97 | } | ||
98 | |||
99 | /* System context map to GART space */ | ||
100 | WREG32_MC(RS600_MC_PT0_SYSTEM_APERTURE_LOW_ADDR, rdev->mc.gtt_location); | ||
101 | tmp = rdev->mc.gtt_location + rdev->mc.gtt_size - 1; | ||
102 | WREG32_MC(RS600_MC_PT0_SYSTEM_APERTURE_HIGH_ADDR, tmp); | ||
103 | |||
104 | /* enable first context */ | ||
105 | WREG32_MC(RS600_MC_PT0_CONTEXT0_FLAT_START_ADDR, rdev->mc.gtt_location); | ||
106 | tmp = rdev->mc.gtt_location + rdev->mc.gtt_size - 1; | ||
107 | WREG32_MC(RS600_MC_PT0_CONTEXT0_FLAT_END_ADDR, tmp); | ||
108 | WREG32_MC(RS600_MC_PT0_CONTEXT0_CNTL, | ||
109 | (RS600_ENABLE_PAGE_TABLE | RS600_PAGE_TABLE_TYPE_FLAT)); | ||
110 | /* disable all other contexts */ | ||
111 | for (i = 1; i < 8; i++) { | ||
112 | WREG32_MC(RS600_MC_PT0_CONTEXT0_CNTL + i, 0); | ||
113 | } | ||
114 | |||
115 | /* setup the page table */ | ||
116 | WREG32_MC(RS600_MC_PT0_CONTEXT0_FLAT_BASE_ADDR, | ||
117 | rdev->gart.table_addr); | ||
118 | WREG32_MC(RS600_MC_PT0_CONTEXT0_DEFAULT_READ_ADDR, 0); | ||
119 | |||
120 | /* enable page tables */ | ||
121 | tmp = RREG32_MC(RS600_MC_PT0_CNTL); | ||
122 | WREG32_MC(RS600_MC_PT0_CNTL, (tmp | RS600_ENABLE_PT)); | ||
123 | tmp = RREG32_MC(RS600_MC_CNTL1); | ||
124 | WREG32_MC(RS600_MC_CNTL1, (tmp | RS600_ENABLE_PAGE_TABLES)); | ||
125 | rs600_gart_tlb_flush(rdev); | ||
126 | rdev->gart.ready = true; | ||
127 | return 0; | ||
128 | } | ||
129 | |||
130 | void rs600_gart_disable(struct radeon_device *rdev) | ||
131 | { | ||
132 | uint32_t tmp; | ||
133 | |||
134 | /* FIXME: disable out of gart access */ | ||
135 | WREG32_MC(RS600_MC_PT0_CNTL, 0); | ||
136 | tmp = RREG32_MC(RS600_MC_CNTL1); | ||
137 | tmp &= ~RS600_ENABLE_PAGE_TABLES; | ||
138 | WREG32_MC(RS600_MC_CNTL1, tmp); | ||
139 | radeon_object_kunmap(rdev->gart.table.vram.robj); | ||
140 | radeon_object_unpin(rdev->gart.table.vram.robj); | ||
141 | } | ||
142 | |||
143 | #define R600_PTE_VALID (1 << 0) | ||
144 | #define R600_PTE_SYSTEM (1 << 1) | ||
145 | #define R600_PTE_SNOOPED (1 << 2) | ||
146 | #define R600_PTE_READABLE (1 << 5) | ||
147 | #define R600_PTE_WRITEABLE (1 << 6) | ||
148 | |||
149 | int rs600_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr) | ||
150 | { | ||
151 | void __iomem *ptr = (void *)rdev->gart.table.vram.ptr; | ||
152 | |||
153 | if (i < 0 || i > rdev->gart.num_gpu_pages) { | ||
154 | return -EINVAL; | ||
155 | } | ||
156 | addr = addr & 0xFFFFFFFFFFFFF000ULL; | ||
157 | addr |= R600_PTE_VALID | R600_PTE_SYSTEM | R600_PTE_SNOOPED; | ||
158 | addr |= R600_PTE_READABLE | R600_PTE_WRITEABLE; | ||
159 | writeq(addr, ((void __iomem *)ptr) + (i * 8)); | ||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | |||
164 | /* | ||
165 | * MC. | ||
166 | */ | ||
167 | void rs600_mc_disable_clients(struct radeon_device *rdev) | ||
168 | { | ||
169 | unsigned tmp; | ||
170 | |||
171 | if (r100_gui_wait_for_idle(rdev)) { | ||
172 | printk(KERN_WARNING "Failed to wait GUI idle while " | ||
173 | "programming pipes. Bad things might happen.\n"); | ||
174 | } | ||
175 | |||
176 | tmp = RREG32(AVIVO_D1VGA_CONTROL); | ||
177 | WREG32(AVIVO_D1VGA_CONTROL, tmp & ~AVIVO_DVGA_CONTROL_MODE_ENABLE); | ||
178 | tmp = RREG32(AVIVO_D2VGA_CONTROL); | ||
179 | WREG32(AVIVO_D2VGA_CONTROL, tmp & ~AVIVO_DVGA_CONTROL_MODE_ENABLE); | ||
180 | |||
181 | tmp = RREG32(AVIVO_D1CRTC_CONTROL); | ||
182 | WREG32(AVIVO_D1CRTC_CONTROL, tmp & ~AVIVO_CRTC_EN); | ||
183 | tmp = RREG32(AVIVO_D2CRTC_CONTROL); | ||
184 | WREG32(AVIVO_D2CRTC_CONTROL, tmp & ~AVIVO_CRTC_EN); | ||
185 | |||
186 | /* make sure all previous write got through */ | ||
187 | tmp = RREG32(AVIVO_D2CRTC_CONTROL); | ||
188 | |||
189 | mdelay(1); | ||
190 | } | ||
191 | |||
192 | int rs600_mc_init(struct radeon_device *rdev) | ||
193 | { | ||
194 | uint32_t tmp; | ||
195 | int r; | ||
196 | |||
197 | if (r100_debugfs_rbbm_init(rdev)) { | ||
198 | DRM_ERROR("Failed to register debugfs file for RBBM !\n"); | ||
199 | } | ||
200 | |||
201 | rs600_gpu_init(rdev); | ||
202 | rs600_gart_disable(rdev); | ||
203 | |||
204 | /* Setup GPU memory space */ | ||
205 | rdev->mc.vram_location = 0xFFFFFFFFUL; | ||
206 | rdev->mc.gtt_location = 0xFFFFFFFFUL; | ||
207 | r = radeon_mc_setup(rdev); | ||
208 | if (r) { | ||
209 | return r; | ||
210 | } | ||
211 | |||
212 | /* Program GPU memory space */ | ||
213 | /* Enable bus master */ | ||
214 | tmp = RREG32(RADEON_BUS_CNTL) & ~RS600_BUS_MASTER_DIS; | ||
215 | WREG32(RADEON_BUS_CNTL, tmp); | ||
216 | /* FIXME: What does AGP means for such chipset ? */ | ||
217 | WREG32_MC(RS600_MC_AGP_LOCATION, 0x0FFFFFFF); | ||
218 | /* FIXME: are this AGP reg in indirect MC range ? */ | ||
219 | WREG32_MC(RS600_MC_AGP_BASE, 0); | ||
220 | WREG32_MC(RS600_MC_AGP_BASE_2, 0); | ||
221 | rs600_mc_disable_clients(rdev); | ||
222 | if (rs600_mc_wait_for_idle(rdev)) { | ||
223 | printk(KERN_WARNING "Failed to wait MC idle while " | ||
224 | "programming pipes. Bad things might happen.\n"); | ||
225 | } | ||
226 | tmp = rdev->mc.vram_location + rdev->mc.vram_size - 1; | ||
227 | tmp = REG_SET(RS600_MC_FB_TOP, tmp >> 16); | ||
228 | tmp |= REG_SET(RS600_MC_FB_START, rdev->mc.vram_location >> 16); | ||
229 | WREG32_MC(RS600_MC_FB_LOCATION, tmp); | ||
230 | WREG32(RS690_HDP_FB_LOCATION, rdev->mc.vram_location >> 16); | ||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | void rs600_mc_fini(struct radeon_device *rdev) | ||
235 | { | ||
236 | rs600_gart_disable(rdev); | ||
237 | radeon_gart_table_vram_free(rdev); | ||
238 | radeon_gart_fini(rdev); | ||
239 | } | ||
240 | |||
241 | |||
242 | /* | ||
243 | * Global GPU functions | ||
244 | */ | ||
245 | void rs600_disable_vga(struct radeon_device *rdev) | ||
246 | { | ||
247 | unsigned tmp; | ||
248 | |||
249 | WREG32(0x330, 0); | ||
250 | WREG32(0x338, 0); | ||
251 | tmp = RREG32(0x300); | ||
252 | tmp &= ~(3 << 16); | ||
253 | WREG32(0x300, tmp); | ||
254 | WREG32(0x308, (1 << 8)); | ||
255 | WREG32(0x310, rdev->mc.vram_location); | ||
256 | WREG32(0x594, 0); | ||
257 | } | ||
258 | |||
259 | int rs600_mc_wait_for_idle(struct radeon_device *rdev) | ||
260 | { | ||
261 | unsigned i; | ||
262 | uint32_t tmp; | ||
263 | |||
264 | for (i = 0; i < rdev->usec_timeout; i++) { | ||
265 | /* read MC_STATUS */ | ||
266 | tmp = RREG32_MC(RS600_MC_STATUS); | ||
267 | if (tmp & RS600_MC_STATUS_IDLE) { | ||
268 | return 0; | ||
269 | } | ||
270 | DRM_UDELAY(1); | ||
271 | } | ||
272 | return -1; | ||
273 | } | ||
274 | |||
275 | void rs600_errata(struct radeon_device *rdev) | ||
276 | { | ||
277 | rdev->pll_errata = 0; | ||
278 | } | ||
279 | |||
280 | void rs600_gpu_init(struct radeon_device *rdev) | ||
281 | { | ||
282 | /* FIXME: HDP same place on rs600 ? */ | ||
283 | r100_hdp_reset(rdev); | ||
284 | rs600_disable_vga(rdev); | ||
285 | /* FIXME: is this correct ? */ | ||
286 | r420_pipes_init(rdev); | ||
287 | if (rs600_mc_wait_for_idle(rdev)) { | ||
288 | printk(KERN_WARNING "Failed to wait MC idle while " | ||
289 | "programming pipes. Bad things might happen.\n"); | ||
290 | } | ||
291 | } | ||
292 | |||
293 | |||
294 | /* | ||
295 | * VRAM info. | ||
296 | */ | ||
297 | void rs600_vram_info(struct radeon_device *rdev) | ||
298 | { | ||
299 | /* FIXME: to do or is these values sane ? */ | ||
300 | rdev->mc.vram_is_ddr = true; | ||
301 | rdev->mc.vram_width = 128; | ||
302 | } | ||
303 | |||
304 | |||
305 | /* | ||
306 | * Indirect registers accessor | ||
307 | */ | ||
308 | uint32_t rs600_mc_rreg(struct radeon_device *rdev, uint32_t reg) | ||
309 | { | ||
310 | uint32_t r; | ||
311 | |||
312 | WREG32(RS600_MC_INDEX, | ||
313 | ((reg & RS600_MC_ADDR_MASK) | RS600_MC_IND_CITF_ARB0)); | ||
314 | r = RREG32(RS600_MC_DATA); | ||
315 | return r; | ||
316 | } | ||
317 | |||
318 | void rs600_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) | ||
319 | { | ||
320 | WREG32(RS600_MC_INDEX, | ||
321 | RS600_MC_IND_WR_EN | RS600_MC_IND_CITF_ARB0 | | ||
322 | ((reg) & RS600_MC_ADDR_MASK)); | ||
323 | WREG32(RS600_MC_DATA, v); | ||
324 | } | ||