xref: /dflybsd-src/sys/dev/drm/radeon/radeon_bios.c (revision a85cb24f18e3804e75ab8bcda7692564d0563317)
1926deccbSFrançois Tigeot /*
2926deccbSFrançois Tigeot  * Copyright 2008 Advanced Micro Devices, Inc.
3926deccbSFrançois Tigeot  * Copyright 2008 Red Hat Inc.
4926deccbSFrançois Tigeot  * Copyright 2009 Jerome Glisse.
5926deccbSFrançois Tigeot  *
6926deccbSFrançois Tigeot  * Permission is hereby granted, free of charge, to any person obtaining a
7926deccbSFrançois Tigeot  * copy of this software and associated documentation files (the "Software"),
8926deccbSFrançois Tigeot  * to deal in the Software without restriction, including without limitation
9926deccbSFrançois Tigeot  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10926deccbSFrançois Tigeot  * and/or sell copies of the Software, and to permit persons to whom the
11926deccbSFrançois Tigeot  * Software is furnished to do so, subject to the following conditions:
12926deccbSFrançois Tigeot  *
13926deccbSFrançois Tigeot  * The above copyright notice and this permission notice shall be included in
14926deccbSFrançois Tigeot  * all copies or substantial portions of the Software.
15926deccbSFrançois Tigeot  *
16926deccbSFrançois Tigeot  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17926deccbSFrançois Tigeot  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18926deccbSFrançois Tigeot  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19926deccbSFrançois Tigeot  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
20926deccbSFrançois Tigeot  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21926deccbSFrançois Tigeot  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22926deccbSFrançois Tigeot  * OTHER DEALINGS IN THE SOFTWARE.
23926deccbSFrançois Tigeot  *
24926deccbSFrançois Tigeot  * Authors: Dave Airlie
25926deccbSFrançois Tigeot  *          Alex Deucher
26926deccbSFrançois Tigeot  *          Jerome Glisse
27926deccbSFrançois Tigeot  *
28926deccbSFrançois Tigeot  * $FreeBSD: head/sys/dev/drm2/radeon/radeon_bios.c 255572 2013-09-14 17:22:34Z dumbbell $
29926deccbSFrançois Tigeot  */
30926deccbSFrançois Tigeot 
31926deccbSFrançois Tigeot #include <drm/drmP.h>
32926deccbSFrançois Tigeot #include "radeon_reg.h"
33926deccbSFrançois Tigeot #include "radeon.h"
34926deccbSFrançois Tigeot #include "atom.h"
35926deccbSFrançois Tigeot 
36c4ef309bSzrj #include <linux/slab.h>
37926deccbSFrançois Tigeot /*
38926deccbSFrançois Tigeot  * BIOS.
39926deccbSFrançois Tigeot  */
40926deccbSFrançois Tigeot 
41926deccbSFrançois Tigeot /* If you boot an IGP board with a discrete card as the primary,
42926deccbSFrançois Tigeot  * the IGP rom is not accessible via the rom bar as the IGP rom is
43926deccbSFrançois Tigeot  * part of the system bios.  On boot, the system bios puts a
44926deccbSFrançois Tigeot  * copy of the igp rom at the start of vram if a discrete card is
45926deccbSFrançois Tigeot  * present.
46926deccbSFrançois Tigeot  */
igp_read_bios_from_vram(struct radeon_device * rdev)47926deccbSFrançois Tigeot static bool igp_read_bios_from_vram(struct radeon_device *rdev)
48926deccbSFrançois Tigeot {
49926deccbSFrançois Tigeot 	uint8_t __iomem *bios;
50926deccbSFrançois Tigeot 	resource_size_t vram_base;
51926deccbSFrançois Tigeot 	resource_size_t size = 256 * 1024; /* ??? */
52926deccbSFrançois Tigeot 
53926deccbSFrançois Tigeot 	if (!(rdev->flags & RADEON_IS_IGP))
546431cd91SFrançois Tigeot 		if (!radeon_card_posted(rdev))
55926deccbSFrançois Tigeot 			return false;
56926deccbSFrançois Tigeot 
57926deccbSFrançois Tigeot 	rdev->bios = NULL;
584a26d795SImre Vadasz 	vram_base = pci_resource_start(rdev->pdev, 0);
596431cd91SFrançois Tigeot 	bios = ioremap(vram_base, size);
606431cd91SFrançois Tigeot 	if (!bios) {
61926deccbSFrançois Tigeot 		return false;
62926deccbSFrançois Tigeot 	}
63926deccbSFrançois Tigeot 
64926deccbSFrançois Tigeot 	if (size == 0 || bios[0] != 0x55 || bios[1] != 0xaa) {
6524409b39SFrançois Tigeot 		iounmap(bios);
66926deccbSFrançois Tigeot 		return false;
67926deccbSFrançois Tigeot 	}
685a3b77d5SFrançois Tigeot 	rdev->bios = kmalloc(size, M_DRM, M_WAITOK);
69926deccbSFrançois Tigeot 	if (rdev->bios == NULL) {
7024409b39SFrançois Tigeot 		iounmap(bios);
71926deccbSFrançois Tigeot 		return false;
72926deccbSFrançois Tigeot 	}
73926deccbSFrançois Tigeot 	memcpy_fromio(rdev->bios, bios, size);
7424409b39SFrançois Tigeot 	iounmap(bios);
75926deccbSFrançois Tigeot 	return true;
76926deccbSFrançois Tigeot }
77926deccbSFrançois Tigeot 
radeon_read_bios(struct radeon_device * rdev)78926deccbSFrançois Tigeot static bool radeon_read_bios(struct radeon_device *rdev)
79926deccbSFrançois Tigeot {
807dcf36dcSFrançois Tigeot 	uint8_t __iomem *bios, val1, val2;
81926deccbSFrançois Tigeot 	size_t size;
827dcf36dcSFrançois Tigeot 	device_t vga_dev = device_get_parent(rdev->dev->bsddev);
83926deccbSFrançois Tigeot 
84926deccbSFrançois Tigeot 	rdev->bios = NULL;
85926deccbSFrançois Tigeot 	/* XXX: some cards may return 0 for rom size? ddx has a workaround */
86926deccbSFrançois Tigeot 	bios = vga_pci_map_bios(vga_dev, &size);
87926deccbSFrançois Tigeot 	if (!bios) {
88926deccbSFrançois Tigeot 		return false;
89926deccbSFrançois Tigeot 	}
90926deccbSFrançois Tigeot 
917dcf36dcSFrançois Tigeot 	val1 = readb(&bios[0]);
927dcf36dcSFrançois Tigeot 	val2 = readb(&bios[1]);
937dcf36dcSFrançois Tigeot 
947dcf36dcSFrançois Tigeot 	if (size == 0 || val1 != 0x55 || val2 != 0xaa) {
95926deccbSFrançois Tigeot 		vga_pci_unmap_bios(vga_dev, bios);
967112e8c7Sdumbbell 		return false;
97926deccbSFrançois Tigeot 	}
987dcf36dcSFrançois Tigeot 	rdev->bios = kzalloc(size, GFP_KERNEL);
997dcf36dcSFrançois Tigeot 	if (rdev->bios == NULL) {
1007dcf36dcSFrançois Tigeot 		vga_pci_unmap_bios(vga_dev, bios);
1017dcf36dcSFrançois Tigeot 		return false;
1027dcf36dcSFrançois Tigeot 	}
1037dcf36dcSFrançois Tigeot 	memcpy_fromio(rdev->bios, bios, size);
104926deccbSFrançois Tigeot 	vga_pci_unmap_bios(vga_dev, bios);
105926deccbSFrançois Tigeot 	return true;
106926deccbSFrançois Tigeot }
107926deccbSFrançois Tigeot 
radeon_read_platform_bios(struct radeon_device * rdev)108b403bed8SMichael Neumann static bool radeon_read_platform_bios(struct radeon_device *rdev)
109b403bed8SMichael Neumann {
110b403bed8SMichael Neumann 	uint8_t __iomem *bios;
111b403bed8SMichael Neumann 	size_t size;
112b403bed8SMichael Neumann 
113b403bed8SMichael Neumann 	rdev->bios = NULL;
114b403bed8SMichael Neumann 
115b403bed8SMichael Neumann #if 0
116b403bed8SMichael Neumann 	// XXX: FIXME
117b403bed8SMichael Neumann 	bios = pci_platform_rom(rdev->pdev, &size);
118b403bed8SMichael Neumann #else
119b403bed8SMichael Neumann 	size = 0;
120b403bed8SMichael Neumann 	bios = NULL;
121b403bed8SMichael Neumann #endif
122b403bed8SMichael Neumann 	if (!bios) {
123b403bed8SMichael Neumann 		return false;
124b403bed8SMichael Neumann 	}
125b403bed8SMichael Neumann 
126b403bed8SMichael Neumann 	if (size == 0 || bios[0] != 0x55 || bios[1] != 0xaa) {
127b403bed8SMichael Neumann 		return false;
128b403bed8SMichael Neumann 	}
1297dcf36dcSFrançois Tigeot 	rdev->bios = kmemdup(bios, size, GFP_KERNEL);
130b403bed8SMichael Neumann 	if (rdev->bios == NULL) {
131b403bed8SMichael Neumann 		return false;
132b403bed8SMichael Neumann 	}
1337dcf36dcSFrançois Tigeot 
134b403bed8SMichael Neumann 	return true;
135b403bed8SMichael Neumann }
136b403bed8SMichael Neumann 
137452a88ebSzrj #ifdef CONFIG_ACPI
138926deccbSFrançois Tigeot /* ATRM is used to get the BIOS on the discrete cards in
139926deccbSFrançois Tigeot  * dual-gpu systems.
140926deccbSFrançois Tigeot  */
141926deccbSFrançois Tigeot /* retrieve the ROM in 4k blocks */
142926deccbSFrançois Tigeot #define ATRM_BIOS_PAGE 4096
143926deccbSFrançois Tigeot /**
144926deccbSFrançois Tigeot  * radeon_atrm_call - fetch a chunk of the vbios
145926deccbSFrançois Tigeot  *
146926deccbSFrançois Tigeot  * @atrm_handle: acpi ATRM handle
147926deccbSFrançois Tigeot  * @bios: vbios image pointer
148926deccbSFrançois Tigeot  * @offset: offset of vbios image data to fetch
149926deccbSFrançois Tigeot  * @len: length of vbios image data to fetch
150926deccbSFrançois Tigeot  *
151926deccbSFrançois Tigeot  * Executes ATRM to fetch a chunk of the discrete
152926deccbSFrançois Tigeot  * vbios image on PX systems (all asics).
153926deccbSFrançois Tigeot  * Returns the length of the buffer fetched.
154926deccbSFrançois Tigeot  */
radeon_atrm_call(ACPI_HANDLE atrm_handle,uint8_t * bios,int offset,int len)155926deccbSFrançois Tigeot static int radeon_atrm_call(ACPI_HANDLE atrm_handle, uint8_t *bios,
156926deccbSFrançois Tigeot 			    int offset, int len)
157926deccbSFrançois Tigeot {
158926deccbSFrançois Tigeot 	ACPI_STATUS status;
159926deccbSFrançois Tigeot 	ACPI_OBJECT atrm_arg_elements[2], *obj;
160926deccbSFrançois Tigeot 	ACPI_OBJECT_LIST atrm_arg;
161926deccbSFrançois Tigeot 	ACPI_BUFFER buffer = { ACPI_ALLOCATE_BUFFER, NULL};
162926deccbSFrançois Tigeot 
163926deccbSFrançois Tigeot 	atrm_arg.Count = 2;
164926deccbSFrançois Tigeot 	atrm_arg.Pointer = &atrm_arg_elements[0];
165926deccbSFrançois Tigeot 
166926deccbSFrançois Tigeot 	atrm_arg_elements[0].Type = ACPI_TYPE_INTEGER;
167926deccbSFrançois Tigeot 	atrm_arg_elements[0].Integer.Value = offset;
168926deccbSFrançois Tigeot 
169926deccbSFrançois Tigeot 	atrm_arg_elements[1].Type = ACPI_TYPE_INTEGER;
170926deccbSFrançois Tigeot 	atrm_arg_elements[1].Integer.Value = len;
171926deccbSFrançois Tigeot 
172926deccbSFrançois Tigeot 	status = AcpiEvaluateObject(atrm_handle, NULL, &atrm_arg, &buffer);
173926deccbSFrançois Tigeot 	if (ACPI_FAILURE(status)) {
174c4ef309bSzrj 		printk("failed to evaluate ATRM got %s\n", AcpiFormatException(status));
175926deccbSFrançois Tigeot 		return -ENODEV;
176926deccbSFrançois Tigeot 	}
177926deccbSFrançois Tigeot 
178926deccbSFrançois Tigeot 	obj = (ACPI_OBJECT *)buffer.Pointer;
179926deccbSFrançois Tigeot 	memcpy(bios+offset, obj->Buffer.Pointer, obj->Buffer.Length);
180926deccbSFrançois Tigeot 	len = obj->Buffer.Length;
181926deccbSFrançois Tigeot 	AcpiOsFree(buffer.Pointer);
182926deccbSFrançois Tigeot 	return len;
183926deccbSFrançois Tigeot }
184926deccbSFrançois Tigeot 
radeon_atrm_get_bios(struct radeon_device * rdev)185926deccbSFrançois Tigeot static bool radeon_atrm_get_bios(struct radeon_device *rdev)
186926deccbSFrançois Tigeot {
187926deccbSFrançois Tigeot 	int ret;
188926deccbSFrançois Tigeot 	int size = 256 * 1024;
189926deccbSFrançois Tigeot 	int i;
190926deccbSFrançois Tigeot 	device_t dev;
191926deccbSFrançois Tigeot 	ACPI_HANDLE dhandle, atrm_handle;
192926deccbSFrançois Tigeot 	ACPI_STATUS status;
193926deccbSFrançois Tigeot 	bool found = false;
194926deccbSFrançois Tigeot 
195926deccbSFrançois Tigeot 	DRM_INFO("%s: ===> Try ATRM...\n", __func__);
196926deccbSFrançois Tigeot 
197926deccbSFrançois Tigeot 	/* ATRM is for the discrete card only */
198926deccbSFrançois Tigeot 	if (rdev->flags & RADEON_IS_IGP) {
199926deccbSFrançois Tigeot 		DRM_INFO("%s: IGP card detected, skipping this method...\n",
200926deccbSFrançois Tigeot 		    __func__);
201926deccbSFrançois Tigeot 		return false;
202926deccbSFrançois Tigeot 	}
203926deccbSFrançois Tigeot 
204926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP
205926deccbSFrançois Tigeot 	while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
206926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */
207926deccbSFrançois Tigeot 	if ((dev = pci_find_class(PCIC_DISPLAY, PCIS_DISPLAY_VGA)) != NULL) {
208926deccbSFrançois Tigeot 		DRM_INFO("%s: pci_find_class() found: %d:%d:%d:%d, vendor=%04x, device=%04x\n",
209926deccbSFrançois Tigeot 		    __func__,
210926deccbSFrançois Tigeot 		    pci_get_domain(dev),
211926deccbSFrançois Tigeot 		    pci_get_bus(dev),
212926deccbSFrançois Tigeot 		    pci_get_slot(dev),
213926deccbSFrançois Tigeot 		    pci_get_function(dev),
214926deccbSFrançois Tigeot 		    pci_get_vendor(dev),
215926deccbSFrançois Tigeot 		    pci_get_device(dev));
216926deccbSFrançois Tigeot 		DRM_INFO("%s: Get ACPI device handle\n", __func__);
217926deccbSFrançois Tigeot 		dhandle = acpi_get_handle(dev);
218926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP
219926deccbSFrançois Tigeot 		if (!dhandle)
220926deccbSFrançois Tigeot 			continue;
221926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */
222926deccbSFrançois Tigeot 		if (!dhandle)
223926deccbSFrançois Tigeot 			return false;
224926deccbSFrançois Tigeot 
225926deccbSFrançois Tigeot 		DRM_INFO("%s: Get ACPI handle for \"ATRM\"\n", __func__);
226926deccbSFrançois Tigeot 		status = AcpiGetHandle(dhandle, "ATRM", &atrm_handle);
227926deccbSFrançois Tigeot 		if (!ACPI_FAILURE(status)) {
228926deccbSFrançois Tigeot 			found = true;
229926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP
230926deccbSFrançois Tigeot 			break;
231926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */
232926deccbSFrançois Tigeot 		} else {
233926deccbSFrançois Tigeot 			DRM_INFO("%s: Failed to get \"ATRM\" handle: %s\n",
234926deccbSFrançois Tigeot 			    __func__, AcpiFormatException(status));
235926deccbSFrançois Tigeot 		}
236926deccbSFrançois Tigeot 	}
237926deccbSFrançois Tigeot 
238926deccbSFrançois Tigeot 	if (!found)
239926deccbSFrançois Tigeot 		return false;
240926deccbSFrançois Tigeot 
2415a3b77d5SFrançois Tigeot 	rdev->bios = kmalloc(size, M_DRM, M_WAITOK);
242926deccbSFrançois Tigeot 	if (!rdev->bios) {
243926deccbSFrançois Tigeot 		DRM_ERROR("Unable to allocate bios\n");
244926deccbSFrançois Tigeot 		return false;
245926deccbSFrançois Tigeot 	}
246926deccbSFrançois Tigeot 
247926deccbSFrançois Tigeot 	for (i = 0; i < size / ATRM_BIOS_PAGE; i++) {
248926deccbSFrançois Tigeot 		DRM_INFO("%s: Call radeon_atrm_call()\n", __func__);
249926deccbSFrançois Tigeot 		ret = radeon_atrm_call(atrm_handle,
250926deccbSFrançois Tigeot 				       rdev->bios,
251926deccbSFrançois Tigeot 				       (i * ATRM_BIOS_PAGE),
252926deccbSFrançois Tigeot 				       ATRM_BIOS_PAGE);
253926deccbSFrançois Tigeot 		if (ret < ATRM_BIOS_PAGE)
254926deccbSFrançois Tigeot 			break;
255926deccbSFrançois Tigeot 	}
256926deccbSFrançois Tigeot 
257926deccbSFrançois Tigeot 	if (i == 0 || rdev->bios[0] != 0x55 || rdev->bios[1] != 0xaa) {
258926deccbSFrançois Tigeot 		if (i == 0) {
259926deccbSFrançois Tigeot 			DRM_INFO("%s: Incorrect BIOS size\n", __func__);
260926deccbSFrançois Tigeot 		} else {
261926deccbSFrançois Tigeot 			DRM_INFO("%s: Incorrect BIOS signature: 0x%02X%02X\n",
262926deccbSFrançois Tigeot 			    __func__, rdev->bios[0], rdev->bios[1]);
263926deccbSFrançois Tigeot 		}
264c4ef309bSzrj 		kfree(rdev->bios);
265926deccbSFrançois Tigeot 		return false;
266926deccbSFrançois Tigeot 	}
267926deccbSFrançois Tigeot 	return true;
268926deccbSFrançois Tigeot }
269452a88ebSzrj #else
270452a88ebSzrj static inline bool radeon_atrm_get_bios(struct radeon_device *rdev)
271452a88ebSzrj {
272452a88ebSzrj 	return false;
273452a88ebSzrj }
274452a88ebSzrj #endif
275926deccbSFrançois Tigeot 
276926deccbSFrançois Tigeot static bool ni_read_disabled_bios(struct radeon_device *rdev)
277926deccbSFrançois Tigeot {
278926deccbSFrançois Tigeot 	u32 bus_cntl;
279926deccbSFrançois Tigeot 	u32 d1vga_control;
280926deccbSFrançois Tigeot 	u32 d2vga_control;
281926deccbSFrançois Tigeot 	u32 vga_render_control;
282926deccbSFrançois Tigeot 	u32 rom_cntl;
283926deccbSFrançois Tigeot 	bool r;
284926deccbSFrançois Tigeot 
285926deccbSFrançois Tigeot 	DRM_INFO("%s: ===> Try disabled BIOS (ni)...\n", __func__);
286926deccbSFrançois Tigeot 
287926deccbSFrançois Tigeot 	bus_cntl = RREG32(R600_BUS_CNTL);
288926deccbSFrançois Tigeot 	d1vga_control = RREG32(AVIVO_D1VGA_CONTROL);
289926deccbSFrançois Tigeot 	d2vga_control = RREG32(AVIVO_D2VGA_CONTROL);
290926deccbSFrançois Tigeot 	vga_render_control = RREG32(AVIVO_VGA_RENDER_CONTROL);
291926deccbSFrançois Tigeot 	rom_cntl = RREG32(R600_ROM_CNTL);
292926deccbSFrançois Tigeot 
293926deccbSFrançois Tigeot 	/* enable the rom */
294926deccbSFrançois Tigeot 	WREG32(R600_BUS_CNTL, (bus_cntl & ~R600_BIOS_ROM_DIS));
295f43cf1b1SMichael Neumann 	if (!ASIC_IS_NODCE(rdev)) {
296926deccbSFrançois Tigeot 		/* Disable VGA mode */
297926deccbSFrançois Tigeot 		WREG32(AVIVO_D1VGA_CONTROL,
298926deccbSFrançois Tigeot 		       (d1vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE |
299926deccbSFrançois Tigeot 					  AVIVO_DVGA_CONTROL_TIMING_SELECT)));
300926deccbSFrançois Tigeot 		WREG32(AVIVO_D2VGA_CONTROL,
301926deccbSFrançois Tigeot 		       (d2vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE |
302926deccbSFrançois Tigeot 					  AVIVO_DVGA_CONTROL_TIMING_SELECT)));
303926deccbSFrançois Tigeot 		WREG32(AVIVO_VGA_RENDER_CONTROL,
304926deccbSFrançois Tigeot 		       (vga_render_control & ~AVIVO_VGA_VSTATUS_CNTL_MASK));
305f43cf1b1SMichael Neumann 	}
306926deccbSFrançois Tigeot 	WREG32(R600_ROM_CNTL, rom_cntl | R600_SCK_OVERWRITE);
307926deccbSFrançois Tigeot 
308926deccbSFrançois Tigeot 	r = radeon_read_bios(rdev);
309926deccbSFrançois Tigeot 
310926deccbSFrançois Tigeot 	/* restore regs */
311926deccbSFrançois Tigeot 	WREG32(R600_BUS_CNTL, bus_cntl);
312f43cf1b1SMichael Neumann 	if (!ASIC_IS_NODCE(rdev)) {
313926deccbSFrançois Tigeot 		WREG32(AVIVO_D1VGA_CONTROL, d1vga_control);
314926deccbSFrançois Tigeot 		WREG32(AVIVO_D2VGA_CONTROL, d2vga_control);
315926deccbSFrançois Tigeot 		WREG32(AVIVO_VGA_RENDER_CONTROL, vga_render_control);
316f43cf1b1SMichael Neumann 	}
317926deccbSFrançois Tigeot 	WREG32(R600_ROM_CNTL, rom_cntl);
318926deccbSFrançois Tigeot 	return r;
319926deccbSFrançois Tigeot }
320926deccbSFrançois Tigeot 
321926deccbSFrançois Tigeot static bool r700_read_disabled_bios(struct radeon_device *rdev)
322926deccbSFrançois Tigeot {
323926deccbSFrançois Tigeot 	uint32_t viph_control;
324926deccbSFrançois Tigeot 	uint32_t bus_cntl;
325926deccbSFrançois Tigeot 	uint32_t d1vga_control;
326926deccbSFrançois Tigeot 	uint32_t d2vga_control;
327926deccbSFrançois Tigeot 	uint32_t vga_render_control;
328926deccbSFrançois Tigeot 	uint32_t rom_cntl;
329926deccbSFrançois Tigeot 	uint32_t cg_spll_func_cntl = 0;
330926deccbSFrançois Tigeot 	uint32_t cg_spll_status;
331926deccbSFrançois Tigeot 	bool r;
332926deccbSFrançois Tigeot 
333926deccbSFrançois Tigeot 	DRM_INFO("%s: ===> Try disabled BIOS (r700)...\n", __func__);
334926deccbSFrançois Tigeot 
335926deccbSFrançois Tigeot 	viph_control = RREG32(RADEON_VIPH_CONTROL);
336926deccbSFrançois Tigeot 	bus_cntl = RREG32(R600_BUS_CNTL);
337926deccbSFrançois Tigeot 	d1vga_control = RREG32(AVIVO_D1VGA_CONTROL);
338926deccbSFrançois Tigeot 	d2vga_control = RREG32(AVIVO_D2VGA_CONTROL);
339926deccbSFrançois Tigeot 	vga_render_control = RREG32(AVIVO_VGA_RENDER_CONTROL);
340926deccbSFrançois Tigeot 	rom_cntl = RREG32(R600_ROM_CNTL);
341926deccbSFrançois Tigeot 
342926deccbSFrançois Tigeot 	/* disable VIP */
343926deccbSFrançois Tigeot 	WREG32(RADEON_VIPH_CONTROL, (viph_control & ~RADEON_VIPH_EN));
344926deccbSFrançois Tigeot 	/* enable the rom */
345926deccbSFrançois Tigeot 	WREG32(R600_BUS_CNTL, (bus_cntl & ~R600_BIOS_ROM_DIS));
346926deccbSFrançois Tigeot 	/* Disable VGA mode */
347926deccbSFrançois Tigeot 	WREG32(AVIVO_D1VGA_CONTROL,
348926deccbSFrançois Tigeot 	       (d1vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE |
349926deccbSFrançois Tigeot 		AVIVO_DVGA_CONTROL_TIMING_SELECT)));
350926deccbSFrançois Tigeot 	WREG32(AVIVO_D2VGA_CONTROL,
351926deccbSFrançois Tigeot 	       (d2vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE |
352926deccbSFrançois Tigeot 		AVIVO_DVGA_CONTROL_TIMING_SELECT)));
353926deccbSFrançois Tigeot 	WREG32(AVIVO_VGA_RENDER_CONTROL,
354926deccbSFrançois Tigeot 	       (vga_render_control & ~AVIVO_VGA_VSTATUS_CNTL_MASK));
355926deccbSFrançois Tigeot 
356926deccbSFrançois Tigeot 	if (rdev->family == CHIP_RV730) {
357926deccbSFrançois Tigeot 		cg_spll_func_cntl = RREG32(R600_CG_SPLL_FUNC_CNTL);
358926deccbSFrançois Tigeot 
359926deccbSFrançois Tigeot 		/* enable bypass mode */
360926deccbSFrançois Tigeot 		WREG32(R600_CG_SPLL_FUNC_CNTL, (cg_spll_func_cntl |
361926deccbSFrançois Tigeot 						R600_SPLL_BYPASS_EN));
362926deccbSFrançois Tigeot 
363926deccbSFrançois Tigeot 		/* wait for SPLL_CHG_STATUS to change to 1 */
364926deccbSFrançois Tigeot 		cg_spll_status = 0;
365926deccbSFrançois Tigeot 		while (!(cg_spll_status & R600_SPLL_CHG_STATUS))
366926deccbSFrançois Tigeot 			cg_spll_status = RREG32(R600_CG_SPLL_STATUS);
367926deccbSFrançois Tigeot 
368926deccbSFrançois Tigeot 		WREG32(R600_ROM_CNTL, (rom_cntl & ~R600_SCK_OVERWRITE));
369926deccbSFrançois Tigeot 	} else
370926deccbSFrançois Tigeot 		WREG32(R600_ROM_CNTL, (rom_cntl | R600_SCK_OVERWRITE));
371926deccbSFrançois Tigeot 
372926deccbSFrançois Tigeot 	r = radeon_read_bios(rdev);
373926deccbSFrançois Tigeot 
374926deccbSFrançois Tigeot 	/* restore regs */
375926deccbSFrançois Tigeot 	if (rdev->family == CHIP_RV730) {
376926deccbSFrançois Tigeot 		WREG32(R600_CG_SPLL_FUNC_CNTL, cg_spll_func_cntl);
377926deccbSFrançois Tigeot 
378926deccbSFrançois Tigeot 		/* wait for SPLL_CHG_STATUS to change to 1 */
379926deccbSFrançois Tigeot 		cg_spll_status = 0;
380926deccbSFrançois Tigeot 		while (!(cg_spll_status & R600_SPLL_CHG_STATUS))
381926deccbSFrançois Tigeot 			cg_spll_status = RREG32(R600_CG_SPLL_STATUS);
382926deccbSFrançois Tigeot 	}
383926deccbSFrançois Tigeot 	WREG32(RADEON_VIPH_CONTROL, viph_control);
384926deccbSFrançois Tigeot 	WREG32(R600_BUS_CNTL, bus_cntl);
385926deccbSFrançois Tigeot 	WREG32(AVIVO_D1VGA_CONTROL, d1vga_control);
386926deccbSFrançois Tigeot 	WREG32(AVIVO_D2VGA_CONTROL, d2vga_control);
387926deccbSFrançois Tigeot 	WREG32(AVIVO_VGA_RENDER_CONTROL, vga_render_control);
388926deccbSFrançois Tigeot 	WREG32(R600_ROM_CNTL, rom_cntl);
389926deccbSFrançois Tigeot 	return r;
390926deccbSFrançois Tigeot }
391926deccbSFrançois Tigeot 
392926deccbSFrançois Tigeot static bool r600_read_disabled_bios(struct radeon_device *rdev)
393926deccbSFrançois Tigeot {
394926deccbSFrançois Tigeot 	uint32_t viph_control;
395926deccbSFrançois Tigeot 	uint32_t bus_cntl;
396926deccbSFrançois Tigeot 	uint32_t d1vga_control;
397926deccbSFrançois Tigeot 	uint32_t d2vga_control;
398926deccbSFrançois Tigeot 	uint32_t vga_render_control;
399926deccbSFrançois Tigeot 	uint32_t rom_cntl;
400926deccbSFrançois Tigeot 	uint32_t general_pwrmgt;
401926deccbSFrançois Tigeot 	uint32_t low_vid_lower_gpio_cntl;
402926deccbSFrançois Tigeot 	uint32_t medium_vid_lower_gpio_cntl;
403926deccbSFrançois Tigeot 	uint32_t high_vid_lower_gpio_cntl;
404926deccbSFrançois Tigeot 	uint32_t ctxsw_vid_lower_gpio_cntl;
405926deccbSFrançois Tigeot 	uint32_t lower_gpio_enable;
406926deccbSFrançois Tigeot 	bool r;
407926deccbSFrançois Tigeot 
408926deccbSFrançois Tigeot 	DRM_INFO("%s: ===> Try disabled BIOS (r600)...\n", __func__);
409926deccbSFrançois Tigeot 
410926deccbSFrançois Tigeot 	viph_control = RREG32(RADEON_VIPH_CONTROL);
411926deccbSFrançois Tigeot 	bus_cntl = RREG32(R600_BUS_CNTL);
412926deccbSFrançois Tigeot 	d1vga_control = RREG32(AVIVO_D1VGA_CONTROL);
413926deccbSFrançois Tigeot 	d2vga_control = RREG32(AVIVO_D2VGA_CONTROL);
414926deccbSFrançois Tigeot 	vga_render_control = RREG32(AVIVO_VGA_RENDER_CONTROL);
415926deccbSFrançois Tigeot 	rom_cntl = RREG32(R600_ROM_CNTL);
416926deccbSFrançois Tigeot 	general_pwrmgt = RREG32(R600_GENERAL_PWRMGT);
417926deccbSFrançois Tigeot 	low_vid_lower_gpio_cntl = RREG32(R600_LOW_VID_LOWER_GPIO_CNTL);
418926deccbSFrançois Tigeot 	medium_vid_lower_gpio_cntl = RREG32(R600_MEDIUM_VID_LOWER_GPIO_CNTL);
419926deccbSFrançois Tigeot 	high_vid_lower_gpio_cntl = RREG32(R600_HIGH_VID_LOWER_GPIO_CNTL);
420926deccbSFrançois Tigeot 	ctxsw_vid_lower_gpio_cntl = RREG32(R600_CTXSW_VID_LOWER_GPIO_CNTL);
421926deccbSFrançois Tigeot 	lower_gpio_enable = RREG32(R600_LOWER_GPIO_ENABLE);
422926deccbSFrançois Tigeot 
423926deccbSFrançois Tigeot 	/* disable VIP */
424926deccbSFrançois Tigeot 	WREG32(RADEON_VIPH_CONTROL, (viph_control & ~RADEON_VIPH_EN));
425926deccbSFrançois Tigeot 	/* enable the rom */
426926deccbSFrançois Tigeot 	WREG32(R600_BUS_CNTL, (bus_cntl & ~R600_BIOS_ROM_DIS));
427926deccbSFrançois Tigeot 	/* Disable VGA mode */
428926deccbSFrançois Tigeot 	WREG32(AVIVO_D1VGA_CONTROL,
429926deccbSFrançois Tigeot 	       (d1vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE |
430926deccbSFrançois Tigeot 		AVIVO_DVGA_CONTROL_TIMING_SELECT)));
431926deccbSFrançois Tigeot 	WREG32(AVIVO_D2VGA_CONTROL,
432926deccbSFrançois Tigeot 	       (d2vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE |
433926deccbSFrançois Tigeot 		AVIVO_DVGA_CONTROL_TIMING_SELECT)));
434926deccbSFrançois Tigeot 	WREG32(AVIVO_VGA_RENDER_CONTROL,
435926deccbSFrançois Tigeot 	       (vga_render_control & ~AVIVO_VGA_VSTATUS_CNTL_MASK));
436926deccbSFrançois Tigeot 
437926deccbSFrançois Tigeot 	WREG32(R600_ROM_CNTL,
438926deccbSFrançois Tigeot 	       ((rom_cntl & ~R600_SCK_PRESCALE_CRYSTAL_CLK_MASK) |
439926deccbSFrançois Tigeot 		(1 << R600_SCK_PRESCALE_CRYSTAL_CLK_SHIFT) |
440926deccbSFrançois Tigeot 		R600_SCK_OVERWRITE));
441926deccbSFrançois Tigeot 
442926deccbSFrançois Tigeot 	WREG32(R600_GENERAL_PWRMGT, (general_pwrmgt & ~R600_OPEN_DRAIN_PADS));
443926deccbSFrançois Tigeot 	WREG32(R600_LOW_VID_LOWER_GPIO_CNTL,
444926deccbSFrançois Tigeot 	       (low_vid_lower_gpio_cntl & ~0x400));
445926deccbSFrançois Tigeot 	WREG32(R600_MEDIUM_VID_LOWER_GPIO_CNTL,
446926deccbSFrançois Tigeot 	       (medium_vid_lower_gpio_cntl & ~0x400));
447926deccbSFrançois Tigeot 	WREG32(R600_HIGH_VID_LOWER_GPIO_CNTL,
448926deccbSFrançois Tigeot 	       (high_vid_lower_gpio_cntl & ~0x400));
449926deccbSFrançois Tigeot 	WREG32(R600_CTXSW_VID_LOWER_GPIO_CNTL,
450926deccbSFrançois Tigeot 	       (ctxsw_vid_lower_gpio_cntl & ~0x400));
451926deccbSFrançois Tigeot 	WREG32(R600_LOWER_GPIO_ENABLE, (lower_gpio_enable | 0x400));
452926deccbSFrançois Tigeot 
453926deccbSFrançois Tigeot 	r = radeon_read_bios(rdev);
454926deccbSFrançois Tigeot 
455926deccbSFrançois Tigeot 	/* restore regs */
456926deccbSFrançois Tigeot 	WREG32(RADEON_VIPH_CONTROL, viph_control);
457926deccbSFrançois Tigeot 	WREG32(R600_BUS_CNTL, bus_cntl);
458926deccbSFrançois Tigeot 	WREG32(AVIVO_D1VGA_CONTROL, d1vga_control);
459926deccbSFrançois Tigeot 	WREG32(AVIVO_D2VGA_CONTROL, d2vga_control);
460926deccbSFrançois Tigeot 	WREG32(AVIVO_VGA_RENDER_CONTROL, vga_render_control);
461926deccbSFrançois Tigeot 	WREG32(R600_ROM_CNTL, rom_cntl);
462926deccbSFrançois Tigeot 	WREG32(R600_GENERAL_PWRMGT, general_pwrmgt);
463926deccbSFrançois Tigeot 	WREG32(R600_LOW_VID_LOWER_GPIO_CNTL, low_vid_lower_gpio_cntl);
464926deccbSFrançois Tigeot 	WREG32(R600_MEDIUM_VID_LOWER_GPIO_CNTL, medium_vid_lower_gpio_cntl);
465926deccbSFrançois Tigeot 	WREG32(R600_HIGH_VID_LOWER_GPIO_CNTL, high_vid_lower_gpio_cntl);
466926deccbSFrançois Tigeot 	WREG32(R600_CTXSW_VID_LOWER_GPIO_CNTL, ctxsw_vid_lower_gpio_cntl);
467926deccbSFrançois Tigeot 	WREG32(R600_LOWER_GPIO_ENABLE, lower_gpio_enable);
468926deccbSFrançois Tigeot 	return r;
469926deccbSFrançois Tigeot }
470926deccbSFrançois Tigeot 
471926deccbSFrançois Tigeot static bool avivo_read_disabled_bios(struct radeon_device *rdev)
472926deccbSFrançois Tigeot {
473926deccbSFrançois Tigeot 	uint32_t seprom_cntl1;
474926deccbSFrançois Tigeot 	uint32_t viph_control;
475926deccbSFrançois Tigeot 	uint32_t bus_cntl;
476926deccbSFrançois Tigeot 	uint32_t d1vga_control;
477926deccbSFrançois Tigeot 	uint32_t d2vga_control;
478926deccbSFrançois Tigeot 	uint32_t vga_render_control;
479926deccbSFrançois Tigeot 	uint32_t gpiopad_a;
480926deccbSFrançois Tigeot 	uint32_t gpiopad_en;
481926deccbSFrançois Tigeot 	uint32_t gpiopad_mask;
482926deccbSFrançois Tigeot 	bool r;
483926deccbSFrançois Tigeot 
484926deccbSFrançois Tigeot 	DRM_INFO("%s: ===> Try disabled BIOS (avivo)...\n", __func__);
485926deccbSFrançois Tigeot 
486926deccbSFrançois Tigeot 	seprom_cntl1 = RREG32(RADEON_SEPROM_CNTL1);
487926deccbSFrançois Tigeot 	viph_control = RREG32(RADEON_VIPH_CONTROL);
488926deccbSFrançois Tigeot 	bus_cntl = RREG32(RV370_BUS_CNTL);
489926deccbSFrançois Tigeot 	d1vga_control = RREG32(AVIVO_D1VGA_CONTROL);
490926deccbSFrançois Tigeot 	d2vga_control = RREG32(AVIVO_D2VGA_CONTROL);
491926deccbSFrançois Tigeot 	vga_render_control = RREG32(AVIVO_VGA_RENDER_CONTROL);
492926deccbSFrançois Tigeot 	gpiopad_a = RREG32(RADEON_GPIOPAD_A);
493926deccbSFrançois Tigeot 	gpiopad_en = RREG32(RADEON_GPIOPAD_EN);
494926deccbSFrançois Tigeot 	gpiopad_mask = RREG32(RADEON_GPIOPAD_MASK);
495926deccbSFrançois Tigeot 
496926deccbSFrançois Tigeot 	WREG32(RADEON_SEPROM_CNTL1,
497926deccbSFrançois Tigeot 	       ((seprom_cntl1 & ~RADEON_SCK_PRESCALE_MASK) |
498926deccbSFrançois Tigeot 		(0xc << RADEON_SCK_PRESCALE_SHIFT)));
499926deccbSFrançois Tigeot 	WREG32(RADEON_GPIOPAD_A, 0);
500926deccbSFrançois Tigeot 	WREG32(RADEON_GPIOPAD_EN, 0);
501926deccbSFrançois Tigeot 	WREG32(RADEON_GPIOPAD_MASK, 0);
502926deccbSFrançois Tigeot 
503926deccbSFrançois Tigeot 	/* disable VIP */
504926deccbSFrançois Tigeot 	WREG32(RADEON_VIPH_CONTROL, (viph_control & ~RADEON_VIPH_EN));
505926deccbSFrançois Tigeot 
506926deccbSFrançois Tigeot 	/* enable the rom */
507926deccbSFrançois Tigeot 	WREG32(RV370_BUS_CNTL, (bus_cntl & ~RV370_BUS_BIOS_DIS_ROM));
508926deccbSFrançois Tigeot 
509926deccbSFrançois Tigeot 	/* Disable VGA mode */
510926deccbSFrançois Tigeot 	WREG32(AVIVO_D1VGA_CONTROL,
511926deccbSFrançois Tigeot 	       (d1vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE |
512926deccbSFrançois Tigeot 		AVIVO_DVGA_CONTROL_TIMING_SELECT)));
513926deccbSFrançois Tigeot 	WREG32(AVIVO_D2VGA_CONTROL,
514926deccbSFrançois Tigeot 	       (d2vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE |
515926deccbSFrançois Tigeot 		AVIVO_DVGA_CONTROL_TIMING_SELECT)));
516926deccbSFrançois Tigeot 	WREG32(AVIVO_VGA_RENDER_CONTROL,
517926deccbSFrançois Tigeot 	       (vga_render_control & ~AVIVO_VGA_VSTATUS_CNTL_MASK));
518926deccbSFrançois Tigeot 
519926deccbSFrançois Tigeot 	r = radeon_read_bios(rdev);
520926deccbSFrançois Tigeot 
521926deccbSFrançois Tigeot 	/* restore regs */
522926deccbSFrançois Tigeot 	WREG32(RADEON_SEPROM_CNTL1, seprom_cntl1);
523926deccbSFrançois Tigeot 	WREG32(RADEON_VIPH_CONTROL, viph_control);
524926deccbSFrançois Tigeot 	WREG32(RV370_BUS_CNTL, bus_cntl);
525926deccbSFrançois Tigeot 	WREG32(AVIVO_D1VGA_CONTROL, d1vga_control);
526926deccbSFrançois Tigeot 	WREG32(AVIVO_D2VGA_CONTROL, d2vga_control);
527926deccbSFrançois Tigeot 	WREG32(AVIVO_VGA_RENDER_CONTROL, vga_render_control);
528926deccbSFrançois Tigeot 	WREG32(RADEON_GPIOPAD_A, gpiopad_a);
529926deccbSFrançois Tigeot 	WREG32(RADEON_GPIOPAD_EN, gpiopad_en);
530926deccbSFrançois Tigeot 	WREG32(RADEON_GPIOPAD_MASK, gpiopad_mask);
531926deccbSFrançois Tigeot 	return r;
532926deccbSFrançois Tigeot }
533926deccbSFrançois Tigeot 
534926deccbSFrançois Tigeot static bool legacy_read_disabled_bios(struct radeon_device *rdev)
535926deccbSFrançois Tigeot {
536926deccbSFrançois Tigeot 	uint32_t seprom_cntl1;
537926deccbSFrançois Tigeot 	uint32_t viph_control;
538926deccbSFrançois Tigeot 	uint32_t bus_cntl;
539926deccbSFrançois Tigeot 	uint32_t crtc_gen_cntl;
540926deccbSFrançois Tigeot 	uint32_t crtc2_gen_cntl;
541926deccbSFrançois Tigeot 	uint32_t crtc_ext_cntl;
542926deccbSFrançois Tigeot 	uint32_t fp2_gen_cntl;
543926deccbSFrançois Tigeot 	bool r;
544926deccbSFrançois Tigeot 
545926deccbSFrançois Tigeot 	DRM_INFO("%s: ===> Try disabled BIOS (legacy)...\n", __func__);
546926deccbSFrançois Tigeot 
547926deccbSFrançois Tigeot 	seprom_cntl1 = RREG32(RADEON_SEPROM_CNTL1);
548926deccbSFrançois Tigeot 	viph_control = RREG32(RADEON_VIPH_CONTROL);
549926deccbSFrançois Tigeot 	if (rdev->flags & RADEON_IS_PCIE)
550926deccbSFrançois Tigeot 		bus_cntl = RREG32(RV370_BUS_CNTL);
551926deccbSFrançois Tigeot 	else
552926deccbSFrançois Tigeot 		bus_cntl = RREG32(RADEON_BUS_CNTL);
553926deccbSFrançois Tigeot 	crtc_gen_cntl = RREG32(RADEON_CRTC_GEN_CNTL);
554926deccbSFrançois Tigeot 	crtc2_gen_cntl = 0;
555926deccbSFrançois Tigeot 	crtc_ext_cntl = RREG32(RADEON_CRTC_EXT_CNTL);
556926deccbSFrançois Tigeot 	fp2_gen_cntl = 0;
557926deccbSFrançois Tigeot 
558926deccbSFrançois Tigeot #define	PCI_DEVICE_ID_ATI_RADEON_QY	0x5159
559926deccbSFrançois Tigeot 
560c6f73aabSFrançois Tigeot 	if (rdev->ddev->pdev->device == PCI_DEVICE_ID_ATI_RADEON_QY) {
561926deccbSFrançois Tigeot 		fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL);
562926deccbSFrançois Tigeot 	}
563926deccbSFrançois Tigeot 
564926deccbSFrançois Tigeot 	if (!(rdev->flags & RADEON_SINGLE_CRTC)) {
565926deccbSFrançois Tigeot 		crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL);
566926deccbSFrançois Tigeot 	}
567926deccbSFrançois Tigeot 
568926deccbSFrançois Tigeot 	WREG32(RADEON_SEPROM_CNTL1,
569926deccbSFrançois Tigeot 	       ((seprom_cntl1 & ~RADEON_SCK_PRESCALE_MASK) |
570926deccbSFrançois Tigeot 		(0xc << RADEON_SCK_PRESCALE_SHIFT)));
571926deccbSFrançois Tigeot 
572926deccbSFrançois Tigeot 	/* disable VIP */
573926deccbSFrançois Tigeot 	WREG32(RADEON_VIPH_CONTROL, (viph_control & ~RADEON_VIPH_EN));
574926deccbSFrançois Tigeot 
575926deccbSFrançois Tigeot 	/* enable the rom */
576926deccbSFrançois Tigeot 	if (rdev->flags & RADEON_IS_PCIE)
577926deccbSFrançois Tigeot 		WREG32(RV370_BUS_CNTL, (bus_cntl & ~RV370_BUS_BIOS_DIS_ROM));
578926deccbSFrançois Tigeot 	else
579926deccbSFrançois Tigeot 		WREG32(RADEON_BUS_CNTL, (bus_cntl & ~RADEON_BUS_BIOS_DIS_ROM));
580926deccbSFrançois Tigeot 
581926deccbSFrançois Tigeot 	/* Turn off mem requests and CRTC for both controllers */
582926deccbSFrançois Tigeot 	WREG32(RADEON_CRTC_GEN_CNTL,
583926deccbSFrançois Tigeot 	       ((crtc_gen_cntl & ~RADEON_CRTC_EN) |
584926deccbSFrançois Tigeot 		(RADEON_CRTC_DISP_REQ_EN_B |
585926deccbSFrançois Tigeot 		 RADEON_CRTC_EXT_DISP_EN)));
586926deccbSFrançois Tigeot 	if (!(rdev->flags & RADEON_SINGLE_CRTC)) {
587926deccbSFrançois Tigeot 		WREG32(RADEON_CRTC2_GEN_CNTL,
588926deccbSFrançois Tigeot 		       ((crtc2_gen_cntl & ~RADEON_CRTC2_EN) |
589926deccbSFrançois Tigeot 			RADEON_CRTC2_DISP_REQ_EN_B));
590926deccbSFrançois Tigeot 	}
591926deccbSFrançois Tigeot 	/* Turn off CRTC */
592926deccbSFrançois Tigeot 	WREG32(RADEON_CRTC_EXT_CNTL,
593926deccbSFrançois Tigeot 	       ((crtc_ext_cntl & ~RADEON_CRTC_CRT_ON) |
594926deccbSFrançois Tigeot 		(RADEON_CRTC_SYNC_TRISTAT |
595926deccbSFrançois Tigeot 		 RADEON_CRTC_DISPLAY_DIS)));
596926deccbSFrançois Tigeot 
597c6f73aabSFrançois Tigeot 	if (rdev->ddev->pdev->device == PCI_DEVICE_ID_ATI_RADEON_QY) {
598926deccbSFrançois Tigeot 		WREG32(RADEON_FP2_GEN_CNTL, (fp2_gen_cntl & ~RADEON_FP2_ON));
599926deccbSFrançois Tigeot 	}
600926deccbSFrançois Tigeot 
601926deccbSFrançois Tigeot 	r = radeon_read_bios(rdev);
602926deccbSFrançois Tigeot 
603926deccbSFrançois Tigeot 	/* restore regs */
604926deccbSFrançois Tigeot 	WREG32(RADEON_SEPROM_CNTL1, seprom_cntl1);
605926deccbSFrançois Tigeot 	WREG32(RADEON_VIPH_CONTROL, viph_control);
606926deccbSFrançois Tigeot 	if (rdev->flags & RADEON_IS_PCIE)
607926deccbSFrançois Tigeot 		WREG32(RV370_BUS_CNTL, bus_cntl);
608926deccbSFrançois Tigeot 	else
609926deccbSFrançois Tigeot 		WREG32(RADEON_BUS_CNTL, bus_cntl);
610926deccbSFrançois Tigeot 	WREG32(RADEON_CRTC_GEN_CNTL, crtc_gen_cntl);
611926deccbSFrançois Tigeot 	if (!(rdev->flags & RADEON_SINGLE_CRTC)) {
612926deccbSFrançois Tigeot 		WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl);
613926deccbSFrançois Tigeot 	}
614926deccbSFrançois Tigeot 	WREG32(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl);
615c6f73aabSFrançois Tigeot 	if (rdev->ddev->pdev->device == PCI_DEVICE_ID_ATI_RADEON_QY) {
616926deccbSFrançois Tigeot 		WREG32(RADEON_FP2_GEN_CNTL, fp2_gen_cntl);
617926deccbSFrançois Tigeot 	}
618926deccbSFrançois Tigeot 	return r;
619926deccbSFrançois Tigeot }
620926deccbSFrançois Tigeot 
621926deccbSFrançois Tigeot static bool radeon_read_disabled_bios(struct radeon_device *rdev)
622926deccbSFrançois Tigeot {
623926deccbSFrançois Tigeot 	if (rdev->flags & RADEON_IS_IGP)
624926deccbSFrançois Tigeot 		return igp_read_bios_from_vram(rdev);
625926deccbSFrançois Tigeot 	else if (rdev->family >= CHIP_BARTS)
626926deccbSFrançois Tigeot 		return ni_read_disabled_bios(rdev);
627926deccbSFrançois Tigeot 	else if (rdev->family >= CHIP_RV770)
628926deccbSFrançois Tigeot 		return r700_read_disabled_bios(rdev);
629926deccbSFrançois Tigeot 	else if (rdev->family >= CHIP_R600)
630926deccbSFrançois Tigeot 		return r600_read_disabled_bios(rdev);
631926deccbSFrançois Tigeot 	else if (rdev->family >= CHIP_RS600)
632926deccbSFrançois Tigeot 		return avivo_read_disabled_bios(rdev);
633926deccbSFrançois Tigeot 	else
634926deccbSFrançois Tigeot 		return legacy_read_disabled_bios(rdev);
635926deccbSFrançois Tigeot }
636926deccbSFrançois Tigeot 
637452a88ebSzrj #ifdef CONFIG_ACPI
638926deccbSFrançois Tigeot static bool radeon_acpi_vfct_bios(struct radeon_device *rdev)
639926deccbSFrançois Tigeot {
640*a85cb24fSFrançois Tigeot 	bool ret = false;
641926deccbSFrançois Tigeot 	ACPI_TABLE_HEADER *hdr;
642926deccbSFrançois Tigeot 	ACPI_SIZE tbl_size;
643926deccbSFrançois Tigeot 	UEFI_ACPI_VFCT *vfct;
644*a85cb24fSFrançois Tigeot 	GOP_VBIOS_CONTENT *vbios;
645*a85cb24fSFrançois Tigeot 	VFCT_IMAGE_HEADER *vhdr;
646*a85cb24fSFrançois Tigeot 	ACPI_STATUS status;
647926deccbSFrançois Tigeot 
648*a85cb24fSFrançois Tigeot 	DRM_INFO("%s: ===> Try VFCT...\n", __func__);
649*a85cb24fSFrançois Tigeot 
650*a85cb24fSFrançois Tigeot 	DRM_INFO("%s: Get \"VFCT\" ACPI table\n", __func__);
651*a85cb24fSFrançois Tigeot 	status = AcpiGetTable("VFCT", 1, &hdr);
652*a85cb24fSFrançois Tigeot 	if (!ACPI_SUCCESS(status)) {
653*a85cb24fSFrançois Tigeot 		DRM_INFO("%s: Failed to get \"VFCT\" table: %s\n",
654*a85cb24fSFrançois Tigeot 		    __func__, AcpiFormatException(status));
655926deccbSFrançois Tigeot 		return false;
656*a85cb24fSFrançois Tigeot 	}
657926deccbSFrançois Tigeot 	tbl_size = hdr->Length;
658926deccbSFrançois Tigeot 	if (tbl_size < sizeof(UEFI_ACPI_VFCT)) {
659926deccbSFrançois Tigeot 		DRM_ERROR("ACPI VFCT table present but broken (too short #1)\n");
660*a85cb24fSFrançois Tigeot 		goto out_unmap;
661926deccbSFrançois Tigeot 	}
662926deccbSFrançois Tigeot 
663926deccbSFrançois Tigeot 	vfct = (UEFI_ACPI_VFCT *)hdr;
664*a85cb24fSFrançois Tigeot 	if (vfct->VBIOSImageOffset + sizeof(VFCT_IMAGE_HEADER) > tbl_size) {
6654be47400SFrançois Tigeot 		DRM_ERROR("ACPI VFCT table present but broken (too short #2)\n");
666*a85cb24fSFrançois Tigeot 		goto out_unmap;
667*a85cb24fSFrançois Tigeot 	}
668*a85cb24fSFrançois Tigeot 
669*a85cb24fSFrançois Tigeot 	vbios = (GOP_VBIOS_CONTENT *)((char *)hdr + vfct->VBIOSImageOffset);
670*a85cb24fSFrançois Tigeot 	vhdr = &vbios->VbiosHeader;
671*a85cb24fSFrançois Tigeot 	DRM_INFO("ACPI VFCT contains a BIOS for %02x:%02x.%d %04x:%04x, size %d\n",
672*a85cb24fSFrançois Tigeot 			vhdr->PCIBus, vhdr->PCIDevice, vhdr->PCIFunction,
673*a85cb24fSFrançois Tigeot 			vhdr->VendorID, vhdr->DeviceID, vhdr->ImageLength);
674*a85cb24fSFrançois Tigeot 
675*a85cb24fSFrançois Tigeot 	if (vhdr->PCIBus != rdev->pdev->bus->number ||
676*a85cb24fSFrançois Tigeot 	    vhdr->PCIDevice != rdev->ddev->pci_slot ||
677*a85cb24fSFrançois Tigeot 	    vhdr->PCIFunction != rdev->ddev->pci_func ||
678*a85cb24fSFrançois Tigeot 	    vhdr->VendorID != rdev->pdev->vendor ||
679*a85cb24fSFrançois Tigeot 	    vhdr->DeviceID != rdev->pdev->device) {
680*a85cb24fSFrançois Tigeot 		DRM_INFO("ACPI VFCT table is not for this card\n");
681*a85cb24fSFrançois Tigeot 		goto out_unmap;
682*a85cb24fSFrançois Tigeot 	}
683*a85cb24fSFrançois Tigeot 
684*a85cb24fSFrançois Tigeot 	if (vfct->VBIOSImageOffset + sizeof(VFCT_IMAGE_HEADER) + vhdr->ImageLength > tbl_size) {
685*a85cb24fSFrançois Tigeot 		DRM_ERROR("ACPI VFCT image truncated\n");
686*a85cb24fSFrançois Tigeot 		goto out_unmap;
687*a85cb24fSFrançois Tigeot 	}
688*a85cb24fSFrançois Tigeot 
689*a85cb24fSFrançois Tigeot 	rdev->bios = kmalloc(vhdr->ImageLength, M_DRM, M_WAITOK);
690*a85cb24fSFrançois Tigeot 	memcpy(rdev->bios, &vbios->VbiosContent, vhdr->ImageLength);
691*a85cb24fSFrançois Tigeot 	ret = !!rdev->bios;
692*a85cb24fSFrançois Tigeot 
693*a85cb24fSFrançois Tigeot out_unmap:
694*a85cb24fSFrançois Tigeot 	return ret;
695926deccbSFrançois Tigeot }
696452a88ebSzrj #else
697452a88ebSzrj static inline bool radeon_acpi_vfct_bios(struct radeon_device *rdev)
698452a88ebSzrj {
699452a88ebSzrj 	return false;
700452a88ebSzrj }
701452a88ebSzrj #endif
702926deccbSFrançois Tigeot 
703926deccbSFrançois Tigeot bool radeon_get_bios(struct radeon_device *rdev)
704926deccbSFrançois Tigeot {
705926deccbSFrançois Tigeot 	bool r;
706926deccbSFrançois Tigeot 	uint16_t tmp;
707926deccbSFrançois Tigeot 
708926deccbSFrançois Tigeot 	r = radeon_atrm_get_bios(rdev);
709926deccbSFrançois Tigeot 	if (r == false)
710926deccbSFrançois Tigeot 		r = radeon_acpi_vfct_bios(rdev);
711926deccbSFrançois Tigeot 	if (r == false)
712926deccbSFrançois Tigeot 		r = igp_read_bios_from_vram(rdev);
713926deccbSFrançois Tigeot 	if (r == false)
714926deccbSFrançois Tigeot 		r = radeon_read_bios(rdev);
715591d5043SFrançois Tigeot 	if (r == false)
716926deccbSFrançois Tigeot 		r = radeon_read_disabled_bios(rdev);
717591d5043SFrançois Tigeot 	if (r == false)
718b403bed8SMichael Neumann 		r = radeon_read_platform_bios(rdev);
719926deccbSFrançois Tigeot 	if (r == false || rdev->bios == NULL) {
720926deccbSFrançois Tigeot 		DRM_ERROR("Unable to locate a BIOS ROM\n");
721926deccbSFrançois Tigeot 		rdev->bios = NULL;
722926deccbSFrançois Tigeot 		return false;
723926deccbSFrançois Tigeot 	}
724926deccbSFrançois Tigeot 	if (rdev->bios[0] != 0x55 || rdev->bios[1] != 0xaa) {
725c4ef309bSzrj 		printk("BIOS signature incorrect %x %x\n", rdev->bios[0], rdev->bios[1]);
726926deccbSFrançois Tigeot 		goto free_bios;
727926deccbSFrançois Tigeot 	}
728926deccbSFrançois Tigeot 
729926deccbSFrançois Tigeot 	tmp = RBIOS16(0x18);
730926deccbSFrançois Tigeot 	if (RBIOS8(tmp + 0x14) != 0x0) {
731926deccbSFrançois Tigeot 		DRM_INFO("Not an x86 BIOS ROM, not using.\n");
732926deccbSFrançois Tigeot 		goto free_bios;
733926deccbSFrançois Tigeot 	}
734926deccbSFrançois Tigeot 
735926deccbSFrançois Tigeot 	rdev->bios_header_start = RBIOS16(0x48);
736926deccbSFrançois Tigeot 	if (!rdev->bios_header_start) {
737926deccbSFrançois Tigeot 		goto free_bios;
738926deccbSFrançois Tigeot 	}
739926deccbSFrançois Tigeot 	tmp = rdev->bios_header_start + 4;
740926deccbSFrançois Tigeot 	if (!memcmp(rdev->bios + tmp, "ATOM", 4) ||
741926deccbSFrançois Tigeot 	    !memcmp(rdev->bios + tmp, "MOTA", 4)) {
742926deccbSFrançois Tigeot 		rdev->is_atom_bios = true;
743926deccbSFrançois Tigeot 	} else {
744926deccbSFrançois Tigeot 		rdev->is_atom_bios = false;
745926deccbSFrançois Tigeot 	}
746926deccbSFrançois Tigeot 
747926deccbSFrançois Tigeot 	DRM_DEBUG("%sBIOS detected\n", rdev->is_atom_bios ? "ATOM" : "COM");
748926deccbSFrançois Tigeot 	return true;
749926deccbSFrançois Tigeot free_bios:
750c4ef309bSzrj 	kfree(rdev->bios);
751926deccbSFrançois Tigeot 	rdev->bios = NULL;
752926deccbSFrançois Tigeot 	return false;
753926deccbSFrançois Tigeot }
754