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 */
28c59a5c48SFrançois Tigeot #include <linux/console.h>
29926deccbSFrançois Tigeot #include <drm/drmP.h>
304250aa95Szrj #include "drm/drm_legacy.h" /* for drm_dma_handle_t */
31926deccbSFrançois Tigeot #include <drm/drm_crtc_helper.h>
3283b4b9b9SFrançois Tigeot #include <drm/radeon_drm.h>
33c59a5c48SFrançois Tigeot #include <linux/vgaarb.h>
34c59a5c48SFrançois Tigeot #include <linux/vga_switcheroo.h>
35926deccbSFrançois Tigeot #include "radeon_reg.h"
36926deccbSFrançois Tigeot #include "radeon.h"
37926deccbSFrançois Tigeot #include "atom.h"
38926deccbSFrançois Tigeot
39c59a5c48SFrançois Tigeot #include <asm/cpufeature.h>
40c59a5c48SFrançois Tigeot
41926deccbSFrançois Tigeot static const char radeon_family_name[][16] = {
42926deccbSFrançois Tigeot "R100",
43926deccbSFrançois Tigeot "RV100",
44926deccbSFrançois Tigeot "RS100",
45926deccbSFrançois Tigeot "RV200",
46926deccbSFrançois Tigeot "RS200",
47926deccbSFrançois Tigeot "R200",
48926deccbSFrançois Tigeot "RV250",
49926deccbSFrançois Tigeot "RS300",
50926deccbSFrançois Tigeot "RV280",
51926deccbSFrançois Tigeot "R300",
52926deccbSFrançois Tigeot "R350",
53926deccbSFrançois Tigeot "RV350",
54926deccbSFrançois Tigeot "RV380",
55926deccbSFrançois Tigeot "R420",
56926deccbSFrançois Tigeot "R423",
57926deccbSFrançois Tigeot "RV410",
58926deccbSFrançois Tigeot "RS400",
59926deccbSFrançois Tigeot "RS480",
60926deccbSFrançois Tigeot "RS600",
61926deccbSFrançois Tigeot "RS690",
62926deccbSFrançois Tigeot "RS740",
63926deccbSFrançois Tigeot "RV515",
64926deccbSFrançois Tigeot "R520",
65926deccbSFrançois Tigeot "RV530",
66926deccbSFrançois Tigeot "RV560",
67926deccbSFrançois Tigeot "RV570",
68926deccbSFrançois Tigeot "R580",
69926deccbSFrançois Tigeot "R600",
70926deccbSFrançois Tigeot "RV610",
71926deccbSFrançois Tigeot "RV630",
72926deccbSFrançois Tigeot "RV670",
73926deccbSFrançois Tigeot "RV620",
74926deccbSFrançois Tigeot "RV635",
75926deccbSFrançois Tigeot "RS780",
76926deccbSFrançois Tigeot "RS880",
77926deccbSFrançois Tigeot "RV770",
78926deccbSFrançois Tigeot "RV730",
79926deccbSFrançois Tigeot "RV710",
80926deccbSFrançois Tigeot "RV740",
81926deccbSFrançois Tigeot "CEDAR",
82926deccbSFrançois Tigeot "REDWOOD",
83926deccbSFrançois Tigeot "JUNIPER",
84926deccbSFrançois Tigeot "CYPRESS",
85926deccbSFrançois Tigeot "HEMLOCK",
86926deccbSFrançois Tigeot "PALM",
87926deccbSFrançois Tigeot "SUMO",
88926deccbSFrançois Tigeot "SUMO2",
89926deccbSFrançois Tigeot "BARTS",
90926deccbSFrançois Tigeot "TURKS",
91926deccbSFrançois Tigeot "CAICOS",
92926deccbSFrançois Tigeot "CAYMAN",
93926deccbSFrançois Tigeot "ARUBA",
94926deccbSFrançois Tigeot "TAHITI",
95926deccbSFrançois Tigeot "PITCAIRN",
96926deccbSFrançois Tigeot "VERDE",
97b403bed8SMichael Neumann "OLAND",
98f43cf1b1SMichael Neumann "HAINAN",
9957e252bfSMichael Neumann "BONAIRE",
10057e252bfSMichael Neumann "KAVERI",
10157e252bfSMichael Neumann "KABINI",
102c6f73aabSFrançois Tigeot "HAWAII",
103c6f73aabSFrançois Tigeot "MULLINS",
104926deccbSFrançois Tigeot "LAST",
105926deccbSFrançois Tigeot };
106926deccbSFrançois Tigeot
1071dedbd3bSFrançois Tigeot #if defined(CONFIG_VGA_SWITCHEROO)
1081dedbd3bSFrançois Tigeot bool radeon_has_atpx_dgpu_power_cntl(void);
1091dedbd3bSFrançois Tigeot bool radeon_is_atpx_hybrid(void);
1101dedbd3bSFrançois Tigeot #else
radeon_has_atpx_dgpu_power_cntl(void)1111dedbd3bSFrançois Tigeot static inline bool radeon_has_atpx_dgpu_power_cntl(void) { return false; }
radeon_is_atpx_hybrid(void)1121dedbd3bSFrançois Tigeot static inline bool radeon_is_atpx_hybrid(void) { return false; }
1131dedbd3bSFrançois Tigeot #endif
1141dedbd3bSFrançois Tigeot
115c6f73aabSFrançois Tigeot #define RADEON_PX_QUIRK_DISABLE_PX (1 << 0)
116c6f73aabSFrançois Tigeot
117c6f73aabSFrançois Tigeot struct radeon_px_quirk {
118c6f73aabSFrançois Tigeot u32 chip_vendor;
119c6f73aabSFrançois Tigeot u32 chip_device;
120c6f73aabSFrançois Tigeot u32 subsys_vendor;
121c6f73aabSFrançois Tigeot u32 subsys_device;
122c6f73aabSFrançois Tigeot u32 px_quirk_flags;
123c6f73aabSFrançois Tigeot };
124c6f73aabSFrançois Tigeot
125c6f73aabSFrançois Tigeot static struct radeon_px_quirk radeon_px_quirk_list[] = {
126c6f73aabSFrançois Tigeot /* Acer aspire 5560g (CPU: AMD A4-3305M; GPU: AMD Radeon HD 6480g + 7470m)
127c6f73aabSFrançois Tigeot * https://bugzilla.kernel.org/show_bug.cgi?id=74551
128c6f73aabSFrançois Tigeot */
129c6f73aabSFrançois Tigeot { PCI_VENDOR_ID_ATI, 0x6760, 0x1025, 0x0672, RADEON_PX_QUIRK_DISABLE_PX },
130c6f73aabSFrançois Tigeot /* Asus K73TA laptop with AMD A6-3400M APU and Radeon 6550 GPU
131c6f73aabSFrançois Tigeot * https://bugzilla.kernel.org/show_bug.cgi?id=51381
132c6f73aabSFrançois Tigeot */
133c6f73aabSFrançois Tigeot { PCI_VENDOR_ID_ATI, 0x6741, 0x1043, 0x108c, RADEON_PX_QUIRK_DISABLE_PX },
134c6f73aabSFrançois Tigeot /* Asus K53TK laptop with AMD A6-3420M APU and Radeon 7670m GPU
135c6f73aabSFrançois Tigeot * https://bugzilla.kernel.org/show_bug.cgi?id=51381
136c6f73aabSFrançois Tigeot */
137c6f73aabSFrançois Tigeot { PCI_VENDOR_ID_ATI, 0x6840, 0x1043, 0x2122, RADEON_PX_QUIRK_DISABLE_PX },
138c59a5c48SFrançois Tigeot /* Asus K53TK laptop with AMD A6-3420M APU and Radeon 7670m GPU
139c59a5c48SFrançois Tigeot * https://bugs.freedesktop.org/show_bug.cgi?id=101491
140c59a5c48SFrançois Tigeot */
141*3f2dd94aSFrançois Tigeot { PCI_VENDOR_ID_ATI, 0x6840, 0x1043, 0x2122, RADEON_PX_QUIRK_DISABLE_PX },
142c6f73aabSFrançois Tigeot { 0, 0, 0, 0, 0 },
143c6f73aabSFrançois Tigeot };
144c6f73aabSFrançois Tigeot
radeon_is_px(struct drm_device * dev)145c6f73aabSFrançois Tigeot bool radeon_is_px(struct drm_device *dev)
146c6f73aabSFrançois Tigeot {
147c6f73aabSFrançois Tigeot struct radeon_device *rdev = dev->dev_private;
148c6f73aabSFrançois Tigeot
149c6f73aabSFrançois Tigeot if (rdev->flags & RADEON_IS_PX)
150c6f73aabSFrançois Tigeot return true;
151c6f73aabSFrançois Tigeot return false;
152c6f73aabSFrançois Tigeot }
153c6f73aabSFrançois Tigeot
radeon_device_handle_px_quirks(struct radeon_device * rdev)154c6f73aabSFrançois Tigeot static void radeon_device_handle_px_quirks(struct radeon_device *rdev)
155c6f73aabSFrançois Tigeot {
156c6f73aabSFrançois Tigeot struct radeon_px_quirk *p = radeon_px_quirk_list;
157c6f73aabSFrançois Tigeot
158c6f73aabSFrançois Tigeot /* Apply PX quirks */
159c6f73aabSFrançois Tigeot while (p && p->chip_device != 0) {
160c6f73aabSFrançois Tigeot if (rdev->pdev->vendor == p->chip_vendor &&
161c6f73aabSFrançois Tigeot rdev->pdev->device == p->chip_device &&
162c6f73aabSFrançois Tigeot rdev->pdev->subsystem_vendor == p->subsys_vendor &&
163c6f73aabSFrançois Tigeot rdev->pdev->subsystem_device == p->subsys_device) {
164c6f73aabSFrançois Tigeot rdev->px_quirk_flags = p->px_quirk_flags;
165c6f73aabSFrançois Tigeot break;
166c6f73aabSFrançois Tigeot }
167c6f73aabSFrançois Tigeot ++p;
168c6f73aabSFrançois Tigeot }
169c6f73aabSFrançois Tigeot
170c6f73aabSFrançois Tigeot if (rdev->px_quirk_flags & RADEON_PX_QUIRK_DISABLE_PX)
171c6f73aabSFrançois Tigeot rdev->flags &= ~RADEON_IS_PX;
1721dedbd3bSFrançois Tigeot
1731dedbd3bSFrançois Tigeot /* disable PX is the system doesn't support dGPU power control or hybrid gfx */
1741dedbd3bSFrançois Tigeot if (!radeon_is_atpx_hybrid() &&
1751dedbd3bSFrançois Tigeot !radeon_has_atpx_dgpu_power_cntl())
1761dedbd3bSFrançois Tigeot rdev->flags &= ~RADEON_IS_PX;
177c6f73aabSFrançois Tigeot }
178c6f73aabSFrançois Tigeot
179926deccbSFrançois Tigeot /**
180f43cf1b1SMichael Neumann * radeon_program_register_sequence - program an array of registers.
181f43cf1b1SMichael Neumann *
182f43cf1b1SMichael Neumann * @rdev: radeon_device pointer
183f43cf1b1SMichael Neumann * @registers: pointer to the register array
184f43cf1b1SMichael Neumann * @array_size: size of the register array
185f43cf1b1SMichael Neumann *
186f43cf1b1SMichael Neumann * Programs an array or registers with and and or masks.
187f43cf1b1SMichael Neumann * This is a helper for setting golden registers.
188f43cf1b1SMichael Neumann */
radeon_program_register_sequence(struct radeon_device * rdev,const u32 * registers,const u32 array_size)189f43cf1b1SMichael Neumann void radeon_program_register_sequence(struct radeon_device *rdev,
190f43cf1b1SMichael Neumann const u32 *registers,
191f43cf1b1SMichael Neumann const u32 array_size)
192f43cf1b1SMichael Neumann {
193f43cf1b1SMichael Neumann u32 tmp, reg, and_mask, or_mask;
194f43cf1b1SMichael Neumann int i;
195f43cf1b1SMichael Neumann
196f43cf1b1SMichael Neumann if (array_size % 3)
197f43cf1b1SMichael Neumann return;
198f43cf1b1SMichael Neumann
199f43cf1b1SMichael Neumann for (i = 0; i < array_size; i +=3) {
200f43cf1b1SMichael Neumann reg = registers[i + 0];
201f43cf1b1SMichael Neumann and_mask = registers[i + 1];
202f43cf1b1SMichael Neumann or_mask = registers[i + 2];
203f43cf1b1SMichael Neumann
204f43cf1b1SMichael Neumann if (and_mask == 0xffffffff) {
205f43cf1b1SMichael Neumann tmp = or_mask;
206f43cf1b1SMichael Neumann } else {
207f43cf1b1SMichael Neumann tmp = RREG32(reg);
208f43cf1b1SMichael Neumann tmp &= ~and_mask;
209f43cf1b1SMichael Neumann tmp |= or_mask;
210f43cf1b1SMichael Neumann }
211f43cf1b1SMichael Neumann WREG32(reg, tmp);
212f43cf1b1SMichael Neumann }
213f43cf1b1SMichael Neumann }
214f43cf1b1SMichael Neumann
radeon_pci_config_reset(struct radeon_device * rdev)215c6f73aabSFrançois Tigeot void radeon_pci_config_reset(struct radeon_device *rdev)
216c6f73aabSFrançois Tigeot {
217c6f73aabSFrançois Tigeot pci_write_config_dword(rdev->pdev, 0x7c, RADEON_ASIC_RESET_DATA);
218c6f73aabSFrançois Tigeot }
219c6f73aabSFrançois Tigeot
220f43cf1b1SMichael Neumann /**
221926deccbSFrançois Tigeot * radeon_surface_init - Clear GPU surface registers.
222926deccbSFrançois Tigeot *
223926deccbSFrançois Tigeot * @rdev: radeon_device pointer
224926deccbSFrançois Tigeot *
225926deccbSFrançois Tigeot * Clear GPU surface registers (r1xx-r5xx).
226926deccbSFrançois Tigeot */
radeon_surface_init(struct radeon_device * rdev)227926deccbSFrançois Tigeot void radeon_surface_init(struct radeon_device *rdev)
228926deccbSFrançois Tigeot {
229926deccbSFrançois Tigeot /* FIXME: check this out */
230926deccbSFrançois Tigeot if (rdev->family < CHIP_R600) {
231926deccbSFrançois Tigeot int i;
232926deccbSFrançois Tigeot
233926deccbSFrançois Tigeot for (i = 0; i < RADEON_GEM_MAX_SURFACES; i++) {
234926deccbSFrançois Tigeot if (rdev->surface_regs[i].bo)
235926deccbSFrançois Tigeot radeon_bo_get_surface_reg(rdev->surface_regs[i].bo);
236926deccbSFrançois Tigeot else
237926deccbSFrançois Tigeot radeon_clear_surface_reg(rdev, i);
238926deccbSFrançois Tigeot }
239926deccbSFrançois Tigeot /* enable surfaces */
240926deccbSFrançois Tigeot WREG32(RADEON_SURFACE_CNTL, 0);
241926deccbSFrançois Tigeot }
242926deccbSFrançois Tigeot }
243926deccbSFrançois Tigeot
244926deccbSFrançois Tigeot /*
245926deccbSFrançois Tigeot * GPU scratch registers helpers function.
246926deccbSFrançois Tigeot */
247926deccbSFrançois Tigeot /**
248926deccbSFrançois Tigeot * radeon_scratch_init - Init scratch register driver information.
249926deccbSFrançois Tigeot *
250926deccbSFrançois Tigeot * @rdev: radeon_device pointer
251926deccbSFrançois Tigeot *
252926deccbSFrançois Tigeot * Init CP scratch register driver information (r1xx-r5xx)
253926deccbSFrançois Tigeot */
radeon_scratch_init(struct radeon_device * rdev)254926deccbSFrançois Tigeot void radeon_scratch_init(struct radeon_device *rdev)
255926deccbSFrançois Tigeot {
256926deccbSFrançois Tigeot int i;
257926deccbSFrançois Tigeot
258926deccbSFrançois Tigeot /* FIXME: check this out */
259926deccbSFrançois Tigeot if (rdev->family < CHIP_R300) {
260926deccbSFrançois Tigeot rdev->scratch.num_reg = 5;
261926deccbSFrançois Tigeot } else {
262926deccbSFrançois Tigeot rdev->scratch.num_reg = 7;
263926deccbSFrançois Tigeot }
264926deccbSFrançois Tigeot rdev->scratch.reg_base = RADEON_SCRATCH_REG0;
265926deccbSFrançois Tigeot for (i = 0; i < rdev->scratch.num_reg; i++) {
266926deccbSFrançois Tigeot rdev->scratch.free[i] = true;
267926deccbSFrançois Tigeot rdev->scratch.reg[i] = rdev->scratch.reg_base + (i * 4);
268926deccbSFrançois Tigeot }
269926deccbSFrançois Tigeot }
270926deccbSFrançois Tigeot
271926deccbSFrançois Tigeot /**
272926deccbSFrançois Tigeot * radeon_scratch_get - Allocate a scratch register
273926deccbSFrançois Tigeot *
274926deccbSFrançois Tigeot * @rdev: radeon_device pointer
275926deccbSFrançois Tigeot * @reg: scratch register mmio offset
276926deccbSFrançois Tigeot *
277926deccbSFrançois Tigeot * Allocate a CP scratch register for use by the driver (all asics).
278926deccbSFrançois Tigeot * Returns 0 on success or -EINVAL on failure.
279926deccbSFrançois Tigeot */
radeon_scratch_get(struct radeon_device * rdev,uint32_t * reg)280926deccbSFrançois Tigeot int radeon_scratch_get(struct radeon_device *rdev, uint32_t *reg)
281926deccbSFrançois Tigeot {
282926deccbSFrançois Tigeot int i;
283926deccbSFrançois Tigeot
284926deccbSFrançois Tigeot for (i = 0; i < rdev->scratch.num_reg; i++) {
285926deccbSFrançois Tigeot if (rdev->scratch.free[i]) {
286926deccbSFrançois Tigeot rdev->scratch.free[i] = false;
287926deccbSFrançois Tigeot *reg = rdev->scratch.reg[i];
288926deccbSFrançois Tigeot return 0;
289926deccbSFrançois Tigeot }
290926deccbSFrançois Tigeot }
291926deccbSFrançois Tigeot return -EINVAL;
292926deccbSFrançois Tigeot }
293926deccbSFrançois Tigeot
294926deccbSFrançois Tigeot /**
295926deccbSFrançois Tigeot * radeon_scratch_free - Free a scratch register
296926deccbSFrançois Tigeot *
297926deccbSFrançois Tigeot * @rdev: radeon_device pointer
298926deccbSFrançois Tigeot * @reg: scratch register mmio offset
299926deccbSFrançois Tigeot *
300926deccbSFrançois Tigeot * Free a CP scratch register allocated for use by the driver (all asics)
301926deccbSFrançois Tigeot */
radeon_scratch_free(struct radeon_device * rdev,uint32_t reg)302926deccbSFrançois Tigeot void radeon_scratch_free(struct radeon_device *rdev, uint32_t reg)
303926deccbSFrançois Tigeot {
304926deccbSFrançois Tigeot int i;
305926deccbSFrançois Tigeot
306926deccbSFrançois Tigeot for (i = 0; i < rdev->scratch.num_reg; i++) {
307926deccbSFrançois Tigeot if (rdev->scratch.reg[i] == reg) {
308926deccbSFrançois Tigeot rdev->scratch.free[i] = true;
309926deccbSFrançois Tigeot return;
310926deccbSFrançois Tigeot }
311926deccbSFrançois Tigeot }
312926deccbSFrançois Tigeot }
313926deccbSFrançois Tigeot
314926deccbSFrançois Tigeot /*
31557e252bfSMichael Neumann * GPU doorbell aperture helpers function.
31657e252bfSMichael Neumann */
31757e252bfSMichael Neumann /**
31857e252bfSMichael Neumann * radeon_doorbell_init - Init doorbell driver information.
31957e252bfSMichael Neumann *
32057e252bfSMichael Neumann * @rdev: radeon_device pointer
32157e252bfSMichael Neumann *
32257e252bfSMichael Neumann * Init doorbell driver information (CIK)
32357e252bfSMichael Neumann * Returns 0 on success, error on failure.
32457e252bfSMichael Neumann */
radeon_doorbell_init(struct radeon_device * rdev)325c6f73aabSFrançois Tigeot static int radeon_doorbell_init(struct radeon_device *rdev)
32657e252bfSMichael Neumann {
32757e252bfSMichael Neumann /* doorbell bar mapping */
3284a26d795SImre Vadasz rdev->doorbell.base = pci_resource_start(rdev->pdev, 2);
3294a26d795SImre Vadasz rdev->doorbell.size = pci_resource_len(rdev->pdev, 2);
33057e252bfSMichael Neumann
331c6f73aabSFrançois Tigeot rdev->doorbell.num_doorbells = min_t(u32, rdev->doorbell.size / sizeof(u32), RADEON_MAX_DOORBELLS);
332c6f73aabSFrançois Tigeot if (rdev->doorbell.num_doorbells == 0)
333c6f73aabSFrançois Tigeot return -EINVAL;
33457e252bfSMichael Neumann
335c6f73aabSFrançois Tigeot rdev->doorbell.ptr = ioremap(rdev->doorbell.base, rdev->doorbell.num_doorbells * sizeof(u32));
33657e252bfSMichael Neumann if (rdev->doorbell.ptr == NULL) {
33757e252bfSMichael Neumann return -ENOMEM;
33857e252bfSMichael Neumann }
33957e252bfSMichael Neumann DRM_INFO("doorbell mmio base: 0x%08X\n", (uint32_t)rdev->doorbell.base);
34057e252bfSMichael Neumann DRM_INFO("doorbell mmio size: %u\n", (unsigned)rdev->doorbell.size);
34157e252bfSMichael Neumann
342c6f73aabSFrançois Tigeot memset(&rdev->doorbell.used, 0, sizeof(rdev->doorbell.used));
34357e252bfSMichael Neumann
34457e252bfSMichael Neumann return 0;
34557e252bfSMichael Neumann }
34657e252bfSMichael Neumann
34757e252bfSMichael Neumann /**
34857e252bfSMichael Neumann * radeon_doorbell_fini - Tear down doorbell driver information.
34957e252bfSMichael Neumann *
35057e252bfSMichael Neumann * @rdev: radeon_device pointer
35157e252bfSMichael Neumann *
35257e252bfSMichael Neumann * Tear down doorbell driver information (CIK)
35357e252bfSMichael Neumann */
radeon_doorbell_fini(struct radeon_device * rdev)354c6f73aabSFrançois Tigeot static void radeon_doorbell_fini(struct radeon_device *rdev)
35557e252bfSMichael Neumann {
35624409b39SFrançois Tigeot iounmap(rdev->doorbell.ptr);
35757e252bfSMichael Neumann rdev->doorbell.ptr = NULL;
35857e252bfSMichael Neumann }
35957e252bfSMichael Neumann
36057e252bfSMichael Neumann /**
361c6f73aabSFrançois Tigeot * radeon_doorbell_get - Allocate a doorbell entry
36257e252bfSMichael Neumann *
36357e252bfSMichael Neumann * @rdev: radeon_device pointer
364c6f73aabSFrançois Tigeot * @doorbell: doorbell index
36557e252bfSMichael Neumann *
366c6f73aabSFrançois Tigeot * Allocate a doorbell for use by the driver (all asics).
36757e252bfSMichael Neumann * Returns 0 on success or -EINVAL on failure.
36857e252bfSMichael Neumann */
radeon_doorbell_get(struct radeon_device * rdev,u32 * doorbell)36957e252bfSMichael Neumann int radeon_doorbell_get(struct radeon_device *rdev, u32 *doorbell)
37057e252bfSMichael Neumann {
371c6f73aabSFrançois Tigeot unsigned long offset = find_first_zero_bit(rdev->doorbell.used, rdev->doorbell.num_doorbells);
372c6f73aabSFrançois Tigeot if (offset < rdev->doorbell.num_doorbells) {
373c6f73aabSFrançois Tigeot __set_bit(offset, rdev->doorbell.used);
374c6f73aabSFrançois Tigeot *doorbell = offset;
37557e252bfSMichael Neumann return 0;
376c6f73aabSFrançois Tigeot } else {
37757e252bfSMichael Neumann return -EINVAL;
37857e252bfSMichael Neumann }
379c6f73aabSFrançois Tigeot }
38057e252bfSMichael Neumann
38157e252bfSMichael Neumann /**
382c6f73aabSFrançois Tigeot * radeon_doorbell_free - Free a doorbell entry
38357e252bfSMichael Neumann *
38457e252bfSMichael Neumann * @rdev: radeon_device pointer
385c6f73aabSFrançois Tigeot * @doorbell: doorbell index
38657e252bfSMichael Neumann *
387c6f73aabSFrançois Tigeot * Free a doorbell allocated for use by the driver (all asics)
38857e252bfSMichael Neumann */
radeon_doorbell_free(struct radeon_device * rdev,u32 doorbell)38957e252bfSMichael Neumann void radeon_doorbell_free(struct radeon_device *rdev, u32 doorbell)
39057e252bfSMichael Neumann {
391c6f73aabSFrançois Tigeot if (doorbell < rdev->doorbell.num_doorbells)
392c6f73aabSFrançois Tigeot __clear_bit(doorbell, rdev->doorbell.used);
39357e252bfSMichael Neumann }
39457e252bfSMichael Neumann
3957dcf36dcSFrançois Tigeot /**
3967dcf36dcSFrançois Tigeot * radeon_doorbell_get_kfd_info - Report doorbell configuration required to
3977dcf36dcSFrançois Tigeot * setup KFD
3987dcf36dcSFrançois Tigeot *
3997dcf36dcSFrançois Tigeot * @rdev: radeon_device pointer
4007dcf36dcSFrançois Tigeot * @aperture_base: output returning doorbell aperture base physical address
4017dcf36dcSFrançois Tigeot * @aperture_size: output returning doorbell aperture size in bytes
4027dcf36dcSFrançois Tigeot * @start_offset: output returning # of doorbell bytes reserved for radeon.
4037dcf36dcSFrançois Tigeot *
4047dcf36dcSFrançois Tigeot * Radeon and the KFD share the doorbell aperture. Radeon sets it up,
4057dcf36dcSFrançois Tigeot * takes doorbells required for its own rings and reports the setup to KFD.
4067dcf36dcSFrançois Tigeot * Radeon reserved doorbells are at the start of the doorbell aperture.
4077dcf36dcSFrançois Tigeot */
radeon_doorbell_get_kfd_info(struct radeon_device * rdev,phys_addr_t * aperture_base,size_t * aperture_size,size_t * start_offset)4087dcf36dcSFrançois Tigeot void radeon_doorbell_get_kfd_info(struct radeon_device *rdev,
4097dcf36dcSFrançois Tigeot phys_addr_t *aperture_base,
4107dcf36dcSFrançois Tigeot size_t *aperture_size,
4117dcf36dcSFrançois Tigeot size_t *start_offset)
4127dcf36dcSFrançois Tigeot {
4137dcf36dcSFrançois Tigeot /* The first num_doorbells are used by radeon.
4147dcf36dcSFrançois Tigeot * KFD takes whatever's left in the aperture. */
4157dcf36dcSFrançois Tigeot if (rdev->doorbell.size > rdev->doorbell.num_doorbells * sizeof(u32)) {
4167dcf36dcSFrançois Tigeot *aperture_base = rdev->doorbell.base;
4177dcf36dcSFrançois Tigeot *aperture_size = rdev->doorbell.size;
4187dcf36dcSFrançois Tigeot *start_offset = rdev->doorbell.num_doorbells * sizeof(u32);
4197dcf36dcSFrançois Tigeot } else {
4207dcf36dcSFrançois Tigeot *aperture_base = 0;
4217dcf36dcSFrançois Tigeot *aperture_size = 0;
4227dcf36dcSFrançois Tigeot *start_offset = 0;
4237dcf36dcSFrançois Tigeot }
4247dcf36dcSFrançois Tigeot }
4257dcf36dcSFrançois Tigeot
42657e252bfSMichael Neumann /*
427926deccbSFrançois Tigeot * radeon_wb_*()
428926deccbSFrançois Tigeot * Writeback is the the method by which the the GPU updates special pages
429926deccbSFrançois Tigeot * in memory with the status of certain GPU events (fences, ring pointers,
430926deccbSFrançois Tigeot * etc.).
431926deccbSFrançois Tigeot */
432926deccbSFrançois Tigeot
433926deccbSFrançois Tigeot /**
434926deccbSFrançois Tigeot * radeon_wb_disable - Disable Writeback
435926deccbSFrançois Tigeot *
436926deccbSFrançois Tigeot * @rdev: radeon_device pointer
437926deccbSFrançois Tigeot *
438926deccbSFrançois Tigeot * Disables Writeback (all asics). Used for suspend.
439926deccbSFrançois Tigeot */
radeon_wb_disable(struct radeon_device * rdev)440926deccbSFrançois Tigeot void radeon_wb_disable(struct radeon_device *rdev)
441926deccbSFrançois Tigeot {
442926deccbSFrançois Tigeot rdev->wb.enabled = false;
443926deccbSFrançois Tigeot }
444926deccbSFrançois Tigeot
445926deccbSFrançois Tigeot /**
446926deccbSFrançois Tigeot * radeon_wb_fini - Disable Writeback and free memory
447926deccbSFrançois Tigeot *
448926deccbSFrançois Tigeot * @rdev: radeon_device pointer
449926deccbSFrançois Tigeot *
450926deccbSFrançois Tigeot * Disables Writeback and frees the Writeback memory (all asics).
451926deccbSFrançois Tigeot * Used at driver shutdown.
452926deccbSFrançois Tigeot */
radeon_wb_fini(struct radeon_device * rdev)453926deccbSFrançois Tigeot void radeon_wb_fini(struct radeon_device *rdev)
454926deccbSFrançois Tigeot {
455926deccbSFrançois Tigeot radeon_wb_disable(rdev);
456926deccbSFrançois Tigeot if (rdev->wb.wb_obj) {
457f43cf1b1SMichael Neumann if (!radeon_bo_reserve(rdev->wb.wb_obj, false)) {
458f43cf1b1SMichael Neumann radeon_bo_kunmap(rdev->wb.wb_obj);
459f43cf1b1SMichael Neumann radeon_bo_unpin(rdev->wb.wb_obj);
460f43cf1b1SMichael Neumann radeon_bo_unreserve(rdev->wb.wb_obj);
461f43cf1b1SMichael Neumann }
462926deccbSFrançois Tigeot radeon_bo_unref(&rdev->wb.wb_obj);
463926deccbSFrançois Tigeot rdev->wb.wb = NULL;
464926deccbSFrançois Tigeot rdev->wb.wb_obj = NULL;
465926deccbSFrançois Tigeot }
466926deccbSFrançois Tigeot }
467926deccbSFrançois Tigeot
468926deccbSFrançois Tigeot /**
469926deccbSFrançois Tigeot * radeon_wb_init- Init Writeback driver info and allocate memory
470926deccbSFrançois Tigeot *
471926deccbSFrançois Tigeot * @rdev: radeon_device pointer
472926deccbSFrançois Tigeot *
473926deccbSFrançois Tigeot * Disables Writeback and frees the Writeback memory (all asics).
474926deccbSFrançois Tigeot * Used at driver startup.
475926deccbSFrançois Tigeot * Returns 0 on success or an -error on failure.
476926deccbSFrançois Tigeot */
radeon_wb_init(struct radeon_device * rdev)477926deccbSFrançois Tigeot int radeon_wb_init(struct radeon_device *rdev)
478926deccbSFrançois Tigeot {
479926deccbSFrançois Tigeot int r;
480c59a5c48SFrançois Tigeot void *wb_ptr = NULL;
481926deccbSFrançois Tigeot
482926deccbSFrançois Tigeot if (rdev->wb.wb_obj == NULL) {
483926deccbSFrançois Tigeot r = radeon_bo_create(rdev, RADEON_GPU_PAGE_SIZE, PAGE_SIZE, true,
4847dcf36dcSFrançois Tigeot RADEON_GEM_DOMAIN_GTT, 0, NULL, NULL,
485c6f73aabSFrançois Tigeot &rdev->wb.wb_obj);
486926deccbSFrançois Tigeot if (r) {
487926deccbSFrançois Tigeot dev_warn(rdev->dev, "(%d) create WB bo failed\n", r);
488926deccbSFrançois Tigeot return r;
489926deccbSFrançois Tigeot }
490926deccbSFrançois Tigeot r = radeon_bo_reserve(rdev->wb.wb_obj, false);
491926deccbSFrançois Tigeot if (unlikely(r != 0)) {
492926deccbSFrançois Tigeot radeon_wb_fini(rdev);
493926deccbSFrançois Tigeot return r;
494926deccbSFrançois Tigeot }
495926deccbSFrançois Tigeot r = radeon_bo_pin(rdev->wb.wb_obj, RADEON_GEM_DOMAIN_GTT,
496f77dbd6cSFrançois Tigeot (u64 *)&rdev->wb.gpu_addr);
497926deccbSFrançois Tigeot if (r) {
498926deccbSFrançois Tigeot radeon_bo_unreserve(rdev->wb.wb_obj);
499926deccbSFrançois Tigeot dev_warn(rdev->dev, "(%d) pin WB bo failed\n", r);
500926deccbSFrançois Tigeot radeon_wb_fini(rdev);
501926deccbSFrançois Tigeot return r;
502926deccbSFrançois Tigeot }
503926deccbSFrançois Tigeot wb_ptr = &rdev->wb.wb;
504926deccbSFrançois Tigeot r = radeon_bo_kmap(rdev->wb.wb_obj, wb_ptr);
505926deccbSFrançois Tigeot radeon_bo_unreserve(rdev->wb.wb_obj);
506926deccbSFrançois Tigeot if (r) {
507926deccbSFrançois Tigeot dev_warn(rdev->dev, "(%d) map WB bo failed\n", r);
508926deccbSFrançois Tigeot radeon_wb_fini(rdev);
509926deccbSFrançois Tigeot return r;
510926deccbSFrançois Tigeot }
511f43cf1b1SMichael Neumann }
512f43cf1b1SMichael Neumann
513c59a5c48SFrançois Tigeot /* clear wb memory */
514c59a5c48SFrançois Tigeot memset(*(void **)wb_ptr, 0, RADEON_GPU_PAGE_SIZE);
515926deccbSFrançois Tigeot /* disable event_write fences */
516926deccbSFrançois Tigeot rdev->wb.use_event = false;
517926deccbSFrançois Tigeot /* disabled via module param */
518926deccbSFrançois Tigeot if (radeon_no_wb == 1) {
519926deccbSFrançois Tigeot rdev->wb.enabled = false;
520926deccbSFrançois Tigeot } else {
521926deccbSFrançois Tigeot if (rdev->flags & RADEON_IS_AGP) {
522926deccbSFrançois Tigeot /* often unreliable on AGP */
523926deccbSFrançois Tigeot rdev->wb.enabled = false;
524926deccbSFrançois Tigeot } else if (rdev->family < CHIP_R300) {
525926deccbSFrançois Tigeot /* often unreliable on pre-r300 */
526926deccbSFrançois Tigeot rdev->wb.enabled = false;
527926deccbSFrançois Tigeot } else {
528926deccbSFrançois Tigeot rdev->wb.enabled = true;
529926deccbSFrançois Tigeot /* event_write fences are only available on r600+ */
530926deccbSFrançois Tigeot if (rdev->family >= CHIP_R600) {
531926deccbSFrançois Tigeot rdev->wb.use_event = true;
532926deccbSFrançois Tigeot }
533926deccbSFrançois Tigeot }
534926deccbSFrançois Tigeot }
535926deccbSFrançois Tigeot /* always use writeback/events on NI, APUs */
536926deccbSFrançois Tigeot if (rdev->family >= CHIP_PALM) {
537926deccbSFrançois Tigeot rdev->wb.enabled = true;
538926deccbSFrançois Tigeot rdev->wb.use_event = true;
539926deccbSFrançois Tigeot }
540926deccbSFrançois Tigeot
541926deccbSFrançois Tigeot dev_info(rdev->dev, "WB %sabled\n", rdev->wb.enabled ? "en" : "dis");
542926deccbSFrançois Tigeot
543926deccbSFrançois Tigeot return 0;
544926deccbSFrançois Tigeot }
545926deccbSFrançois Tigeot
546926deccbSFrançois Tigeot /**
547926deccbSFrançois Tigeot * radeon_vram_location - try to find VRAM location
548926deccbSFrançois Tigeot * @rdev: radeon device structure holding all necessary informations
549926deccbSFrançois Tigeot * @mc: memory controller structure holding memory informations
550926deccbSFrançois Tigeot * @base: base address at which to put VRAM
551926deccbSFrançois Tigeot *
552926deccbSFrançois Tigeot * Function will place try to place VRAM at base address provided
553926deccbSFrançois Tigeot * as parameter (which is so far either PCI aperture address or
554926deccbSFrançois Tigeot * for IGP TOM base address).
555926deccbSFrançois Tigeot *
556926deccbSFrançois Tigeot * If there is not enough space to fit the unvisible VRAM in the 32bits
557926deccbSFrançois Tigeot * address space then we limit the VRAM size to the aperture.
558926deccbSFrançois Tigeot *
559926deccbSFrançois Tigeot * If we are using AGP and if the AGP aperture doesn't allow us to have
560926deccbSFrançois Tigeot * room for all the VRAM than we restrict the VRAM to the PCI aperture
561926deccbSFrançois Tigeot * size and print a warning.
562926deccbSFrançois Tigeot *
563926deccbSFrançois Tigeot * This function will never fails, worst case are limiting VRAM.
564926deccbSFrançois Tigeot *
565926deccbSFrançois Tigeot * Note: GTT start, end, size should be initialized before calling this
566926deccbSFrançois Tigeot * function on AGP platform.
567926deccbSFrançois Tigeot *
568926deccbSFrançois Tigeot * Note: We don't explicitly enforce VRAM start to be aligned on VRAM size,
569926deccbSFrançois Tigeot * this shouldn't be a problem as we are using the PCI aperture as a reference.
570926deccbSFrançois Tigeot * Otherwise this would be needed for rv280, all r3xx, and all r4xx, but
571926deccbSFrançois Tigeot * not IGP.
572926deccbSFrançois Tigeot *
573926deccbSFrançois Tigeot * Note: we use mc_vram_size as on some board we need to program the mc to
574926deccbSFrançois Tigeot * cover the whole aperture even if VRAM size is inferior to aperture size
575926deccbSFrançois Tigeot * Novell bug 204882 + along with lots of ubuntu ones
576926deccbSFrançois Tigeot *
577926deccbSFrançois Tigeot * Note: when limiting vram it's safe to overwritte real_vram_size because
578926deccbSFrançois Tigeot * we are not in case where real_vram_size is inferior to mc_vram_size (ie
579926deccbSFrançois Tigeot * note afected by bogus hw of Novell bug 204882 + along with lots of ubuntu
580926deccbSFrançois Tigeot * ones)
581926deccbSFrançois Tigeot *
582926deccbSFrançois Tigeot * Note: IGP TOM addr should be the same as the aperture addr, we don't
583926deccbSFrançois Tigeot * explicitly check for that thought.
584926deccbSFrançois Tigeot *
585926deccbSFrançois Tigeot * FIXME: when reducing VRAM size align new size on power of 2.
586926deccbSFrançois Tigeot */
radeon_vram_location(struct radeon_device * rdev,struct radeon_mc * mc,u64 base)587926deccbSFrançois Tigeot void radeon_vram_location(struct radeon_device *rdev, struct radeon_mc *mc, u64 base)
588926deccbSFrançois Tigeot {
589926deccbSFrançois Tigeot uint64_t limit = (uint64_t)radeon_vram_limit << 20;
590926deccbSFrançois Tigeot
591926deccbSFrançois Tigeot mc->vram_start = base;
592f43cf1b1SMichael Neumann if (mc->mc_vram_size > (rdev->mc.mc_mask - base + 1)) {
593926deccbSFrançois Tigeot dev_warn(rdev->dev, "limiting VRAM to PCI aperture size\n");
594926deccbSFrançois Tigeot mc->real_vram_size = mc->aper_size;
595926deccbSFrançois Tigeot mc->mc_vram_size = mc->aper_size;
596926deccbSFrançois Tigeot }
597926deccbSFrançois Tigeot mc->vram_end = mc->vram_start + mc->mc_vram_size - 1;
598926deccbSFrançois Tigeot if (rdev->flags & RADEON_IS_AGP && mc->vram_end > mc->gtt_start && mc->vram_start <= mc->gtt_end) {
599926deccbSFrançois Tigeot dev_warn(rdev->dev, "limiting VRAM to PCI aperture size\n");
600926deccbSFrançois Tigeot mc->real_vram_size = mc->aper_size;
601926deccbSFrançois Tigeot mc->mc_vram_size = mc->aper_size;
602926deccbSFrançois Tigeot }
603926deccbSFrançois Tigeot mc->vram_end = mc->vram_start + mc->mc_vram_size - 1;
604926deccbSFrançois Tigeot if (limit && limit < mc->real_vram_size)
605926deccbSFrançois Tigeot mc->real_vram_size = limit;
606f77dbd6cSFrançois Tigeot dev_info(rdev->dev, "VRAM: %lluM 0x%016llX - 0x%016llX (%lluM used)\n",
6074cd92098Szrj mc->mc_vram_size >> 20, mc->vram_start,
6084cd92098Szrj mc->vram_end, mc->real_vram_size >> 20);
609926deccbSFrançois Tigeot }
610926deccbSFrançois Tigeot
611926deccbSFrançois Tigeot /**
612926deccbSFrançois Tigeot * radeon_gtt_location - try to find GTT location
613926deccbSFrançois Tigeot * @rdev: radeon device structure holding all necessary informations
614926deccbSFrançois Tigeot * @mc: memory controller structure holding memory informations
615926deccbSFrançois Tigeot *
616926deccbSFrançois Tigeot * Function will place try to place GTT before or after VRAM.
617926deccbSFrançois Tigeot *
618926deccbSFrançois Tigeot * If GTT size is bigger than space left then we ajust GTT size.
619926deccbSFrançois Tigeot * Thus function will never fails.
620926deccbSFrançois Tigeot *
621926deccbSFrançois Tigeot * FIXME: when reducing GTT size align new size on power of 2.
622926deccbSFrançois Tigeot */
radeon_gtt_location(struct radeon_device * rdev,struct radeon_mc * mc)623926deccbSFrançois Tigeot void radeon_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc)
624926deccbSFrançois Tigeot {
625926deccbSFrançois Tigeot u64 size_af, size_bf;
626926deccbSFrançois Tigeot
627f43cf1b1SMichael Neumann size_af = ((rdev->mc.mc_mask - mc->vram_end) + mc->gtt_base_align) & ~mc->gtt_base_align;
628926deccbSFrançois Tigeot size_bf = mc->vram_start & ~mc->gtt_base_align;
629926deccbSFrançois Tigeot if (size_bf > size_af) {
630926deccbSFrançois Tigeot if (mc->gtt_size > size_bf) {
631926deccbSFrançois Tigeot dev_warn(rdev->dev, "limiting GTT\n");
632926deccbSFrançois Tigeot mc->gtt_size = size_bf;
633926deccbSFrançois Tigeot }
634926deccbSFrançois Tigeot mc->gtt_start = (mc->vram_start & ~mc->gtt_base_align) - mc->gtt_size;
635926deccbSFrançois Tigeot } else {
636926deccbSFrançois Tigeot if (mc->gtt_size > size_af) {
637926deccbSFrançois Tigeot dev_warn(rdev->dev, "limiting GTT\n");
638926deccbSFrançois Tigeot mc->gtt_size = size_af;
639926deccbSFrançois Tigeot }
640926deccbSFrançois Tigeot mc->gtt_start = (mc->vram_end + 1 + mc->gtt_base_align) & ~mc->gtt_base_align;
641926deccbSFrançois Tigeot }
642926deccbSFrançois Tigeot mc->gtt_end = mc->gtt_start + mc->gtt_size - 1;
643f77dbd6cSFrançois Tigeot dev_info(rdev->dev, "GTT: %lluM 0x%016llX - 0x%016llX\n",
6444cd92098Szrj mc->gtt_size >> 20, mc->gtt_start, mc->gtt_end);
645926deccbSFrançois Tigeot }
646926deccbSFrançois Tigeot
647926deccbSFrançois Tigeot /*
648926deccbSFrançois Tigeot * GPU helpers function.
649926deccbSFrançois Tigeot */
650c59a5c48SFrançois Tigeot
651c59a5c48SFrançois Tigeot /**
652c59a5c48SFrançois Tigeot * radeon_device_is_virtual - check if we are running is a virtual environment
653c59a5c48SFrançois Tigeot *
654c59a5c48SFrançois Tigeot * Check if the asic has been passed through to a VM (all asics).
655c59a5c48SFrançois Tigeot * Used at driver startup.
656c59a5c48SFrançois Tigeot * Returns true if virtual or false if not.
657c59a5c48SFrançois Tigeot */
6581dedbd3bSFrançois Tigeot bool radeon_device_is_virtual(void);
radeon_device_is_virtual(void)6591dedbd3bSFrançois Tigeot bool radeon_device_is_virtual(void)
660c59a5c48SFrançois Tigeot {
661c59a5c48SFrançois Tigeot #ifdef CONFIG_X86
662c59a5c48SFrançois Tigeot return boot_cpu_has(X86_FEATURE_HYPERVISOR);
663c59a5c48SFrançois Tigeot #else
664c59a5c48SFrançois Tigeot return false;
665c59a5c48SFrançois Tigeot #endif
666c59a5c48SFrançois Tigeot }
667c59a5c48SFrançois Tigeot
668926deccbSFrançois Tigeot /**
669926deccbSFrançois Tigeot * radeon_card_posted - check if the hw has already been initialized
670926deccbSFrançois Tigeot *
671926deccbSFrançois Tigeot * @rdev: radeon_device pointer
672926deccbSFrançois Tigeot *
673926deccbSFrançois Tigeot * Check if the asic has been initialized (all asics).
674926deccbSFrançois Tigeot * Used at driver startup.
675926deccbSFrançois Tigeot * Returns true if initialized or false if not.
676926deccbSFrançois Tigeot */
radeon_card_posted(struct radeon_device * rdev)677926deccbSFrançois Tigeot bool radeon_card_posted(struct radeon_device *rdev)
678926deccbSFrançois Tigeot {
679926deccbSFrançois Tigeot uint32_t reg;
680926deccbSFrançois Tigeot
681c59a5c48SFrançois Tigeot /* for pass through, always force asic_init for CI */
682c59a5c48SFrançois Tigeot if (rdev->family >= CHIP_BONAIRE &&
683c59a5c48SFrançois Tigeot radeon_device_is_virtual())
684c59a5c48SFrançois Tigeot return false;
685c59a5c48SFrançois Tigeot
686926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP
687f43cf1b1SMichael Neumann /* required for EFI mode on macbook2,1 which uses an r5xx asic */
688926deccbSFrançois Tigeot if (efi_enabled(EFI_BOOT) &&
689c6f73aabSFrançois Tigeot (rdev->pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE) &&
690f43cf1b1SMichael Neumann (rdev->family < CHIP_R600))
691926deccbSFrançois Tigeot return false;
692926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */
693926deccbSFrançois Tigeot
694f43cf1b1SMichael Neumann if (ASIC_IS_NODCE(rdev))
695f43cf1b1SMichael Neumann goto check_memsize;
696f43cf1b1SMichael Neumann
697926deccbSFrançois Tigeot /* first check CRTCs */
698f43cf1b1SMichael Neumann if (ASIC_IS_DCE4(rdev)) {
699926deccbSFrançois Tigeot reg = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET) |
700926deccbSFrançois Tigeot RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET);
701f43cf1b1SMichael Neumann if (rdev->num_crtc >= 4) {
702f43cf1b1SMichael Neumann reg |= RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET) |
703f43cf1b1SMichael Neumann RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET);
704f43cf1b1SMichael Neumann }
705f43cf1b1SMichael Neumann if (rdev->num_crtc >= 6) {
706f43cf1b1SMichael Neumann reg |= RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET) |
707926deccbSFrançois Tigeot RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET);
708f43cf1b1SMichael Neumann }
709926deccbSFrançois Tigeot if (reg & EVERGREEN_CRTC_MASTER_EN)
710926deccbSFrançois Tigeot return true;
711926deccbSFrançois Tigeot } else if (ASIC_IS_AVIVO(rdev)) {
712926deccbSFrançois Tigeot reg = RREG32(AVIVO_D1CRTC_CONTROL) |
713926deccbSFrançois Tigeot RREG32(AVIVO_D2CRTC_CONTROL);
714926deccbSFrançois Tigeot if (reg & AVIVO_CRTC_EN) {
715926deccbSFrançois Tigeot return true;
716926deccbSFrançois Tigeot }
717926deccbSFrançois Tigeot } else {
718926deccbSFrançois Tigeot reg = RREG32(RADEON_CRTC_GEN_CNTL) |
719926deccbSFrançois Tigeot RREG32(RADEON_CRTC2_GEN_CNTL);
720926deccbSFrançois Tigeot if (reg & RADEON_CRTC_EN) {
721926deccbSFrançois Tigeot return true;
722926deccbSFrançois Tigeot }
723926deccbSFrançois Tigeot }
724926deccbSFrançois Tigeot
725f43cf1b1SMichael Neumann check_memsize:
726926deccbSFrançois Tigeot /* then check MEM_SIZE, in case the crtcs are off */
727926deccbSFrançois Tigeot if (rdev->family >= CHIP_R600)
728926deccbSFrançois Tigeot reg = RREG32(R600_CONFIG_MEMSIZE);
729926deccbSFrançois Tigeot else
730926deccbSFrançois Tigeot reg = RREG32(RADEON_CONFIG_MEMSIZE);
731926deccbSFrançois Tigeot
732926deccbSFrançois Tigeot if (reg)
733926deccbSFrançois Tigeot return true;
734926deccbSFrançois Tigeot
735926deccbSFrançois Tigeot return false;
736926deccbSFrançois Tigeot
737926deccbSFrançois Tigeot }
738926deccbSFrançois Tigeot
739926deccbSFrançois Tigeot /**
740926deccbSFrançois Tigeot * radeon_update_bandwidth_info - update display bandwidth params
741926deccbSFrançois Tigeot *
742926deccbSFrançois Tigeot * @rdev: radeon_device pointer
743926deccbSFrançois Tigeot *
744926deccbSFrançois Tigeot * Used when sclk/mclk are switched or display modes are set.
745926deccbSFrançois Tigeot * params are used to calculate display watermarks (all asics)
746926deccbSFrançois Tigeot */
radeon_update_bandwidth_info(struct radeon_device * rdev)747926deccbSFrançois Tigeot void radeon_update_bandwidth_info(struct radeon_device *rdev)
748926deccbSFrançois Tigeot {
749926deccbSFrançois Tigeot fixed20_12 a;
750926deccbSFrançois Tigeot u32 sclk = rdev->pm.current_sclk;
751926deccbSFrançois Tigeot u32 mclk = rdev->pm.current_mclk;
752926deccbSFrançois Tigeot
753926deccbSFrançois Tigeot /* sclk/mclk in Mhz */
754926deccbSFrançois Tigeot a.full = dfixed_const(100);
755926deccbSFrançois Tigeot rdev->pm.sclk.full = dfixed_const(sclk);
756926deccbSFrançois Tigeot rdev->pm.sclk.full = dfixed_div(rdev->pm.sclk, a);
757926deccbSFrançois Tigeot rdev->pm.mclk.full = dfixed_const(mclk);
758926deccbSFrançois Tigeot rdev->pm.mclk.full = dfixed_div(rdev->pm.mclk, a);
759926deccbSFrançois Tigeot
760926deccbSFrançois Tigeot if (rdev->flags & RADEON_IS_IGP) {
761926deccbSFrançois Tigeot a.full = dfixed_const(16);
762926deccbSFrançois Tigeot /* core_bandwidth = sclk(Mhz) * 16 */
763926deccbSFrançois Tigeot rdev->pm.core_bandwidth.full = dfixed_div(rdev->pm.sclk, a);
764926deccbSFrançois Tigeot }
765926deccbSFrançois Tigeot }
766926deccbSFrançois Tigeot
767926deccbSFrançois Tigeot /**
768926deccbSFrançois Tigeot * radeon_boot_test_post_card - check and possibly initialize the hw
769926deccbSFrançois Tigeot *
770926deccbSFrançois Tigeot * @rdev: radeon_device pointer
771926deccbSFrançois Tigeot *
772926deccbSFrançois Tigeot * Check if the asic is initialized and if not, attempt to initialize
773926deccbSFrançois Tigeot * it (all asics).
774926deccbSFrançois Tigeot * Returns true if initialized or false if not.
775926deccbSFrançois Tigeot */
radeon_boot_test_post_card(struct radeon_device * rdev)776926deccbSFrançois Tigeot bool radeon_boot_test_post_card(struct radeon_device *rdev)
777926deccbSFrançois Tigeot {
778926deccbSFrançois Tigeot if (radeon_card_posted(rdev))
779926deccbSFrançois Tigeot return true;
780926deccbSFrançois Tigeot
781926deccbSFrançois Tigeot if (rdev->bios) {
782926deccbSFrançois Tigeot DRM_INFO("GPU not posted. posting now...\n");
783926deccbSFrançois Tigeot if (rdev->is_atom_bios)
784926deccbSFrançois Tigeot atom_asic_init(rdev->mode_info.atom_context);
785926deccbSFrançois Tigeot else
786926deccbSFrançois Tigeot radeon_combios_asic_init(rdev->ddev);
787926deccbSFrançois Tigeot return true;
788926deccbSFrançois Tigeot } else {
789926deccbSFrançois Tigeot dev_err(rdev->dev, "Card not posted and no BIOS - ignoring\n");
790926deccbSFrançois Tigeot return false;
791926deccbSFrançois Tigeot }
792926deccbSFrançois Tigeot }
793926deccbSFrançois Tigeot
794926deccbSFrançois Tigeot /**
795926deccbSFrançois Tigeot * radeon_dummy_page_init - init dummy page used by the driver
796926deccbSFrançois Tigeot *
797926deccbSFrançois Tigeot * @rdev: radeon_device pointer
798926deccbSFrançois Tigeot *
799926deccbSFrançois Tigeot * Allocate the dummy page used by the driver (all asics).
800926deccbSFrançois Tigeot * This dummy page is used by the driver as a filler for gart entries
801926deccbSFrançois Tigeot * when pages are taken out of the GART
802926deccbSFrançois Tigeot * Returns 0 on sucess, -ENOMEM on failure.
803926deccbSFrançois Tigeot */
radeon_dummy_page_init(struct radeon_device * rdev)804926deccbSFrançois Tigeot int radeon_dummy_page_init(struct radeon_device *rdev)
805926deccbSFrançois Tigeot {
806926deccbSFrançois Tigeot if (rdev->dummy_page.dmah)
807926deccbSFrançois Tigeot return 0;
808c59a5c48SFrançois Tigeot rdev->dummy_page.dmah = drm_pci_alloc(rdev->ddev, PAGE_SIZE, PAGE_SIZE);
809926deccbSFrançois Tigeot if (rdev->dummy_page.dmah == NULL)
810926deccbSFrançois Tigeot return -ENOMEM;
811c59a5c48SFrançois Tigeot rdev->dummy_page.addr = (dma_addr_t)rdev->dummy_page.dmah->busaddr;
812926deccbSFrançois Tigeot return 0;
813926deccbSFrançois Tigeot }
814926deccbSFrançois Tigeot
815926deccbSFrançois Tigeot /**
816926deccbSFrançois Tigeot * radeon_dummy_page_fini - free dummy page used by the driver
817926deccbSFrançois Tigeot *
818926deccbSFrançois Tigeot * @rdev: radeon_device pointer
819926deccbSFrançois Tigeot *
820926deccbSFrançois Tigeot * Frees the dummy page used by the driver (all asics).
821926deccbSFrançois Tigeot */
radeon_dummy_page_fini(struct radeon_device * rdev)822926deccbSFrançois Tigeot void radeon_dummy_page_fini(struct radeon_device *rdev)
823926deccbSFrançois Tigeot {
824926deccbSFrançois Tigeot if (rdev->dummy_page.dmah == NULL)
825926deccbSFrançois Tigeot return;
826926deccbSFrançois Tigeot drm_pci_free(rdev->ddev, rdev->dummy_page.dmah);
827926deccbSFrançois Tigeot rdev->dummy_page.addr = 0;
828c59a5c48SFrançois Tigeot rdev->dummy_page.dmah = NULL;
829926deccbSFrançois Tigeot }
830926deccbSFrançois Tigeot
831926deccbSFrançois Tigeot
832926deccbSFrançois Tigeot /* ATOM accessor methods */
833926deccbSFrançois Tigeot /*
834926deccbSFrançois Tigeot * ATOM is an interpreted byte code stored in tables in the vbios. The
835926deccbSFrançois Tigeot * driver registers callbacks to access registers and the interpreter
836926deccbSFrançois Tigeot * in the driver parses the tables and executes then to program specific
837926deccbSFrançois Tigeot * actions (set display modes, asic init, etc.). See radeon_atombios.c,
838926deccbSFrançois Tigeot * atombios.h, and atom.c
839926deccbSFrançois Tigeot */
840926deccbSFrançois Tigeot
841926deccbSFrançois Tigeot /**
842926deccbSFrançois Tigeot * cail_pll_read - read PLL register
843926deccbSFrançois Tigeot *
844926deccbSFrançois Tigeot * @info: atom card_info pointer
845926deccbSFrançois Tigeot * @reg: PLL register offset
846926deccbSFrançois Tigeot *
847926deccbSFrançois Tigeot * Provides a PLL register accessor for the atom interpreter (r4xx+).
848926deccbSFrançois Tigeot * Returns the value of the PLL register.
849926deccbSFrançois Tigeot */
cail_pll_read(struct card_info * info,uint32_t reg)850926deccbSFrançois Tigeot static uint32_t cail_pll_read(struct card_info *info, uint32_t reg)
851926deccbSFrançois Tigeot {
852926deccbSFrançois Tigeot struct radeon_device *rdev = info->dev->dev_private;
853926deccbSFrançois Tigeot uint32_t r;
854926deccbSFrançois Tigeot
855926deccbSFrançois Tigeot r = rdev->pll_rreg(rdev, reg);
856926deccbSFrançois Tigeot return r;
857926deccbSFrançois Tigeot }
858926deccbSFrançois Tigeot
859926deccbSFrançois Tigeot /**
860926deccbSFrançois Tigeot * cail_pll_write - write PLL register
861926deccbSFrançois Tigeot *
862926deccbSFrançois Tigeot * @info: atom card_info pointer
863926deccbSFrançois Tigeot * @reg: PLL register offset
864926deccbSFrançois Tigeot * @val: value to write to the pll register
865926deccbSFrançois Tigeot *
866926deccbSFrançois Tigeot * Provides a PLL register accessor for the atom interpreter (r4xx+).
867926deccbSFrançois Tigeot */
cail_pll_write(struct card_info * info,uint32_t reg,uint32_t val)868926deccbSFrançois Tigeot static void cail_pll_write(struct card_info *info, uint32_t reg, uint32_t val)
869926deccbSFrançois Tigeot {
870926deccbSFrançois Tigeot struct radeon_device *rdev = info->dev->dev_private;
871926deccbSFrançois Tigeot
872926deccbSFrançois Tigeot rdev->pll_wreg(rdev, reg, val);
873926deccbSFrançois Tigeot }
874926deccbSFrançois Tigeot
875926deccbSFrançois Tigeot /**
876926deccbSFrançois Tigeot * cail_mc_read - read MC (Memory Controller) register
877926deccbSFrançois Tigeot *
878926deccbSFrançois Tigeot * @info: atom card_info pointer
879926deccbSFrançois Tigeot * @reg: MC register offset
880926deccbSFrançois Tigeot *
881926deccbSFrançois Tigeot * Provides an MC register accessor for the atom interpreter (r4xx+).
882926deccbSFrançois Tigeot * Returns the value of the MC register.
883926deccbSFrançois Tigeot */
cail_mc_read(struct card_info * info,uint32_t reg)884926deccbSFrançois Tigeot static uint32_t cail_mc_read(struct card_info *info, uint32_t reg)
885926deccbSFrançois Tigeot {
886926deccbSFrançois Tigeot struct radeon_device *rdev = info->dev->dev_private;
887926deccbSFrançois Tigeot uint32_t r;
888926deccbSFrançois Tigeot
889926deccbSFrançois Tigeot r = rdev->mc_rreg(rdev, reg);
890926deccbSFrançois Tigeot return r;
891926deccbSFrançois Tigeot }
892926deccbSFrançois Tigeot
893926deccbSFrançois Tigeot /**
894926deccbSFrançois Tigeot * cail_mc_write - write MC (Memory Controller) register
895926deccbSFrançois Tigeot *
896926deccbSFrançois Tigeot * @info: atom card_info pointer
897926deccbSFrançois Tigeot * @reg: MC register offset
898926deccbSFrançois Tigeot * @val: value to write to the pll register
899926deccbSFrançois Tigeot *
900926deccbSFrançois Tigeot * Provides a MC register accessor for the atom interpreter (r4xx+).
901926deccbSFrançois Tigeot */
cail_mc_write(struct card_info * info,uint32_t reg,uint32_t val)902926deccbSFrançois Tigeot static void cail_mc_write(struct card_info *info, uint32_t reg, uint32_t val)
903926deccbSFrançois Tigeot {
904926deccbSFrançois Tigeot struct radeon_device *rdev = info->dev->dev_private;
905926deccbSFrançois Tigeot
906926deccbSFrançois Tigeot rdev->mc_wreg(rdev, reg, val);
907926deccbSFrançois Tigeot }
908926deccbSFrançois Tigeot
909926deccbSFrançois Tigeot /**
910926deccbSFrançois Tigeot * cail_reg_write - write MMIO register
911926deccbSFrançois Tigeot *
912926deccbSFrançois Tigeot * @info: atom card_info pointer
913926deccbSFrançois Tigeot * @reg: MMIO register offset
914926deccbSFrançois Tigeot * @val: value to write to the pll register
915926deccbSFrançois Tigeot *
916926deccbSFrançois Tigeot * Provides a MMIO register accessor for the atom interpreter (r4xx+).
917926deccbSFrançois Tigeot */
cail_reg_write(struct card_info * info,uint32_t reg,uint32_t val)918926deccbSFrançois Tigeot static void cail_reg_write(struct card_info *info, uint32_t reg, uint32_t val)
919926deccbSFrançois Tigeot {
920926deccbSFrançois Tigeot struct radeon_device *rdev = info->dev->dev_private;
921926deccbSFrançois Tigeot
922926deccbSFrançois Tigeot WREG32(reg*4, val);
923926deccbSFrançois Tigeot }
924926deccbSFrançois Tigeot
925926deccbSFrançois Tigeot /**
926926deccbSFrançois Tigeot * cail_reg_read - read MMIO register
927926deccbSFrançois Tigeot *
928926deccbSFrançois Tigeot * @info: atom card_info pointer
929926deccbSFrançois Tigeot * @reg: MMIO register offset
930926deccbSFrançois Tigeot *
931926deccbSFrançois Tigeot * Provides an MMIO register accessor for the atom interpreter (r4xx+).
932926deccbSFrançois Tigeot * Returns the value of the MMIO register.
933926deccbSFrançois Tigeot */
cail_reg_read(struct card_info * info,uint32_t reg)934926deccbSFrançois Tigeot static uint32_t cail_reg_read(struct card_info *info, uint32_t reg)
935926deccbSFrançois Tigeot {
936926deccbSFrançois Tigeot struct radeon_device *rdev = info->dev->dev_private;
937926deccbSFrançois Tigeot uint32_t r;
938926deccbSFrançois Tigeot
939926deccbSFrançois Tigeot r = RREG32(reg*4);
940926deccbSFrançois Tigeot return r;
941926deccbSFrançois Tigeot }
942926deccbSFrançois Tigeot
943926deccbSFrançois Tigeot /**
944926deccbSFrançois Tigeot * cail_ioreg_write - write IO register
945926deccbSFrançois Tigeot *
946926deccbSFrançois Tigeot * @info: atom card_info pointer
947926deccbSFrançois Tigeot * @reg: IO register offset
948926deccbSFrançois Tigeot * @val: value to write to the pll register
949926deccbSFrançois Tigeot *
950926deccbSFrançois Tigeot * Provides a IO register accessor for the atom interpreter (r4xx+).
951926deccbSFrançois Tigeot */
cail_ioreg_write(struct card_info * info,uint32_t reg,uint32_t val)952926deccbSFrançois Tigeot static void cail_ioreg_write(struct card_info *info, uint32_t reg, uint32_t val)
953926deccbSFrançois Tigeot {
954926deccbSFrançois Tigeot struct radeon_device *rdev = info->dev->dev_private;
955926deccbSFrançois Tigeot
956926deccbSFrançois Tigeot WREG32_IO(reg*4, val);
957926deccbSFrançois Tigeot }
958926deccbSFrançois Tigeot
959926deccbSFrançois Tigeot /**
960926deccbSFrançois Tigeot * cail_ioreg_read - read IO register
961926deccbSFrançois Tigeot *
962926deccbSFrançois Tigeot * @info: atom card_info pointer
963926deccbSFrançois Tigeot * @reg: IO register offset
964926deccbSFrançois Tigeot *
965926deccbSFrançois Tigeot * Provides an IO register accessor for the atom interpreter (r4xx+).
966926deccbSFrançois Tigeot * Returns the value of the IO register.
967926deccbSFrançois Tigeot */
cail_ioreg_read(struct card_info * info,uint32_t reg)968926deccbSFrançois Tigeot static uint32_t cail_ioreg_read(struct card_info *info, uint32_t reg)
969926deccbSFrançois Tigeot {
970926deccbSFrançois Tigeot struct radeon_device *rdev = info->dev->dev_private;
971926deccbSFrançois Tigeot uint32_t r;
972926deccbSFrançois Tigeot
973926deccbSFrançois Tigeot r = RREG32_IO(reg*4);
974926deccbSFrançois Tigeot return r;
975926deccbSFrançois Tigeot }
976926deccbSFrançois Tigeot
977926deccbSFrançois Tigeot /**
978926deccbSFrançois Tigeot * radeon_atombios_init - init the driver info and callbacks for atombios
979926deccbSFrançois Tigeot *
980926deccbSFrançois Tigeot * @rdev: radeon_device pointer
981926deccbSFrançois Tigeot *
982926deccbSFrançois Tigeot * Initializes the driver info and register access callbacks for the
983926deccbSFrançois Tigeot * ATOM interpreter (r4xx+).
984926deccbSFrançois Tigeot * Returns 0 on sucess, -ENOMEM on failure.
985926deccbSFrançois Tigeot * Called at driver startup.
986926deccbSFrançois Tigeot */
radeon_atombios_init(struct radeon_device * rdev)987926deccbSFrançois Tigeot int radeon_atombios_init(struct radeon_device *rdev)
988926deccbSFrançois Tigeot {
989926deccbSFrançois Tigeot struct card_info *atom_card_info =
990c4ef309bSzrj kzalloc(sizeof(struct card_info), GFP_KERNEL);
991926deccbSFrançois Tigeot
992926deccbSFrançois Tigeot if (!atom_card_info)
993926deccbSFrançois Tigeot return -ENOMEM;
994926deccbSFrançois Tigeot
995926deccbSFrançois Tigeot rdev->mode_info.atom_card_info = atom_card_info;
996926deccbSFrançois Tigeot atom_card_info->dev = rdev->ddev;
997926deccbSFrançois Tigeot atom_card_info->reg_read = cail_reg_read;
998926deccbSFrançois Tigeot atom_card_info->reg_write = cail_reg_write;
999926deccbSFrançois Tigeot /* needed for iio ops */
1000926deccbSFrançois Tigeot if (rdev->rio_mem) {
1001926deccbSFrançois Tigeot atom_card_info->ioreg_read = cail_ioreg_read;
1002926deccbSFrançois Tigeot atom_card_info->ioreg_write = cail_ioreg_write;
1003926deccbSFrançois Tigeot } else {
1004926deccbSFrançois Tigeot DRM_ERROR("Unable to find PCI I/O BAR; using MMIO for ATOM IIO\n");
1005926deccbSFrançois Tigeot atom_card_info->ioreg_read = cail_reg_read;
1006926deccbSFrançois Tigeot atom_card_info->ioreg_write = cail_reg_write;
1007926deccbSFrançois Tigeot }
1008926deccbSFrançois Tigeot atom_card_info->mc_read = cail_mc_read;
1009926deccbSFrançois Tigeot atom_card_info->mc_write = cail_mc_write;
1010926deccbSFrançois Tigeot atom_card_info->pll_read = cail_pll_read;
1011926deccbSFrançois Tigeot atom_card_info->pll_write = cail_pll_write;
1012926deccbSFrançois Tigeot
1013926deccbSFrançois Tigeot rdev->mode_info.atom_context = atom_parse(atom_card_info, rdev->bios);
1014b403bed8SMichael Neumann if (!rdev->mode_info.atom_context) {
1015b403bed8SMichael Neumann radeon_atombios_fini(rdev);
1016b403bed8SMichael Neumann return -ENOMEM;
1017b403bed8SMichael Neumann }
1018b403bed8SMichael Neumann
1019591d5043SFrançois Tigeot lockinit(&rdev->mode_info.atom_context->mutex, "rmiacmtx", 0, LK_CANRECURSE);
1020591d5043SFrançois Tigeot lockinit(&rdev->mode_info.atom_context->scratch_mutex, "rmiacsmtx", 0, LK_CANRECURSE);
1021926deccbSFrançois Tigeot radeon_atom_initialize_bios_scratch_regs(rdev->ddev);
1022926deccbSFrançois Tigeot atom_allocate_fb_scratch(rdev->mode_info.atom_context);
1023926deccbSFrançois Tigeot return 0;
1024926deccbSFrançois Tigeot }
1025926deccbSFrançois Tigeot
1026926deccbSFrançois Tigeot /**
1027926deccbSFrançois Tigeot * radeon_atombios_fini - free the driver info and callbacks for atombios
1028926deccbSFrançois Tigeot *
1029926deccbSFrançois Tigeot * @rdev: radeon_device pointer
1030926deccbSFrançois Tigeot *
1031926deccbSFrançois Tigeot * Frees the driver info and register access callbacks for the ATOM
1032926deccbSFrançois Tigeot * interpreter (r4xx+).
1033926deccbSFrançois Tigeot * Called at driver shutdown.
1034926deccbSFrançois Tigeot */
radeon_atombios_fini(struct radeon_device * rdev)1035926deccbSFrançois Tigeot void radeon_atombios_fini(struct radeon_device *rdev)
1036926deccbSFrançois Tigeot {
1037926deccbSFrançois Tigeot if (rdev->mode_info.atom_context) {
1038c4ef309bSzrj kfree(rdev->mode_info.atom_context->scratch);
1039926deccbSFrançois Tigeot }
1040c4ef309bSzrj kfree(rdev->mode_info.atom_context);
1041b403bed8SMichael Neumann rdev->mode_info.atom_context = NULL;
1042c4ef309bSzrj kfree(rdev->mode_info.atom_card_info);
1043b403bed8SMichael Neumann rdev->mode_info.atom_card_info = NULL;
1044926deccbSFrançois Tigeot }
1045926deccbSFrançois Tigeot
1046926deccbSFrançois Tigeot /* COMBIOS */
1047926deccbSFrançois Tigeot /*
1048926deccbSFrançois Tigeot * COMBIOS is the bios format prior to ATOM. It provides
1049926deccbSFrançois Tigeot * command tables similar to ATOM, but doesn't have a unified
1050926deccbSFrançois Tigeot * parser. See radeon_combios.c
1051926deccbSFrançois Tigeot */
1052926deccbSFrançois Tigeot
1053926deccbSFrançois Tigeot /**
1054926deccbSFrançois Tigeot * radeon_combios_init - init the driver info for combios
1055926deccbSFrançois Tigeot *
1056926deccbSFrançois Tigeot * @rdev: radeon_device pointer
1057926deccbSFrançois Tigeot *
1058926deccbSFrançois Tigeot * Initializes the driver info for combios (r1xx-r3xx).
1059926deccbSFrançois Tigeot * Returns 0 on sucess.
1060926deccbSFrançois Tigeot * Called at driver startup.
1061926deccbSFrançois Tigeot */
radeon_combios_init(struct radeon_device * rdev)1062926deccbSFrançois Tigeot int radeon_combios_init(struct radeon_device *rdev)
1063926deccbSFrançois Tigeot {
1064926deccbSFrançois Tigeot radeon_combios_initialize_bios_scratch_regs(rdev->ddev);
1065926deccbSFrançois Tigeot return 0;
1066926deccbSFrançois Tigeot }
1067926deccbSFrançois Tigeot
1068926deccbSFrançois Tigeot /**
1069926deccbSFrançois Tigeot * radeon_combios_fini - free the driver info for combios
1070926deccbSFrançois Tigeot *
1071926deccbSFrançois Tigeot * @rdev: radeon_device pointer
1072926deccbSFrançois Tigeot *
1073926deccbSFrançois Tigeot * Frees the driver info for combios (r1xx-r3xx).
1074926deccbSFrançois Tigeot * Called at driver shutdown.
1075926deccbSFrançois Tigeot */
radeon_combios_fini(struct radeon_device * rdev)1076926deccbSFrançois Tigeot void radeon_combios_fini(struct radeon_device *rdev)
1077926deccbSFrançois Tigeot {
1078926deccbSFrançois Tigeot }
1079926deccbSFrançois Tigeot
1080926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP
1081926deccbSFrançois Tigeot /* if we get transitioned to only one device, take VGA back */
1082926deccbSFrançois Tigeot /**
1083926deccbSFrançois Tigeot * radeon_vga_set_decode - enable/disable vga decode
1084926deccbSFrançois Tigeot *
1085926deccbSFrançois Tigeot * @cookie: radeon_device pointer
1086926deccbSFrançois Tigeot * @state: enable/disable vga decode
1087926deccbSFrançois Tigeot *
1088926deccbSFrançois Tigeot * Enable/disable vga decode (all asics).
1089926deccbSFrançois Tigeot * Returns VGA resource flags.
1090926deccbSFrançois Tigeot */
radeon_vga_set_decode(void * cookie,bool state)1091926deccbSFrançois Tigeot static unsigned int radeon_vga_set_decode(void *cookie, bool state)
1092926deccbSFrançois Tigeot {
1093926deccbSFrançois Tigeot struct radeon_device *rdev = cookie;
1094926deccbSFrançois Tigeot radeon_vga_set_state(rdev, state);
1095926deccbSFrançois Tigeot if (state)
1096926deccbSFrançois Tigeot return VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM |
1097926deccbSFrançois Tigeot VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
1098926deccbSFrançois Tigeot else
1099926deccbSFrançois Tigeot return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
1100926deccbSFrançois Tigeot }
1101926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */
1102926deccbSFrançois Tigeot
1103926deccbSFrançois Tigeot /**
1104926deccbSFrançois Tigeot * radeon_check_pot_argument - check that argument is a power of two
1105926deccbSFrançois Tigeot *
1106926deccbSFrançois Tigeot * @arg: value to check
1107926deccbSFrançois Tigeot *
1108926deccbSFrançois Tigeot * Validates that a certain argument is a power of two (all asics).
1109926deccbSFrançois Tigeot * Returns true if argument is valid.
1110926deccbSFrançois Tigeot */
radeon_check_pot_argument(int arg)1111926deccbSFrançois Tigeot static bool radeon_check_pot_argument(int arg)
1112926deccbSFrançois Tigeot {
1113926deccbSFrançois Tigeot return (arg & (arg - 1)) == 0;
1114926deccbSFrançois Tigeot }
1115926deccbSFrançois Tigeot
1116926deccbSFrançois Tigeot /**
1117c59a5c48SFrançois Tigeot * Determine a sensible default GART size according to ASIC family.
1118c59a5c48SFrançois Tigeot *
1119c59a5c48SFrançois Tigeot * @family ASIC family name
1120c59a5c48SFrançois Tigeot */
radeon_gart_size_auto(enum radeon_family family)1121c59a5c48SFrançois Tigeot static int radeon_gart_size_auto(enum radeon_family family)
1122c59a5c48SFrançois Tigeot {
1123c59a5c48SFrançois Tigeot /* default to a larger gart size on newer asics */
1124c59a5c48SFrançois Tigeot if (family >= CHIP_TAHITI)
1125c59a5c48SFrançois Tigeot return 2048;
1126c59a5c48SFrançois Tigeot else if (family >= CHIP_RV770)
1127c59a5c48SFrançois Tigeot return 1024;
1128c59a5c48SFrançois Tigeot else
1129c59a5c48SFrançois Tigeot return 512;
1130c59a5c48SFrançois Tigeot }
1131c59a5c48SFrançois Tigeot
1132c59a5c48SFrançois Tigeot /**
1133926deccbSFrançois Tigeot * radeon_check_arguments - validate module params
1134926deccbSFrançois Tigeot *
1135926deccbSFrançois Tigeot * @rdev: radeon_device pointer
1136926deccbSFrançois Tigeot *
1137926deccbSFrançois Tigeot * Validates certain module parameters and updates
1138926deccbSFrançois Tigeot * the associated values used by the driver (all asics).
1139926deccbSFrançois Tigeot */
radeon_check_arguments(struct radeon_device * rdev)1140926deccbSFrançois Tigeot static void radeon_check_arguments(struct radeon_device *rdev)
1141926deccbSFrançois Tigeot {
1142926deccbSFrançois Tigeot /* vramlimit must be a power of two */
1143926deccbSFrançois Tigeot if (!radeon_check_pot_argument(radeon_vram_limit)) {
1144926deccbSFrançois Tigeot dev_warn(rdev->dev, "vram limit (%d) must be a power of 2\n",
1145926deccbSFrançois Tigeot radeon_vram_limit);
1146926deccbSFrançois Tigeot radeon_vram_limit = 0;
1147926deccbSFrançois Tigeot }
1148926deccbSFrançois Tigeot
11494cd92098Szrj if (radeon_gart_size == -1) {
1150c59a5c48SFrançois Tigeot radeon_gart_size = radeon_gart_size_auto(rdev->family);
11514cd92098Szrj }
1152926deccbSFrançois Tigeot /* gtt size must be power of two and greater or equal to 32M */
1153926deccbSFrançois Tigeot if (radeon_gart_size < 32) {
11544cd92098Szrj dev_warn(rdev->dev, "gart size (%d) too small\n",
1155926deccbSFrançois Tigeot radeon_gart_size);
1156c59a5c48SFrançois Tigeot radeon_gart_size = radeon_gart_size_auto(rdev->family);
1157926deccbSFrançois Tigeot } else if (!radeon_check_pot_argument(radeon_gart_size)) {
1158926deccbSFrançois Tigeot dev_warn(rdev->dev, "gart size (%d) must be a power of 2\n",
1159926deccbSFrançois Tigeot radeon_gart_size);
1160c59a5c48SFrançois Tigeot radeon_gart_size = radeon_gart_size_auto(rdev->family);
1161926deccbSFrançois Tigeot }
1162926deccbSFrançois Tigeot rdev->mc.gtt_size = (uint64_t)radeon_gart_size << 20;
1163926deccbSFrançois Tigeot
1164926deccbSFrançois Tigeot /* AGP mode can only be -1, 1, 2, 4, 8 */
1165926deccbSFrançois Tigeot switch (radeon_agpmode) {
1166926deccbSFrançois Tigeot case -1:
1167926deccbSFrançois Tigeot case 0:
1168926deccbSFrançois Tigeot case 1:
1169926deccbSFrançois Tigeot case 2:
1170926deccbSFrançois Tigeot case 4:
1171926deccbSFrançois Tigeot case 8:
1172926deccbSFrançois Tigeot break;
1173926deccbSFrançois Tigeot default:
1174926deccbSFrançois Tigeot dev_warn(rdev->dev, "invalid AGP mode %d (valid mode: "
1175926deccbSFrançois Tigeot "-1, 0, 1, 2, 4, 8)\n", radeon_agpmode);
1176926deccbSFrançois Tigeot radeon_agpmode = 0;
1177926deccbSFrançois Tigeot break;
1178926deccbSFrançois Tigeot }
1179c6f73aabSFrançois Tigeot
1180c6f73aabSFrançois Tigeot if (!radeon_check_pot_argument(radeon_vm_size)) {
1181c6f73aabSFrançois Tigeot dev_warn(rdev->dev, "VM size (%d) must be a power of 2\n",
1182c6f73aabSFrançois Tigeot radeon_vm_size);
1183c6f73aabSFrançois Tigeot radeon_vm_size = 4;
1184926deccbSFrançois Tigeot }
1185926deccbSFrançois Tigeot
1186c6f73aabSFrançois Tigeot if (radeon_vm_size < 1) {
1187d78d3a22SFrançois Tigeot dev_warn(rdev->dev, "VM size (%d) too small, min is 1GB\n",
1188c6f73aabSFrançois Tigeot radeon_vm_size);
1189c6f73aabSFrançois Tigeot radeon_vm_size = 4;
1190c6f73aabSFrançois Tigeot }
1191c6f73aabSFrançois Tigeot
1192c6f73aabSFrançois Tigeot /*
1193c6f73aabSFrançois Tigeot * Max GPUVM size for Cayman, SI and CI are 40 bits.
1194926deccbSFrançois Tigeot */
1195c6f73aabSFrançois Tigeot if (radeon_vm_size > 1024) {
1196c6f73aabSFrançois Tigeot dev_warn(rdev->dev, "VM size (%d) too large, max is 1TB\n",
1197c6f73aabSFrançois Tigeot radeon_vm_size);
1198c6f73aabSFrançois Tigeot radeon_vm_size = 4;
1199926deccbSFrançois Tigeot }
1200926deccbSFrançois Tigeot
1201c6f73aabSFrançois Tigeot /* defines number of bits in page table versus page directory,
1202c6f73aabSFrançois Tigeot * a page is 4KB so we have 12 bits offset, minimum 9 bits in the
1203c6f73aabSFrançois Tigeot * page table and the remaining bits are in the page directory */
1204c6f73aabSFrançois Tigeot if (radeon_vm_block_size == -1) {
1205c6f73aabSFrançois Tigeot
1206c6f73aabSFrançois Tigeot /* Total bits covered by PD + PTs */
1207591d5043SFrançois Tigeot unsigned bits = ilog2(radeon_vm_size) + 18;
1208c6f73aabSFrançois Tigeot
1209c6f73aabSFrançois Tigeot /* Make sure the PD is 4K in size up to 8GB address space.
1210c6f73aabSFrançois Tigeot Above that split equal between PD and PTs */
1211c6f73aabSFrançois Tigeot if (radeon_vm_size <= 8)
1212c6f73aabSFrançois Tigeot radeon_vm_block_size = bits - 9;
1213c6f73aabSFrançois Tigeot else
1214c6f73aabSFrançois Tigeot radeon_vm_block_size = (bits + 3) / 2;
1215c6f73aabSFrançois Tigeot
1216c6f73aabSFrançois Tigeot } else if (radeon_vm_block_size < 9) {
1217c6f73aabSFrançois Tigeot dev_warn(rdev->dev, "VM page table size (%d) too small\n",
1218c6f73aabSFrançois Tigeot radeon_vm_block_size);
1219c6f73aabSFrançois Tigeot radeon_vm_block_size = 9;
1220926deccbSFrançois Tigeot }
1221c6f73aabSFrançois Tigeot
1222c6f73aabSFrançois Tigeot if (radeon_vm_block_size > 24 ||
1223c6f73aabSFrançois Tigeot (radeon_vm_size * 1024) < (1ull << radeon_vm_block_size)) {
1224c6f73aabSFrançois Tigeot dev_warn(rdev->dev, "VM page table size (%d) too large\n",
1225c6f73aabSFrançois Tigeot radeon_vm_block_size);
1226c6f73aabSFrançois Tigeot radeon_vm_block_size = 9;
1227c6f73aabSFrançois Tigeot }
1228c6f73aabSFrançois Tigeot }
1229926deccbSFrançois Tigeot
1230926deccbSFrançois Tigeot /**
1231926deccbSFrançois Tigeot * radeon_switcheroo_set_state - set switcheroo state
1232926deccbSFrançois Tigeot *
1233926deccbSFrançois Tigeot * @pdev: pci dev pointer
1234c59a5c48SFrançois Tigeot * @state: vga_switcheroo state
1235926deccbSFrançois Tigeot *
1236926deccbSFrançois Tigeot * Callback for the switcheroo driver. Suspends or resumes the
1237926deccbSFrançois Tigeot * the asics before or after it is powered up using ACPI methods.
1238926deccbSFrançois Tigeot */
1239926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP
radeon_switcheroo_set_state(struct pci_dev * pdev,enum vga_switcheroo_state state)1240926deccbSFrançois Tigeot static void radeon_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_state state)
1241926deccbSFrançois Tigeot {
1242926deccbSFrançois Tigeot struct drm_device *dev = pci_get_drvdata(pdev);
1243c6f73aabSFrançois Tigeot
1244c6f73aabSFrançois Tigeot if (radeon_is_px(dev) && state == VGA_SWITCHEROO_OFF)
1245c6f73aabSFrançois Tigeot return;
1246c6f73aabSFrançois Tigeot
1247926deccbSFrançois Tigeot if (state == VGA_SWITCHEROO_ON) {
1248a85cb24fSFrançois Tigeot pr_info("radeon: switched on\n");
1249926deccbSFrançois Tigeot /* don't suspend or resume card normally */
1250926deccbSFrançois Tigeot dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
1251926deccbSFrançois Tigeot
1252c6f73aabSFrançois Tigeot radeon_resume_kms(dev, true, true);
1253926deccbSFrançois Tigeot
1254926deccbSFrançois Tigeot dev->switch_power_state = DRM_SWITCH_POWER_ON;
1255926deccbSFrançois Tigeot drm_kms_helper_poll_enable(dev);
1256926deccbSFrançois Tigeot } else {
1257a85cb24fSFrançois Tigeot pr_info("radeon: switched off\n");
1258926deccbSFrançois Tigeot drm_kms_helper_poll_disable(dev);
1259926deccbSFrançois Tigeot dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
1260d78d3a22SFrançois Tigeot radeon_suspend_kms(dev, true, true, false);
1261926deccbSFrançois Tigeot dev->switch_power_state = DRM_SWITCH_POWER_OFF;
1262926deccbSFrançois Tigeot }
1263926deccbSFrançois Tigeot }
1264926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */
1265926deccbSFrançois Tigeot
1266926deccbSFrançois Tigeot /**
1267926deccbSFrançois Tigeot * radeon_switcheroo_can_switch - see if switcheroo state can change
1268926deccbSFrançois Tigeot *
1269926deccbSFrançois Tigeot * @pdev: pci dev pointer
1270926deccbSFrançois Tigeot *
1271926deccbSFrançois Tigeot * Callback for the switcheroo driver. Check of the switcheroo
1272926deccbSFrançois Tigeot * state can be changed.
1273926deccbSFrançois Tigeot * Returns true if the state can be changed, false if not.
1274926deccbSFrançois Tigeot */
1275926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP
radeon_switcheroo_can_switch(struct pci_dev * pdev)1276926deccbSFrançois Tigeot static bool radeon_switcheroo_can_switch(struct pci_dev *pdev)
1277926deccbSFrançois Tigeot {
1278926deccbSFrançois Tigeot struct drm_device *dev = pci_get_drvdata(pdev);
1279926deccbSFrançois Tigeot
1280c6f73aabSFrançois Tigeot /*
1281c6f73aabSFrançois Tigeot * FIXME: open_count is protected by drm_global_mutex but that would lead to
1282c6f73aabSFrançois Tigeot * locking inversion with the driver load path. And the access here is
1283c6f73aabSFrançois Tigeot * completely racy anyway. So don't bother with locking for now.
1284c6f73aabSFrançois Tigeot */
1285c6f73aabSFrançois Tigeot return dev->open_count == 0;
1286926deccbSFrançois Tigeot }
1287926deccbSFrançois Tigeot
1288926deccbSFrançois Tigeot static const struct vga_switcheroo_client_ops radeon_switcheroo_ops = {
1289926deccbSFrançois Tigeot .set_gpu_state = radeon_switcheroo_set_state,
1290926deccbSFrançois Tigeot .reprobe = NULL,
1291926deccbSFrançois Tigeot .can_switch = radeon_switcheroo_can_switch,
1292926deccbSFrançois Tigeot };
1293926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */
1294926deccbSFrançois Tigeot
1295926deccbSFrançois Tigeot /**
1296926deccbSFrançois Tigeot * radeon_device_init - initialize the driver
1297926deccbSFrançois Tigeot *
1298926deccbSFrançois Tigeot * @rdev: radeon_device pointer
1299926deccbSFrançois Tigeot * @pdev: drm dev pointer
1300c6f73aabSFrançois Tigeot * @pdev: pci dev pointer
1301926deccbSFrançois Tigeot * @flags: driver flags
1302926deccbSFrançois Tigeot *
1303926deccbSFrançois Tigeot * Initializes the driver info and hw (all asics).
1304926deccbSFrançois Tigeot * Returns 0 for success or an error on failure.
1305926deccbSFrançois Tigeot * Called at driver startup.
1306926deccbSFrançois Tigeot */
radeon_device_init(struct radeon_device * rdev,struct drm_device * ddev,struct pci_dev * pdev,uint32_t flags)1307926deccbSFrançois Tigeot int radeon_device_init(struct radeon_device *rdev,
1308926deccbSFrançois Tigeot struct drm_device *ddev,
1309c6f73aabSFrançois Tigeot struct pci_dev *pdev,
1310926deccbSFrançois Tigeot uint32_t flags)
1311926deccbSFrançois Tigeot {
1312926deccbSFrançois Tigeot int r, i;
1313926deccbSFrançois Tigeot int dma_bits;
1314c6f73aabSFrançois Tigeot #ifdef PM_TODO
1315c6f73aabSFrançois Tigeot bool runtime = false;
1316c6f73aabSFrançois Tigeot #endif
1317926deccbSFrançois Tigeot
1318926deccbSFrançois Tigeot rdev->shutdown = false;
1319fb572d17SFrançois Tigeot rdev->dev = &pdev->dev;
1320926deccbSFrançois Tigeot rdev->ddev = ddev;
1321c6f73aabSFrançois Tigeot rdev->pdev = pdev;
1322926deccbSFrançois Tigeot rdev->flags = flags;
1323926deccbSFrançois Tigeot rdev->family = flags & RADEON_FAMILY_MASK;
1324926deccbSFrançois Tigeot rdev->is_atom_bios = false;
1325926deccbSFrançois Tigeot rdev->usec_timeout = RADEON_MAX_USEC_TIMEOUT;
13264cd92098Szrj rdev->mc.gtt_size = 512 * 1024 * 1024;
1327926deccbSFrançois Tigeot rdev->accel_working = false;
1328926deccbSFrançois Tigeot rdev->fictitious_range_registered = false;
1329926deccbSFrançois Tigeot /* set up ring ids */
1330926deccbSFrançois Tigeot for (i = 0; i < RADEON_NUM_RINGS; i++) {
1331926deccbSFrançois Tigeot rdev->ring[i].idx = i;
1332926deccbSFrançois Tigeot }
13336559babbSFrançois Tigeot rdev->fence_context = dma_fence_context_alloc(RADEON_NUM_RINGS);
1334926deccbSFrançois Tigeot
1335d78d3a22SFrançois Tigeot DRM_INFO("initializing kernel modesetting (%s 0x%04X:0x%04X 0x%04X:0x%04X 0x%02X).\n",
1336c6f73aabSFrançois Tigeot radeon_family_name[rdev->family], pdev->vendor, pdev->device,
1337d78d3a22SFrançois Tigeot pdev->subsystem_vendor, pdev->subsystem_device, pdev->revision);
1338926deccbSFrançois Tigeot
1339926deccbSFrançois Tigeot /* mutex initialization are all done here so we
1340926deccbSFrançois Tigeot * can recall function without having locking issues */
13411ca17f9bSFrançois Tigeot lockinit(&rdev->ring_lock, "drdrl", 0, LK_CANRECURSE);
13421ca17f9bSFrançois Tigeot lockinit(&rdev->dc_hw_i2c_mutex, "drddi2cm", 0, LK_CANRECURSE);
1343926deccbSFrançois Tigeot atomic_set(&rdev->ih.lock, 0);
1344fefad7a7SFrançois Tigeot lockinit(&rdev->gem.mutex, "radeon_gemmtx", 0, LK_CANRECURSE);
13451ca17f9bSFrançois Tigeot lockinit(&rdev->pm.mutex, "drdpmm", 0, LK_CANRECURSE);
1346fefad7a7SFrançois Tigeot lockinit(&rdev->gpu_clock_mutex, "radeon_clockmtx", 0, LK_CANRECURSE);
1347fefad7a7SFrançois Tigeot lockinit(&rdev->srbm_mutex, "radeon_srbm_mutex", 0, LK_CANRECURSE);
13487dcf36dcSFrançois Tigeot lockinit(&rdev->grbm_idx_mutex, "drgim", 0, LK_CANRECURSE);
13491ca17f9bSFrançois Tigeot lockinit(&rdev->pm.mclk_lock, "drpmml", 0, LK_CANRECURSE);
13501ca17f9bSFrançois Tigeot lockinit(&rdev->exclusive_lock, "drdel", 0, LK_CANRECURSE);
1351c6f73aabSFrançois Tigeot init_waitqueue_head(&rdev->irq.vblank_queue);
13521cfef1a5SFrançois Tigeot lockinit(&rdev->mn_lock, "drrml", 0, LK_CANRECURSE);
1353926deccbSFrançois Tigeot r = radeon_gem_init(rdev);
1354926deccbSFrançois Tigeot if (r)
1355926deccbSFrançois Tigeot return r;
1356c6f73aabSFrançois Tigeot
1357c6f73aabSFrançois Tigeot radeon_check_arguments(rdev);
1358926deccbSFrançois Tigeot /* Adjust VM size here.
1359c6f73aabSFrançois Tigeot * Max GPUVM size for cayman+ is 40 bits.
1360926deccbSFrançois Tigeot */
1361c6f73aabSFrançois Tigeot rdev->vm_manager.max_pfn = radeon_vm_size << 18;
1362926deccbSFrançois Tigeot
1363926deccbSFrançois Tigeot /* Set asic functions */
1364926deccbSFrançois Tigeot r = radeon_asic_init(rdev);
1365926deccbSFrançois Tigeot if (r)
1366926deccbSFrançois Tigeot return r;
1367926deccbSFrançois Tigeot
1368926deccbSFrançois Tigeot /* all of the newer IGP chips have an internal gart
1369926deccbSFrançois Tigeot * However some rs4xx report as AGP, so remove that here.
1370926deccbSFrançois Tigeot */
1371926deccbSFrançois Tigeot if ((rdev->family >= CHIP_RS400) &&
1372926deccbSFrançois Tigeot (rdev->flags & RADEON_IS_IGP)) {
1373926deccbSFrançois Tigeot rdev->flags &= ~RADEON_IS_AGP;
1374926deccbSFrançois Tigeot }
1375926deccbSFrançois Tigeot
1376926deccbSFrançois Tigeot if (rdev->flags & RADEON_IS_AGP && radeon_agpmode == -1) {
1377926deccbSFrançois Tigeot radeon_agp_disable(rdev);
1378926deccbSFrançois Tigeot }
1379926deccbSFrançois Tigeot
1380f43cf1b1SMichael Neumann /* Set the internal MC address mask
1381f43cf1b1SMichael Neumann * This is the max address of the GPU's
1382f43cf1b1SMichael Neumann * internal address space.
1383f43cf1b1SMichael Neumann */
1384f43cf1b1SMichael Neumann if (rdev->family >= CHIP_CAYMAN)
1385f43cf1b1SMichael Neumann rdev->mc.mc_mask = 0xffffffffffULL; /* 40 bit MC */
1386f43cf1b1SMichael Neumann else if (rdev->family >= CHIP_CEDAR)
1387f43cf1b1SMichael Neumann rdev->mc.mc_mask = 0xfffffffffULL; /* 36 bit MC */
1388f43cf1b1SMichael Neumann else
1389f43cf1b1SMichael Neumann rdev->mc.mc_mask = 0xffffffffULL; /* 32 bit MC */
1390f43cf1b1SMichael Neumann
1391926deccbSFrançois Tigeot /* set DMA mask + need_dma32 flags.
1392926deccbSFrançois Tigeot * PCIE - can handle 40-bits.
1393926deccbSFrançois Tigeot * IGP - can handle 40-bits
1394926deccbSFrançois Tigeot * AGP - generally dma32 is safest
1395926deccbSFrançois Tigeot * PCI - dma32 for legacy pci gart, 40 bits on newer asics
1396926deccbSFrançois Tigeot */
1397926deccbSFrançois Tigeot rdev->need_dma32 = false;
1398926deccbSFrançois Tigeot if (rdev->flags & RADEON_IS_AGP)
1399926deccbSFrançois Tigeot rdev->need_dma32 = true;
1400926deccbSFrançois Tigeot if ((rdev->flags & RADEON_IS_PCI) &&
1401926deccbSFrançois Tigeot (rdev->family <= CHIP_RS740))
1402926deccbSFrançois Tigeot rdev->need_dma32 = true;
1403*3f2dd94aSFrançois Tigeot #ifdef CONFIG_PPC64
1404*3f2dd94aSFrançois Tigeot if (rdev->family == CHIP_CEDAR)
1405*3f2dd94aSFrançois Tigeot rdev->need_dma32 = true;
1406*3f2dd94aSFrançois Tigeot #endif
1407926deccbSFrançois Tigeot
1408926deccbSFrançois Tigeot dma_bits = rdev->need_dma32 ? 32 : 40;
1409926deccbSFrançois Tigeot r = pci_set_dma_mask(rdev->pdev, DMA_BIT_MASK(dma_bits));
1410926deccbSFrançois Tigeot if (r) {
1411926deccbSFrançois Tigeot rdev->need_dma32 = true;
1412926deccbSFrançois Tigeot dma_bits = 32;
1413a85cb24fSFrançois Tigeot pr_warn("radeon: No suitable DMA available\n");
1414926deccbSFrançois Tigeot }
1415926deccbSFrançois Tigeot r = pci_set_consistent_dma_mask(rdev->pdev, DMA_BIT_MASK(dma_bits));
1416926deccbSFrançois Tigeot if (r) {
1417926deccbSFrançois Tigeot pci_set_consistent_dma_mask(rdev->pdev, DMA_BIT_MASK(32));
1418a85cb24fSFrançois Tigeot pr_warn("radeon: No coherent DMA available\n");
1419926deccbSFrançois Tigeot }
1420926deccbSFrançois Tigeot
1421926deccbSFrançois Tigeot /* Registers mapping */
1422926deccbSFrançois Tigeot /* TODO: block userspace mapping of io register */
14239a49c39cSFrançois Tigeot lockinit(&rdev->mmio_idx_lock, "rdnmidl", 0, 0);
14249a49c39cSFrançois Tigeot lockinit(&rdev->smc_idx_lock, "rdnsil", 0, 0);
14259a49c39cSFrançois Tigeot lockinit(&rdev->pll_idx_lock, "rdnpll", 0, 0);
14269a49c39cSFrançois Tigeot lockinit(&rdev->mc_idx_lock, "rdnmcil", 0, 0);
14279a49c39cSFrançois Tigeot lockinit(&rdev->pcie_idx_lock, "rdnpil", 0, 0);
14289a49c39cSFrançois Tigeot lockinit(&rdev->pciep_idx_lock, "rdnppil", 0, 0);
14299a49c39cSFrançois Tigeot lockinit(&rdev->pif_idx_lock, "rdnpif", 0, 0);
14309a49c39cSFrançois Tigeot lockinit(&rdev->cg_idx_lock, "rdncgil", 0, 0);
14319a49c39cSFrançois Tigeot lockinit(&rdev->uvd_idx_lock, "rdnuvd", 0, 0);
14329a49c39cSFrançois Tigeot lockinit(&rdev->rcu_idx_lock, "rdnrcu", 0, 0);
14339a49c39cSFrançois Tigeot lockinit(&rdev->didt_idx_lock, "rdndidt", 0, 0);
14349a49c39cSFrançois Tigeot lockinit(&rdev->end_idx_lock, "rdneil", 0, 0);
143557e252bfSMichael Neumann if (rdev->family >= CHIP_BONAIRE) {
1436374a0b33SFrançois Tigeot rdev->rmmio_base = pci_resource_start(rdev->pdev, 5);
1437374a0b33SFrançois Tigeot rdev->rmmio_size = pci_resource_len(rdev->pdev, 5);
143857e252bfSMichael Neumann } else {
1439374a0b33SFrançois Tigeot rdev->rmmio_base = pci_resource_start(rdev->pdev, 2);
1440374a0b33SFrançois Tigeot rdev->rmmio_size = pci_resource_len(rdev->pdev, 2);
144157e252bfSMichael Neumann }
1442374a0b33SFrançois Tigeot rdev->rmmio = ioremap(rdev->rmmio_base, rdev->rmmio_size);
1443a85cb24fSFrançois Tigeot if (rdev->rmmio == NULL)
1444926deccbSFrançois Tigeot return -ENOMEM;
1445926deccbSFrançois Tigeot
144657e252bfSMichael Neumann /* doorbell bar mapping */
144757e252bfSMichael Neumann if (rdev->family >= CHIP_BONAIRE)
144857e252bfSMichael Neumann radeon_doorbell_init(rdev);
144957e252bfSMichael Neumann
1450926deccbSFrançois Tigeot /* io port mapping */
1451c59a5c48SFrançois Tigeot for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
1452926deccbSFrançois Tigeot uint32_t data;
1453926deccbSFrançois Tigeot
1454fb572d17SFrançois Tigeot data = pci_read_config(rdev->dev->bsddev, PCIR_BAR(i), 4);
1455926deccbSFrançois Tigeot if (PCI_BAR_IO(data)) {
1456926deccbSFrançois Tigeot rdev->rio_rid = PCIR_BAR(i);
1457c59a5c48SFrançois Tigeot rdev->rio_mem_size = pci_resource_len(rdev->pdev, i);
1458fb572d17SFrançois Tigeot rdev->rio_mem = bus_alloc_resource_any(rdev->dev->bsddev,
1459926deccbSFrançois Tigeot SYS_RES_IOPORT, &rdev->rio_rid,
1460926deccbSFrançois Tigeot RF_ACTIVE | RF_SHAREABLE);
1461926deccbSFrançois Tigeot break;
1462926deccbSFrançois Tigeot }
1463926deccbSFrançois Tigeot }
1464926deccbSFrançois Tigeot if (rdev->rio_mem == NULL)
1465926deccbSFrançois Tigeot DRM_ERROR("Unable to find PCI I/O BAR\n");
1466926deccbSFrançois Tigeot
1467c6f73aabSFrançois Tigeot if (rdev->flags & RADEON_IS_PX)
1468c6f73aabSFrançois Tigeot radeon_device_handle_px_quirks(rdev);
1469c6f73aabSFrançois Tigeot
1470926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP
1471926deccbSFrançois Tigeot /* if we have > 1 VGA cards, then disable the radeon VGA resources */
1472926deccbSFrançois Tigeot /* this will fail for cards that aren't VGA class devices, just
1473926deccbSFrançois Tigeot * ignore it */
1474926deccbSFrançois Tigeot vga_client_register(rdev->pdev, rdev, NULL, radeon_vga_set_decode);
1475c6f73aabSFrançois Tigeot
1476c6f73aabSFrançois Tigeot if (rdev->flags & RADEON_IS_PX)
1477c6f73aabSFrançois Tigeot runtime = true;
1478a85cb24fSFrançois Tigeot if (!pci_is_thunderbolt_attached(rdev->pdev))
1479a85cb24fSFrançois Tigeot vga_switcheroo_register_client(rdev->pdev,
1480a85cb24fSFrançois Tigeot &radeon_switcheroo_ops, runtime);
1481c6f73aabSFrançois Tigeot if (runtime)
1482c59a5c48SFrançois Tigeot vga_switcheroo_init_domain_pm_ops(rdev->dev, &rdev->vga_pm_domain);
1483c6f73aabSFrançois Tigeot #endif
1484926deccbSFrançois Tigeot
1485926deccbSFrançois Tigeot r = radeon_init(rdev);
1486926deccbSFrançois Tigeot if (r)
1487c6f73aabSFrançois Tigeot goto failed;
1488926deccbSFrançois Tigeot
1489f43cf1b1SMichael Neumann r = radeon_gem_debugfs_init(rdev);
1490f43cf1b1SMichael Neumann if (r) {
1491f43cf1b1SMichael Neumann DRM_ERROR("registering gem debugfs failed (%d).\n", r);
1492f43cf1b1SMichael Neumann }
1493f43cf1b1SMichael Neumann
1494c59a5c48SFrançois Tigeot r = radeon_mst_debugfs_init(rdev);
1495c59a5c48SFrançois Tigeot if (r) {
1496c59a5c48SFrançois Tigeot DRM_ERROR("registering mst debugfs failed (%d).\n", r);
1497c59a5c48SFrançois Tigeot }
1498c59a5c48SFrançois Tigeot
1499926deccbSFrançois Tigeot if (rdev->flags & RADEON_IS_AGP && !rdev->accel_working) {
1500926deccbSFrançois Tigeot /* Acceleration not working on AGP card try again
1501926deccbSFrançois Tigeot * with fallback to PCI or PCIE GART
1502926deccbSFrançois Tigeot */
1503926deccbSFrançois Tigeot radeon_asic_reset(rdev);
1504926deccbSFrançois Tigeot radeon_fini(rdev);
1505926deccbSFrançois Tigeot radeon_agp_disable(rdev);
1506926deccbSFrançois Tigeot r = radeon_init(rdev);
1507926deccbSFrançois Tigeot if (r)
1508c6f73aabSFrançois Tigeot goto failed;
1509926deccbSFrançois Tigeot }
1510926deccbSFrançois Tigeot
1511591d5043SFrançois Tigeot r = radeon_ib_ring_tests(rdev);
1512591d5043SFrançois Tigeot if (r)
1513591d5043SFrançois Tigeot DRM_ERROR("ib ring test failed (%d).\n", r);
1514591d5043SFrançois Tigeot
1515f77dbd6cSFrançois Tigeot DRM_INFO("%s: Taking over the fictitious range 0x%lx-0x%llx\n",
1516926deccbSFrançois Tigeot __func__, (uintmax_t)rdev->mc.aper_base,
1517926deccbSFrançois Tigeot (uintmax_t)rdev->mc.aper_base + rdev->mc.visible_vram_size);
1518926deccbSFrançois Tigeot r = vm_phys_fictitious_reg_range(
1519926deccbSFrançois Tigeot rdev->mc.aper_base,
1520926deccbSFrançois Tigeot rdev->mc.aper_base + rdev->mc.visible_vram_size,
1521926deccbSFrançois Tigeot VM_MEMATTR_WRITE_COMBINING);
1522926deccbSFrançois Tigeot if (r != 0) {
1523926deccbSFrançois Tigeot DRM_ERROR("Failed to register fictitious range "
1524f77dbd6cSFrançois Tigeot "0x%lx-0x%llx (%d).\n", (uintmax_t)rdev->mc.aper_base,
1525926deccbSFrançois Tigeot (uintmax_t)rdev->mc.aper_base + rdev->mc.visible_vram_size, r);
1526926deccbSFrançois Tigeot return (-r);
1527926deccbSFrançois Tigeot }
1528926deccbSFrançois Tigeot rdev->fictitious_range_registered = true;
1529926deccbSFrançois Tigeot
1530c59a5c48SFrançois Tigeot /*
1531c59a5c48SFrançois Tigeot * Turks/Thames GPU will freeze whole laptop if DPM is not restarted
1532c59a5c48SFrançois Tigeot * after the CP ring have chew one packet at least. Hence here we stop
1533c59a5c48SFrançois Tigeot * and restart DPM after the radeon_ib_ring_tests().
1534c59a5c48SFrançois Tigeot */
1535c59a5c48SFrançois Tigeot if (rdev->pm.dpm_enabled &&
1536c59a5c48SFrançois Tigeot (rdev->pm.pm_method == PM_METHOD_DPM) &&
1537c59a5c48SFrançois Tigeot (rdev->family == CHIP_TURKS) &&
1538c59a5c48SFrançois Tigeot (rdev->flags & RADEON_IS_MOBILITY)) {
1539c59a5c48SFrançois Tigeot mutex_lock(&rdev->pm.mutex);
1540c59a5c48SFrançois Tigeot radeon_dpm_disable(rdev);
1541c59a5c48SFrançois Tigeot radeon_dpm_enable(rdev);
1542c59a5c48SFrançois Tigeot mutex_unlock(&rdev->pm.mutex);
1543c59a5c48SFrançois Tigeot }
1544c59a5c48SFrançois Tigeot
1545926deccbSFrançois Tigeot if ((radeon_testing & 1)) {
15464cd92098Szrj if (rdev->accel_working)
1547926deccbSFrançois Tigeot radeon_test_moves(rdev);
15484cd92098Szrj else
15494cd92098Szrj DRM_INFO("radeon: acceleration disabled, skipping move tests\n");
1550926deccbSFrançois Tigeot }
1551926deccbSFrançois Tigeot if ((radeon_testing & 2)) {
15524cd92098Szrj if (rdev->accel_working)
1553926deccbSFrançois Tigeot radeon_test_syncing(rdev);
15544cd92098Szrj else
15554cd92098Szrj DRM_INFO("radeon: acceleration disabled, skipping sync tests\n");
1556926deccbSFrançois Tigeot }
1557926deccbSFrançois Tigeot if (radeon_benchmarking) {
15584cd92098Szrj if (rdev->accel_working)
1559926deccbSFrançois Tigeot radeon_benchmark(rdev, radeon_benchmarking);
15604cd92098Szrj else
15614cd92098Szrj DRM_INFO("radeon: acceleration disabled, skipping benchmarks\n");
1562926deccbSFrançois Tigeot }
15637dcf36dcSFrançois Tigeot rdev->dummy_page.entry = radeon_gart_get_page_entry(rdev->dummy_page.addr,
15647dcf36dcSFrançois Tigeot RADEON_GART_PAGE_DUMMY);
1565926deccbSFrançois Tigeot return 0;
1566c6f73aabSFrançois Tigeot
1567c6f73aabSFrançois Tigeot failed:
1568c59a5c48SFrançois Tigeot #if 0
1569c6f73aabSFrançois Tigeot if (runtime)
1570c6f73aabSFrançois Tigeot vga_switcheroo_fini_domain_pm_ops(rdev->dev);
1571c6f73aabSFrançois Tigeot #endif
1572c6f73aabSFrançois Tigeot return r;
1573926deccbSFrançois Tigeot }
1574926deccbSFrançois Tigeot
1575926deccbSFrançois Tigeot /**
1576926deccbSFrançois Tigeot * radeon_device_fini - tear down the driver
1577926deccbSFrançois Tigeot *
1578926deccbSFrançois Tigeot * @rdev: radeon_device pointer
1579926deccbSFrançois Tigeot *
1580926deccbSFrançois Tigeot * Tear down the driver info (all asics).
1581926deccbSFrançois Tigeot * Called at driver shutdown.
1582926deccbSFrançois Tigeot */
radeon_device_fini(struct radeon_device * rdev)1583926deccbSFrançois Tigeot void radeon_device_fini(struct radeon_device *rdev)
1584926deccbSFrançois Tigeot {
1585926deccbSFrançois Tigeot DRM_INFO("radeon: finishing device.\n");
1586926deccbSFrançois Tigeot rdev->shutdown = true;
1587926deccbSFrançois Tigeot /* evict vram memory */
1588926deccbSFrançois Tigeot radeon_bo_evict_vram(rdev);
1589926deccbSFrançois Tigeot
1590926deccbSFrançois Tigeot if (rdev->fictitious_range_registered) {
1591926deccbSFrançois Tigeot vm_phys_fictitious_unreg_range(
1592926deccbSFrançois Tigeot rdev->mc.aper_base,
1593926deccbSFrançois Tigeot rdev->mc.aper_base + rdev->mc.visible_vram_size);
1594926deccbSFrançois Tigeot }
1595926deccbSFrançois Tigeot
1596926deccbSFrançois Tigeot radeon_fini(rdev);
1597926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP
1598a85cb24fSFrançois Tigeot if (!pci_is_thunderbolt_attached(rdev->pdev))
1599926deccbSFrançois Tigeot vga_switcheroo_unregister_client(rdev->pdev);
1600c6f73aabSFrançois Tigeot if (rdev->flags & RADEON_IS_PX)
1601c6f73aabSFrançois Tigeot vga_switcheroo_fini_domain_pm_ops(rdev->dev);
1602926deccbSFrançois Tigeot vga_client_register(rdev->pdev, NULL, NULL, NULL);
1603926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */
1604926deccbSFrançois Tigeot if (rdev->rio_mem)
1605fb572d17SFrançois Tigeot bus_release_resource(rdev->dev->bsddev, SYS_RES_IOPORT, rdev->rio_rid,
1606926deccbSFrançois Tigeot rdev->rio_mem);
1607926deccbSFrançois Tigeot rdev->rio_mem = NULL;
1608374a0b33SFrançois Tigeot iounmap(rdev->rmmio);
1609926deccbSFrançois Tigeot rdev->rmmio = NULL;
161057e252bfSMichael Neumann if (rdev->family >= CHIP_BONAIRE)
161157e252bfSMichael Neumann radeon_doorbell_fini(rdev);
1612926deccbSFrançois Tigeot }
1613926deccbSFrançois Tigeot
1614926deccbSFrançois Tigeot
1615926deccbSFrançois Tigeot /*
1616926deccbSFrançois Tigeot * Suspend & resume.
1617926deccbSFrançois Tigeot */
1618926deccbSFrançois Tigeot /**
1619926deccbSFrançois Tigeot * radeon_suspend_kms - initiate device suspend
1620926deccbSFrançois Tigeot *
1621926deccbSFrançois Tigeot * @pdev: drm dev pointer
1622926deccbSFrançois Tigeot * @state: suspend state
1623926deccbSFrançois Tigeot *
1624926deccbSFrançois Tigeot * Puts the hw in the suspend state (all asics).
1625926deccbSFrançois Tigeot * Returns 0 for success or an error on failure.
1626926deccbSFrançois Tigeot * Called at driver suspend.
1627926deccbSFrançois Tigeot */
radeon_suspend_kms(struct drm_device * dev,bool suspend,bool fbcon,bool freeze)1628d78d3a22SFrançois Tigeot int radeon_suspend_kms(struct drm_device *dev, bool suspend,
1629d78d3a22SFrançois Tigeot bool fbcon, bool freeze)
1630926deccbSFrançois Tigeot {
1631926deccbSFrançois Tigeot struct radeon_device *rdev;
1632926deccbSFrançois Tigeot struct drm_crtc *crtc;
1633926deccbSFrançois Tigeot struct drm_connector *connector;
1634926deccbSFrançois Tigeot int i, r;
1635926deccbSFrançois Tigeot
1636926deccbSFrançois Tigeot if (dev == NULL || dev->dev_private == NULL) {
1637926deccbSFrançois Tigeot return -ENODEV;
1638926deccbSFrançois Tigeot }
1639c6f73aabSFrançois Tigeot
1640926deccbSFrançois Tigeot rdev = dev->dev_private;
1641926deccbSFrançois Tigeot
1642926deccbSFrançois Tigeot if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
1643926deccbSFrançois Tigeot return 0;
1644926deccbSFrançois Tigeot
1645926deccbSFrançois Tigeot drm_kms_helper_poll_disable(dev);
1646926deccbSFrançois Tigeot
1647c59a5c48SFrançois Tigeot drm_modeset_lock_all(dev);
1648926deccbSFrançois Tigeot /* turn off display hw */
1649926deccbSFrançois Tigeot list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
1650926deccbSFrançois Tigeot drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
1651926deccbSFrançois Tigeot }
1652c59a5c48SFrançois Tigeot drm_modeset_unlock_all(dev);
1653926deccbSFrançois Tigeot
1654c59a5c48SFrançois Tigeot /* unpin the front buffers and cursors */
1655926deccbSFrançois Tigeot list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
1656c59a5c48SFrançois Tigeot struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
1657ba55f2f5SFrançois Tigeot struct radeon_framebuffer *rfb = to_radeon_framebuffer(crtc->primary->fb);
1658926deccbSFrançois Tigeot struct radeon_bo *robj;
1659926deccbSFrançois Tigeot
1660c59a5c48SFrançois Tigeot if (radeon_crtc->cursor_bo) {
1661c59a5c48SFrançois Tigeot struct radeon_bo *robj = gem_to_radeon_bo(radeon_crtc->cursor_bo);
1662c59a5c48SFrançois Tigeot r = radeon_bo_reserve(robj, false);
1663c59a5c48SFrançois Tigeot if (r == 0) {
1664c59a5c48SFrançois Tigeot radeon_bo_unpin(robj);
1665c59a5c48SFrançois Tigeot radeon_bo_unreserve(robj);
1666c59a5c48SFrançois Tigeot }
1667c59a5c48SFrançois Tigeot }
1668c59a5c48SFrançois Tigeot
1669926deccbSFrançois Tigeot if (rfb == NULL || rfb->obj == NULL) {
1670926deccbSFrançois Tigeot continue;
1671926deccbSFrançois Tigeot }
1672926deccbSFrançois Tigeot robj = gem_to_radeon_bo(rfb->obj);
1673926deccbSFrançois Tigeot /* don't unpin kernel fb objects */
1674926deccbSFrançois Tigeot if (!radeon_fbdev_robj_is_fb(rdev, robj)) {
1675926deccbSFrançois Tigeot r = radeon_bo_reserve(robj, false);
1676926deccbSFrançois Tigeot if (r == 0) {
1677926deccbSFrançois Tigeot radeon_bo_unpin(robj);
1678926deccbSFrançois Tigeot radeon_bo_unreserve(robj);
1679926deccbSFrançois Tigeot }
1680926deccbSFrançois Tigeot }
1681926deccbSFrançois Tigeot }
1682926deccbSFrançois Tigeot /* evict vram memory */
1683926deccbSFrançois Tigeot radeon_bo_evict_vram(rdev);
1684926deccbSFrançois Tigeot
1685926deccbSFrançois Tigeot /* wait for gpu to finish processing current batch */
1686926deccbSFrançois Tigeot for (i = 0; i < RADEON_NUM_RINGS; i++) {
1687c6f73aabSFrançois Tigeot r = radeon_fence_wait_empty(rdev, i);
1688926deccbSFrançois Tigeot if (r) {
1689926deccbSFrançois Tigeot /* delay GPU reset to resume */
1690c6f73aabSFrançois Tigeot radeon_fence_driver_force_completion(rdev, i);
1691926deccbSFrançois Tigeot }
1692926deccbSFrançois Tigeot }
1693926deccbSFrançois Tigeot
1694926deccbSFrançois Tigeot radeon_save_bios_scratch_regs(rdev);
1695926deccbSFrançois Tigeot
1696926deccbSFrançois Tigeot radeon_suspend(rdev);
1697926deccbSFrançois Tigeot radeon_hpd_fini(rdev);
16984be47400SFrançois Tigeot /* evict remaining vram memory
16994be47400SFrançois Tigeot * This second call to evict vram is to evict the gart page table
17004be47400SFrançois Tigeot * using the CPU.
17014be47400SFrançois Tigeot */
1702926deccbSFrançois Tigeot radeon_bo_evict_vram(rdev);
1703926deccbSFrançois Tigeot
1704926deccbSFrançois Tigeot radeon_agp_suspend(rdev);
1705926deccbSFrançois Tigeot
1706fb572d17SFrançois Tigeot pci_save_state(device_get_parent(rdev->dev->bsddev));
1707*3f2dd94aSFrançois Tigeot if (freeze && rdev->family >= CHIP_CEDAR && !(rdev->flags & RADEON_IS_IGP)) {
1708d78d3a22SFrançois Tigeot rdev->asic->asic_reset(rdev, true);
1709*3f2dd94aSFrançois Tigeot #if 0
1710d78d3a22SFrançois Tigeot pci_restore_state(dev->pdev);
1711*3f2dd94aSFrançois Tigeot #endif
1712d78d3a22SFrançois Tigeot } else if (suspend) {
1713926deccbSFrançois Tigeot /* Shut down the device */
1714*3f2dd94aSFrançois Tigeot #if 0
1715926deccbSFrançois Tigeot pci_disable_device(dev->pdev);
1716*3f2dd94aSFrançois Tigeot pci_set_power_state(dev->pdev, PCI_D3hot);
1717c6f73aabSFrançois Tigeot #endif
1718*3f2dd94aSFrançois Tigeot }
1719c59a5c48SFrançois Tigeot
1720c6f73aabSFrançois Tigeot if (fbcon) {
1721c6f73aabSFrançois Tigeot #ifdef DUMBBELL_WIP
1722926deccbSFrançois Tigeot console_lock();
1723926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */
1724926deccbSFrançois Tigeot radeon_fbdev_set_suspend(rdev, 1);
1725926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP
1726926deccbSFrançois Tigeot console_unlock();
1727926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */
1728c6f73aabSFrançois Tigeot }
1729c59a5c48SFrançois Tigeot rdev->dummy_page.entry = radeon_gart_get_page_entry(rdev->dummy_page.addr,
1730c59a5c48SFrançois Tigeot RADEON_GART_PAGE_DUMMY);
1731926deccbSFrançois Tigeot return 0;
1732926deccbSFrançois Tigeot }
1733926deccbSFrançois Tigeot
1734926deccbSFrançois Tigeot /**
1735926deccbSFrançois Tigeot * radeon_resume_kms - initiate device resume
1736926deccbSFrançois Tigeot *
1737926deccbSFrançois Tigeot * @pdev: drm dev pointer
1738926deccbSFrançois Tigeot *
1739926deccbSFrançois Tigeot * Bring the hw back to operating state (all asics).
1740926deccbSFrançois Tigeot * Returns 0 for success or an error on failure.
1741926deccbSFrançois Tigeot * Called at driver resume.
1742926deccbSFrançois Tigeot */
radeon_resume_kms(struct drm_device * dev,bool resume,bool fbcon)1743c6f73aabSFrançois Tigeot int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon)
1744926deccbSFrançois Tigeot {
1745926deccbSFrançois Tigeot struct drm_connector *connector;
1746926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private;
1747c59a5c48SFrançois Tigeot struct drm_crtc *crtc;
1748926deccbSFrançois Tigeot int r;
1749926deccbSFrançois Tigeot
1750926deccbSFrançois Tigeot if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
1751926deccbSFrançois Tigeot return 0;
1752926deccbSFrançois Tigeot
1753926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP
1754c6f73aabSFrançois Tigeot if (fbcon) {
1755926deccbSFrançois Tigeot console_lock();
1756c6f73aabSFrançois Tigeot }
1757926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */
1758c6f73aabSFrançois Tigeot if (resume) {
1759926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP
1760c59a5c48SFrançois Tigeot pci_set_power_state(dev->pdev, PCI_D0);
1761c59a5c48SFrançois Tigeot pci_restore_state(dev->pdev);
1762926deccbSFrançois Tigeot if (pci_enable_device(dev->pdev)) {
1763c6f73aabSFrançois Tigeot if (fbcon)
1764926deccbSFrançois Tigeot console_unlock();
1765926deccbSFrançois Tigeot return -1;
1766926deccbSFrançois Tigeot }
1767926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */
1768c6f73aabSFrançois Tigeot }
1769926deccbSFrançois Tigeot /* resume AGP if in use */
1770926deccbSFrançois Tigeot radeon_agp_resume(rdev);
1771926deccbSFrançois Tigeot radeon_resume(rdev);
1772926deccbSFrançois Tigeot
1773926deccbSFrançois Tigeot r = radeon_ib_ring_tests(rdev);
1774926deccbSFrançois Tigeot if (r)
1775926deccbSFrançois Tigeot DRM_ERROR("ib ring test failed (%d).\n", r);
1776926deccbSFrançois Tigeot
1777c6f73aabSFrançois Tigeot if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) {
1778c6f73aabSFrançois Tigeot /* do dpm late init */
1779c6f73aabSFrançois Tigeot r = radeon_pm_late_init(rdev);
1780c6f73aabSFrançois Tigeot if (r) {
1781c6f73aabSFrançois Tigeot rdev->pm.dpm_enabled = false;
1782c6f73aabSFrançois Tigeot DRM_ERROR("radeon_pm_late_init failed, disabling dpm\n");
1783c6f73aabSFrançois Tigeot }
1784c6f73aabSFrançois Tigeot } else {
1785c6f73aabSFrançois Tigeot /* resume old pm late */
1786926deccbSFrançois Tigeot radeon_pm_resume(rdev);
1787c6f73aabSFrançois Tigeot }
1788926deccbSFrançois Tigeot
1789c6f73aabSFrançois Tigeot radeon_restore_bios_scratch_regs(rdev);
1790926deccbSFrançois Tigeot
1791c59a5c48SFrançois Tigeot /* pin cursors */
1792c59a5c48SFrançois Tigeot list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
1793c59a5c48SFrançois Tigeot struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
1794c59a5c48SFrançois Tigeot
1795c59a5c48SFrançois Tigeot if (radeon_crtc->cursor_bo) {
1796c59a5c48SFrançois Tigeot struct radeon_bo *robj = gem_to_radeon_bo(radeon_crtc->cursor_bo);
1797c59a5c48SFrançois Tigeot r = radeon_bo_reserve(robj, false);
1798c59a5c48SFrançois Tigeot if (r == 0) {
1799c59a5c48SFrançois Tigeot /* Only 27 bit offset for legacy cursor */
1800c59a5c48SFrançois Tigeot r = radeon_bo_pin_restricted(robj,
1801c59a5c48SFrançois Tigeot RADEON_GEM_DOMAIN_VRAM,
1802c59a5c48SFrançois Tigeot ASIC_IS_AVIVO(rdev) ?
1803c59a5c48SFrançois Tigeot 0 : 1 << 27,
1804c59a5c48SFrançois Tigeot (u64 *)&radeon_crtc->cursor_addr);
1805c59a5c48SFrançois Tigeot if (r != 0)
1806c59a5c48SFrançois Tigeot DRM_ERROR("Failed to pin cursor BO (%d)\n", r);
1807c59a5c48SFrançois Tigeot radeon_bo_unreserve(robj);
1808c59a5c48SFrançois Tigeot }
1809c59a5c48SFrançois Tigeot }
1810c59a5c48SFrançois Tigeot }
1811c59a5c48SFrançois Tigeot
1812926deccbSFrançois Tigeot /* init dig PHYs, disp eng pll */
1813926deccbSFrançois Tigeot if (rdev->is_atom_bios) {
1814926deccbSFrançois Tigeot radeon_atom_encoder_init(rdev);
1815926deccbSFrançois Tigeot radeon_atom_disp_eng_pll_init(rdev);
1816926deccbSFrançois Tigeot /* turn on the BL */
1817926deccbSFrançois Tigeot if (rdev->mode_info.bl_encoder) {
1818926deccbSFrançois Tigeot u8 bl_level = radeon_get_backlight_level(rdev,
1819926deccbSFrançois Tigeot rdev->mode_info.bl_encoder);
1820926deccbSFrançois Tigeot radeon_set_backlight_level(rdev, rdev->mode_info.bl_encoder,
1821926deccbSFrançois Tigeot bl_level);
1822926deccbSFrançois Tigeot }
1823926deccbSFrançois Tigeot }
1824926deccbSFrançois Tigeot /* reset hpd state */
1825926deccbSFrançois Tigeot radeon_hpd_init(rdev);
1826926deccbSFrançois Tigeot /* blat the mode back in */
1827c6f73aabSFrançois Tigeot if (fbcon) {
1828926deccbSFrançois Tigeot drm_helper_resume_force_mode(dev);
1829926deccbSFrançois Tigeot /* turn on display hw */
1830c59a5c48SFrançois Tigeot drm_modeset_lock_all(dev);
1831926deccbSFrançois Tigeot list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
1832926deccbSFrançois Tigeot drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
1833926deccbSFrançois Tigeot }
1834c59a5c48SFrançois Tigeot drm_modeset_unlock_all(dev);
1835c6f73aabSFrançois Tigeot }
1836926deccbSFrançois Tigeot
1837926deccbSFrançois Tigeot drm_kms_helper_poll_enable(dev);
1838c6f73aabSFrançois Tigeot
1839c6f73aabSFrançois Tigeot /* set the power state here in case we are a PX system or headless */
1840c6f73aabSFrançois Tigeot if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled)
1841c6f73aabSFrançois Tigeot radeon_pm_compute_clocks(rdev);
1842c6f73aabSFrançois Tigeot
1843c6f73aabSFrançois Tigeot if (fbcon) {
1844c6f73aabSFrançois Tigeot radeon_fbdev_set_suspend(rdev, 0);
1845c6f73aabSFrançois Tigeot #ifdef DUMBBELL_WIP
1846c6f73aabSFrançois Tigeot console_unlock();
1847c6f73aabSFrançois Tigeot #endif /* DUMBBELL_WIP */
1848c6f73aabSFrançois Tigeot }
1849c6f73aabSFrançois Tigeot
1850926deccbSFrançois Tigeot return 0;
1851926deccbSFrançois Tigeot }
1852926deccbSFrançois Tigeot
1853926deccbSFrançois Tigeot /**
1854926deccbSFrançois Tigeot * radeon_gpu_reset - reset the asic
1855926deccbSFrançois Tigeot *
1856926deccbSFrançois Tigeot * @rdev: radeon device pointer
1857926deccbSFrançois Tigeot *
1858926deccbSFrançois Tigeot * Attempt the reset the GPU if it has hung (all asics).
1859926deccbSFrançois Tigeot * Returns 0 for success or an error on failure.
1860926deccbSFrançois Tigeot */
radeon_gpu_reset(struct radeon_device * rdev)1861926deccbSFrançois Tigeot int radeon_gpu_reset(struct radeon_device *rdev)
1862926deccbSFrançois Tigeot {
1863926deccbSFrançois Tigeot unsigned ring_sizes[RADEON_NUM_RINGS];
1864926deccbSFrançois Tigeot uint32_t *ring_data[RADEON_NUM_RINGS];
1865926deccbSFrançois Tigeot
1866926deccbSFrançois Tigeot bool saved = false;
1867926deccbSFrançois Tigeot
1868926deccbSFrançois Tigeot int i, r;
1869926deccbSFrançois Tigeot int resched;
1870926deccbSFrançois Tigeot
1871c59a5c48SFrançois Tigeot down_write(&rdev->exclusive_lock);
1872c6f73aabSFrançois Tigeot
1873c6f73aabSFrançois Tigeot if (!rdev->needs_reset) {
1874c59a5c48SFrançois Tigeot up_write(&rdev->exclusive_lock);
1875c6f73aabSFrançois Tigeot return 0;
1876c6f73aabSFrançois Tigeot }
1877c6f73aabSFrançois Tigeot
1878c59a5c48SFrançois Tigeot atomic_inc(&rdev->gpu_reset_counter);
1879c59a5c48SFrançois Tigeot
1880926deccbSFrançois Tigeot radeon_save_bios_scratch_regs(rdev);
1881926deccbSFrançois Tigeot /* block TTM */
1882926deccbSFrançois Tigeot resched = ttm_bo_lock_delayed_workqueue(&rdev->mman.bdev);
1883926deccbSFrançois Tigeot radeon_suspend(rdev);
1884c6f73aabSFrançois Tigeot radeon_hpd_fini(rdev);
1885926deccbSFrançois Tigeot
1886926deccbSFrançois Tigeot for (i = 0; i < RADEON_NUM_RINGS; ++i) {
1887926deccbSFrançois Tigeot ring_sizes[i] = radeon_ring_backup(rdev, &rdev->ring[i],
1888926deccbSFrançois Tigeot &ring_data[i]);
1889926deccbSFrançois Tigeot if (ring_sizes[i]) {
1890926deccbSFrançois Tigeot saved = true;
1891926deccbSFrançois Tigeot dev_info(rdev->dev, "Saved %d dwords of commands "
1892926deccbSFrançois Tigeot "on ring %d.\n", ring_sizes[i], i);
1893926deccbSFrançois Tigeot }
1894926deccbSFrançois Tigeot }
1895926deccbSFrançois Tigeot
1896926deccbSFrançois Tigeot r = radeon_asic_reset(rdev);
1897926deccbSFrançois Tigeot if (!r) {
1898926deccbSFrançois Tigeot dev_info(rdev->dev, "GPU reset succeeded, trying to resume\n");
1899926deccbSFrançois Tigeot radeon_resume(rdev);
1900926deccbSFrançois Tigeot }
1901926deccbSFrançois Tigeot
1902926deccbSFrançois Tigeot radeon_restore_bios_scratch_regs(rdev);
1903926deccbSFrançois Tigeot
1904926deccbSFrançois Tigeot for (i = 0; i < RADEON_NUM_RINGS; ++i) {
1905591d5043SFrançois Tigeot if (!r && ring_data[i]) {
1906926deccbSFrançois Tigeot radeon_ring_restore(rdev, &rdev->ring[i],
1907926deccbSFrançois Tigeot ring_sizes[i], ring_data[i]);
1908926deccbSFrançois Tigeot } else {
1909c6f73aabSFrançois Tigeot radeon_fence_driver_force_completion(rdev, i);
1910c4ef309bSzrj kfree(ring_data[i]);
1911926deccbSFrançois Tigeot }
1912926deccbSFrançois Tigeot }
1913926deccbSFrançois Tigeot
1914c6f73aabSFrançois Tigeot if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) {
1915c6f73aabSFrançois Tigeot /* do dpm late init */
1916c6f73aabSFrançois Tigeot r = radeon_pm_late_init(rdev);
1917c6f73aabSFrançois Tigeot if (r) {
1918c6f73aabSFrançois Tigeot rdev->pm.dpm_enabled = false;
1919c6f73aabSFrançois Tigeot DRM_ERROR("radeon_pm_late_init failed, disabling dpm\n");
1920c6f73aabSFrançois Tigeot }
1921c6f73aabSFrançois Tigeot } else {
1922c6f73aabSFrançois Tigeot /* resume old pm late */
192357e252bfSMichael Neumann radeon_pm_resume(rdev);
1924c6f73aabSFrançois Tigeot }
1925c6f73aabSFrançois Tigeot
1926c6f73aabSFrançois Tigeot /* init dig PHYs, disp eng pll */
1927c6f73aabSFrançois Tigeot if (rdev->is_atom_bios) {
1928c6f73aabSFrançois Tigeot radeon_atom_encoder_init(rdev);
1929c6f73aabSFrançois Tigeot radeon_atom_disp_eng_pll_init(rdev);
1930c6f73aabSFrançois Tigeot /* turn on the BL */
1931c6f73aabSFrançois Tigeot if (rdev->mode_info.bl_encoder) {
1932c6f73aabSFrançois Tigeot u8 bl_level = radeon_get_backlight_level(rdev,
1933c6f73aabSFrançois Tigeot rdev->mode_info.bl_encoder);
1934c6f73aabSFrançois Tigeot radeon_set_backlight_level(rdev, rdev->mode_info.bl_encoder,
1935c6f73aabSFrançois Tigeot bl_level);
1936c6f73aabSFrançois Tigeot }
1937c6f73aabSFrançois Tigeot }
1938c6f73aabSFrançois Tigeot /* reset hpd state */
1939c6f73aabSFrançois Tigeot radeon_hpd_init(rdev);
1940c6f73aabSFrançois Tigeot
1941591d5043SFrançois Tigeot ttm_bo_unlock_delayed_workqueue(&rdev->mman.bdev, resched);
1942591d5043SFrançois Tigeot
1943591d5043SFrançois Tigeot rdev->in_reset = true;
1944591d5043SFrançois Tigeot rdev->needs_reset = false;
1945591d5043SFrançois Tigeot
1946591d5043SFrançois Tigeot #if 0
1947591d5043SFrançois Tigeot downgrade_write(&rdev->exclusive_lock);
1948591d5043SFrançois Tigeot #endif
1949591d5043SFrançois Tigeot
1950926deccbSFrançois Tigeot drm_helper_resume_force_mode(rdev->ddev);
1951926deccbSFrançois Tigeot
1952c6f73aabSFrançois Tigeot /* set the power state here in case we are a PX system or headless */
1953c6f73aabSFrançois Tigeot if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled)
1954c6f73aabSFrançois Tigeot radeon_pm_compute_clocks(rdev);
1955c6f73aabSFrançois Tigeot
1956591d5043SFrançois Tigeot if (!r) {
1957591d5043SFrançois Tigeot r = radeon_ib_ring_tests(rdev);
1958591d5043SFrançois Tigeot if (r && saved)
1959591d5043SFrançois Tigeot r = -EAGAIN;
1960591d5043SFrançois Tigeot } else {
1961926deccbSFrançois Tigeot /* bad news, how to tell it to userspace ? */
1962926deccbSFrançois Tigeot dev_info(rdev->dev, "GPU reset failed\n");
1963926deccbSFrançois Tigeot }
1964926deccbSFrançois Tigeot
1965591d5043SFrançois Tigeot rdev->needs_reset = r == -EAGAIN;
1966591d5043SFrançois Tigeot rdev->in_reset = false;
1967591d5043SFrançois Tigeot
1968c59a5c48SFrançois Tigeot up_read(&rdev->exclusive_lock);
1969926deccbSFrançois Tigeot return r;
1970926deccbSFrançois Tigeot }
1971926deccbSFrançois Tigeot
1972926deccbSFrançois Tigeot
1973926deccbSFrançois Tigeot /*
1974926deccbSFrançois Tigeot * Debugfs
1975926deccbSFrançois Tigeot */
radeon_debugfs_add_files(struct radeon_device * rdev,struct drm_info_list * files,unsigned nfiles)1976926deccbSFrançois Tigeot int radeon_debugfs_add_files(struct radeon_device *rdev,
1977926deccbSFrançois Tigeot struct drm_info_list *files,
1978926deccbSFrançois Tigeot unsigned nfiles)
1979926deccbSFrançois Tigeot {
1980926deccbSFrançois Tigeot unsigned i;
1981926deccbSFrançois Tigeot
1982926deccbSFrançois Tigeot for (i = 0; i < rdev->debugfs_count; i++) {
1983926deccbSFrançois Tigeot if (rdev->debugfs[i].files == files) {
1984926deccbSFrançois Tigeot /* Already registered */
1985926deccbSFrançois Tigeot return 0;
1986926deccbSFrançois Tigeot }
1987926deccbSFrançois Tigeot }
1988926deccbSFrançois Tigeot
1989926deccbSFrançois Tigeot i = rdev->debugfs_count + 1;
1990926deccbSFrançois Tigeot if (i > RADEON_DEBUGFS_MAX_COMPONENTS) {
1991926deccbSFrançois Tigeot DRM_ERROR("Reached maximum number of debugfs components.\n");
1992926deccbSFrançois Tigeot DRM_ERROR("Report so we increase "
1993926deccbSFrançois Tigeot "RADEON_DEBUGFS_MAX_COMPONENTS.\n");
1994926deccbSFrançois Tigeot return -EINVAL;
1995926deccbSFrançois Tigeot }
1996926deccbSFrançois Tigeot rdev->debugfs[rdev->debugfs_count].files = files;
1997926deccbSFrançois Tigeot rdev->debugfs[rdev->debugfs_count].num_files = nfiles;
1998926deccbSFrançois Tigeot rdev->debugfs_count = i;
1999926deccbSFrançois Tigeot #if defined(CONFIG_DEBUG_FS)
2000926deccbSFrançois Tigeot drm_debugfs_create_files(files, nfiles,
2001926deccbSFrançois Tigeot rdev->ddev->primary->debugfs_root,
2002926deccbSFrançois Tigeot rdev->ddev->primary);
2003926deccbSFrançois Tigeot #endif
2004926deccbSFrançois Tigeot return 0;
2005926deccbSFrançois Tigeot }
2006