1926deccbSFrançois Tigeot /*
2926deccbSFrançois Tigeot * Copyright 2008 Advanced Micro Devices, Inc.
3926deccbSFrançois Tigeot * Copyright 2008 Red Hat Inc.
4926deccbSFrançois Tigeot * Copyright 2009 Jerome Glisse.
5926deccbSFrançois Tigeot *
6926deccbSFrançois Tigeot * Permission is hereby granted, free of charge, to any person obtaining a
7926deccbSFrançois Tigeot * copy of this software and associated documentation files (the "Software"),
8926deccbSFrançois Tigeot * to deal in the Software without restriction, including without limitation
9926deccbSFrançois Tigeot * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10926deccbSFrançois Tigeot * and/or sell copies of the Software, and to permit persons to whom the
11926deccbSFrançois Tigeot * Software is furnished to do so, subject to the following conditions:
12926deccbSFrançois Tigeot *
13926deccbSFrançois Tigeot * The above copyright notice and this permission notice shall be included in
14926deccbSFrançois Tigeot * all copies or substantial portions of the Software.
15926deccbSFrançois Tigeot *
16926deccbSFrançois Tigeot * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17926deccbSFrançois Tigeot * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18926deccbSFrançois Tigeot * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19926deccbSFrançois Tigeot * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
20926deccbSFrançois Tigeot * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21926deccbSFrançois Tigeot * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22926deccbSFrançois Tigeot * OTHER DEALINGS IN THE SOFTWARE.
23926deccbSFrançois Tigeot *
24926deccbSFrançois Tigeot * Authors: Dave Airlie
25926deccbSFrançois Tigeot * Alex Deucher
26926deccbSFrançois Tigeot * Jerome Glisse
27926deccbSFrançois Tigeot */
28926deccbSFrançois Tigeot #include <drm/drmP.h>
29926deccbSFrançois Tigeot #include "radeon.h"
30926deccbSFrançois Tigeot #include "radeon_asic.h"
31926deccbSFrançois Tigeot #include "atom.h"
32926deccbSFrançois Tigeot #include "r520d.h"
33926deccbSFrançois Tigeot
34926deccbSFrançois Tigeot /* This files gather functions specifics to: r520,rv530,rv560,rv570,r580 */
35926deccbSFrançois Tigeot
r520_mc_wait_for_idle(struct radeon_device * rdev)36926deccbSFrançois Tigeot int r520_mc_wait_for_idle(struct radeon_device *rdev)
37926deccbSFrançois Tigeot {
38926deccbSFrançois Tigeot unsigned i;
39926deccbSFrançois Tigeot uint32_t tmp;
40926deccbSFrançois Tigeot
41926deccbSFrançois Tigeot for (i = 0; i < rdev->usec_timeout; i++) {
42926deccbSFrançois Tigeot /* read MC_STATUS */
43926deccbSFrançois Tigeot tmp = RREG32_MC(R520_MC_STATUS);
44926deccbSFrançois Tigeot if (tmp & R520_MC_STATUS_IDLE) {
45926deccbSFrançois Tigeot return 0;
46926deccbSFrançois Tigeot }
47926deccbSFrançois Tigeot DRM_UDELAY(1);
48926deccbSFrançois Tigeot }
49926deccbSFrançois Tigeot return -1;
50926deccbSFrançois Tigeot }
51926deccbSFrançois Tigeot
r520_gpu_init(struct radeon_device * rdev)52926deccbSFrançois Tigeot static void r520_gpu_init(struct radeon_device *rdev)
53926deccbSFrançois Tigeot {
54926deccbSFrançois Tigeot unsigned pipe_select_current, gb_pipe_select, tmp;
55926deccbSFrançois Tigeot
56926deccbSFrançois Tigeot rv515_vga_render_disable(rdev);
57926deccbSFrançois Tigeot /*
58926deccbSFrançois Tigeot * DST_PIPE_CONFIG 0x170C
59926deccbSFrançois Tigeot * GB_TILE_CONFIG 0x4018
60926deccbSFrançois Tigeot * GB_FIFO_SIZE 0x4024
61926deccbSFrançois Tigeot * GB_PIPE_SELECT 0x402C
62926deccbSFrançois Tigeot * GB_PIPE_SELECT2 0x4124
63926deccbSFrançois Tigeot * Z_PIPE_SHIFT 0
64926deccbSFrançois Tigeot * Z_PIPE_MASK 0x000000003
65926deccbSFrançois Tigeot * GB_FIFO_SIZE2 0x4128
66926deccbSFrançois Tigeot * SC_SFIFO_SIZE_SHIFT 0
67926deccbSFrançois Tigeot * SC_SFIFO_SIZE_MASK 0x000000003
68926deccbSFrançois Tigeot * SC_MFIFO_SIZE_SHIFT 2
69926deccbSFrançois Tigeot * SC_MFIFO_SIZE_MASK 0x00000000C
70926deccbSFrançois Tigeot * FG_SFIFO_SIZE_SHIFT 4
71926deccbSFrançois Tigeot * FG_SFIFO_SIZE_MASK 0x000000030
72926deccbSFrançois Tigeot * ZB_MFIFO_SIZE_SHIFT 6
73926deccbSFrançois Tigeot * ZB_MFIFO_SIZE_MASK 0x0000000C0
74926deccbSFrançois Tigeot * GA_ENHANCE 0x4274
75926deccbSFrançois Tigeot * SU_REG_DEST 0x42C8
76926deccbSFrançois Tigeot */
77926deccbSFrançois Tigeot /* workaround for RV530 */
78926deccbSFrançois Tigeot if (rdev->family == CHIP_RV530) {
79926deccbSFrançois Tigeot WREG32(0x4128, 0xFF);
80926deccbSFrançois Tigeot }
81926deccbSFrançois Tigeot r420_pipes_init(rdev);
82926deccbSFrançois Tigeot gb_pipe_select = RREG32(R400_GB_PIPE_SELECT);
83926deccbSFrançois Tigeot tmp = RREG32(R300_DST_PIPE_CONFIG);
84926deccbSFrançois Tigeot pipe_select_current = (tmp >> 2) & 3;
85926deccbSFrançois Tigeot tmp = (1 << pipe_select_current) |
86926deccbSFrançois Tigeot (((gb_pipe_select >> 8) & 0xF) << 4);
87926deccbSFrançois Tigeot WREG32_PLL(0x000D, tmp);
88926deccbSFrançois Tigeot if (r520_mc_wait_for_idle(rdev)) {
89*a85cb24fSFrançois Tigeot pr_warn("Failed to wait MC idle while programming pipes. Bad things might happen.\n");
90926deccbSFrançois Tigeot }
91926deccbSFrançois Tigeot }
92926deccbSFrançois Tigeot
r520_vram_get_type(struct radeon_device * rdev)93926deccbSFrançois Tigeot static void r520_vram_get_type(struct radeon_device *rdev)
94926deccbSFrançois Tigeot {
95926deccbSFrançois Tigeot uint32_t tmp;
96926deccbSFrançois Tigeot
97926deccbSFrançois Tigeot rdev->mc.vram_width = 128;
98926deccbSFrançois Tigeot rdev->mc.vram_is_ddr = true;
99926deccbSFrançois Tigeot tmp = RREG32_MC(R520_MC_CNTL0);
100926deccbSFrançois Tigeot switch ((tmp & R520_MEM_NUM_CHANNELS_MASK) >> R520_MEM_NUM_CHANNELS_SHIFT) {
101926deccbSFrançois Tigeot case 0:
102926deccbSFrançois Tigeot rdev->mc.vram_width = 32;
103926deccbSFrançois Tigeot break;
104926deccbSFrançois Tigeot case 1:
105926deccbSFrançois Tigeot rdev->mc.vram_width = 64;
106926deccbSFrançois Tigeot break;
107926deccbSFrançois Tigeot case 2:
108926deccbSFrançois Tigeot rdev->mc.vram_width = 128;
109926deccbSFrançois Tigeot break;
110926deccbSFrançois Tigeot case 3:
111926deccbSFrançois Tigeot rdev->mc.vram_width = 256;
112926deccbSFrançois Tigeot break;
113926deccbSFrançois Tigeot default:
114926deccbSFrançois Tigeot rdev->mc.vram_width = 128;
115926deccbSFrançois Tigeot break;
116926deccbSFrançois Tigeot }
117926deccbSFrançois Tigeot if (tmp & R520_MC_CHANNEL_SIZE)
118926deccbSFrançois Tigeot rdev->mc.vram_width *= 2;
119926deccbSFrançois Tigeot }
120926deccbSFrançois Tigeot
r520_mc_init(struct radeon_device * rdev)121926deccbSFrançois Tigeot static void r520_mc_init(struct radeon_device *rdev)
122926deccbSFrançois Tigeot {
123926deccbSFrançois Tigeot
124926deccbSFrançois Tigeot r520_vram_get_type(rdev);
125926deccbSFrançois Tigeot r100_vram_init_sizes(rdev);
126926deccbSFrançois Tigeot radeon_vram_location(rdev, &rdev->mc, 0);
127926deccbSFrançois Tigeot rdev->mc.gtt_base_align = 0;
128926deccbSFrançois Tigeot if (!(rdev->flags & RADEON_IS_AGP))
129926deccbSFrançois Tigeot radeon_gtt_location(rdev, &rdev->mc);
130926deccbSFrançois Tigeot radeon_update_bandwidth_info(rdev);
131926deccbSFrançois Tigeot }
132926deccbSFrançois Tigeot
r520_mc_program(struct radeon_device * rdev)133926deccbSFrançois Tigeot static void r520_mc_program(struct radeon_device *rdev)
134926deccbSFrançois Tigeot {
135926deccbSFrançois Tigeot struct rv515_mc_save save;
136926deccbSFrançois Tigeot
137926deccbSFrançois Tigeot /* Stops all mc clients */
138926deccbSFrançois Tigeot rv515_mc_stop(rdev, &save);
139926deccbSFrançois Tigeot
140926deccbSFrançois Tigeot /* Wait for mc idle */
141926deccbSFrançois Tigeot if (r520_mc_wait_for_idle(rdev))
142926deccbSFrançois Tigeot dev_warn(rdev->dev, "Wait MC idle timeout before updating MC.\n");
143926deccbSFrançois Tigeot /* Write VRAM size in case we are limiting it */
144926deccbSFrançois Tigeot WREG32(R_0000F8_CONFIG_MEMSIZE, rdev->mc.real_vram_size);
145926deccbSFrançois Tigeot /* Program MC, should be a 32bits limited address space */
146926deccbSFrançois Tigeot WREG32_MC(R_000004_MC_FB_LOCATION,
147926deccbSFrançois Tigeot S_000004_MC_FB_START(rdev->mc.vram_start >> 16) |
148926deccbSFrançois Tigeot S_000004_MC_FB_TOP(rdev->mc.vram_end >> 16));
149926deccbSFrançois Tigeot WREG32(R_000134_HDP_FB_LOCATION,
150926deccbSFrançois Tigeot S_000134_HDP_FB_START(rdev->mc.vram_start >> 16));
151926deccbSFrançois Tigeot if (rdev->flags & RADEON_IS_AGP) {
152926deccbSFrançois Tigeot WREG32_MC(R_000005_MC_AGP_LOCATION,
153926deccbSFrançois Tigeot S_000005_MC_AGP_START(rdev->mc.gtt_start >> 16) |
154926deccbSFrançois Tigeot S_000005_MC_AGP_TOP(rdev->mc.gtt_end >> 16));
155926deccbSFrançois Tigeot WREG32_MC(R_000006_AGP_BASE, lower_32_bits(rdev->mc.agp_base));
156926deccbSFrançois Tigeot WREG32_MC(R_000007_AGP_BASE_2,
157926deccbSFrançois Tigeot S_000007_AGP_BASE_ADDR_2(upper_32_bits(rdev->mc.agp_base)));
158926deccbSFrançois Tigeot } else {
159926deccbSFrançois Tigeot WREG32_MC(R_000005_MC_AGP_LOCATION, 0xFFFFFFFF);
160926deccbSFrançois Tigeot WREG32_MC(R_000006_AGP_BASE, 0);
161926deccbSFrançois Tigeot WREG32_MC(R_000007_AGP_BASE_2, 0);
162926deccbSFrançois Tigeot }
163926deccbSFrançois Tigeot
164926deccbSFrançois Tigeot rv515_mc_resume(rdev, &save);
165926deccbSFrançois Tigeot }
166926deccbSFrançois Tigeot
r520_startup(struct radeon_device * rdev)167926deccbSFrançois Tigeot static int r520_startup(struct radeon_device *rdev)
168926deccbSFrançois Tigeot {
169926deccbSFrançois Tigeot int r;
170926deccbSFrançois Tigeot
171926deccbSFrançois Tigeot r520_mc_program(rdev);
172926deccbSFrançois Tigeot /* Resume clock */
173926deccbSFrançois Tigeot rv515_clock_startup(rdev);
174926deccbSFrançois Tigeot /* Initialize GPU configuration (# pipes, ...) */
175926deccbSFrançois Tigeot r520_gpu_init(rdev);
176926deccbSFrançois Tigeot /* Initialize GART (initialize after TTM so we can allocate
177926deccbSFrançois Tigeot * memory through TTM but finalize after TTM) */
178926deccbSFrançois Tigeot if (rdev->flags & RADEON_IS_PCIE) {
179926deccbSFrançois Tigeot r = rv370_pcie_gart_enable(rdev);
180926deccbSFrançois Tigeot if (r)
181926deccbSFrançois Tigeot return r;
182926deccbSFrançois Tigeot }
183926deccbSFrançois Tigeot
184926deccbSFrançois Tigeot /* allocate wb buffer */
185926deccbSFrançois Tigeot r = radeon_wb_init(rdev);
186926deccbSFrançois Tigeot if (r)
187926deccbSFrançois Tigeot return r;
188926deccbSFrançois Tigeot
189926deccbSFrançois Tigeot r = radeon_fence_driver_start_ring(rdev, RADEON_RING_TYPE_GFX_INDEX);
190926deccbSFrançois Tigeot if (r) {
191926deccbSFrançois Tigeot dev_err(rdev->dev, "failed initializing CP fences (%d).\n", r);
192926deccbSFrançois Tigeot return r;
193926deccbSFrançois Tigeot }
194926deccbSFrançois Tigeot
195926deccbSFrançois Tigeot /* Enable IRQ */
196f43cf1b1SMichael Neumann if (!rdev->irq.installed) {
197f43cf1b1SMichael Neumann r = radeon_irq_kms_init(rdev);
198f43cf1b1SMichael Neumann if (r)
199f43cf1b1SMichael Neumann return r;
200f43cf1b1SMichael Neumann }
201f43cf1b1SMichael Neumann
202926deccbSFrançois Tigeot rs600_irq_set(rdev);
203926deccbSFrançois Tigeot rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);
204926deccbSFrançois Tigeot /* 1M ring buffer */
205926deccbSFrançois Tigeot r = r100_cp_init(rdev, 1024 * 1024);
206926deccbSFrançois Tigeot if (r) {
207926deccbSFrançois Tigeot dev_err(rdev->dev, "failed initializing CP (%d).\n", r);
208926deccbSFrançois Tigeot return r;
209926deccbSFrançois Tigeot }
210926deccbSFrançois Tigeot
211926deccbSFrançois Tigeot r = radeon_ib_pool_init(rdev);
212926deccbSFrançois Tigeot if (r) {
213926deccbSFrançois Tigeot dev_err(rdev->dev, "IB initialization failed (%d).\n", r);
214926deccbSFrançois Tigeot return r;
215926deccbSFrançois Tigeot }
216926deccbSFrançois Tigeot
217926deccbSFrançois Tigeot return 0;
218926deccbSFrançois Tigeot }
219926deccbSFrançois Tigeot
r520_resume(struct radeon_device * rdev)220926deccbSFrançois Tigeot int r520_resume(struct radeon_device *rdev)
221926deccbSFrançois Tigeot {
222926deccbSFrançois Tigeot int r;
223926deccbSFrançois Tigeot
224926deccbSFrançois Tigeot /* Make sur GART are not working */
225926deccbSFrançois Tigeot if (rdev->flags & RADEON_IS_PCIE)
226926deccbSFrançois Tigeot rv370_pcie_gart_disable(rdev);
227926deccbSFrançois Tigeot /* Resume clock before doing reset */
228926deccbSFrançois Tigeot rv515_clock_startup(rdev);
229926deccbSFrançois Tigeot /* Reset gpu before posting otherwise ATOM will enter infinite loop */
230926deccbSFrançois Tigeot if (radeon_asic_reset(rdev)) {
231926deccbSFrançois Tigeot dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n",
232926deccbSFrançois Tigeot RREG32(R_000E40_RBBM_STATUS),
233926deccbSFrançois Tigeot RREG32(R_0007C0_CP_STAT));
234926deccbSFrançois Tigeot }
235926deccbSFrançois Tigeot /* post */
236926deccbSFrançois Tigeot atom_asic_init(rdev->mode_info.atom_context);
237926deccbSFrançois Tigeot /* Resume clock after posting */
238926deccbSFrançois Tigeot rv515_clock_startup(rdev);
239926deccbSFrançois Tigeot /* Initialize surface registers */
240926deccbSFrançois Tigeot radeon_surface_init(rdev);
241926deccbSFrançois Tigeot
242926deccbSFrançois Tigeot rdev->accel_working = true;
243926deccbSFrançois Tigeot r = r520_startup(rdev);
244926deccbSFrançois Tigeot if (r) {
245926deccbSFrançois Tigeot rdev->accel_working = false;
246926deccbSFrançois Tigeot }
247926deccbSFrançois Tigeot return r;
248926deccbSFrançois Tigeot }
249926deccbSFrançois Tigeot
r520_init(struct radeon_device * rdev)250926deccbSFrançois Tigeot int r520_init(struct radeon_device *rdev)
251926deccbSFrançois Tigeot {
252926deccbSFrançois Tigeot int r;
253926deccbSFrançois Tigeot
254926deccbSFrançois Tigeot /* Initialize scratch registers */
255926deccbSFrançois Tigeot radeon_scratch_init(rdev);
256926deccbSFrançois Tigeot /* Initialize surface registers */
257926deccbSFrançois Tigeot radeon_surface_init(rdev);
258926deccbSFrançois Tigeot /* restore some register to sane defaults */
259926deccbSFrançois Tigeot r100_restore_sanity(rdev);
260926deccbSFrançois Tigeot /* TODO: disable VGA need to use VGA request */
261926deccbSFrançois Tigeot /* BIOS*/
262926deccbSFrançois Tigeot if (!radeon_get_bios(rdev)) {
263926deccbSFrançois Tigeot if (ASIC_IS_AVIVO(rdev))
264926deccbSFrançois Tigeot return -EINVAL;
265926deccbSFrançois Tigeot }
266926deccbSFrançois Tigeot if (rdev->is_atom_bios) {
267926deccbSFrançois Tigeot r = radeon_atombios_init(rdev);
268926deccbSFrançois Tigeot if (r)
269926deccbSFrançois Tigeot return r;
270926deccbSFrançois Tigeot } else {
271926deccbSFrançois Tigeot dev_err(rdev->dev, "Expecting atombios for RV515 GPU\n");
272926deccbSFrançois Tigeot return -EINVAL;
273926deccbSFrançois Tigeot }
274926deccbSFrançois Tigeot /* Reset gpu before posting otherwise ATOM will enter infinite loop */
275926deccbSFrançois Tigeot if (radeon_asic_reset(rdev)) {
276926deccbSFrançois Tigeot dev_warn(rdev->dev,
277926deccbSFrançois Tigeot "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n",
278926deccbSFrançois Tigeot RREG32(R_000E40_RBBM_STATUS),
279926deccbSFrançois Tigeot RREG32(R_0007C0_CP_STAT));
280926deccbSFrançois Tigeot }
281926deccbSFrançois Tigeot /* check if cards are posted or not */
282926deccbSFrançois Tigeot if (radeon_boot_test_post_card(rdev) == false)
283926deccbSFrançois Tigeot return -EINVAL;
284926deccbSFrançois Tigeot
285926deccbSFrançois Tigeot if (!radeon_card_posted(rdev) && rdev->bios) {
286926deccbSFrançois Tigeot DRM_INFO("GPU not posted. posting now...\n");
287926deccbSFrançois Tigeot atom_asic_init(rdev->mode_info.atom_context);
288926deccbSFrançois Tigeot }
289926deccbSFrançois Tigeot /* Initialize clocks */
290926deccbSFrançois Tigeot radeon_get_clock_info(rdev->ddev);
291926deccbSFrançois Tigeot /* initialize AGP */
292926deccbSFrançois Tigeot if (rdev->flags & RADEON_IS_AGP) {
293926deccbSFrançois Tigeot r = radeon_agp_init(rdev);
294926deccbSFrançois Tigeot if (r) {
295926deccbSFrançois Tigeot radeon_agp_disable(rdev);
296926deccbSFrançois Tigeot }
297926deccbSFrançois Tigeot }
298926deccbSFrançois Tigeot /* initialize memory controller */
299926deccbSFrançois Tigeot r520_mc_init(rdev);
300926deccbSFrançois Tigeot rv515_debugfs(rdev);
301926deccbSFrançois Tigeot /* Fence driver */
302926deccbSFrançois Tigeot r = radeon_fence_driver_init(rdev);
303926deccbSFrançois Tigeot if (r)
304926deccbSFrançois Tigeot return r;
305926deccbSFrançois Tigeot /* Memory manager */
306926deccbSFrançois Tigeot r = radeon_bo_init(rdev);
307926deccbSFrançois Tigeot if (r)
308926deccbSFrançois Tigeot return r;
309926deccbSFrançois Tigeot r = rv370_pcie_gart_init(rdev);
310926deccbSFrançois Tigeot if (r)
311926deccbSFrançois Tigeot return r;
312926deccbSFrançois Tigeot rv515_set_safe_registers(rdev);
313926deccbSFrançois Tigeot
314c6f73aabSFrançois Tigeot /* Initialize power management */
315c6f73aabSFrançois Tigeot radeon_pm_init(rdev);
316c6f73aabSFrançois Tigeot
317926deccbSFrançois Tigeot rdev->accel_working = true;
318926deccbSFrançois Tigeot r = r520_startup(rdev);
319926deccbSFrançois Tigeot if (r) {
320926deccbSFrançois Tigeot /* Somethings want wront with the accel init stop accel */
321926deccbSFrançois Tigeot dev_err(rdev->dev, "Disabling GPU acceleration\n");
322926deccbSFrançois Tigeot r100_cp_fini(rdev);
323926deccbSFrançois Tigeot radeon_wb_fini(rdev);
324926deccbSFrançois Tigeot radeon_ib_pool_fini(rdev);
325926deccbSFrançois Tigeot radeon_irq_kms_fini(rdev);
326926deccbSFrançois Tigeot rv370_pcie_gart_fini(rdev);
327926deccbSFrançois Tigeot radeon_agp_fini(rdev);
328926deccbSFrançois Tigeot rdev->accel_working = false;
329926deccbSFrançois Tigeot }
330926deccbSFrançois Tigeot return 0;
331926deccbSFrançois Tigeot }
332