xref: /dflybsd-src/sys/dev/drm/radeon/radeon_device.c (revision 1cfef1a587a371344cf93e80367482432b0933a2)
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  * $FreeBSD: head/sys/dev/drm2/radeon/radeon_device.c 255573 2013-09-14 17:24:41Z dumbbell $
29926deccbSFrançois Tigeot  */
30926deccbSFrançois Tigeot #include <drm/drmP.h>
314250aa95Szrj #include "drm/drm_legacy.h"		/* for drm_dma_handle_t */
32926deccbSFrançois Tigeot #include <drm/drm_crtc_helper.h>
3383b4b9b9SFrançois Tigeot #include <drm/radeon_drm.h>
3457e252bfSMichael Neumann #include <asm/io.h>
35926deccbSFrançois Tigeot #include "radeon_reg.h"
36926deccbSFrançois Tigeot #include "radeon.h"
37926deccbSFrançois Tigeot #include "atom.h"
38926deccbSFrançois Tigeot 
39926deccbSFrançois Tigeot static const char radeon_family_name[][16] = {
40926deccbSFrançois Tigeot 	"R100",
41926deccbSFrançois Tigeot 	"RV100",
42926deccbSFrançois Tigeot 	"RS100",
43926deccbSFrançois Tigeot 	"RV200",
44926deccbSFrançois Tigeot 	"RS200",
45926deccbSFrançois Tigeot 	"R200",
46926deccbSFrançois Tigeot 	"RV250",
47926deccbSFrançois Tigeot 	"RS300",
48926deccbSFrançois Tigeot 	"RV280",
49926deccbSFrançois Tigeot 	"R300",
50926deccbSFrançois Tigeot 	"R350",
51926deccbSFrançois Tigeot 	"RV350",
52926deccbSFrançois Tigeot 	"RV380",
53926deccbSFrançois Tigeot 	"R420",
54926deccbSFrançois Tigeot 	"R423",
55926deccbSFrançois Tigeot 	"RV410",
56926deccbSFrançois Tigeot 	"RS400",
57926deccbSFrançois Tigeot 	"RS480",
58926deccbSFrançois Tigeot 	"RS600",
59926deccbSFrançois Tigeot 	"RS690",
60926deccbSFrançois Tigeot 	"RS740",
61926deccbSFrançois Tigeot 	"RV515",
62926deccbSFrançois Tigeot 	"R520",
63926deccbSFrançois Tigeot 	"RV530",
64926deccbSFrançois Tigeot 	"RV560",
65926deccbSFrançois Tigeot 	"RV570",
66926deccbSFrançois Tigeot 	"R580",
67926deccbSFrançois Tigeot 	"R600",
68926deccbSFrançois Tigeot 	"RV610",
69926deccbSFrançois Tigeot 	"RV630",
70926deccbSFrançois Tigeot 	"RV670",
71926deccbSFrançois Tigeot 	"RV620",
72926deccbSFrançois Tigeot 	"RV635",
73926deccbSFrançois Tigeot 	"RS780",
74926deccbSFrançois Tigeot 	"RS880",
75926deccbSFrançois Tigeot 	"RV770",
76926deccbSFrançois Tigeot 	"RV730",
77926deccbSFrançois Tigeot 	"RV710",
78926deccbSFrançois Tigeot 	"RV740",
79926deccbSFrançois Tigeot 	"CEDAR",
80926deccbSFrançois Tigeot 	"REDWOOD",
81926deccbSFrançois Tigeot 	"JUNIPER",
82926deccbSFrançois Tigeot 	"CYPRESS",
83926deccbSFrançois Tigeot 	"HEMLOCK",
84926deccbSFrançois Tigeot 	"PALM",
85926deccbSFrançois Tigeot 	"SUMO",
86926deccbSFrançois Tigeot 	"SUMO2",
87926deccbSFrançois Tigeot 	"BARTS",
88926deccbSFrançois Tigeot 	"TURKS",
89926deccbSFrançois Tigeot 	"CAICOS",
90926deccbSFrançois Tigeot 	"CAYMAN",
91926deccbSFrançois Tigeot 	"ARUBA",
92926deccbSFrançois Tigeot 	"TAHITI",
93926deccbSFrançois Tigeot 	"PITCAIRN",
94926deccbSFrançois Tigeot 	"VERDE",
95b403bed8SMichael Neumann 	"OLAND",
96f43cf1b1SMichael Neumann 	"HAINAN",
9757e252bfSMichael Neumann 	"BONAIRE",
9857e252bfSMichael Neumann 	"KAVERI",
9957e252bfSMichael Neumann 	"KABINI",
100c6f73aabSFrançois Tigeot 	"HAWAII",
101c6f73aabSFrançois Tigeot 	"MULLINS",
102926deccbSFrançois Tigeot 	"LAST",
103926deccbSFrançois Tigeot };
104926deccbSFrançois Tigeot 
105c6f73aabSFrançois Tigeot #define RADEON_PX_QUIRK_DISABLE_PX  (1 << 0)
106c6f73aabSFrançois Tigeot #define RADEON_PX_QUIRK_LONG_WAKEUP (1 << 1)
107c6f73aabSFrançois Tigeot 
108c6f73aabSFrançois Tigeot struct radeon_px_quirk {
109c6f73aabSFrançois Tigeot 	u32 chip_vendor;
110c6f73aabSFrançois Tigeot 	u32 chip_device;
111c6f73aabSFrançois Tigeot 	u32 subsys_vendor;
112c6f73aabSFrançois Tigeot 	u32 subsys_device;
113c6f73aabSFrançois Tigeot 	u32 px_quirk_flags;
114c6f73aabSFrançois Tigeot };
115c6f73aabSFrançois Tigeot 
116c6f73aabSFrançois Tigeot static struct radeon_px_quirk radeon_px_quirk_list[] = {
117c6f73aabSFrançois Tigeot 	/* Acer aspire 5560g (CPU: AMD A4-3305M; GPU: AMD Radeon HD 6480g + 7470m)
118c6f73aabSFrançois Tigeot 	 * https://bugzilla.kernel.org/show_bug.cgi?id=74551
119c6f73aabSFrançois Tigeot 	 */
120c6f73aabSFrançois Tigeot 	{ PCI_VENDOR_ID_ATI, 0x6760, 0x1025, 0x0672, RADEON_PX_QUIRK_DISABLE_PX },
121c6f73aabSFrançois Tigeot 	/* Asus K73TA laptop with AMD A6-3400M APU and Radeon 6550 GPU
122c6f73aabSFrançois Tigeot 	 * https://bugzilla.kernel.org/show_bug.cgi?id=51381
123c6f73aabSFrançois Tigeot 	 */
124c6f73aabSFrançois Tigeot 	{ PCI_VENDOR_ID_ATI, 0x6741, 0x1043, 0x108c, RADEON_PX_QUIRK_DISABLE_PX },
125c6f73aabSFrançois Tigeot 	/* Asus K53TK laptop with AMD A6-3420M APU and Radeon 7670m GPU
126c6f73aabSFrançois Tigeot 	 * https://bugzilla.kernel.org/show_bug.cgi?id=51381
127c6f73aabSFrançois Tigeot 	 */
128c6f73aabSFrançois Tigeot 	{ PCI_VENDOR_ID_ATI, 0x6840, 0x1043, 0x2122, RADEON_PX_QUIRK_DISABLE_PX },
129c6f73aabSFrançois Tigeot 	/* macbook pro 8.2 */
130c6f73aabSFrançois Tigeot 	{ PCI_VENDOR_ID_ATI, 0x6741, PCI_VENDOR_ID_APPLE, 0x00e2, RADEON_PX_QUIRK_LONG_WAKEUP },
131c6f73aabSFrançois Tigeot 	{ 0, 0, 0, 0, 0 },
132c6f73aabSFrançois Tigeot };
133c6f73aabSFrançois Tigeot 
134c6f73aabSFrançois Tigeot bool radeon_is_px(struct drm_device *dev)
135c6f73aabSFrançois Tigeot {
136c6f73aabSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
137c6f73aabSFrançois Tigeot 
138c6f73aabSFrançois Tigeot 	if (rdev->flags & RADEON_IS_PX)
139c6f73aabSFrançois Tigeot 		return true;
140c6f73aabSFrançois Tigeot 	return false;
141c6f73aabSFrançois Tigeot }
142c6f73aabSFrançois Tigeot 
143c6f73aabSFrançois Tigeot static void radeon_device_handle_px_quirks(struct radeon_device *rdev)
144c6f73aabSFrançois Tigeot {
145c6f73aabSFrançois Tigeot 	struct radeon_px_quirk *p = radeon_px_quirk_list;
146c6f73aabSFrançois Tigeot 
147c6f73aabSFrançois Tigeot 	/* Apply PX quirks */
148c6f73aabSFrançois Tigeot 	while (p && p->chip_device != 0) {
149c6f73aabSFrançois Tigeot 		if (rdev->pdev->vendor == p->chip_vendor &&
150c6f73aabSFrançois Tigeot 		    rdev->pdev->device == p->chip_device &&
151c6f73aabSFrançois Tigeot 		    rdev->pdev->subsystem_vendor == p->subsys_vendor &&
152c6f73aabSFrançois Tigeot 		    rdev->pdev->subsystem_device == p->subsys_device) {
153c6f73aabSFrançois Tigeot 			rdev->px_quirk_flags = p->px_quirk_flags;
154c6f73aabSFrançois Tigeot 			break;
155c6f73aabSFrançois Tigeot 		}
156c6f73aabSFrançois Tigeot 		++p;
157c6f73aabSFrançois Tigeot 	}
158c6f73aabSFrançois Tigeot 
159c6f73aabSFrançois Tigeot 	if (rdev->px_quirk_flags & RADEON_PX_QUIRK_DISABLE_PX)
160c6f73aabSFrançois Tigeot 		rdev->flags &= ~RADEON_IS_PX;
161c6f73aabSFrançois Tigeot }
162c6f73aabSFrançois Tigeot 
163926deccbSFrançois Tigeot /**
164f43cf1b1SMichael Neumann  * radeon_program_register_sequence - program an array of registers.
165f43cf1b1SMichael Neumann  *
166f43cf1b1SMichael Neumann  * @rdev: radeon_device pointer
167f43cf1b1SMichael Neumann  * @registers: pointer to the register array
168f43cf1b1SMichael Neumann  * @array_size: size of the register array
169f43cf1b1SMichael Neumann  *
170f43cf1b1SMichael Neumann  * Programs an array or registers with and and or masks.
171f43cf1b1SMichael Neumann  * This is a helper for setting golden registers.
172f43cf1b1SMichael Neumann  */
173f43cf1b1SMichael Neumann void radeon_program_register_sequence(struct radeon_device *rdev,
174f43cf1b1SMichael Neumann 				      const u32 *registers,
175f43cf1b1SMichael Neumann 				      const u32 array_size)
176f43cf1b1SMichael Neumann {
177f43cf1b1SMichael Neumann 	u32 tmp, reg, and_mask, or_mask;
178f43cf1b1SMichael Neumann 	int i;
179f43cf1b1SMichael Neumann 
180f43cf1b1SMichael Neumann 	if (array_size % 3)
181f43cf1b1SMichael Neumann 		return;
182f43cf1b1SMichael Neumann 
183f43cf1b1SMichael Neumann 	for (i = 0; i < array_size; i +=3) {
184f43cf1b1SMichael Neumann 		reg = registers[i + 0];
185f43cf1b1SMichael Neumann 		and_mask = registers[i + 1];
186f43cf1b1SMichael Neumann 		or_mask = registers[i + 2];
187f43cf1b1SMichael Neumann 
188f43cf1b1SMichael Neumann 		if (and_mask == 0xffffffff) {
189f43cf1b1SMichael Neumann 			tmp = or_mask;
190f43cf1b1SMichael Neumann 		} else {
191f43cf1b1SMichael Neumann 			tmp = RREG32(reg);
192f43cf1b1SMichael Neumann 			tmp &= ~and_mask;
193f43cf1b1SMichael Neumann 			tmp |= or_mask;
194f43cf1b1SMichael Neumann 		}
195f43cf1b1SMichael Neumann 		WREG32(reg, tmp);
196f43cf1b1SMichael Neumann 	}
197f43cf1b1SMichael Neumann }
198f43cf1b1SMichael Neumann 
199c6f73aabSFrançois Tigeot void radeon_pci_config_reset(struct radeon_device *rdev)
200c6f73aabSFrançois Tigeot {
201c6f73aabSFrançois Tigeot 	pci_write_config_dword(rdev->pdev, 0x7c, RADEON_ASIC_RESET_DATA);
202c6f73aabSFrançois Tigeot }
203c6f73aabSFrançois Tigeot 
204f43cf1b1SMichael Neumann /**
205926deccbSFrançois Tigeot  * radeon_surface_init - Clear GPU surface registers.
206926deccbSFrançois Tigeot  *
207926deccbSFrançois Tigeot  * @rdev: radeon_device pointer
208926deccbSFrançois Tigeot  *
209926deccbSFrançois Tigeot  * Clear GPU surface registers (r1xx-r5xx).
210926deccbSFrançois Tigeot  */
211926deccbSFrançois Tigeot void radeon_surface_init(struct radeon_device *rdev)
212926deccbSFrançois Tigeot {
213926deccbSFrançois Tigeot 	/* FIXME: check this out */
214926deccbSFrançois Tigeot 	if (rdev->family < CHIP_R600) {
215926deccbSFrançois Tigeot 		int i;
216926deccbSFrançois Tigeot 
217926deccbSFrançois Tigeot 		for (i = 0; i < RADEON_GEM_MAX_SURFACES; i++) {
218926deccbSFrançois Tigeot 			if (rdev->surface_regs[i].bo)
219926deccbSFrançois Tigeot 				radeon_bo_get_surface_reg(rdev->surface_regs[i].bo);
220926deccbSFrançois Tigeot 			else
221926deccbSFrançois Tigeot 				radeon_clear_surface_reg(rdev, i);
222926deccbSFrançois Tigeot 		}
223926deccbSFrançois Tigeot 		/* enable surfaces */
224926deccbSFrançois Tigeot 		WREG32(RADEON_SURFACE_CNTL, 0);
225926deccbSFrançois Tigeot 	}
226926deccbSFrançois Tigeot }
227926deccbSFrançois Tigeot 
228926deccbSFrançois Tigeot /*
229926deccbSFrançois Tigeot  * GPU scratch registers helpers function.
230926deccbSFrançois Tigeot  */
231926deccbSFrançois Tigeot /**
232926deccbSFrançois Tigeot  * radeon_scratch_init - Init scratch register driver information.
233926deccbSFrançois Tigeot  *
234926deccbSFrançois Tigeot  * @rdev: radeon_device pointer
235926deccbSFrançois Tigeot  *
236926deccbSFrançois Tigeot  * Init CP scratch register driver information (r1xx-r5xx)
237926deccbSFrançois Tigeot  */
238926deccbSFrançois Tigeot void radeon_scratch_init(struct radeon_device *rdev)
239926deccbSFrançois Tigeot {
240926deccbSFrançois Tigeot 	int i;
241926deccbSFrançois Tigeot 
242926deccbSFrançois Tigeot 	/* FIXME: check this out */
243926deccbSFrançois Tigeot 	if (rdev->family < CHIP_R300) {
244926deccbSFrançois Tigeot 		rdev->scratch.num_reg = 5;
245926deccbSFrançois Tigeot 	} else {
246926deccbSFrançois Tigeot 		rdev->scratch.num_reg = 7;
247926deccbSFrançois Tigeot 	}
248926deccbSFrançois Tigeot 	rdev->scratch.reg_base = RADEON_SCRATCH_REG0;
249926deccbSFrançois Tigeot 	for (i = 0; i < rdev->scratch.num_reg; i++) {
250926deccbSFrançois Tigeot 		rdev->scratch.free[i] = true;
251926deccbSFrançois Tigeot 		rdev->scratch.reg[i] = rdev->scratch.reg_base + (i * 4);
252926deccbSFrançois Tigeot 	}
253926deccbSFrançois Tigeot }
254926deccbSFrançois Tigeot 
255926deccbSFrançois Tigeot /**
256926deccbSFrançois Tigeot  * radeon_scratch_get - Allocate a scratch register
257926deccbSFrançois Tigeot  *
258926deccbSFrançois Tigeot  * @rdev: radeon_device pointer
259926deccbSFrançois Tigeot  * @reg: scratch register mmio offset
260926deccbSFrançois Tigeot  *
261926deccbSFrançois Tigeot  * Allocate a CP scratch register for use by the driver (all asics).
262926deccbSFrançois Tigeot  * Returns 0 on success or -EINVAL on failure.
263926deccbSFrançois Tigeot  */
264926deccbSFrançois Tigeot int radeon_scratch_get(struct radeon_device *rdev, uint32_t *reg)
265926deccbSFrançois Tigeot {
266926deccbSFrançois Tigeot 	int i;
267926deccbSFrançois Tigeot 
268926deccbSFrançois Tigeot 	for (i = 0; i < rdev->scratch.num_reg; i++) {
269926deccbSFrançois Tigeot 		if (rdev->scratch.free[i]) {
270926deccbSFrançois Tigeot 			rdev->scratch.free[i] = false;
271926deccbSFrançois Tigeot 			*reg = rdev->scratch.reg[i];
272926deccbSFrançois Tigeot 			return 0;
273926deccbSFrançois Tigeot 		}
274926deccbSFrançois Tigeot 	}
275926deccbSFrançois Tigeot 	return -EINVAL;
276926deccbSFrançois Tigeot }
277926deccbSFrançois Tigeot 
278926deccbSFrançois Tigeot /**
279926deccbSFrançois Tigeot  * radeon_scratch_free - Free a scratch register
280926deccbSFrançois Tigeot  *
281926deccbSFrançois Tigeot  * @rdev: radeon_device pointer
282926deccbSFrançois Tigeot  * @reg: scratch register mmio offset
283926deccbSFrançois Tigeot  *
284926deccbSFrançois Tigeot  * Free a CP scratch register allocated for use by the driver (all asics)
285926deccbSFrançois Tigeot  */
286926deccbSFrançois Tigeot void radeon_scratch_free(struct radeon_device *rdev, uint32_t reg)
287926deccbSFrançois Tigeot {
288926deccbSFrançois Tigeot 	int i;
289926deccbSFrançois Tigeot 
290926deccbSFrançois Tigeot 	for (i = 0; i < rdev->scratch.num_reg; i++) {
291926deccbSFrançois Tigeot 		if (rdev->scratch.reg[i] == reg) {
292926deccbSFrançois Tigeot 			rdev->scratch.free[i] = true;
293926deccbSFrançois Tigeot 			return;
294926deccbSFrançois Tigeot 		}
295926deccbSFrançois Tigeot 	}
296926deccbSFrançois Tigeot }
297926deccbSFrançois Tigeot 
298926deccbSFrançois Tigeot /*
29957e252bfSMichael Neumann  * GPU doorbell aperture helpers function.
30057e252bfSMichael Neumann  */
30157e252bfSMichael Neumann /**
30257e252bfSMichael Neumann  * radeon_doorbell_init - Init doorbell driver information.
30357e252bfSMichael Neumann  *
30457e252bfSMichael Neumann  * @rdev: radeon_device pointer
30557e252bfSMichael Neumann  *
30657e252bfSMichael Neumann  * Init doorbell driver information (CIK)
30757e252bfSMichael Neumann  * Returns 0 on success, error on failure.
30857e252bfSMichael Neumann  */
309c6f73aabSFrançois Tigeot static int radeon_doorbell_init(struct radeon_device *rdev)
31057e252bfSMichael Neumann {
31157e252bfSMichael Neumann 	/* doorbell bar mapping */
3124a26d795SImre Vadasz 	rdev->doorbell.base = pci_resource_start(rdev->pdev, 2);
3134a26d795SImre Vadasz 	rdev->doorbell.size = pci_resource_len(rdev->pdev, 2);
31457e252bfSMichael Neumann 
315c6f73aabSFrançois Tigeot 	rdev->doorbell.num_doorbells = min_t(u32, rdev->doorbell.size / sizeof(u32), RADEON_MAX_DOORBELLS);
316c6f73aabSFrançois Tigeot 	if (rdev->doorbell.num_doorbells == 0)
317c6f73aabSFrançois Tigeot 		return -EINVAL;
31857e252bfSMichael Neumann 
319c6f73aabSFrançois Tigeot 	rdev->doorbell.ptr = ioremap(rdev->doorbell.base, rdev->doorbell.num_doorbells * sizeof(u32));
32057e252bfSMichael Neumann 	if (rdev->doorbell.ptr == NULL) {
32157e252bfSMichael Neumann 		return -ENOMEM;
32257e252bfSMichael Neumann 	}
32357e252bfSMichael Neumann 	DRM_INFO("doorbell mmio base: 0x%08X\n", (uint32_t)rdev->doorbell.base);
32457e252bfSMichael Neumann 	DRM_INFO("doorbell mmio size: %u\n", (unsigned)rdev->doorbell.size);
32557e252bfSMichael Neumann 
326c6f73aabSFrançois Tigeot 	memset(&rdev->doorbell.used, 0, sizeof(rdev->doorbell.used));
32757e252bfSMichael Neumann 
32857e252bfSMichael Neumann 	return 0;
32957e252bfSMichael Neumann }
33057e252bfSMichael Neumann 
33157e252bfSMichael Neumann /**
33257e252bfSMichael Neumann  * radeon_doorbell_fini - Tear down doorbell driver information.
33357e252bfSMichael Neumann  *
33457e252bfSMichael Neumann  * @rdev: radeon_device pointer
33557e252bfSMichael Neumann  *
33657e252bfSMichael Neumann  * Tear down doorbell driver information (CIK)
33757e252bfSMichael Neumann  */
338c6f73aabSFrançois Tigeot static void radeon_doorbell_fini(struct radeon_device *rdev)
33957e252bfSMichael Neumann {
34024409b39SFrançois Tigeot 	iounmap(rdev->doorbell.ptr);
34157e252bfSMichael Neumann 	rdev->doorbell.ptr = NULL;
34257e252bfSMichael Neumann }
34357e252bfSMichael Neumann 
34457e252bfSMichael Neumann /**
345c6f73aabSFrançois Tigeot  * radeon_doorbell_get - Allocate a doorbell entry
34657e252bfSMichael Neumann  *
34757e252bfSMichael Neumann  * @rdev: radeon_device pointer
348c6f73aabSFrançois Tigeot  * @doorbell: doorbell index
34957e252bfSMichael Neumann  *
350c6f73aabSFrançois Tigeot  * Allocate a doorbell for use by the driver (all asics).
35157e252bfSMichael Neumann  * Returns 0 on success or -EINVAL on failure.
35257e252bfSMichael Neumann  */
35357e252bfSMichael Neumann int radeon_doorbell_get(struct radeon_device *rdev, u32 *doorbell)
35457e252bfSMichael Neumann {
355c6f73aabSFrançois Tigeot 	unsigned long offset = find_first_zero_bit(rdev->doorbell.used, rdev->doorbell.num_doorbells);
356c6f73aabSFrançois Tigeot 	if (offset < rdev->doorbell.num_doorbells) {
357c6f73aabSFrançois Tigeot 		__set_bit(offset, rdev->doorbell.used);
358c6f73aabSFrançois Tigeot 		*doorbell = offset;
35957e252bfSMichael Neumann 		return 0;
360c6f73aabSFrançois Tigeot 	} else {
36157e252bfSMichael Neumann 		return -EINVAL;
36257e252bfSMichael Neumann 	}
363c6f73aabSFrançois Tigeot }
36457e252bfSMichael Neumann 
36557e252bfSMichael Neumann /**
366c6f73aabSFrançois Tigeot  * radeon_doorbell_free - Free a doorbell entry
36757e252bfSMichael Neumann  *
36857e252bfSMichael Neumann  * @rdev: radeon_device pointer
369c6f73aabSFrançois Tigeot  * @doorbell: doorbell index
37057e252bfSMichael Neumann  *
371c6f73aabSFrançois Tigeot  * Free a doorbell allocated for use by the driver (all asics)
37257e252bfSMichael Neumann  */
37357e252bfSMichael Neumann void radeon_doorbell_free(struct radeon_device *rdev, u32 doorbell)
37457e252bfSMichael Neumann {
375c6f73aabSFrançois Tigeot 	if (doorbell < rdev->doorbell.num_doorbells)
376c6f73aabSFrançois Tigeot 		__clear_bit(doorbell, rdev->doorbell.used);
37757e252bfSMichael Neumann }
37857e252bfSMichael Neumann 
37957e252bfSMichael Neumann /*
380926deccbSFrançois Tigeot  * radeon_wb_*()
381926deccbSFrançois Tigeot  * Writeback is the the method by which the the GPU updates special pages
382926deccbSFrançois Tigeot  * in memory with the status of certain GPU events (fences, ring pointers,
383926deccbSFrançois Tigeot  * etc.).
384926deccbSFrançois Tigeot  */
385926deccbSFrançois Tigeot 
386926deccbSFrançois Tigeot /**
387926deccbSFrançois Tigeot  * radeon_wb_disable - Disable Writeback
388926deccbSFrançois Tigeot  *
389926deccbSFrançois Tigeot  * @rdev: radeon_device pointer
390926deccbSFrançois Tigeot  *
391926deccbSFrançois Tigeot  * Disables Writeback (all asics).  Used for suspend.
392926deccbSFrançois Tigeot  */
393926deccbSFrançois Tigeot void radeon_wb_disable(struct radeon_device *rdev)
394926deccbSFrançois Tigeot {
395926deccbSFrançois Tigeot 	rdev->wb.enabled = false;
396926deccbSFrançois Tigeot }
397926deccbSFrançois Tigeot 
398926deccbSFrançois Tigeot /**
399926deccbSFrançois Tigeot  * radeon_wb_fini - Disable Writeback and free memory
400926deccbSFrançois Tigeot  *
401926deccbSFrançois Tigeot  * @rdev: radeon_device pointer
402926deccbSFrançois Tigeot  *
403926deccbSFrançois Tigeot  * Disables Writeback and frees the Writeback memory (all asics).
404926deccbSFrançois Tigeot  * Used at driver shutdown.
405926deccbSFrançois Tigeot  */
406926deccbSFrançois Tigeot void radeon_wb_fini(struct radeon_device *rdev)
407926deccbSFrançois Tigeot {
408926deccbSFrançois Tigeot 	radeon_wb_disable(rdev);
409926deccbSFrançois Tigeot 	if (rdev->wb.wb_obj) {
410f43cf1b1SMichael Neumann 		if (!radeon_bo_reserve(rdev->wb.wb_obj, false)) {
411f43cf1b1SMichael Neumann 			radeon_bo_kunmap(rdev->wb.wb_obj);
412f43cf1b1SMichael Neumann 			radeon_bo_unpin(rdev->wb.wb_obj);
413f43cf1b1SMichael Neumann 			radeon_bo_unreserve(rdev->wb.wb_obj);
414f43cf1b1SMichael Neumann 		}
415926deccbSFrançois Tigeot 		radeon_bo_unref(&rdev->wb.wb_obj);
416926deccbSFrançois Tigeot 		rdev->wb.wb = NULL;
417926deccbSFrançois Tigeot 		rdev->wb.wb_obj = NULL;
418926deccbSFrançois Tigeot 	}
419926deccbSFrançois Tigeot }
420926deccbSFrançois Tigeot 
421926deccbSFrançois Tigeot /**
422926deccbSFrançois Tigeot  * radeon_wb_init- Init Writeback driver info and allocate memory
423926deccbSFrançois Tigeot  *
424926deccbSFrançois Tigeot  * @rdev: radeon_device pointer
425926deccbSFrançois Tigeot  *
426926deccbSFrançois Tigeot  * Disables Writeback and frees the Writeback memory (all asics).
427926deccbSFrançois Tigeot  * Used at driver startup.
428926deccbSFrançois Tigeot  * Returns 0 on success or an -error on failure.
429926deccbSFrançois Tigeot  */
430926deccbSFrançois Tigeot int radeon_wb_init(struct radeon_device *rdev)
431926deccbSFrançois Tigeot {
432926deccbSFrançois Tigeot 	int r;
433926deccbSFrançois Tigeot 	void *wb_ptr;
434926deccbSFrançois Tigeot 
435926deccbSFrançois Tigeot 	if (rdev->wb.wb_obj == NULL) {
436926deccbSFrançois Tigeot 		r = radeon_bo_create(rdev, RADEON_GPU_PAGE_SIZE, PAGE_SIZE, true,
437c6f73aabSFrançois Tigeot 				     RADEON_GEM_DOMAIN_GTT, 0, NULL,
438c6f73aabSFrançois Tigeot 				     &rdev->wb.wb_obj);
439926deccbSFrançois Tigeot 		if (r) {
440926deccbSFrançois Tigeot 			dev_warn(rdev->dev, "(%d) create WB bo failed\n", r);
441926deccbSFrançois Tigeot 			return r;
442926deccbSFrançois Tigeot 		}
443926deccbSFrançois Tigeot 		r = radeon_bo_reserve(rdev->wb.wb_obj, false);
444926deccbSFrançois Tigeot 		if (unlikely(r != 0)) {
445926deccbSFrançois Tigeot 			radeon_wb_fini(rdev);
446926deccbSFrançois Tigeot 			return r;
447926deccbSFrançois Tigeot 		}
448926deccbSFrançois Tigeot 		r = radeon_bo_pin(rdev->wb.wb_obj, RADEON_GEM_DOMAIN_GTT,
449f77dbd6cSFrançois Tigeot 				(u64 *)&rdev->wb.gpu_addr);
450926deccbSFrançois Tigeot 		if (r) {
451926deccbSFrançois Tigeot 			radeon_bo_unreserve(rdev->wb.wb_obj);
452926deccbSFrançois Tigeot 			dev_warn(rdev->dev, "(%d) pin WB bo failed\n", r);
453926deccbSFrançois Tigeot 			radeon_wb_fini(rdev);
454926deccbSFrançois Tigeot 			return r;
455926deccbSFrançois Tigeot 		}
456926deccbSFrançois Tigeot 		wb_ptr = &rdev->wb.wb;
457926deccbSFrançois Tigeot 		r = radeon_bo_kmap(rdev->wb.wb_obj, wb_ptr);
458926deccbSFrançois Tigeot 		radeon_bo_unreserve(rdev->wb.wb_obj);
459926deccbSFrançois Tigeot 		if (r) {
460926deccbSFrançois Tigeot 			dev_warn(rdev->dev, "(%d) map WB bo failed\n", r);
461926deccbSFrançois Tigeot 			radeon_wb_fini(rdev);
462926deccbSFrançois Tigeot 			return r;
463926deccbSFrançois Tigeot 		}
464ee479021SImre Vadász 		/* clear wb memory */
465ee479021SImre Vadász 		memset(*(void **)wb_ptr, 0, RADEON_GPU_PAGE_SIZE);
466f43cf1b1SMichael Neumann 	}
467f43cf1b1SMichael Neumann 
468926deccbSFrançois Tigeot 	/* disable event_write fences */
469926deccbSFrançois Tigeot 	rdev->wb.use_event = false;
470926deccbSFrançois Tigeot 	/* disabled via module param */
471926deccbSFrançois Tigeot 	if (radeon_no_wb == 1) {
472926deccbSFrançois Tigeot 		rdev->wb.enabled = false;
473926deccbSFrançois Tigeot 	} else {
474926deccbSFrançois Tigeot 		if (rdev->flags & RADEON_IS_AGP) {
475926deccbSFrançois Tigeot 			/* often unreliable on AGP */
476926deccbSFrançois Tigeot 			rdev->wb.enabled = false;
477926deccbSFrançois Tigeot 		} else if (rdev->family < CHIP_R300) {
478926deccbSFrançois Tigeot 			/* often unreliable on pre-r300 */
479926deccbSFrançois Tigeot 			rdev->wb.enabled = false;
480926deccbSFrançois Tigeot 		} else {
481926deccbSFrançois Tigeot 			rdev->wb.enabled = true;
482926deccbSFrançois Tigeot 			/* event_write fences are only available on r600+ */
483926deccbSFrançois Tigeot 			if (rdev->family >= CHIP_R600) {
484926deccbSFrançois Tigeot 				rdev->wb.use_event = true;
485926deccbSFrançois Tigeot 			}
486926deccbSFrançois Tigeot 		}
487926deccbSFrançois Tigeot 	}
488926deccbSFrançois Tigeot 	/* always use writeback/events on NI, APUs */
489926deccbSFrançois Tigeot 	if (rdev->family >= CHIP_PALM) {
490926deccbSFrançois Tigeot 		rdev->wb.enabled = true;
491926deccbSFrançois Tigeot 		rdev->wb.use_event = true;
492926deccbSFrançois Tigeot 	}
493926deccbSFrançois Tigeot 
494926deccbSFrançois Tigeot 	dev_info(rdev->dev, "WB %sabled\n", rdev->wb.enabled ? "en" : "dis");
495926deccbSFrançois Tigeot 
496926deccbSFrançois Tigeot 	return 0;
497926deccbSFrançois Tigeot }
498926deccbSFrançois Tigeot 
499926deccbSFrançois Tigeot /**
500926deccbSFrançois Tigeot  * radeon_vram_location - try to find VRAM location
501926deccbSFrançois Tigeot  * @rdev: radeon device structure holding all necessary informations
502926deccbSFrançois Tigeot  * @mc: memory controller structure holding memory informations
503926deccbSFrançois Tigeot  * @base: base address at which to put VRAM
504926deccbSFrançois Tigeot  *
505926deccbSFrançois Tigeot  * Function will place try to place VRAM at base address provided
506926deccbSFrançois Tigeot  * as parameter (which is so far either PCI aperture address or
507926deccbSFrançois Tigeot  * for IGP TOM base address).
508926deccbSFrançois Tigeot  *
509926deccbSFrançois Tigeot  * If there is not enough space to fit the unvisible VRAM in the 32bits
510926deccbSFrançois Tigeot  * address space then we limit the VRAM size to the aperture.
511926deccbSFrançois Tigeot  *
512926deccbSFrançois Tigeot  * If we are using AGP and if the AGP aperture doesn't allow us to have
513926deccbSFrançois Tigeot  * room for all the VRAM than we restrict the VRAM to the PCI aperture
514926deccbSFrançois Tigeot  * size and print a warning.
515926deccbSFrançois Tigeot  *
516926deccbSFrançois Tigeot  * This function will never fails, worst case are limiting VRAM.
517926deccbSFrançois Tigeot  *
518926deccbSFrançois Tigeot  * Note: GTT start, end, size should be initialized before calling this
519926deccbSFrançois Tigeot  * function on AGP platform.
520926deccbSFrançois Tigeot  *
521926deccbSFrançois Tigeot  * Note: We don't explicitly enforce VRAM start to be aligned on VRAM size,
522926deccbSFrançois Tigeot  * this shouldn't be a problem as we are using the PCI aperture as a reference.
523926deccbSFrançois Tigeot  * Otherwise this would be needed for rv280, all r3xx, and all r4xx, but
524926deccbSFrançois Tigeot  * not IGP.
525926deccbSFrançois Tigeot  *
526926deccbSFrançois Tigeot  * Note: we use mc_vram_size as on some board we need to program the mc to
527926deccbSFrançois Tigeot  * cover the whole aperture even if VRAM size is inferior to aperture size
528926deccbSFrançois Tigeot  * Novell bug 204882 + along with lots of ubuntu ones
529926deccbSFrançois Tigeot  *
530926deccbSFrançois Tigeot  * Note: when limiting vram it's safe to overwritte real_vram_size because
531926deccbSFrançois Tigeot  * we are not in case where real_vram_size is inferior to mc_vram_size (ie
532926deccbSFrançois Tigeot  * note afected by bogus hw of Novell bug 204882 + along with lots of ubuntu
533926deccbSFrançois Tigeot  * ones)
534926deccbSFrançois Tigeot  *
535926deccbSFrançois Tigeot  * Note: IGP TOM addr should be the same as the aperture addr, we don't
536926deccbSFrançois Tigeot  * explicitly check for that thought.
537926deccbSFrançois Tigeot  *
538926deccbSFrançois Tigeot  * FIXME: when reducing VRAM size align new size on power of 2.
539926deccbSFrançois Tigeot  */
540926deccbSFrançois Tigeot void radeon_vram_location(struct radeon_device *rdev, struct radeon_mc *mc, u64 base)
541926deccbSFrançois Tigeot {
542926deccbSFrançois Tigeot 	uint64_t limit = (uint64_t)radeon_vram_limit << 20;
543926deccbSFrançois Tigeot 
544926deccbSFrançois Tigeot 	mc->vram_start = base;
545f43cf1b1SMichael Neumann 	if (mc->mc_vram_size > (rdev->mc.mc_mask - base + 1)) {
546926deccbSFrançois Tigeot 		dev_warn(rdev->dev, "limiting VRAM to PCI aperture size\n");
547926deccbSFrançois Tigeot 		mc->real_vram_size = mc->aper_size;
548926deccbSFrançois Tigeot 		mc->mc_vram_size = mc->aper_size;
549926deccbSFrançois Tigeot 	}
550926deccbSFrançois Tigeot 	mc->vram_end = mc->vram_start + mc->mc_vram_size - 1;
551926deccbSFrançois Tigeot 	if (rdev->flags & RADEON_IS_AGP && mc->vram_end > mc->gtt_start && mc->vram_start <= mc->gtt_end) {
552926deccbSFrançois Tigeot 		dev_warn(rdev->dev, "limiting VRAM to PCI aperture size\n");
553926deccbSFrançois Tigeot 		mc->real_vram_size = mc->aper_size;
554926deccbSFrançois Tigeot 		mc->mc_vram_size = mc->aper_size;
555926deccbSFrançois Tigeot 	}
556926deccbSFrançois Tigeot 	mc->vram_end = mc->vram_start + mc->mc_vram_size - 1;
557926deccbSFrançois Tigeot 	if (limit && limit < mc->real_vram_size)
558926deccbSFrançois Tigeot 		mc->real_vram_size = limit;
559f77dbd6cSFrançois Tigeot 	dev_info(rdev->dev, "VRAM: %lluM 0x%016llX - 0x%016llX (%lluM used)\n",
5604cd92098Szrj 			mc->mc_vram_size >> 20, mc->vram_start,
5614cd92098Szrj 			mc->vram_end, mc->real_vram_size >> 20);
562926deccbSFrançois Tigeot }
563926deccbSFrançois Tigeot 
564926deccbSFrançois Tigeot /**
565926deccbSFrançois Tigeot  * radeon_gtt_location - try to find GTT location
566926deccbSFrançois Tigeot  * @rdev: radeon device structure holding all necessary informations
567926deccbSFrançois Tigeot  * @mc: memory controller structure holding memory informations
568926deccbSFrançois Tigeot  *
569926deccbSFrançois Tigeot  * Function will place try to place GTT before or after VRAM.
570926deccbSFrançois Tigeot  *
571926deccbSFrançois Tigeot  * If GTT size is bigger than space left then we ajust GTT size.
572926deccbSFrançois Tigeot  * Thus function will never fails.
573926deccbSFrançois Tigeot  *
574926deccbSFrançois Tigeot  * FIXME: when reducing GTT size align new size on power of 2.
575926deccbSFrançois Tigeot  */
576926deccbSFrançois Tigeot void radeon_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc)
577926deccbSFrançois Tigeot {
578926deccbSFrançois Tigeot 	u64 size_af, size_bf;
579926deccbSFrançois Tigeot 
580f43cf1b1SMichael Neumann 	size_af = ((rdev->mc.mc_mask - mc->vram_end) + mc->gtt_base_align) & ~mc->gtt_base_align;
581926deccbSFrançois Tigeot 	size_bf = mc->vram_start & ~mc->gtt_base_align;
582926deccbSFrançois Tigeot 	if (size_bf > size_af) {
583926deccbSFrançois Tigeot 		if (mc->gtt_size > size_bf) {
584926deccbSFrançois Tigeot 			dev_warn(rdev->dev, "limiting GTT\n");
585926deccbSFrançois Tigeot 			mc->gtt_size = size_bf;
586926deccbSFrançois Tigeot 		}
587926deccbSFrançois Tigeot 		mc->gtt_start = (mc->vram_start & ~mc->gtt_base_align) - mc->gtt_size;
588926deccbSFrançois Tigeot 	} else {
589926deccbSFrançois Tigeot 		if (mc->gtt_size > size_af) {
590926deccbSFrançois Tigeot 			dev_warn(rdev->dev, "limiting GTT\n");
591926deccbSFrançois Tigeot 			mc->gtt_size = size_af;
592926deccbSFrançois Tigeot 		}
593926deccbSFrançois Tigeot 		mc->gtt_start = (mc->vram_end + 1 + mc->gtt_base_align) & ~mc->gtt_base_align;
594926deccbSFrançois Tigeot 	}
595926deccbSFrançois Tigeot 	mc->gtt_end = mc->gtt_start + mc->gtt_size - 1;
596f77dbd6cSFrançois Tigeot 	dev_info(rdev->dev, "GTT: %lluM 0x%016llX - 0x%016llX\n",
5974cd92098Szrj 			mc->gtt_size >> 20, mc->gtt_start, mc->gtt_end);
598926deccbSFrançois Tigeot }
599926deccbSFrançois Tigeot 
600926deccbSFrançois Tigeot /*
601926deccbSFrançois Tigeot  * GPU helpers function.
602926deccbSFrançois Tigeot  */
603926deccbSFrançois Tigeot /**
604926deccbSFrançois Tigeot  * radeon_card_posted - check if the hw has already been initialized
605926deccbSFrançois Tigeot  *
606926deccbSFrançois Tigeot  * @rdev: radeon_device pointer
607926deccbSFrançois Tigeot  *
608926deccbSFrançois Tigeot  * Check if the asic has been initialized (all asics).
609926deccbSFrançois Tigeot  * Used at driver startup.
610926deccbSFrançois Tigeot  * Returns true if initialized or false if not.
611926deccbSFrançois Tigeot  */
612926deccbSFrançois Tigeot bool radeon_card_posted(struct radeon_device *rdev)
613926deccbSFrançois Tigeot {
614926deccbSFrançois Tigeot 	uint32_t reg;
615926deccbSFrançois Tigeot 
616926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP
617f43cf1b1SMichael Neumann 	/* required for EFI mode on macbook2,1 which uses an r5xx asic */
618926deccbSFrançois Tigeot 	if (efi_enabled(EFI_BOOT) &&
619c6f73aabSFrançois Tigeot 	    (rdev->pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE) &&
620f43cf1b1SMichael Neumann 	    (rdev->family < CHIP_R600))
621926deccbSFrançois Tigeot 		return false;
622926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */
623926deccbSFrançois Tigeot 
624f43cf1b1SMichael Neumann 	if (ASIC_IS_NODCE(rdev))
625f43cf1b1SMichael Neumann 		goto check_memsize;
626f43cf1b1SMichael Neumann 
627926deccbSFrançois Tigeot 	/* first check CRTCs */
628f43cf1b1SMichael Neumann 	if (ASIC_IS_DCE4(rdev)) {
629926deccbSFrançois Tigeot 		reg = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET) |
630926deccbSFrançois Tigeot 			RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET);
631f43cf1b1SMichael Neumann 			if (rdev->num_crtc >= 4) {
632f43cf1b1SMichael Neumann 				reg |= RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET) |
633f43cf1b1SMichael Neumann 					RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET);
634f43cf1b1SMichael Neumann 			}
635f43cf1b1SMichael Neumann 			if (rdev->num_crtc >= 6) {
636f43cf1b1SMichael Neumann 				reg |= RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET) |
637926deccbSFrançois Tigeot 					RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET);
638f43cf1b1SMichael Neumann 			}
639926deccbSFrançois Tigeot 		if (reg & EVERGREEN_CRTC_MASTER_EN)
640926deccbSFrançois Tigeot 			return true;
641926deccbSFrançois Tigeot 	} else if (ASIC_IS_AVIVO(rdev)) {
642926deccbSFrançois Tigeot 		reg = RREG32(AVIVO_D1CRTC_CONTROL) |
643926deccbSFrançois Tigeot 		      RREG32(AVIVO_D2CRTC_CONTROL);
644926deccbSFrançois Tigeot 		if (reg & AVIVO_CRTC_EN) {
645926deccbSFrançois Tigeot 			return true;
646926deccbSFrançois Tigeot 		}
647926deccbSFrançois Tigeot 	} else {
648926deccbSFrançois Tigeot 		reg = RREG32(RADEON_CRTC_GEN_CNTL) |
649926deccbSFrançois Tigeot 		      RREG32(RADEON_CRTC2_GEN_CNTL);
650926deccbSFrançois Tigeot 		if (reg & RADEON_CRTC_EN) {
651926deccbSFrançois Tigeot 			return true;
652926deccbSFrançois Tigeot 		}
653926deccbSFrançois Tigeot 	}
654926deccbSFrançois Tigeot 
655f43cf1b1SMichael Neumann check_memsize:
656926deccbSFrançois Tigeot 	/* then check MEM_SIZE, in case the crtcs are off */
657926deccbSFrançois Tigeot 	if (rdev->family >= CHIP_R600)
658926deccbSFrançois Tigeot 		reg = RREG32(R600_CONFIG_MEMSIZE);
659926deccbSFrançois Tigeot 	else
660926deccbSFrançois Tigeot 		reg = RREG32(RADEON_CONFIG_MEMSIZE);
661926deccbSFrançois Tigeot 
662926deccbSFrançois Tigeot 	if (reg)
663926deccbSFrançois Tigeot 		return true;
664926deccbSFrançois Tigeot 
665926deccbSFrançois Tigeot 	return false;
666926deccbSFrançois Tigeot 
667926deccbSFrançois Tigeot }
668926deccbSFrançois Tigeot 
669926deccbSFrançois Tigeot /**
670926deccbSFrançois Tigeot  * radeon_update_bandwidth_info - update display bandwidth params
671926deccbSFrançois Tigeot  *
672926deccbSFrançois Tigeot  * @rdev: radeon_device pointer
673926deccbSFrançois Tigeot  *
674926deccbSFrançois Tigeot  * Used when sclk/mclk are switched or display modes are set.
675926deccbSFrançois Tigeot  * params are used to calculate display watermarks (all asics)
676926deccbSFrançois Tigeot  */
677926deccbSFrançois Tigeot void radeon_update_bandwidth_info(struct radeon_device *rdev)
678926deccbSFrançois Tigeot {
679926deccbSFrançois Tigeot 	fixed20_12 a;
680926deccbSFrançois Tigeot 	u32 sclk = rdev->pm.current_sclk;
681926deccbSFrançois Tigeot 	u32 mclk = rdev->pm.current_mclk;
682926deccbSFrançois Tigeot 
683926deccbSFrançois Tigeot 	/* sclk/mclk in Mhz */
684926deccbSFrançois Tigeot 	a.full = dfixed_const(100);
685926deccbSFrançois Tigeot 	rdev->pm.sclk.full = dfixed_const(sclk);
686926deccbSFrançois Tigeot 	rdev->pm.sclk.full = dfixed_div(rdev->pm.sclk, a);
687926deccbSFrançois Tigeot 	rdev->pm.mclk.full = dfixed_const(mclk);
688926deccbSFrançois Tigeot 	rdev->pm.mclk.full = dfixed_div(rdev->pm.mclk, a);
689926deccbSFrançois Tigeot 
690926deccbSFrançois Tigeot 	if (rdev->flags & RADEON_IS_IGP) {
691926deccbSFrançois Tigeot 		a.full = dfixed_const(16);
692926deccbSFrançois Tigeot 		/* core_bandwidth = sclk(Mhz) * 16 */
693926deccbSFrançois Tigeot 		rdev->pm.core_bandwidth.full = dfixed_div(rdev->pm.sclk, a);
694926deccbSFrançois Tigeot 	}
695926deccbSFrançois Tigeot }
696926deccbSFrançois Tigeot 
697926deccbSFrançois Tigeot /**
698926deccbSFrançois Tigeot  * radeon_boot_test_post_card - check and possibly initialize the hw
699926deccbSFrançois Tigeot  *
700926deccbSFrançois Tigeot  * @rdev: radeon_device pointer
701926deccbSFrançois Tigeot  *
702926deccbSFrançois Tigeot  * Check if the asic is initialized and if not, attempt to initialize
703926deccbSFrançois Tigeot  * it (all asics).
704926deccbSFrançois Tigeot  * Returns true if initialized or false if not.
705926deccbSFrançois Tigeot  */
706926deccbSFrançois Tigeot bool radeon_boot_test_post_card(struct radeon_device *rdev)
707926deccbSFrançois Tigeot {
708926deccbSFrançois Tigeot 	if (radeon_card_posted(rdev))
709926deccbSFrançois Tigeot 		return true;
710926deccbSFrançois Tigeot 
711926deccbSFrançois Tigeot 	if (rdev->bios) {
712926deccbSFrançois Tigeot 		DRM_INFO("GPU not posted. posting now...\n");
713926deccbSFrançois Tigeot 		if (rdev->is_atom_bios)
714926deccbSFrançois Tigeot 			atom_asic_init(rdev->mode_info.atom_context);
715926deccbSFrançois Tigeot 		else
716926deccbSFrançois Tigeot 			radeon_combios_asic_init(rdev->ddev);
717926deccbSFrançois Tigeot 		return true;
718926deccbSFrançois Tigeot 	} else {
719926deccbSFrançois Tigeot 		dev_err(rdev->dev, "Card not posted and no BIOS - ignoring\n");
720926deccbSFrançois Tigeot 		return false;
721926deccbSFrançois Tigeot 	}
722926deccbSFrançois Tigeot }
723926deccbSFrançois Tigeot 
724926deccbSFrançois Tigeot /**
725926deccbSFrançois Tigeot  * radeon_dummy_page_init - init dummy page used by the driver
726926deccbSFrançois Tigeot  *
727926deccbSFrançois Tigeot  * @rdev: radeon_device pointer
728926deccbSFrançois Tigeot  *
729926deccbSFrançois Tigeot  * Allocate the dummy page used by the driver (all asics).
730926deccbSFrançois Tigeot  * This dummy page is used by the driver as a filler for gart entries
731926deccbSFrançois Tigeot  * when pages are taken out of the GART
732926deccbSFrançois Tigeot  * Returns 0 on sucess, -ENOMEM on failure.
733926deccbSFrançois Tigeot  */
734926deccbSFrançois Tigeot int radeon_dummy_page_init(struct radeon_device *rdev)
735926deccbSFrançois Tigeot {
736926deccbSFrançois Tigeot 	if (rdev->dummy_page.dmah)
737926deccbSFrançois Tigeot 		return 0;
738926deccbSFrançois Tigeot 	rdev->dummy_page.dmah = drm_pci_alloc(rdev->ddev,
739b31e9d59SFrançois Tigeot 	    PAGE_SIZE, PAGE_SIZE);
740926deccbSFrançois Tigeot 	if (rdev->dummy_page.dmah == NULL)
741926deccbSFrançois Tigeot 		return -ENOMEM;
74217afe8a4SSascha Wildner 	rdev->dummy_page.addr =
743dea697ccSImre Vadasz 	    (dma_addr_t)rdev->dummy_page.dmah->busaddr;
744926deccbSFrançois Tigeot 	return 0;
745926deccbSFrançois Tigeot }
746926deccbSFrançois Tigeot 
747926deccbSFrançois Tigeot /**
748926deccbSFrançois Tigeot  * radeon_dummy_page_fini - free dummy page used by the driver
749926deccbSFrançois Tigeot  *
750926deccbSFrançois Tigeot  * @rdev: radeon_device pointer
751926deccbSFrançois Tigeot  *
752926deccbSFrançois Tigeot  * Frees the dummy page used by the driver (all asics).
753926deccbSFrançois Tigeot  */
754926deccbSFrançois Tigeot void radeon_dummy_page_fini(struct radeon_device *rdev)
755926deccbSFrançois Tigeot {
756926deccbSFrançois Tigeot 	if (rdev->dummy_page.dmah == NULL)
757926deccbSFrançois Tigeot 		return;
758926deccbSFrançois Tigeot 	drm_pci_free(rdev->ddev, rdev->dummy_page.dmah);
759926deccbSFrançois Tigeot 	rdev->dummy_page.dmah = NULL;
760926deccbSFrançois Tigeot 	rdev->dummy_page.addr = 0;
761926deccbSFrançois Tigeot }
762926deccbSFrançois Tigeot 
763926deccbSFrançois Tigeot 
764926deccbSFrançois Tigeot /* ATOM accessor methods */
765926deccbSFrançois Tigeot /*
766926deccbSFrançois Tigeot  * ATOM is an interpreted byte code stored in tables in the vbios.  The
767926deccbSFrançois Tigeot  * driver registers callbacks to access registers and the interpreter
768926deccbSFrançois Tigeot  * in the driver parses the tables and executes then to program specific
769926deccbSFrançois Tigeot  * actions (set display modes, asic init, etc.).  See radeon_atombios.c,
770926deccbSFrançois Tigeot  * atombios.h, and atom.c
771926deccbSFrançois Tigeot  */
772926deccbSFrançois Tigeot 
773926deccbSFrançois Tigeot /**
774926deccbSFrançois Tigeot  * cail_pll_read - read PLL register
775926deccbSFrançois Tigeot  *
776926deccbSFrançois Tigeot  * @info: atom card_info pointer
777926deccbSFrançois Tigeot  * @reg: PLL register offset
778926deccbSFrançois Tigeot  *
779926deccbSFrançois Tigeot  * Provides a PLL register accessor for the atom interpreter (r4xx+).
780926deccbSFrançois Tigeot  * Returns the value of the PLL register.
781926deccbSFrançois Tigeot  */
782926deccbSFrançois Tigeot static uint32_t cail_pll_read(struct card_info *info, uint32_t reg)
783926deccbSFrançois Tigeot {
784926deccbSFrançois Tigeot 	struct radeon_device *rdev = info->dev->dev_private;
785926deccbSFrançois Tigeot 	uint32_t r;
786926deccbSFrançois Tigeot 
787926deccbSFrançois Tigeot 	r = rdev->pll_rreg(rdev, reg);
788926deccbSFrançois Tigeot 	return r;
789926deccbSFrançois Tigeot }
790926deccbSFrançois Tigeot 
791926deccbSFrançois Tigeot /**
792926deccbSFrançois Tigeot  * cail_pll_write - write PLL register
793926deccbSFrançois Tigeot  *
794926deccbSFrançois Tigeot  * @info: atom card_info pointer
795926deccbSFrançois Tigeot  * @reg: PLL register offset
796926deccbSFrançois Tigeot  * @val: value to write to the pll register
797926deccbSFrançois Tigeot  *
798926deccbSFrançois Tigeot  * Provides a PLL register accessor for the atom interpreter (r4xx+).
799926deccbSFrançois Tigeot  */
800926deccbSFrançois Tigeot static void cail_pll_write(struct card_info *info, uint32_t reg, uint32_t val)
801926deccbSFrançois Tigeot {
802926deccbSFrançois Tigeot 	struct radeon_device *rdev = info->dev->dev_private;
803926deccbSFrançois Tigeot 
804926deccbSFrançois Tigeot 	rdev->pll_wreg(rdev, reg, val);
805926deccbSFrançois Tigeot }
806926deccbSFrançois Tigeot 
807926deccbSFrançois Tigeot /**
808926deccbSFrançois Tigeot  * cail_mc_read - read MC (Memory Controller) register
809926deccbSFrançois Tigeot  *
810926deccbSFrançois Tigeot  * @info: atom card_info pointer
811926deccbSFrançois Tigeot  * @reg: MC register offset
812926deccbSFrançois Tigeot  *
813926deccbSFrançois Tigeot  * Provides an MC register accessor for the atom interpreter (r4xx+).
814926deccbSFrançois Tigeot  * Returns the value of the MC register.
815926deccbSFrançois Tigeot  */
816926deccbSFrançois Tigeot static uint32_t cail_mc_read(struct card_info *info, uint32_t reg)
817926deccbSFrançois Tigeot {
818926deccbSFrançois Tigeot 	struct radeon_device *rdev = info->dev->dev_private;
819926deccbSFrançois Tigeot 	uint32_t r;
820926deccbSFrançois Tigeot 
821926deccbSFrançois Tigeot 	r = rdev->mc_rreg(rdev, reg);
822926deccbSFrançois Tigeot 	return r;
823926deccbSFrançois Tigeot }
824926deccbSFrançois Tigeot 
825926deccbSFrançois Tigeot /**
826926deccbSFrançois Tigeot  * cail_mc_write - write MC (Memory Controller) register
827926deccbSFrançois Tigeot  *
828926deccbSFrançois Tigeot  * @info: atom card_info pointer
829926deccbSFrançois Tigeot  * @reg: MC register offset
830926deccbSFrançois Tigeot  * @val: value to write to the pll register
831926deccbSFrançois Tigeot  *
832926deccbSFrançois Tigeot  * Provides a MC register accessor for the atom interpreter (r4xx+).
833926deccbSFrançois Tigeot  */
834926deccbSFrançois Tigeot static void cail_mc_write(struct card_info *info, uint32_t reg, uint32_t val)
835926deccbSFrançois Tigeot {
836926deccbSFrançois Tigeot 	struct radeon_device *rdev = info->dev->dev_private;
837926deccbSFrançois Tigeot 
838926deccbSFrançois Tigeot 	rdev->mc_wreg(rdev, reg, val);
839926deccbSFrançois Tigeot }
840926deccbSFrançois Tigeot 
841926deccbSFrançois Tigeot /**
842926deccbSFrançois Tigeot  * cail_reg_write - write MMIO register
843926deccbSFrançois Tigeot  *
844926deccbSFrançois Tigeot  * @info: atom card_info pointer
845926deccbSFrançois Tigeot  * @reg: MMIO register offset
846926deccbSFrançois Tigeot  * @val: value to write to the pll register
847926deccbSFrançois Tigeot  *
848926deccbSFrançois Tigeot  * Provides a MMIO register accessor for the atom interpreter (r4xx+).
849926deccbSFrançois Tigeot  */
850926deccbSFrançois Tigeot static void cail_reg_write(struct card_info *info, uint32_t reg, uint32_t val)
851926deccbSFrançois Tigeot {
852926deccbSFrançois Tigeot 	struct radeon_device *rdev = info->dev->dev_private;
853926deccbSFrançois Tigeot 
854926deccbSFrançois Tigeot 	WREG32(reg*4, val);
855926deccbSFrançois Tigeot }
856926deccbSFrançois Tigeot 
857926deccbSFrançois Tigeot /**
858926deccbSFrançois Tigeot  * cail_reg_read - read MMIO register
859926deccbSFrançois Tigeot  *
860926deccbSFrançois Tigeot  * @info: atom card_info pointer
861926deccbSFrançois Tigeot  * @reg: MMIO register offset
862926deccbSFrançois Tigeot  *
863926deccbSFrançois Tigeot  * Provides an MMIO register accessor for the atom interpreter (r4xx+).
864926deccbSFrançois Tigeot  * Returns the value of the MMIO register.
865926deccbSFrançois Tigeot  */
866926deccbSFrançois Tigeot static uint32_t cail_reg_read(struct card_info *info, uint32_t reg)
867926deccbSFrançois Tigeot {
868926deccbSFrançois Tigeot 	struct radeon_device *rdev = info->dev->dev_private;
869926deccbSFrançois Tigeot 	uint32_t r;
870926deccbSFrançois Tigeot 
871926deccbSFrançois Tigeot 	r = RREG32(reg*4);
872926deccbSFrançois Tigeot 	return r;
873926deccbSFrançois Tigeot }
874926deccbSFrançois Tigeot 
875926deccbSFrançois Tigeot /**
876926deccbSFrançois Tigeot  * cail_ioreg_write - write IO register
877926deccbSFrançois Tigeot  *
878926deccbSFrançois Tigeot  * @info: atom card_info pointer
879926deccbSFrançois Tigeot  * @reg: IO register offset
880926deccbSFrançois Tigeot  * @val: value to write to the pll register
881926deccbSFrançois Tigeot  *
882926deccbSFrançois Tigeot  * Provides a IO register accessor for the atom interpreter (r4xx+).
883926deccbSFrançois Tigeot  */
884926deccbSFrançois Tigeot static void cail_ioreg_write(struct card_info *info, uint32_t reg, uint32_t val)
885926deccbSFrançois Tigeot {
886926deccbSFrançois Tigeot 	struct radeon_device *rdev = info->dev->dev_private;
887926deccbSFrançois Tigeot 
888926deccbSFrançois Tigeot 	WREG32_IO(reg*4, val);
889926deccbSFrançois Tigeot }
890926deccbSFrançois Tigeot 
891926deccbSFrançois Tigeot /**
892926deccbSFrançois Tigeot  * cail_ioreg_read - read IO register
893926deccbSFrançois Tigeot  *
894926deccbSFrançois Tigeot  * @info: atom card_info pointer
895926deccbSFrançois Tigeot  * @reg: IO register offset
896926deccbSFrançois Tigeot  *
897926deccbSFrançois Tigeot  * Provides an IO register accessor for the atom interpreter (r4xx+).
898926deccbSFrançois Tigeot  * Returns the value of the IO register.
899926deccbSFrançois Tigeot  */
900926deccbSFrançois Tigeot static uint32_t cail_ioreg_read(struct card_info *info, uint32_t reg)
901926deccbSFrançois Tigeot {
902926deccbSFrançois Tigeot 	struct radeon_device *rdev = info->dev->dev_private;
903926deccbSFrançois Tigeot 	uint32_t r;
904926deccbSFrançois Tigeot 
905926deccbSFrançois Tigeot 	r = RREG32_IO(reg*4);
906926deccbSFrançois Tigeot 	return r;
907926deccbSFrançois Tigeot }
908926deccbSFrançois Tigeot 
909926deccbSFrançois Tigeot /**
910926deccbSFrançois Tigeot  * radeon_atombios_init - init the driver info and callbacks for atombios
911926deccbSFrançois Tigeot  *
912926deccbSFrançois Tigeot  * @rdev: radeon_device pointer
913926deccbSFrançois Tigeot  *
914926deccbSFrançois Tigeot  * Initializes the driver info and register access callbacks for the
915926deccbSFrançois Tigeot  * ATOM interpreter (r4xx+).
916926deccbSFrançois Tigeot  * Returns 0 on sucess, -ENOMEM on failure.
917926deccbSFrançois Tigeot  * Called at driver startup.
918926deccbSFrançois Tigeot  */
919926deccbSFrançois Tigeot int radeon_atombios_init(struct radeon_device *rdev)
920926deccbSFrançois Tigeot {
921926deccbSFrançois Tigeot 	struct card_info *atom_card_info =
922c4ef309bSzrj 	    kzalloc(sizeof(struct card_info), GFP_KERNEL);
923926deccbSFrançois Tigeot 
924926deccbSFrançois Tigeot 	if (!atom_card_info)
925926deccbSFrançois Tigeot 		return -ENOMEM;
926926deccbSFrançois Tigeot 
927926deccbSFrançois Tigeot 	rdev->mode_info.atom_card_info = atom_card_info;
928926deccbSFrançois Tigeot 	atom_card_info->dev = rdev->ddev;
929926deccbSFrançois Tigeot 	atom_card_info->reg_read = cail_reg_read;
930926deccbSFrançois Tigeot 	atom_card_info->reg_write = cail_reg_write;
931926deccbSFrançois Tigeot 	/* needed for iio ops */
932926deccbSFrançois Tigeot 	if (rdev->rio_mem) {
933926deccbSFrançois Tigeot 		atom_card_info->ioreg_read = cail_ioreg_read;
934926deccbSFrançois Tigeot 		atom_card_info->ioreg_write = cail_ioreg_write;
935926deccbSFrançois Tigeot 	} else {
936926deccbSFrançois Tigeot 		DRM_ERROR("Unable to find PCI I/O BAR; using MMIO for ATOM IIO\n");
937926deccbSFrançois Tigeot 		atom_card_info->ioreg_read = cail_reg_read;
938926deccbSFrançois Tigeot 		atom_card_info->ioreg_write = cail_reg_write;
939926deccbSFrançois Tigeot 	}
940926deccbSFrançois Tigeot 	atom_card_info->mc_read = cail_mc_read;
941926deccbSFrançois Tigeot 	atom_card_info->mc_write = cail_mc_write;
942926deccbSFrançois Tigeot 	atom_card_info->pll_read = cail_pll_read;
943926deccbSFrançois Tigeot 	atom_card_info->pll_write = cail_pll_write;
944926deccbSFrançois Tigeot 
945926deccbSFrançois Tigeot 	rdev->mode_info.atom_context = atom_parse(atom_card_info, rdev->bios);
946b403bed8SMichael Neumann 	if (!rdev->mode_info.atom_context) {
947b403bed8SMichael Neumann 		radeon_atombios_fini(rdev);
948b403bed8SMichael Neumann 		return -ENOMEM;
949b403bed8SMichael Neumann 	}
950b403bed8SMichael Neumann 
951591d5043SFrançois Tigeot 	lockinit(&rdev->mode_info.atom_context->mutex, "rmiacmtx", 0, LK_CANRECURSE);
952591d5043SFrançois Tigeot 	lockinit(&rdev->mode_info.atom_context->scratch_mutex, "rmiacsmtx", 0, LK_CANRECURSE);
953926deccbSFrançois Tigeot 	radeon_atom_initialize_bios_scratch_regs(rdev->ddev);
954926deccbSFrançois Tigeot 	atom_allocate_fb_scratch(rdev->mode_info.atom_context);
955926deccbSFrançois Tigeot 	return 0;
956926deccbSFrançois Tigeot }
957926deccbSFrançois Tigeot 
958926deccbSFrançois Tigeot /**
959926deccbSFrançois Tigeot  * radeon_atombios_fini - free the driver info and callbacks for atombios
960926deccbSFrançois Tigeot  *
961926deccbSFrançois Tigeot  * @rdev: radeon_device pointer
962926deccbSFrançois Tigeot  *
963926deccbSFrançois Tigeot  * Frees the driver info and register access callbacks for the ATOM
964926deccbSFrançois Tigeot  * interpreter (r4xx+).
965926deccbSFrançois Tigeot  * Called at driver shutdown.
966926deccbSFrançois Tigeot  */
967926deccbSFrançois Tigeot void radeon_atombios_fini(struct radeon_device *rdev)
968926deccbSFrançois Tigeot {
969926deccbSFrançois Tigeot 	if (rdev->mode_info.atom_context) {
970ee479021SImre Vadász 		/* prevents leaking 512 bytes */
971ee479021SImre Vadász 		kfree(rdev->mode_info.atom_context->iio);
972ee479021SImre Vadász 
973c4ef309bSzrj 		kfree(rdev->mode_info.atom_context->scratch);
974926deccbSFrançois Tigeot 	}
975c4ef309bSzrj 	kfree(rdev->mode_info.atom_context);
976b403bed8SMichael Neumann 	rdev->mode_info.atom_context = NULL;
977c4ef309bSzrj 	kfree(rdev->mode_info.atom_card_info);
978b403bed8SMichael Neumann 	rdev->mode_info.atom_card_info = NULL;
979926deccbSFrançois Tigeot }
980926deccbSFrançois Tigeot 
981926deccbSFrançois Tigeot /* COMBIOS */
982926deccbSFrançois Tigeot /*
983926deccbSFrançois Tigeot  * COMBIOS is the bios format prior to ATOM. It provides
984926deccbSFrançois Tigeot  * command tables similar to ATOM, but doesn't have a unified
985926deccbSFrançois Tigeot  * parser.  See radeon_combios.c
986926deccbSFrançois Tigeot  */
987926deccbSFrançois Tigeot 
988926deccbSFrançois Tigeot /**
989926deccbSFrançois Tigeot  * radeon_combios_init - init the driver info for combios
990926deccbSFrançois Tigeot  *
991926deccbSFrançois Tigeot  * @rdev: radeon_device pointer
992926deccbSFrançois Tigeot  *
993926deccbSFrançois Tigeot  * Initializes the driver info for combios (r1xx-r3xx).
994926deccbSFrançois Tigeot  * Returns 0 on sucess.
995926deccbSFrançois Tigeot  * Called at driver startup.
996926deccbSFrançois Tigeot  */
997926deccbSFrançois Tigeot int radeon_combios_init(struct radeon_device *rdev)
998926deccbSFrançois Tigeot {
999926deccbSFrançois Tigeot 	radeon_combios_initialize_bios_scratch_regs(rdev->ddev);
1000926deccbSFrançois Tigeot 	return 0;
1001926deccbSFrançois Tigeot }
1002926deccbSFrançois Tigeot 
1003926deccbSFrançois Tigeot /**
1004926deccbSFrançois Tigeot  * radeon_combios_fini - free the driver info for combios
1005926deccbSFrançois Tigeot  *
1006926deccbSFrançois Tigeot  * @rdev: radeon_device pointer
1007926deccbSFrançois Tigeot  *
1008926deccbSFrançois Tigeot  * Frees the driver info for combios (r1xx-r3xx).
1009926deccbSFrançois Tigeot  * Called at driver shutdown.
1010926deccbSFrançois Tigeot  */
1011926deccbSFrançois Tigeot void radeon_combios_fini(struct radeon_device *rdev)
1012926deccbSFrançois Tigeot {
1013926deccbSFrançois Tigeot }
1014926deccbSFrançois Tigeot 
1015926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP
1016926deccbSFrançois Tigeot /* if we get transitioned to only one device, take VGA back */
1017926deccbSFrançois Tigeot /**
1018926deccbSFrançois Tigeot  * radeon_vga_set_decode - enable/disable vga decode
1019926deccbSFrançois Tigeot  *
1020926deccbSFrançois Tigeot  * @cookie: radeon_device pointer
1021926deccbSFrançois Tigeot  * @state: enable/disable vga decode
1022926deccbSFrançois Tigeot  *
1023926deccbSFrançois Tigeot  * Enable/disable vga decode (all asics).
1024926deccbSFrançois Tigeot  * Returns VGA resource flags.
1025926deccbSFrançois Tigeot  */
1026926deccbSFrançois Tigeot static unsigned int radeon_vga_set_decode(void *cookie, bool state)
1027926deccbSFrançois Tigeot {
1028926deccbSFrançois Tigeot 	struct radeon_device *rdev = cookie;
1029926deccbSFrançois Tigeot 	radeon_vga_set_state(rdev, state);
1030926deccbSFrançois Tigeot 	if (state)
1031926deccbSFrançois Tigeot 		return VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM |
1032926deccbSFrançois Tigeot 		       VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
1033926deccbSFrançois Tigeot 	else
1034926deccbSFrançois Tigeot 		return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
1035926deccbSFrançois Tigeot }
1036926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */
1037926deccbSFrançois Tigeot 
1038926deccbSFrançois Tigeot /**
1039926deccbSFrançois Tigeot  * radeon_check_pot_argument - check that argument is a power of two
1040926deccbSFrançois Tigeot  *
1041926deccbSFrançois Tigeot  * @arg: value to check
1042926deccbSFrançois Tigeot  *
1043926deccbSFrançois Tigeot  * Validates that a certain argument is a power of two (all asics).
1044926deccbSFrançois Tigeot  * Returns true if argument is valid.
1045926deccbSFrançois Tigeot  */
1046926deccbSFrançois Tigeot static bool radeon_check_pot_argument(int arg)
1047926deccbSFrançois Tigeot {
1048926deccbSFrançois Tigeot 	return (arg & (arg - 1)) == 0;
1049926deccbSFrançois Tigeot }
1050926deccbSFrançois Tigeot 
1051926deccbSFrançois Tigeot /**
1052926deccbSFrançois Tigeot  * radeon_check_arguments - validate module params
1053926deccbSFrançois Tigeot  *
1054926deccbSFrançois Tigeot  * @rdev: radeon_device pointer
1055926deccbSFrançois Tigeot  *
1056926deccbSFrançois Tigeot  * Validates certain module parameters and updates
1057926deccbSFrançois Tigeot  * the associated values used by the driver (all asics).
1058926deccbSFrançois Tigeot  */
1059926deccbSFrançois Tigeot static void radeon_check_arguments(struct radeon_device *rdev)
1060926deccbSFrançois Tigeot {
1061926deccbSFrançois Tigeot 	/* vramlimit must be a power of two */
1062926deccbSFrançois Tigeot 	if (!radeon_check_pot_argument(radeon_vram_limit)) {
1063926deccbSFrançois Tigeot 		dev_warn(rdev->dev, "vram limit (%d) must be a power of 2\n",
1064926deccbSFrançois Tigeot 				radeon_vram_limit);
1065926deccbSFrançois Tigeot 		radeon_vram_limit = 0;
1066926deccbSFrançois Tigeot 	}
1067926deccbSFrançois Tigeot 
10684cd92098Szrj 	if (radeon_gart_size == -1) {
1069ee479021SImre Vadász 		/* default to a larger gart size on newer asics */
1070ee479021SImre Vadász 		if (rdev->family >= CHIP_RV770)
1071ee479021SImre Vadász 			radeon_gart_size = 1024;
1072ee479021SImre Vadász 		else
1073ee479021SImre Vadász 			radeon_gart_size = 512;
10744cd92098Szrj 	}
1075926deccbSFrançois Tigeot 	/* gtt size must be power of two and greater or equal to 32M */
1076926deccbSFrançois Tigeot 	if (radeon_gart_size < 32) {
10774cd92098Szrj 		dev_warn(rdev->dev, "gart size (%d) too small\n",
1078926deccbSFrançois Tigeot 				radeon_gart_size);
1079ee479021SImre Vadász 		if (rdev->family >= CHIP_RV770)
1080ee479021SImre Vadász 			radeon_gart_size = 1024;
1081ee479021SImre Vadász 		else
1082ee479021SImre Vadász 			radeon_gart_size = 512;
1083926deccbSFrançois Tigeot 	} else if (!radeon_check_pot_argument(radeon_gart_size)) {
1084926deccbSFrançois Tigeot 		dev_warn(rdev->dev, "gart size (%d) must be a power of 2\n",
1085926deccbSFrançois Tigeot 				radeon_gart_size);
1086ee479021SImre Vadász 		if (rdev->family >= CHIP_RV770)
1087ee479021SImre Vadász 			radeon_gart_size = 1024;
1088ee479021SImre Vadász 		else
1089ee479021SImre Vadász 			radeon_gart_size = 512;
1090926deccbSFrançois Tigeot 	}
1091926deccbSFrançois Tigeot 	rdev->mc.gtt_size = (uint64_t)radeon_gart_size << 20;
1092926deccbSFrançois Tigeot 
1093926deccbSFrançois Tigeot 	/* AGP mode can only be -1, 1, 2, 4, 8 */
1094926deccbSFrançois Tigeot 	switch (radeon_agpmode) {
1095926deccbSFrançois Tigeot 	case -1:
1096926deccbSFrançois Tigeot 	case 0:
1097926deccbSFrançois Tigeot 	case 1:
1098926deccbSFrançois Tigeot 	case 2:
1099926deccbSFrançois Tigeot 	case 4:
1100926deccbSFrançois Tigeot 	case 8:
1101926deccbSFrançois Tigeot 		break;
1102926deccbSFrançois Tigeot 	default:
1103926deccbSFrançois Tigeot 		dev_warn(rdev->dev, "invalid AGP mode %d (valid mode: "
1104926deccbSFrançois Tigeot 				"-1, 0, 1, 2, 4, 8)\n", radeon_agpmode);
1105926deccbSFrançois Tigeot 		radeon_agpmode = 0;
1106926deccbSFrançois Tigeot 		break;
1107926deccbSFrançois Tigeot 	}
1108c6f73aabSFrançois Tigeot 
1109c6f73aabSFrançois Tigeot 	if (!radeon_check_pot_argument(radeon_vm_size)) {
1110c6f73aabSFrançois Tigeot 		dev_warn(rdev->dev, "VM size (%d) must be a power of 2\n",
1111c6f73aabSFrançois Tigeot 			 radeon_vm_size);
1112c6f73aabSFrançois Tigeot 		radeon_vm_size = 4;
1113926deccbSFrançois Tigeot 	}
1114926deccbSFrançois Tigeot 
1115c6f73aabSFrançois Tigeot 	if (radeon_vm_size < 1) {
1116ee479021SImre Vadász 		dev_warn(rdev->dev, "VM size (%d) to small, min is 1GB\n",
1117c6f73aabSFrançois Tigeot 			 radeon_vm_size);
1118c6f73aabSFrançois Tigeot 		radeon_vm_size = 4;
1119c6f73aabSFrançois Tigeot 	}
1120c6f73aabSFrançois Tigeot 
1121c6f73aabSFrançois Tigeot        /*
1122c6f73aabSFrançois Tigeot         * Max GPUVM size for Cayman, SI and CI are 40 bits.
1123926deccbSFrançois Tigeot         */
1124c6f73aabSFrançois Tigeot 	if (radeon_vm_size > 1024) {
1125c6f73aabSFrançois Tigeot 		dev_warn(rdev->dev, "VM size (%d) too large, max is 1TB\n",
1126c6f73aabSFrançois Tigeot 			 radeon_vm_size);
1127c6f73aabSFrançois Tigeot 		radeon_vm_size = 4;
1128926deccbSFrançois Tigeot 	}
1129926deccbSFrançois Tigeot 
1130c6f73aabSFrançois Tigeot 	/* defines number of bits in page table versus page directory,
1131c6f73aabSFrançois Tigeot 	 * a page is 4KB so we have 12 bits offset, minimum 9 bits in the
1132c6f73aabSFrançois Tigeot 	 * page table and the remaining bits are in the page directory */
1133c6f73aabSFrançois Tigeot 	if (radeon_vm_block_size == -1) {
1134c6f73aabSFrançois Tigeot 
1135c6f73aabSFrançois Tigeot 		/* Total bits covered by PD + PTs */
1136591d5043SFrançois Tigeot 		unsigned bits = ilog2(radeon_vm_size) + 18;
1137c6f73aabSFrançois Tigeot 
1138c6f73aabSFrançois Tigeot 		/* Make sure the PD is 4K in size up to 8GB address space.
1139c6f73aabSFrançois Tigeot 		   Above that split equal between PD and PTs */
1140c6f73aabSFrançois Tigeot 		if (radeon_vm_size <= 8)
1141c6f73aabSFrançois Tigeot 			radeon_vm_block_size = bits - 9;
1142c6f73aabSFrançois Tigeot 		else
1143c6f73aabSFrançois Tigeot 			radeon_vm_block_size = (bits + 3) / 2;
1144c6f73aabSFrançois Tigeot 
1145c6f73aabSFrançois Tigeot 	} else if (radeon_vm_block_size < 9) {
1146c6f73aabSFrançois Tigeot 		dev_warn(rdev->dev, "VM page table size (%d) too small\n",
1147c6f73aabSFrançois Tigeot 			 radeon_vm_block_size);
1148c6f73aabSFrançois Tigeot 		radeon_vm_block_size = 9;
1149926deccbSFrançois Tigeot 	}
1150c6f73aabSFrançois Tigeot 
1151c6f73aabSFrançois Tigeot 	if (radeon_vm_block_size > 24 ||
1152c6f73aabSFrançois Tigeot 	    (radeon_vm_size * 1024) < (1ull << radeon_vm_block_size)) {
1153c6f73aabSFrançois Tigeot 		dev_warn(rdev->dev, "VM page table size (%d) too large\n",
1154c6f73aabSFrançois Tigeot 			 radeon_vm_block_size);
1155c6f73aabSFrançois Tigeot 		radeon_vm_block_size = 9;
1156c6f73aabSFrançois Tigeot 	}
1157c6f73aabSFrançois Tigeot }
1158926deccbSFrançois Tigeot 
1159926deccbSFrançois Tigeot /**
1160926deccbSFrançois Tigeot  * radeon_switcheroo_set_state - set switcheroo state
1161926deccbSFrançois Tigeot  *
1162926deccbSFrançois Tigeot  * @pdev: pci dev pointer
1163ee479021SImre Vadász  * @state: vga switcheroo state
1164926deccbSFrançois Tigeot  *
1165926deccbSFrançois Tigeot  * Callback for the switcheroo driver.  Suspends or resumes the
1166926deccbSFrançois Tigeot  * the asics before or after it is powered up using ACPI methods.
1167926deccbSFrançois Tigeot  */
1168926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP
1169926deccbSFrançois Tigeot static void radeon_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_state state)
1170926deccbSFrançois Tigeot {
1171926deccbSFrançois Tigeot 	struct drm_device *dev = pci_get_drvdata(pdev);
1172c6f73aabSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
1173c6f73aabSFrançois Tigeot 
1174c6f73aabSFrançois Tigeot 	if (radeon_is_px(dev) && state == VGA_SWITCHEROO_OFF)
1175c6f73aabSFrançois Tigeot 		return;
1176c6f73aabSFrançois Tigeot 
1177926deccbSFrançois Tigeot 	if (state == VGA_SWITCHEROO_ON) {
1178926deccbSFrançois Tigeot 		unsigned d3_delay = dev->pdev->d3_delay;
1179926deccbSFrançois Tigeot 
1180926deccbSFrançois Tigeot 		printk(KERN_INFO "radeon: switched on\n");
1181926deccbSFrançois Tigeot 		/* don't suspend or resume card normally */
1182926deccbSFrançois Tigeot 		dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
1183926deccbSFrançois Tigeot 
1184c6f73aabSFrançois Tigeot 		if (d3_delay < 20 && (rdev->px_quirk_flags & RADEON_PX_QUIRK_LONG_WAKEUP))
1185926deccbSFrançois Tigeot 			dev->pdev->d3_delay = 20;
1186926deccbSFrançois Tigeot 
1187c6f73aabSFrançois Tigeot 		radeon_resume_kms(dev, true, true);
1188926deccbSFrançois Tigeot 
1189926deccbSFrançois Tigeot 		dev->pdev->d3_delay = d3_delay;
1190926deccbSFrançois Tigeot 
1191926deccbSFrançois Tigeot 		dev->switch_power_state = DRM_SWITCH_POWER_ON;
1192926deccbSFrançois Tigeot 		drm_kms_helper_poll_enable(dev);
1193926deccbSFrançois Tigeot 	} else {
1194926deccbSFrançois Tigeot 		printk(KERN_INFO "radeon: switched off\n");
1195926deccbSFrançois Tigeot 		drm_kms_helper_poll_disable(dev);
1196926deccbSFrançois Tigeot 		dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
1197ee479021SImre Vadász 		radeon_suspend_kms(dev, true, true);
1198926deccbSFrançois Tigeot 		dev->switch_power_state = DRM_SWITCH_POWER_OFF;
1199926deccbSFrançois Tigeot 	}
1200926deccbSFrançois Tigeot }
1201926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */
1202926deccbSFrançois Tigeot 
1203926deccbSFrançois Tigeot /**
1204926deccbSFrançois Tigeot  * radeon_switcheroo_can_switch - see if switcheroo state can change
1205926deccbSFrançois Tigeot  *
1206926deccbSFrançois Tigeot  * @pdev: pci dev pointer
1207926deccbSFrançois Tigeot  *
1208926deccbSFrançois Tigeot  * Callback for the switcheroo driver.  Check of the switcheroo
1209926deccbSFrançois Tigeot  * state can be changed.
1210926deccbSFrançois Tigeot  * Returns true if the state can be changed, false if not.
1211926deccbSFrançois Tigeot  */
1212926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP
1213926deccbSFrançois Tigeot static bool radeon_switcheroo_can_switch(struct pci_dev *pdev)
1214926deccbSFrançois Tigeot {
1215926deccbSFrançois Tigeot 	struct drm_device *dev = pci_get_drvdata(pdev);
1216926deccbSFrançois Tigeot 
1217c6f73aabSFrançois Tigeot 	/*
1218c6f73aabSFrançois Tigeot 	 * FIXME: open_count is protected by drm_global_mutex but that would lead to
1219c6f73aabSFrançois Tigeot 	 * locking inversion with the driver load path. And the access here is
1220c6f73aabSFrançois Tigeot 	 * completely racy anyway. So don't bother with locking for now.
1221c6f73aabSFrançois Tigeot 	 */
1222c6f73aabSFrançois Tigeot 	return dev->open_count == 0;
1223926deccbSFrançois Tigeot }
1224926deccbSFrançois Tigeot 
1225926deccbSFrançois Tigeot static const struct vga_switcheroo_client_ops radeon_switcheroo_ops = {
1226926deccbSFrançois Tigeot 	.set_gpu_state = radeon_switcheroo_set_state,
1227926deccbSFrançois Tigeot 	.reprobe = NULL,
1228926deccbSFrançois Tigeot 	.can_switch = radeon_switcheroo_can_switch,
1229926deccbSFrançois Tigeot };
1230926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */
1231926deccbSFrançois Tigeot 
1232926deccbSFrançois Tigeot /**
1233926deccbSFrançois Tigeot  * radeon_device_init - initialize the driver
1234926deccbSFrançois Tigeot  *
1235926deccbSFrançois Tigeot  * @rdev: radeon_device pointer
1236926deccbSFrançois Tigeot  * @pdev: drm dev pointer
1237c6f73aabSFrançois Tigeot  * @pdev: pci dev pointer
1238926deccbSFrançois Tigeot  * @flags: driver flags
1239926deccbSFrançois Tigeot  *
1240926deccbSFrançois Tigeot  * Initializes the driver info and hw (all asics).
1241926deccbSFrançois Tigeot  * Returns 0 for success or an error on failure.
1242926deccbSFrançois Tigeot  * Called at driver startup.
1243926deccbSFrançois Tigeot  */
1244926deccbSFrançois Tigeot int radeon_device_init(struct radeon_device *rdev,
1245926deccbSFrançois Tigeot 		       struct drm_device *ddev,
1246c6f73aabSFrançois Tigeot 		       struct pci_dev *pdev,
1247926deccbSFrançois Tigeot 		       uint32_t flags)
1248926deccbSFrançois Tigeot {
1249926deccbSFrançois Tigeot 	int r, i;
1250926deccbSFrançois Tigeot 	int dma_bits;
1251c6f73aabSFrançois Tigeot #ifdef PM_TODO
1252c6f73aabSFrançois Tigeot 	bool runtime = false;
1253c6f73aabSFrançois Tigeot #endif
1254926deccbSFrançois Tigeot 
1255926deccbSFrançois Tigeot 	rdev->shutdown = false;
1256fb572d17SFrançois Tigeot 	rdev->dev = &pdev->dev;
1257926deccbSFrançois Tigeot 	rdev->ddev = ddev;
1258c6f73aabSFrançois Tigeot 	rdev->pdev = pdev;
1259926deccbSFrançois Tigeot 	rdev->flags = flags;
1260926deccbSFrançois Tigeot 	rdev->family = flags & RADEON_FAMILY_MASK;
1261926deccbSFrançois Tigeot 	rdev->is_atom_bios = false;
1262926deccbSFrançois Tigeot 	rdev->usec_timeout = RADEON_MAX_USEC_TIMEOUT;
12634cd92098Szrj 	rdev->mc.gtt_size = 512 * 1024 * 1024;
1264926deccbSFrançois Tigeot 	rdev->accel_working = false;
1265926deccbSFrançois Tigeot 	rdev->fictitious_range_registered = false;
1266926deccbSFrançois Tigeot 	/* set up ring ids */
1267926deccbSFrançois Tigeot 	for (i = 0; i < RADEON_NUM_RINGS; i++) {
1268926deccbSFrançois Tigeot 		rdev->ring[i].idx = i;
1269926deccbSFrançois Tigeot 	}
1270*1cfef1a5SFrançois Tigeot 	rdev->fence_context = fence_context_alloc(RADEON_NUM_RINGS);
1271926deccbSFrançois Tigeot 
1272ee479021SImre Vadász 	DRM_INFO("initializing kernel modesetting (%s 0x%04X:0x%04X 0x%04X:0x%04X).\n",
1273c6f73aabSFrançois Tigeot 		radeon_family_name[rdev->family], pdev->vendor, pdev->device,
1274ee479021SImre Vadász 		pdev->subsystem_vendor, pdev->subsystem_device);
1275926deccbSFrançois Tigeot 
1276926deccbSFrançois Tigeot 	/* mutex initialization are all done here so we
1277926deccbSFrançois Tigeot 	 * can recall function without having locking issues */
12781ca17f9bSFrançois Tigeot 	lockinit(&rdev->ring_lock, "drdrl", 0, LK_CANRECURSE);
12791ca17f9bSFrançois Tigeot 	lockinit(&rdev->dc_hw_i2c_mutex, "drddi2cm", 0, LK_CANRECURSE);
1280926deccbSFrançois Tigeot 	atomic_set(&rdev->ih.lock, 0);
1281fefad7a7SFrançois Tigeot 	lockinit(&rdev->gem.mutex, "radeon_gemmtx", 0, LK_CANRECURSE);
12821ca17f9bSFrançois Tigeot 	lockinit(&rdev->pm.mutex, "drdpmm", 0, LK_CANRECURSE);
1283fefad7a7SFrançois Tigeot 
1284fefad7a7SFrançois Tigeot 	lockinit(&rdev->gpu_clock_mutex, "radeon_clockmtx", 0, LK_CANRECURSE);
1285fefad7a7SFrançois Tigeot 	lockinit(&rdev->srbm_mutex, "radeon_srbm_mutex", 0, LK_CANRECURSE);
12861ca17f9bSFrançois Tigeot 	lockinit(&rdev->pm.mclk_lock, "drpmml", 0, LK_CANRECURSE);
12871ca17f9bSFrançois Tigeot 	lockinit(&rdev->exclusive_lock, "drdel", 0, LK_CANRECURSE);
1288c6f73aabSFrançois Tigeot 	init_waitqueue_head(&rdev->irq.vblank_queue);
1289*1cfef1a5SFrançois Tigeot 	lockinit(&rdev->mn_lock, "drrml", 0, LK_CANRECURSE);
1290*1cfef1a5SFrançois Tigeot 	hash_init(rdev->mn_hash);
1291926deccbSFrançois Tigeot 	r = radeon_gem_init(rdev);
1292926deccbSFrançois Tigeot 	if (r)
1293926deccbSFrançois Tigeot 		return r;
1294c6f73aabSFrançois Tigeot 
1295c6f73aabSFrançois Tigeot 	radeon_check_arguments(rdev);
1296926deccbSFrançois Tigeot 	/* Adjust VM size here.
1297c6f73aabSFrançois Tigeot 	 * Max GPUVM size for cayman+ is 40 bits.
1298926deccbSFrançois Tigeot 	 */
1299c6f73aabSFrançois Tigeot 	rdev->vm_manager.max_pfn = radeon_vm_size << 18;
1300926deccbSFrançois Tigeot 
1301926deccbSFrançois Tigeot 	/* Set asic functions */
1302926deccbSFrançois Tigeot 	r = radeon_asic_init(rdev);
1303926deccbSFrançois Tigeot 	if (r)
1304926deccbSFrançois Tigeot 		return r;
1305926deccbSFrançois Tigeot 
1306926deccbSFrançois Tigeot 	/* all of the newer IGP chips have an internal gart
1307926deccbSFrançois Tigeot 	 * However some rs4xx report as AGP, so remove that here.
1308926deccbSFrançois Tigeot 	 */
1309926deccbSFrançois Tigeot 	if ((rdev->family >= CHIP_RS400) &&
1310926deccbSFrançois Tigeot 	    (rdev->flags & RADEON_IS_IGP)) {
1311926deccbSFrançois Tigeot 		rdev->flags &= ~RADEON_IS_AGP;
1312926deccbSFrançois Tigeot 	}
1313926deccbSFrançois Tigeot 
1314926deccbSFrançois Tigeot 	if (rdev->flags & RADEON_IS_AGP && radeon_agpmode == -1) {
1315926deccbSFrançois Tigeot 		radeon_agp_disable(rdev);
1316926deccbSFrançois Tigeot 	}
1317926deccbSFrançois Tigeot 
1318f43cf1b1SMichael Neumann 	/* Set the internal MC address mask
1319f43cf1b1SMichael Neumann 	 * This is the max address of the GPU's
1320f43cf1b1SMichael Neumann 	 * internal address space.
1321f43cf1b1SMichael Neumann 	 */
1322f43cf1b1SMichael Neumann 	if (rdev->family >= CHIP_CAYMAN)
1323f43cf1b1SMichael Neumann 		rdev->mc.mc_mask = 0xffffffffffULL; /* 40 bit MC */
1324f43cf1b1SMichael Neumann 	else if (rdev->family >= CHIP_CEDAR)
1325f43cf1b1SMichael Neumann 		rdev->mc.mc_mask = 0xfffffffffULL; /* 36 bit MC */
1326f43cf1b1SMichael Neumann 	else
1327f43cf1b1SMichael Neumann 		rdev->mc.mc_mask = 0xffffffffULL; /* 32 bit MC */
1328f43cf1b1SMichael Neumann 
1329926deccbSFrançois Tigeot 	/* set DMA mask + need_dma32 flags.
1330926deccbSFrançois Tigeot 	 * PCIE - can handle 40-bits.
1331926deccbSFrançois Tigeot 	 * IGP - can handle 40-bits
1332926deccbSFrançois Tigeot 	 * AGP - generally dma32 is safest
1333926deccbSFrançois Tigeot 	 * PCI - dma32 for legacy pci gart, 40 bits on newer asics
1334926deccbSFrançois Tigeot 	 */
1335926deccbSFrançois Tigeot 	rdev->need_dma32 = false;
1336926deccbSFrançois Tigeot 	if (rdev->flags & RADEON_IS_AGP)
1337926deccbSFrançois Tigeot 		rdev->need_dma32 = true;
1338926deccbSFrançois Tigeot 	if ((rdev->flags & RADEON_IS_PCI) &&
1339926deccbSFrançois Tigeot 	    (rdev->family <= CHIP_RS740))
1340926deccbSFrançois Tigeot 		rdev->need_dma32 = true;
1341926deccbSFrançois Tigeot 
1342926deccbSFrançois Tigeot 	dma_bits = rdev->need_dma32 ? 32 : 40;
1343926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP
1344926deccbSFrançois Tigeot 	r = pci_set_dma_mask(rdev->pdev, DMA_BIT_MASK(dma_bits));
1345926deccbSFrançois Tigeot 	if (r) {
1346926deccbSFrançois Tigeot 		rdev->need_dma32 = true;
1347926deccbSFrançois Tigeot 		dma_bits = 32;
1348926deccbSFrançois Tigeot 		printk(KERN_WARNING "radeon: No suitable DMA available.\n");
1349926deccbSFrançois Tigeot 	}
1350926deccbSFrançois Tigeot 	r = pci_set_consistent_dma_mask(rdev->pdev, DMA_BIT_MASK(dma_bits));
1351926deccbSFrançois Tigeot 	if (r) {
1352926deccbSFrançois Tigeot 		pci_set_consistent_dma_mask(rdev->pdev, DMA_BIT_MASK(32));
1353926deccbSFrançois Tigeot 		printk(KERN_WARNING "radeon: No coherent DMA available.\n");
1354926deccbSFrançois Tigeot 	}
1355926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */
1356926deccbSFrançois Tigeot 
1357926deccbSFrançois Tigeot 	/* Registers mapping */
1358926deccbSFrançois Tigeot 	/* TODO: block userspace mapping of io register */
1359ee479021SImre Vadász 	spin_init(&rdev->mmio_idx_lock,  "radeon_mpio");
1360ee479021SImre Vadász 	spin_init(&rdev->smc_idx_lock,   "radeon_smc");
1361ee479021SImre Vadász 	spin_init(&rdev->pll_idx_lock,   "radeon_pll");
1362ee479021SImre Vadász 	spin_init(&rdev->mc_idx_lock,    "radeon_mc");
1363ee479021SImre Vadász 	spin_init(&rdev->pcie_idx_lock,  "radeon_pcie");
1364ee479021SImre Vadász 	spin_init(&rdev->pciep_idx_lock, "radeon_pciep");
1365ee479021SImre Vadász 	spin_init(&rdev->pif_idx_lock,   "radeon_pif");
1366ee479021SImre Vadász 	spin_init(&rdev->cg_idx_lock,    "radeon_cg");
1367ee479021SImre Vadász 	spin_init(&rdev->uvd_idx_lock,   "radeon_uvd");
1368ee479021SImre Vadász 	spin_init(&rdev->rcu_idx_lock,   "radeon_rcu");
1369ee479021SImre Vadász 	spin_init(&rdev->didt_idx_lock,  "radeon_didt");
1370ee479021SImre Vadász 	spin_init(&rdev->end_idx_lock,   "radeon_end");
137157e252bfSMichael Neumann 	if (rdev->family >= CHIP_BONAIRE) {
137257e252bfSMichael Neumann 		rdev->rmmio_rid = PCIR_BAR(5);
137357e252bfSMichael Neumann 	} else {
1374926deccbSFrançois Tigeot 		rdev->rmmio_rid = PCIR_BAR(2);
137557e252bfSMichael Neumann 	}
1376fb572d17SFrançois Tigeot 	rdev->rmmio = bus_alloc_resource_any(rdev->dev->bsddev, SYS_RES_MEMORY,
1377926deccbSFrançois Tigeot 	    &rdev->rmmio_rid, RF_ACTIVE | RF_SHAREABLE);
1378926deccbSFrançois Tigeot 	if (rdev->rmmio == NULL) {
1379926deccbSFrançois Tigeot 		return -ENOMEM;
1380926deccbSFrançois Tigeot 	}
1381926deccbSFrançois Tigeot 	rdev->rmmio_base = rman_get_start(rdev->rmmio);
1382926deccbSFrançois Tigeot 	rdev->rmmio_size = rman_get_size(rdev->rmmio);
1383926deccbSFrançois Tigeot 	DRM_INFO("register mmio base: 0x%08X\n", (uint32_t)rdev->rmmio_base);
1384926deccbSFrançois Tigeot 	DRM_INFO("register mmio size: %u\n", (unsigned)rdev->rmmio_size);
1385926deccbSFrançois Tigeot 
138657e252bfSMichael Neumann 	/* doorbell bar mapping */
138757e252bfSMichael Neumann 	if (rdev->family >= CHIP_BONAIRE)
138857e252bfSMichael Neumann 		radeon_doorbell_init(rdev);
138957e252bfSMichael Neumann 
1390926deccbSFrançois Tigeot 	/* io port mapping */
1391926deccbSFrançois Tigeot 	for (i = 0; i < DRM_MAX_PCI_RESOURCE; i++) {
1392926deccbSFrançois Tigeot 		uint32_t data;
1393926deccbSFrançois Tigeot 
1394fb572d17SFrançois Tigeot 		data = pci_read_config(rdev->dev->bsddev, PCIR_BAR(i), 4);
1395926deccbSFrançois Tigeot 		if (PCI_BAR_IO(data)) {
1396926deccbSFrançois Tigeot 			rdev->rio_rid = PCIR_BAR(i);
1397fb572d17SFrançois Tigeot 			rdev->rio_mem = bus_alloc_resource_any(rdev->dev->bsddev,
1398926deccbSFrançois Tigeot 			    SYS_RES_IOPORT, &rdev->rio_rid,
1399926deccbSFrançois Tigeot 			    RF_ACTIVE | RF_SHAREABLE);
1400926deccbSFrançois Tigeot 			break;
1401926deccbSFrançois Tigeot 		}
1402926deccbSFrançois Tigeot 	}
1403926deccbSFrançois Tigeot 	if (rdev->rio_mem == NULL)
1404926deccbSFrançois Tigeot 		DRM_ERROR("Unable to find PCI I/O BAR\n");
1405926deccbSFrançois Tigeot 
1406c6f73aabSFrançois Tigeot 	if (rdev->flags & RADEON_IS_PX)
1407c6f73aabSFrançois Tigeot 		radeon_device_handle_px_quirks(rdev);
1408c6f73aabSFrançois Tigeot 
1409926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP
1410926deccbSFrançois Tigeot 	/* if we have > 1 VGA cards, then disable the radeon VGA resources */
1411926deccbSFrançois Tigeot 	/* this will fail for cards that aren't VGA class devices, just
1412926deccbSFrançois Tigeot 	 * ignore it */
1413926deccbSFrançois Tigeot 	vga_client_register(rdev->pdev, rdev, NULL, radeon_vga_set_decode);
1414c6f73aabSFrançois Tigeot 
1415c6f73aabSFrançois Tigeot #ifdef PM_TODO
1416c6f73aabSFrançois Tigeot 	if (rdev->flags & RADEON_IS_PX)
1417c6f73aabSFrançois Tigeot 		runtime = true;
1418c6f73aabSFrançois Tigeot 	vga_switcheroo_register_client(rdev->pdev, &radeon_switcheroo_ops, runtime);
1419c6f73aabSFrançois Tigeot 	if (runtime)
1420fb572d17SFrançois Tigeot 		vga_switcheroo_init_domain_pm_ops(rdev->dev->bsddev, &rdev->vga_pm_domain);
1421c6f73aabSFrançois Tigeot #endif
1422926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */
1423926deccbSFrançois Tigeot 
1424926deccbSFrançois Tigeot 	r = radeon_init(rdev);
1425926deccbSFrançois Tigeot 	if (r)
1426c6f73aabSFrançois Tigeot 		goto failed;
1427926deccbSFrançois Tigeot 
1428f43cf1b1SMichael Neumann 	r = radeon_gem_debugfs_init(rdev);
1429f43cf1b1SMichael Neumann 	if (r) {
1430f43cf1b1SMichael Neumann 		DRM_ERROR("registering gem debugfs failed (%d).\n", r);
1431f43cf1b1SMichael Neumann 	}
1432f43cf1b1SMichael Neumann 
1433926deccbSFrançois Tigeot 	if (rdev->flags & RADEON_IS_AGP && !rdev->accel_working) {
1434926deccbSFrançois Tigeot 		/* Acceleration not working on AGP card try again
1435926deccbSFrançois Tigeot 		 * with fallback to PCI or PCIE GART
1436926deccbSFrançois Tigeot 		 */
1437926deccbSFrançois Tigeot 		radeon_asic_reset(rdev);
1438926deccbSFrançois Tigeot 		radeon_fini(rdev);
1439926deccbSFrançois Tigeot 		radeon_agp_disable(rdev);
1440926deccbSFrançois Tigeot 		r = radeon_init(rdev);
1441926deccbSFrançois Tigeot 		if (r)
1442c6f73aabSFrançois Tigeot 			goto failed;
1443926deccbSFrançois Tigeot 	}
1444926deccbSFrançois Tigeot 
1445591d5043SFrançois Tigeot 	r = radeon_ib_ring_tests(rdev);
1446591d5043SFrançois Tigeot 	if (r)
1447591d5043SFrançois Tigeot 		DRM_ERROR("ib ring test failed (%d).\n", r);
1448591d5043SFrançois Tigeot 
1449f77dbd6cSFrançois Tigeot 	DRM_INFO("%s: Taking over the fictitious range 0x%lx-0x%llx\n",
1450926deccbSFrançois Tigeot 	    __func__, (uintmax_t)rdev->mc.aper_base,
1451926deccbSFrançois Tigeot 	    (uintmax_t)rdev->mc.aper_base + rdev->mc.visible_vram_size);
1452926deccbSFrançois Tigeot 	r = vm_phys_fictitious_reg_range(
1453926deccbSFrançois Tigeot 	    rdev->mc.aper_base,
1454926deccbSFrançois Tigeot 	    rdev->mc.aper_base + rdev->mc.visible_vram_size,
1455926deccbSFrançois Tigeot 	    VM_MEMATTR_WRITE_COMBINING);
1456926deccbSFrançois Tigeot 	if (r != 0) {
1457926deccbSFrançois Tigeot 		DRM_ERROR("Failed to register fictitious range "
1458f77dbd6cSFrançois Tigeot 		    "0x%lx-0x%llx (%d).\n", (uintmax_t)rdev->mc.aper_base,
1459926deccbSFrançois Tigeot 		    (uintmax_t)rdev->mc.aper_base + rdev->mc.visible_vram_size, r);
1460926deccbSFrançois Tigeot 		return (-r);
1461926deccbSFrançois Tigeot 	}
1462926deccbSFrançois Tigeot 	rdev->fictitious_range_registered = true;
1463926deccbSFrançois Tigeot 
1464926deccbSFrançois Tigeot 	if ((radeon_testing & 1)) {
14654cd92098Szrj 		if (rdev->accel_working)
1466926deccbSFrançois Tigeot 			radeon_test_moves(rdev);
14674cd92098Szrj 		else
14684cd92098Szrj 			DRM_INFO("radeon: acceleration disabled, skipping move tests\n");
1469926deccbSFrançois Tigeot 	}
1470926deccbSFrançois Tigeot 	if ((radeon_testing & 2)) {
14714cd92098Szrj 		if (rdev->accel_working)
1472926deccbSFrançois Tigeot 			radeon_test_syncing(rdev);
14734cd92098Szrj 		else
14744cd92098Szrj 			DRM_INFO("radeon: acceleration disabled, skipping sync tests\n");
1475926deccbSFrançois Tigeot 	}
1476926deccbSFrançois Tigeot 	if (radeon_benchmarking) {
14774cd92098Szrj 		if (rdev->accel_working)
1478926deccbSFrançois Tigeot 			radeon_benchmark(rdev, radeon_benchmarking);
14794cd92098Szrj 		else
14804cd92098Szrj 			DRM_INFO("radeon: acceleration disabled, skipping benchmarks\n");
1481926deccbSFrançois Tigeot 	}
1482926deccbSFrançois Tigeot 	return 0;
1483c6f73aabSFrançois Tigeot 
1484c6f73aabSFrançois Tigeot failed:
1485c6f73aabSFrançois Tigeot #ifdef DRM_BDSM
1486c6f73aabSFrançois Tigeot 	if (runtime)
1487c6f73aabSFrançois Tigeot 		vga_switcheroo_fini_domain_pm_ops(rdev->dev);
1488c6f73aabSFrançois Tigeot #endif
1489c6f73aabSFrançois Tigeot 	return r;
1490926deccbSFrançois Tigeot }
1491926deccbSFrançois Tigeot 
1492926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP
1493926deccbSFrançois Tigeot static void radeon_debugfs_remove_files(struct radeon_device *rdev);
1494926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */
1495926deccbSFrançois Tigeot 
1496926deccbSFrançois Tigeot /**
1497926deccbSFrançois Tigeot  * radeon_device_fini - tear down the driver
1498926deccbSFrançois Tigeot  *
1499926deccbSFrançois Tigeot  * @rdev: radeon_device pointer
1500926deccbSFrançois Tigeot  *
1501926deccbSFrançois Tigeot  * Tear down the driver info (all asics).
1502926deccbSFrançois Tigeot  * Called at driver shutdown.
1503926deccbSFrançois Tigeot  */
1504926deccbSFrançois Tigeot void radeon_device_fini(struct radeon_device *rdev)
1505926deccbSFrançois Tigeot {
1506926deccbSFrançois Tigeot 	DRM_INFO("radeon: finishing device.\n");
1507926deccbSFrançois Tigeot 	rdev->shutdown = true;
1508926deccbSFrançois Tigeot 	/* evict vram memory */
1509926deccbSFrançois Tigeot 	radeon_bo_evict_vram(rdev);
1510926deccbSFrançois Tigeot 
1511926deccbSFrançois Tigeot 	if (rdev->fictitious_range_registered) {
1512926deccbSFrançois Tigeot 		vm_phys_fictitious_unreg_range(
1513926deccbSFrançois Tigeot 		    rdev->mc.aper_base,
1514926deccbSFrançois Tigeot 		    rdev->mc.aper_base + rdev->mc.visible_vram_size);
1515926deccbSFrançois Tigeot 	}
1516926deccbSFrançois Tigeot 
1517926deccbSFrançois Tigeot 	radeon_fini(rdev);
1518926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP
1519926deccbSFrançois Tigeot 	vga_switcheroo_unregister_client(rdev->pdev);
1520c6f73aabSFrançois Tigeot 	if (rdev->flags & RADEON_IS_PX)
1521c6f73aabSFrançois Tigeot 		vga_switcheroo_fini_domain_pm_ops(rdev->dev);
1522926deccbSFrançois Tigeot 	vga_client_register(rdev->pdev, NULL, NULL, NULL);
1523926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */
1524926deccbSFrançois Tigeot 
1525926deccbSFrançois Tigeot 	if (rdev->rio_mem)
1526fb572d17SFrançois Tigeot 		bus_release_resource(rdev->dev->bsddev, SYS_RES_IOPORT, rdev->rio_rid,
1527926deccbSFrançois Tigeot 		    rdev->rio_mem);
1528926deccbSFrançois Tigeot 	rdev->rio_mem = NULL;
1529fb572d17SFrançois Tigeot 	bus_release_resource(rdev->dev->bsddev, SYS_RES_MEMORY, rdev->rmmio_rid,
1530926deccbSFrançois Tigeot 	    rdev->rmmio);
1531926deccbSFrançois Tigeot 	rdev->rmmio = NULL;
153257e252bfSMichael Neumann 	if (rdev->family >= CHIP_BONAIRE)
153357e252bfSMichael Neumann 		radeon_doorbell_fini(rdev);
1534926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP
1535926deccbSFrançois Tigeot 	radeon_debugfs_remove_files(rdev);
1536926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */
1537926deccbSFrançois Tigeot }
1538926deccbSFrançois Tigeot 
1539926deccbSFrançois Tigeot 
1540926deccbSFrançois Tigeot /*
1541926deccbSFrançois Tigeot  * Suspend & resume.
1542926deccbSFrançois Tigeot  */
1543926deccbSFrançois Tigeot /**
1544926deccbSFrançois Tigeot  * radeon_suspend_kms - initiate device suspend
1545926deccbSFrançois Tigeot  *
1546926deccbSFrançois Tigeot  * @pdev: drm dev pointer
1547926deccbSFrançois Tigeot  * @state: suspend state
1548926deccbSFrançois Tigeot  *
1549926deccbSFrançois Tigeot  * Puts the hw in the suspend state (all asics).
1550926deccbSFrançois Tigeot  * Returns 0 for success or an error on failure.
1551926deccbSFrançois Tigeot  * Called at driver suspend.
1552926deccbSFrançois Tigeot  */
1553ee479021SImre Vadász int radeon_suspend_kms(struct drm_device *dev, bool suspend, bool fbcon)
1554926deccbSFrançois Tigeot {
1555926deccbSFrançois Tigeot 	struct radeon_device *rdev;
1556926deccbSFrançois Tigeot 	struct drm_crtc *crtc;
1557926deccbSFrançois Tigeot 	struct drm_connector *connector;
1558926deccbSFrançois Tigeot 	int i, r;
1559926deccbSFrançois Tigeot 
1560926deccbSFrançois Tigeot 	if (dev == NULL || dev->dev_private == NULL) {
1561926deccbSFrançois Tigeot 		return -ENODEV;
1562926deccbSFrançois Tigeot 	}
1563c6f73aabSFrançois Tigeot 
1564926deccbSFrançois Tigeot 	rdev = dev->dev_private;
1565926deccbSFrançois Tigeot 
1566926deccbSFrançois Tigeot 	if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
1567926deccbSFrançois Tigeot 		return 0;
1568926deccbSFrançois Tigeot 
1569926deccbSFrançois Tigeot 	drm_kms_helper_poll_disable(dev);
1570926deccbSFrançois Tigeot 
1571926deccbSFrançois Tigeot 	/* turn off display hw */
1572926deccbSFrançois Tigeot 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
1573926deccbSFrançois Tigeot 		drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
1574926deccbSFrançois Tigeot 	}
1575926deccbSFrançois Tigeot 
1576ee479021SImre Vadász 	/* unpin the front buffers */
1577926deccbSFrançois Tigeot 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
1578ba55f2f5SFrançois Tigeot 		struct radeon_framebuffer *rfb = to_radeon_framebuffer(crtc->primary->fb);
1579926deccbSFrançois Tigeot 		struct radeon_bo *robj;
1580926deccbSFrançois Tigeot 
1581926deccbSFrançois Tigeot 		if (rfb == NULL || rfb->obj == NULL) {
1582926deccbSFrançois Tigeot 			continue;
1583926deccbSFrançois Tigeot 		}
1584926deccbSFrançois Tigeot 		robj = gem_to_radeon_bo(rfb->obj);
1585926deccbSFrançois Tigeot 		/* don't unpin kernel fb objects */
1586926deccbSFrançois Tigeot 		if (!radeon_fbdev_robj_is_fb(rdev, robj)) {
1587926deccbSFrançois Tigeot 			r = radeon_bo_reserve(robj, false);
1588926deccbSFrançois Tigeot 			if (r == 0) {
1589926deccbSFrançois Tigeot 				radeon_bo_unpin(robj);
1590926deccbSFrançois Tigeot 				radeon_bo_unreserve(robj);
1591926deccbSFrançois Tigeot 			}
1592926deccbSFrançois Tigeot 		}
1593926deccbSFrançois Tigeot 	}
1594926deccbSFrançois Tigeot 	/* evict vram memory */
1595926deccbSFrançois Tigeot 	radeon_bo_evict_vram(rdev);
1596926deccbSFrançois Tigeot 
1597926deccbSFrançois Tigeot 	/* wait for gpu to finish processing current batch */
1598926deccbSFrançois Tigeot 	for (i = 0; i < RADEON_NUM_RINGS; i++) {
1599c6f73aabSFrançois Tigeot 		r = radeon_fence_wait_empty(rdev, i);
1600926deccbSFrançois Tigeot 		if (r) {
1601926deccbSFrançois Tigeot 			/* delay GPU reset to resume */
1602c6f73aabSFrançois Tigeot 			radeon_fence_driver_force_completion(rdev, i);
1603926deccbSFrançois Tigeot 		}
1604926deccbSFrançois Tigeot 	}
1605926deccbSFrançois Tigeot 
1606926deccbSFrançois Tigeot 	radeon_save_bios_scratch_regs(rdev);
1607926deccbSFrançois Tigeot 
1608926deccbSFrançois Tigeot 	radeon_suspend(rdev);
1609926deccbSFrançois Tigeot 	radeon_hpd_fini(rdev);
1610926deccbSFrançois Tigeot 	/* evict remaining vram memory */
1611926deccbSFrançois Tigeot 	radeon_bo_evict_vram(rdev);
1612926deccbSFrançois Tigeot 
1613926deccbSFrançois Tigeot 	radeon_agp_suspend(rdev);
1614926deccbSFrançois Tigeot 
1615fb572d17SFrançois Tigeot 	pci_save_state(device_get_parent(rdev->dev->bsddev));
1616926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP
1617ee479021SImre Vadász 	if (suspend) {
1618926deccbSFrançois Tigeot 		/* Shut down the device */
1619926deccbSFrançois Tigeot 		pci_disable_device(dev->pdev);
1620926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */
1621fb572d17SFrançois Tigeot 		pci_set_powerstate(dev->dev->bsddev, PCI_POWERSTATE_D3);
1622926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP
1623926deccbSFrançois Tigeot 	}
1624c6f73aabSFrançois Tigeot #endif
1625c6f73aabSFrançois Tigeot 	if (fbcon) {
1626c6f73aabSFrançois Tigeot #ifdef DUMBBELL_WIP
1627926deccbSFrançois Tigeot 		console_lock();
1628926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */
1629926deccbSFrançois Tigeot 		radeon_fbdev_set_suspend(rdev, 1);
1630926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP
1631926deccbSFrançois Tigeot 		console_unlock();
1632926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */
1633c6f73aabSFrançois Tigeot 	}
1634926deccbSFrançois Tigeot 	return 0;
1635926deccbSFrançois Tigeot }
1636926deccbSFrançois Tigeot 
1637926deccbSFrançois Tigeot /**
1638926deccbSFrançois Tigeot  * radeon_resume_kms - initiate device resume
1639926deccbSFrançois Tigeot  *
1640926deccbSFrançois Tigeot  * @pdev: drm dev pointer
1641926deccbSFrançois Tigeot  *
1642926deccbSFrançois Tigeot  * Bring the hw back to operating state (all asics).
1643926deccbSFrançois Tigeot  * Returns 0 for success or an error on failure.
1644926deccbSFrançois Tigeot  * Called at driver resume.
1645926deccbSFrançois Tigeot  */
1646c6f73aabSFrançois Tigeot int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon)
1647926deccbSFrançois Tigeot {
1648926deccbSFrançois Tigeot 	struct drm_connector *connector;
1649926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
1650926deccbSFrançois Tigeot 	int r;
1651926deccbSFrançois Tigeot 
1652926deccbSFrançois Tigeot 	if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
1653926deccbSFrançois Tigeot 		return 0;
1654926deccbSFrançois Tigeot 
1655926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP
1656c6f73aabSFrançois Tigeot 	if (fbcon) {
1657926deccbSFrançois Tigeot 		console_lock();
1658c6f73aabSFrançois Tigeot 	}
1659926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */
1660c6f73aabSFrançois Tigeot 	if (resume) {
1661fb572d17SFrançois Tigeot 		pci_set_powerstate(dev->dev->bsddev, PCI_POWERSTATE_D0);
1662fb572d17SFrançois Tigeot 		pci_restore_state(device_get_parent(rdev->dev->bsddev));
1663926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP
1664926deccbSFrançois Tigeot 		if (pci_enable_device(dev->pdev)) {
1665c6f73aabSFrançois Tigeot 			if (fbcon)
1666926deccbSFrançois Tigeot 				console_unlock();
1667926deccbSFrançois Tigeot 			return -1;
1668926deccbSFrançois Tigeot 		}
1669926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */
1670c6f73aabSFrançois Tigeot 	}
1671926deccbSFrançois Tigeot 	/* resume AGP if in use */
1672926deccbSFrançois Tigeot 	radeon_agp_resume(rdev);
1673926deccbSFrançois Tigeot 	radeon_resume(rdev);
1674926deccbSFrançois Tigeot 
1675926deccbSFrançois Tigeot 	r = radeon_ib_ring_tests(rdev);
1676926deccbSFrançois Tigeot 	if (r)
1677926deccbSFrançois Tigeot 		DRM_ERROR("ib ring test failed (%d).\n", r);
1678926deccbSFrançois Tigeot 
1679c6f73aabSFrançois Tigeot 	if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) {
1680c6f73aabSFrançois Tigeot 		/* do dpm late init */
1681c6f73aabSFrançois Tigeot 		r = radeon_pm_late_init(rdev);
1682c6f73aabSFrançois Tigeot 		if (r) {
1683c6f73aabSFrançois Tigeot 			rdev->pm.dpm_enabled = false;
1684c6f73aabSFrançois Tigeot 			DRM_ERROR("radeon_pm_late_init failed, disabling dpm\n");
1685c6f73aabSFrançois Tigeot 		}
1686c6f73aabSFrançois Tigeot 	} else {
1687c6f73aabSFrançois Tigeot 		/* resume old pm late */
1688926deccbSFrançois Tigeot 		radeon_pm_resume(rdev);
1689c6f73aabSFrançois Tigeot 	}
1690926deccbSFrançois Tigeot 
1691c6f73aabSFrançois Tigeot 	radeon_restore_bios_scratch_regs(rdev);
1692926deccbSFrançois Tigeot 
1693926deccbSFrançois Tigeot 	/* init dig PHYs, disp eng pll */
1694926deccbSFrançois Tigeot 	if (rdev->is_atom_bios) {
1695926deccbSFrançois Tigeot 		radeon_atom_encoder_init(rdev);
1696926deccbSFrançois Tigeot 		radeon_atom_disp_eng_pll_init(rdev);
1697926deccbSFrançois Tigeot 		/* turn on the BL */
1698926deccbSFrançois Tigeot 		if (rdev->mode_info.bl_encoder) {
1699926deccbSFrançois Tigeot 			u8 bl_level = radeon_get_backlight_level(rdev,
1700926deccbSFrançois Tigeot 								 rdev->mode_info.bl_encoder);
1701926deccbSFrançois Tigeot 			radeon_set_backlight_level(rdev, rdev->mode_info.bl_encoder,
1702926deccbSFrançois Tigeot 						   bl_level);
1703926deccbSFrançois Tigeot 		}
1704926deccbSFrançois Tigeot 	}
1705926deccbSFrançois Tigeot 	/* reset hpd state */
1706926deccbSFrançois Tigeot 	radeon_hpd_init(rdev);
1707926deccbSFrançois Tigeot 	/* blat the mode back in */
1708c6f73aabSFrançois Tigeot 	if (fbcon) {
1709926deccbSFrançois Tigeot 		drm_helper_resume_force_mode(dev);
1710926deccbSFrançois Tigeot 		/* turn on display hw */
1711926deccbSFrançois Tigeot 		list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
1712926deccbSFrançois Tigeot 			drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
1713926deccbSFrançois Tigeot 		}
1714c6f73aabSFrançois Tigeot 	}
1715926deccbSFrançois Tigeot 
1716926deccbSFrançois Tigeot 	drm_kms_helper_poll_enable(dev);
1717c6f73aabSFrançois Tigeot 
1718c6f73aabSFrançois Tigeot 	/* set the power state here in case we are a PX system or headless */
1719c6f73aabSFrançois Tigeot 	if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled)
1720c6f73aabSFrançois Tigeot 		radeon_pm_compute_clocks(rdev);
1721c6f73aabSFrançois Tigeot 
1722c6f73aabSFrançois Tigeot 	if (fbcon) {
1723c6f73aabSFrançois Tigeot 		radeon_fbdev_set_suspend(rdev, 0);
1724c6f73aabSFrançois Tigeot #ifdef DUMBBELL_WIP
1725c6f73aabSFrançois Tigeot 		console_unlock();
1726c6f73aabSFrançois Tigeot #endif /* DUMBBELL_WIP */
1727c6f73aabSFrançois Tigeot 	}
1728c6f73aabSFrançois Tigeot 
1729926deccbSFrançois Tigeot 	return 0;
1730926deccbSFrançois Tigeot }
1731926deccbSFrançois Tigeot 
1732926deccbSFrançois Tigeot /**
1733926deccbSFrançois Tigeot  * radeon_gpu_reset - reset the asic
1734926deccbSFrançois Tigeot  *
1735926deccbSFrançois Tigeot  * @rdev: radeon device pointer
1736926deccbSFrançois Tigeot  *
1737926deccbSFrançois Tigeot  * Attempt the reset the GPU if it has hung (all asics).
1738926deccbSFrançois Tigeot  * Returns 0 for success or an error on failure.
1739926deccbSFrançois Tigeot  */
1740926deccbSFrançois Tigeot int radeon_gpu_reset(struct radeon_device *rdev)
1741926deccbSFrançois Tigeot {
1742926deccbSFrançois Tigeot 	unsigned ring_sizes[RADEON_NUM_RINGS];
1743926deccbSFrançois Tigeot 	uint32_t *ring_data[RADEON_NUM_RINGS];
1744926deccbSFrançois Tigeot 
1745926deccbSFrançois Tigeot 	bool saved = false;
1746926deccbSFrançois Tigeot 
1747926deccbSFrançois Tigeot 	int i, r;
1748926deccbSFrançois Tigeot 	int resched;
1749926deccbSFrançois Tigeot 
1750926deccbSFrançois Tigeot 	lockmgr(&rdev->exclusive_lock, LK_EXCLUSIVE);
1751c6f73aabSFrançois Tigeot 
1752c6f73aabSFrançois Tigeot 	if (!rdev->needs_reset) {
1753c6f73aabSFrançois Tigeot 		lockmgr(&rdev->exclusive_lock, LK_RELEASE);
1754c6f73aabSFrançois Tigeot 		return 0;
1755c6f73aabSFrançois Tigeot 	}
1756c6f73aabSFrançois Tigeot 
1757926deccbSFrançois Tigeot 	radeon_save_bios_scratch_regs(rdev);
1758926deccbSFrançois Tigeot 	/* block TTM */
1759926deccbSFrançois Tigeot 	resched = ttm_bo_lock_delayed_workqueue(&rdev->mman.bdev);
1760926deccbSFrançois Tigeot 	radeon_suspend(rdev);
1761c6f73aabSFrançois Tigeot 	radeon_hpd_fini(rdev);
1762926deccbSFrançois Tigeot 
1763926deccbSFrançois Tigeot 	for (i = 0; i < RADEON_NUM_RINGS; ++i) {
1764926deccbSFrançois Tigeot 		ring_sizes[i] = radeon_ring_backup(rdev, &rdev->ring[i],
1765926deccbSFrançois Tigeot 						   &ring_data[i]);
1766926deccbSFrançois Tigeot 		if (ring_sizes[i]) {
1767926deccbSFrançois Tigeot 			saved = true;
1768926deccbSFrançois Tigeot 			dev_info(rdev->dev, "Saved %d dwords of commands "
1769926deccbSFrançois Tigeot 				 "on ring %d.\n", ring_sizes[i], i);
1770926deccbSFrançois Tigeot 		}
1771926deccbSFrançois Tigeot 	}
1772926deccbSFrançois Tigeot 
1773926deccbSFrançois Tigeot 	r = radeon_asic_reset(rdev);
1774926deccbSFrançois Tigeot 	if (!r) {
1775926deccbSFrançois Tigeot 		dev_info(rdev->dev, "GPU reset succeeded, trying to resume\n");
1776926deccbSFrançois Tigeot 		radeon_resume(rdev);
1777926deccbSFrançois Tigeot 	}
1778926deccbSFrançois Tigeot 
1779926deccbSFrançois Tigeot 	radeon_restore_bios_scratch_regs(rdev);
1780926deccbSFrançois Tigeot 
1781926deccbSFrançois Tigeot 	for (i = 0; i < RADEON_NUM_RINGS; ++i) {
1782591d5043SFrançois Tigeot 		if (!r && ring_data[i]) {
1783926deccbSFrançois Tigeot 			radeon_ring_restore(rdev, &rdev->ring[i],
1784926deccbSFrançois Tigeot 					    ring_sizes[i], ring_data[i]);
1785926deccbSFrançois Tigeot 		} else {
1786c6f73aabSFrançois Tigeot 			radeon_fence_driver_force_completion(rdev, i);
1787c4ef309bSzrj 			kfree(ring_data[i]);
1788926deccbSFrançois Tigeot 		}
1789926deccbSFrançois Tigeot 	}
1790926deccbSFrançois Tigeot 
1791c6f73aabSFrançois Tigeot 	if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) {
1792c6f73aabSFrançois Tigeot 		/* do dpm late init */
1793c6f73aabSFrançois Tigeot 		r = radeon_pm_late_init(rdev);
1794c6f73aabSFrançois Tigeot 		if (r) {
1795c6f73aabSFrançois Tigeot 			rdev->pm.dpm_enabled = false;
1796c6f73aabSFrançois Tigeot 			DRM_ERROR("radeon_pm_late_init failed, disabling dpm\n");
1797c6f73aabSFrançois Tigeot 		}
1798c6f73aabSFrançois Tigeot 	} else {
1799c6f73aabSFrançois Tigeot 		/* resume old pm late */
180057e252bfSMichael Neumann 		radeon_pm_resume(rdev);
1801c6f73aabSFrançois Tigeot 	}
1802c6f73aabSFrançois Tigeot 
1803c6f73aabSFrançois Tigeot 	/* init dig PHYs, disp eng pll */
1804c6f73aabSFrançois Tigeot 	if (rdev->is_atom_bios) {
1805c6f73aabSFrançois Tigeot 		radeon_atom_encoder_init(rdev);
1806c6f73aabSFrançois Tigeot 		radeon_atom_disp_eng_pll_init(rdev);
1807c6f73aabSFrançois Tigeot 		/* turn on the BL */
1808c6f73aabSFrançois Tigeot 		if (rdev->mode_info.bl_encoder) {
1809c6f73aabSFrançois Tigeot 			u8 bl_level = radeon_get_backlight_level(rdev,
1810c6f73aabSFrançois Tigeot 								 rdev->mode_info.bl_encoder);
1811c6f73aabSFrançois Tigeot 			radeon_set_backlight_level(rdev, rdev->mode_info.bl_encoder,
1812c6f73aabSFrançois Tigeot 						   bl_level);
1813c6f73aabSFrançois Tigeot 		}
1814c6f73aabSFrançois Tigeot 	}
1815c6f73aabSFrançois Tigeot 	/* reset hpd state */
1816c6f73aabSFrançois Tigeot 	radeon_hpd_init(rdev);
1817c6f73aabSFrançois Tigeot 
1818591d5043SFrançois Tigeot 	ttm_bo_unlock_delayed_workqueue(&rdev->mman.bdev, resched);
1819591d5043SFrançois Tigeot 
1820591d5043SFrançois Tigeot 	rdev->in_reset = true;
1821591d5043SFrançois Tigeot 	rdev->needs_reset = false;
1822591d5043SFrançois Tigeot 
1823591d5043SFrançois Tigeot #if 0
1824591d5043SFrançois Tigeot 	downgrade_write(&rdev->exclusive_lock);
1825591d5043SFrançois Tigeot #endif
1826591d5043SFrançois Tigeot 
1827926deccbSFrançois Tigeot 	drm_helper_resume_force_mode(rdev->ddev);
1828926deccbSFrançois Tigeot 
1829c6f73aabSFrançois Tigeot 	/* set the power state here in case we are a PX system or headless */
1830c6f73aabSFrançois Tigeot 	if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled)
1831c6f73aabSFrançois Tigeot 		radeon_pm_compute_clocks(rdev);
1832c6f73aabSFrançois Tigeot 
1833591d5043SFrançois Tigeot 	if (!r) {
1834591d5043SFrançois Tigeot 		r = radeon_ib_ring_tests(rdev);
1835591d5043SFrançois Tigeot 		if (r && saved)
1836591d5043SFrançois Tigeot 			r = -EAGAIN;
1837591d5043SFrançois Tigeot 	} else {
1838926deccbSFrançois Tigeot 		/* bad news, how to tell it to userspace ? */
1839926deccbSFrançois Tigeot 		dev_info(rdev->dev, "GPU reset failed\n");
1840926deccbSFrançois Tigeot 	}
1841926deccbSFrançois Tigeot 
1842591d5043SFrançois Tigeot 	rdev->needs_reset = r == -EAGAIN;
1843591d5043SFrançois Tigeot 	rdev->in_reset = false;
1844591d5043SFrançois Tigeot 
1845926deccbSFrançois Tigeot 	lockmgr(&rdev->exclusive_lock, LK_RELEASE);
1846926deccbSFrançois Tigeot 	return r;
1847926deccbSFrançois Tigeot }
1848926deccbSFrançois Tigeot 
1849926deccbSFrançois Tigeot 
1850926deccbSFrançois Tigeot /*
1851926deccbSFrançois Tigeot  * Debugfs
1852926deccbSFrançois Tigeot  */
1853926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP
1854926deccbSFrançois Tigeot int radeon_debugfs_add_files(struct radeon_device *rdev,
1855926deccbSFrançois Tigeot 			     struct drm_info_list *files,
1856926deccbSFrançois Tigeot 			     unsigned nfiles)
1857926deccbSFrançois Tigeot {
1858926deccbSFrançois Tigeot 	unsigned i;
1859926deccbSFrançois Tigeot 
1860926deccbSFrançois Tigeot 	for (i = 0; i < rdev->debugfs_count; i++) {
1861926deccbSFrançois Tigeot 		if (rdev->debugfs[i].files == files) {
1862926deccbSFrançois Tigeot 			/* Already registered */
1863926deccbSFrançois Tigeot 			return 0;
1864926deccbSFrançois Tigeot 		}
1865926deccbSFrançois Tigeot 	}
1866926deccbSFrançois Tigeot 
1867926deccbSFrançois Tigeot 	i = rdev->debugfs_count + 1;
1868926deccbSFrançois Tigeot 	if (i > RADEON_DEBUGFS_MAX_COMPONENTS) {
1869926deccbSFrançois Tigeot 		DRM_ERROR("Reached maximum number of debugfs components.\n");
1870926deccbSFrançois Tigeot 		DRM_ERROR("Report so we increase "
1871926deccbSFrançois Tigeot 		          "RADEON_DEBUGFS_MAX_COMPONENTS.\n");
1872926deccbSFrançois Tigeot 		return -EINVAL;
1873926deccbSFrançois Tigeot 	}
1874926deccbSFrançois Tigeot 	rdev->debugfs[rdev->debugfs_count].files = files;
1875926deccbSFrançois Tigeot 	rdev->debugfs[rdev->debugfs_count].num_files = nfiles;
1876926deccbSFrançois Tigeot 	rdev->debugfs_count = i;
1877926deccbSFrançois Tigeot #if defined(CONFIG_DEBUG_FS)
1878926deccbSFrançois Tigeot 	drm_debugfs_create_files(files, nfiles,
1879926deccbSFrançois Tigeot 				 rdev->ddev->control->debugfs_root,
1880926deccbSFrançois Tigeot 				 rdev->ddev->control);
1881926deccbSFrançois Tigeot 	drm_debugfs_create_files(files, nfiles,
1882926deccbSFrançois Tigeot 				 rdev->ddev->primary->debugfs_root,
1883926deccbSFrançois Tigeot 				 rdev->ddev->primary);
1884926deccbSFrançois Tigeot #endif
1885926deccbSFrançois Tigeot 	return 0;
1886926deccbSFrançois Tigeot }
1887926deccbSFrançois Tigeot 
1888926deccbSFrançois Tigeot static void radeon_debugfs_remove_files(struct radeon_device *rdev)
1889926deccbSFrançois Tigeot {
1890926deccbSFrançois Tigeot #if defined(CONFIG_DEBUG_FS)
1891926deccbSFrançois Tigeot 	unsigned i;
1892926deccbSFrançois Tigeot 
1893926deccbSFrançois Tigeot 	for (i = 0; i < rdev->debugfs_count; i++) {
1894926deccbSFrançois Tigeot 		drm_debugfs_remove_files(rdev->debugfs[i].files,
1895926deccbSFrançois Tigeot 					 rdev->debugfs[i].num_files,
1896926deccbSFrançois Tigeot 					 rdev->ddev->control);
1897926deccbSFrançois Tigeot 		drm_debugfs_remove_files(rdev->debugfs[i].files,
1898926deccbSFrançois Tigeot 					 rdev->debugfs[i].num_files,
1899926deccbSFrançois Tigeot 					 rdev->ddev->primary);
1900926deccbSFrançois Tigeot 	}
1901926deccbSFrançois Tigeot #endif
1902926deccbSFrançois Tigeot }
1903926deccbSFrançois Tigeot 
1904926deccbSFrançois Tigeot #if defined(CONFIG_DEBUG_FS)
1905926deccbSFrançois Tigeot int radeon_debugfs_init(struct drm_minor *minor)
1906926deccbSFrançois Tigeot {
1907926deccbSFrançois Tigeot 	return 0;
1908926deccbSFrançois Tigeot }
1909926deccbSFrançois Tigeot 
1910926deccbSFrançois Tigeot void radeon_debugfs_cleanup(struct drm_minor *minor)
1911926deccbSFrançois Tigeot {
1912926deccbSFrançois Tigeot }
1913926deccbSFrançois Tigeot #endif
1914b6771645Szrj #endif /* DUMBBELL_WIP */
1915