1d38ceaf9SAlex Deucher /*
2d38ceaf9SAlex Deucher  * Copyright 2008 Advanced Micro Devices, Inc.
3d38ceaf9SAlex Deucher  * Copyright 2008 Red Hat Inc.
4d38ceaf9SAlex Deucher  * Copyright 2009 Jerome Glisse.
5d38ceaf9SAlex Deucher  *
6d38ceaf9SAlex Deucher  * Permission is hereby granted, free of charge, to any person obtaining a
7d38ceaf9SAlex Deucher  * copy of this software and associated documentation files (the "Software"),
8d38ceaf9SAlex Deucher  * to deal in the Software without restriction, including without limitation
9d38ceaf9SAlex Deucher  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10d38ceaf9SAlex Deucher  * and/or sell copies of the Software, and to permit persons to whom the
11d38ceaf9SAlex Deucher  * Software is furnished to do so, subject to the following conditions:
12d38ceaf9SAlex Deucher  *
13d38ceaf9SAlex Deucher  * The above copyright notice and this permission notice shall be included in
14d38ceaf9SAlex Deucher  * all copies or substantial portions of the Software.
15d38ceaf9SAlex Deucher  *
16d38ceaf9SAlex Deucher  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17d38ceaf9SAlex Deucher  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18d38ceaf9SAlex Deucher  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19d38ceaf9SAlex Deucher  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
20d38ceaf9SAlex Deucher  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21d38ceaf9SAlex Deucher  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22d38ceaf9SAlex Deucher  * OTHER DEALINGS IN THE SOFTWARE.
23d38ceaf9SAlex Deucher  *
24d38ceaf9SAlex Deucher  * Authors: Dave Airlie
25d38ceaf9SAlex Deucher  *          Alex Deucher
26d38ceaf9SAlex Deucher  *          Jerome Glisse
27d38ceaf9SAlex Deucher  */
28d38ceaf9SAlex Deucher #include <drm/drmP.h>
29d38ceaf9SAlex Deucher #include "amdgpu.h"
30d38ceaf9SAlex Deucher #include "atom.h"
31d38ceaf9SAlex Deucher 
32d38ceaf9SAlex Deucher #include <linux/vga_switcheroo.h>
33d38ceaf9SAlex Deucher #include <linux/slab.h>
34d38ceaf9SAlex Deucher #include <linux/acpi.h>
35d38ceaf9SAlex Deucher /*
36d38ceaf9SAlex Deucher  * BIOS.
37d38ceaf9SAlex Deucher  */
38d38ceaf9SAlex Deucher 
39d38ceaf9SAlex Deucher /* If you boot an IGP board with a discrete card as the primary,
40d38ceaf9SAlex Deucher  * the IGP rom is not accessible via the rom bar as the IGP rom is
41d38ceaf9SAlex Deucher  * part of the system bios.  On boot, the system bios puts a
42d38ceaf9SAlex Deucher  * copy of the igp rom at the start of vram if a discrete card is
43d38ceaf9SAlex Deucher  * present.
44d38ceaf9SAlex Deucher  */
45d38ceaf9SAlex Deucher static bool igp_read_bios_from_vram(struct amdgpu_device *adev)
46d38ceaf9SAlex Deucher {
47d38ceaf9SAlex Deucher 	uint8_t __iomem *bios;
48d38ceaf9SAlex Deucher 	resource_size_t vram_base;
49d38ceaf9SAlex Deucher 	resource_size_t size = 256 * 1024; /* ??? */
50d38ceaf9SAlex Deucher 
51d38ceaf9SAlex Deucher 	if (!(adev->flags & AMDGPU_IS_APU))
52d38ceaf9SAlex Deucher 		if (!amdgpu_card_posted(adev))
53d38ceaf9SAlex Deucher 			return false;
54d38ceaf9SAlex Deucher 
55d38ceaf9SAlex Deucher 	adev->bios = NULL;
56d38ceaf9SAlex Deucher 	vram_base = pci_resource_start(adev->pdev, 0);
57d38ceaf9SAlex Deucher 	bios = ioremap(vram_base, size);
58d38ceaf9SAlex Deucher 	if (!bios) {
59d38ceaf9SAlex Deucher 		return false;
60d38ceaf9SAlex Deucher 	}
61d38ceaf9SAlex Deucher 
62d38ceaf9SAlex Deucher 	if (size == 0 || bios[0] != 0x55 || bios[1] != 0xaa) {
63d38ceaf9SAlex Deucher 		iounmap(bios);
64d38ceaf9SAlex Deucher 		return false;
65d38ceaf9SAlex Deucher 	}
66d38ceaf9SAlex Deucher 	adev->bios = kmalloc(size, GFP_KERNEL);
67d38ceaf9SAlex Deucher 	if (adev->bios == NULL) {
68d38ceaf9SAlex Deucher 		iounmap(bios);
69d38ceaf9SAlex Deucher 		return false;
70d38ceaf9SAlex Deucher 	}
71d38ceaf9SAlex Deucher 	memcpy_fromio(adev->bios, bios, size);
72d38ceaf9SAlex Deucher 	iounmap(bios);
73d38ceaf9SAlex Deucher 	return true;
74d38ceaf9SAlex Deucher }
75d38ceaf9SAlex Deucher 
76d38ceaf9SAlex Deucher bool amdgpu_read_bios(struct amdgpu_device *adev)
77d38ceaf9SAlex Deucher {
78d38ceaf9SAlex Deucher 	uint8_t __iomem *bios;
79d38ceaf9SAlex Deucher 	size_t size;
80d38ceaf9SAlex Deucher 
81d38ceaf9SAlex Deucher 	adev->bios = NULL;
82d38ceaf9SAlex Deucher 	/* XXX: some cards may return 0 for rom size? ddx has a workaround */
83d38ceaf9SAlex Deucher 	bios = pci_map_rom(adev->pdev, &size);
84d38ceaf9SAlex Deucher 	if (!bios) {
85d38ceaf9SAlex Deucher 		return false;
86d38ceaf9SAlex Deucher 	}
87d38ceaf9SAlex Deucher 
88d38ceaf9SAlex Deucher 	if (size == 0 || bios[0] != 0x55 || bios[1] != 0xaa) {
89d38ceaf9SAlex Deucher 		pci_unmap_rom(adev->pdev, bios);
90d38ceaf9SAlex Deucher 		return false;
91d38ceaf9SAlex Deucher 	}
92d38ceaf9SAlex Deucher 	adev->bios = kmemdup(bios, size, GFP_KERNEL);
93d38ceaf9SAlex Deucher 	if (adev->bios == NULL) {
94d38ceaf9SAlex Deucher 		pci_unmap_rom(adev->pdev, bios);
95d38ceaf9SAlex Deucher 		return false;
96d38ceaf9SAlex Deucher 	}
97d38ceaf9SAlex Deucher 	pci_unmap_rom(adev->pdev, bios);
98d38ceaf9SAlex Deucher 	return true;
99d38ceaf9SAlex Deucher }
100d38ceaf9SAlex Deucher 
101d38ceaf9SAlex Deucher static bool amdgpu_read_platform_bios(struct amdgpu_device *adev)
102d38ceaf9SAlex Deucher {
103d38ceaf9SAlex Deucher 	uint8_t __iomem *bios;
104d38ceaf9SAlex Deucher 	size_t size;
105d38ceaf9SAlex Deucher 
106d38ceaf9SAlex Deucher 	adev->bios = NULL;
107d38ceaf9SAlex Deucher 
108d38ceaf9SAlex Deucher 	bios = pci_platform_rom(adev->pdev, &size);
109d38ceaf9SAlex Deucher 	if (!bios) {
110d38ceaf9SAlex Deucher 		return false;
111d38ceaf9SAlex Deucher 	}
112d38ceaf9SAlex Deucher 
113d38ceaf9SAlex Deucher 	if (size == 0 || bios[0] != 0x55 || bios[1] != 0xaa) {
114d38ceaf9SAlex Deucher 		return false;
115d38ceaf9SAlex Deucher 	}
116d38ceaf9SAlex Deucher 	adev->bios = kmemdup(bios, size, GFP_KERNEL);
117d38ceaf9SAlex Deucher 	if (adev->bios == NULL) {
118d38ceaf9SAlex Deucher 		return false;
119d38ceaf9SAlex Deucher 	}
120d38ceaf9SAlex Deucher 
121d38ceaf9SAlex Deucher 	return true;
122d38ceaf9SAlex Deucher }
123d38ceaf9SAlex Deucher 
124d38ceaf9SAlex Deucher #ifdef CONFIG_ACPI
125d38ceaf9SAlex Deucher /* ATRM is used to get the BIOS on the discrete cards in
126d38ceaf9SAlex Deucher  * dual-gpu systems.
127d38ceaf9SAlex Deucher  */
128d38ceaf9SAlex Deucher /* retrieve the ROM in 4k blocks */
129d38ceaf9SAlex Deucher #define ATRM_BIOS_PAGE 4096
130d38ceaf9SAlex Deucher /**
131d38ceaf9SAlex Deucher  * amdgpu_atrm_call - fetch a chunk of the vbios
132d38ceaf9SAlex Deucher  *
133d38ceaf9SAlex Deucher  * @atrm_handle: acpi ATRM handle
134d38ceaf9SAlex Deucher  * @bios: vbios image pointer
135d38ceaf9SAlex Deucher  * @offset: offset of vbios image data to fetch
136d38ceaf9SAlex Deucher  * @len: length of vbios image data to fetch
137d38ceaf9SAlex Deucher  *
138d38ceaf9SAlex Deucher  * Executes ATRM to fetch a chunk of the discrete
139d38ceaf9SAlex Deucher  * vbios image on PX systems (all asics).
140d38ceaf9SAlex Deucher  * Returns the length of the buffer fetched.
141d38ceaf9SAlex Deucher  */
142d38ceaf9SAlex Deucher static int amdgpu_atrm_call(acpi_handle atrm_handle, uint8_t *bios,
143d38ceaf9SAlex Deucher 			    int offset, int len)
144d38ceaf9SAlex Deucher {
145d38ceaf9SAlex Deucher 	acpi_status status;
146d38ceaf9SAlex Deucher 	union acpi_object atrm_arg_elements[2], *obj;
147d38ceaf9SAlex Deucher 	struct acpi_object_list atrm_arg;
148d38ceaf9SAlex Deucher 	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL};
149d38ceaf9SAlex Deucher 
150d38ceaf9SAlex Deucher 	atrm_arg.count = 2;
151d38ceaf9SAlex Deucher 	atrm_arg.pointer = &atrm_arg_elements[0];
152d38ceaf9SAlex Deucher 
153d38ceaf9SAlex Deucher 	atrm_arg_elements[0].type = ACPI_TYPE_INTEGER;
154d38ceaf9SAlex Deucher 	atrm_arg_elements[0].integer.value = offset;
155d38ceaf9SAlex Deucher 
156d38ceaf9SAlex Deucher 	atrm_arg_elements[1].type = ACPI_TYPE_INTEGER;
157d38ceaf9SAlex Deucher 	atrm_arg_elements[1].integer.value = len;
158d38ceaf9SAlex Deucher 
159d38ceaf9SAlex Deucher 	status = acpi_evaluate_object(atrm_handle, NULL, &atrm_arg, &buffer);
160d38ceaf9SAlex Deucher 	if (ACPI_FAILURE(status)) {
161d38ceaf9SAlex Deucher 		printk("failed to evaluate ATRM got %s\n", acpi_format_exception(status));
162d38ceaf9SAlex Deucher 		return -ENODEV;
163d38ceaf9SAlex Deucher 	}
164d38ceaf9SAlex Deucher 
165d38ceaf9SAlex Deucher 	obj = (union acpi_object *)buffer.pointer;
166d38ceaf9SAlex Deucher 	memcpy(bios+offset, obj->buffer.pointer, obj->buffer.length);
167d38ceaf9SAlex Deucher 	len = obj->buffer.length;
168d38ceaf9SAlex Deucher 	kfree(buffer.pointer);
169d38ceaf9SAlex Deucher 	return len;
170d38ceaf9SAlex Deucher }
171d38ceaf9SAlex Deucher 
172d38ceaf9SAlex Deucher static bool amdgpu_atrm_get_bios(struct amdgpu_device *adev)
173d38ceaf9SAlex Deucher {
174d38ceaf9SAlex Deucher 	int ret;
175d38ceaf9SAlex Deucher 	int size = 256 * 1024;
176d38ceaf9SAlex Deucher 	int i;
177d38ceaf9SAlex Deucher 	struct pci_dev *pdev = NULL;
178d38ceaf9SAlex Deucher 	acpi_handle dhandle, atrm_handle;
179d38ceaf9SAlex Deucher 	acpi_status status;
180d38ceaf9SAlex Deucher 	bool found = false;
181d38ceaf9SAlex Deucher 
182d38ceaf9SAlex Deucher 	/* ATRM is for the discrete card only */
183d38ceaf9SAlex Deucher 	if (adev->flags & AMDGPU_IS_APU)
184d38ceaf9SAlex Deucher 		return false;
185d38ceaf9SAlex Deucher 
186d38ceaf9SAlex Deucher 	while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
187d38ceaf9SAlex Deucher 		dhandle = ACPI_HANDLE(&pdev->dev);
188d38ceaf9SAlex Deucher 		if (!dhandle)
189d38ceaf9SAlex Deucher 			continue;
190d38ceaf9SAlex Deucher 
191d38ceaf9SAlex Deucher 		status = acpi_get_handle(dhandle, "ATRM", &atrm_handle);
192d38ceaf9SAlex Deucher 		if (!ACPI_FAILURE(status)) {
193d38ceaf9SAlex Deucher 			found = true;
194d38ceaf9SAlex Deucher 			break;
195d38ceaf9SAlex Deucher 		}
196d38ceaf9SAlex Deucher 	}
197d38ceaf9SAlex Deucher 
198d38ceaf9SAlex Deucher 	if (!found) {
199d38ceaf9SAlex Deucher 		while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_OTHER << 8, pdev)) != NULL) {
200d38ceaf9SAlex Deucher 			dhandle = ACPI_HANDLE(&pdev->dev);
201d38ceaf9SAlex Deucher 			if (!dhandle)
202d38ceaf9SAlex Deucher 				continue;
203d38ceaf9SAlex Deucher 
204d38ceaf9SAlex Deucher 			status = acpi_get_handle(dhandle, "ATRM", &atrm_handle);
205d38ceaf9SAlex Deucher 			if (!ACPI_FAILURE(status)) {
206d38ceaf9SAlex Deucher 				found = true;
207d38ceaf9SAlex Deucher 				break;
208d38ceaf9SAlex Deucher 			}
209d38ceaf9SAlex Deucher 		}
210d38ceaf9SAlex Deucher 	}
211d38ceaf9SAlex Deucher 
212d38ceaf9SAlex Deucher 	if (!found)
213d38ceaf9SAlex Deucher 		return false;
214d38ceaf9SAlex Deucher 
215d38ceaf9SAlex Deucher 	adev->bios = kmalloc(size, GFP_KERNEL);
216d38ceaf9SAlex Deucher 	if (!adev->bios) {
217d38ceaf9SAlex Deucher 		DRM_ERROR("Unable to allocate bios\n");
218d38ceaf9SAlex Deucher 		return false;
219d38ceaf9SAlex Deucher 	}
220d38ceaf9SAlex Deucher 
221d38ceaf9SAlex Deucher 	for (i = 0; i < size / ATRM_BIOS_PAGE; i++) {
222d38ceaf9SAlex Deucher 		ret = amdgpu_atrm_call(atrm_handle,
223d38ceaf9SAlex Deucher 				       adev->bios,
224d38ceaf9SAlex Deucher 				       (i * ATRM_BIOS_PAGE),
225d38ceaf9SAlex Deucher 				       ATRM_BIOS_PAGE);
226d38ceaf9SAlex Deucher 		if (ret < ATRM_BIOS_PAGE)
227d38ceaf9SAlex Deucher 			break;
228d38ceaf9SAlex Deucher 	}
229d38ceaf9SAlex Deucher 
230d38ceaf9SAlex Deucher 	if (i == 0 || adev->bios[0] != 0x55 || adev->bios[1] != 0xaa) {
231d38ceaf9SAlex Deucher 		kfree(adev->bios);
232d38ceaf9SAlex Deucher 		return false;
233d38ceaf9SAlex Deucher 	}
234d38ceaf9SAlex Deucher 	return true;
235d38ceaf9SAlex Deucher }
236d38ceaf9SAlex Deucher #else
237d38ceaf9SAlex Deucher static inline bool amdgpu_atrm_get_bios(struct amdgpu_device *adev)
238d38ceaf9SAlex Deucher {
239d38ceaf9SAlex Deucher 	return false;
240d38ceaf9SAlex Deucher }
241d38ceaf9SAlex Deucher #endif
242d38ceaf9SAlex Deucher 
243d38ceaf9SAlex Deucher static bool amdgpu_read_disabled_bios(struct amdgpu_device *adev)
244d38ceaf9SAlex Deucher {
245d38ceaf9SAlex Deucher 	if (adev->flags & AMDGPU_IS_APU)
246d38ceaf9SAlex Deucher 		return igp_read_bios_from_vram(adev);
247d38ceaf9SAlex Deucher 	else
248d38ceaf9SAlex Deucher 		return amdgpu_asic_read_disabled_bios(adev);
249d38ceaf9SAlex Deucher }
250d38ceaf9SAlex Deucher 
251d38ceaf9SAlex Deucher #ifdef CONFIG_ACPI
252d38ceaf9SAlex Deucher static bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)
253d38ceaf9SAlex Deucher {
254d38ceaf9SAlex Deucher 	bool ret = false;
255d38ceaf9SAlex Deucher 	struct acpi_table_header *hdr;
256d38ceaf9SAlex Deucher 	acpi_size tbl_size;
257d38ceaf9SAlex Deucher 	UEFI_ACPI_VFCT *vfct;
258d38ceaf9SAlex Deucher 	GOP_VBIOS_CONTENT *vbios;
259d38ceaf9SAlex Deucher 	VFCT_IMAGE_HEADER *vhdr;
260d38ceaf9SAlex Deucher 
261d38ceaf9SAlex Deucher 	if (!ACPI_SUCCESS(acpi_get_table_with_size("VFCT", 1, &hdr, &tbl_size)))
262d38ceaf9SAlex Deucher 		return false;
263d38ceaf9SAlex Deucher 	if (tbl_size < sizeof(UEFI_ACPI_VFCT)) {
264d38ceaf9SAlex Deucher 		DRM_ERROR("ACPI VFCT table present but broken (too short #1)\n");
265d38ceaf9SAlex Deucher 		goto out_unmap;
266d38ceaf9SAlex Deucher 	}
267d38ceaf9SAlex Deucher 
268d38ceaf9SAlex Deucher 	vfct = (UEFI_ACPI_VFCT *)hdr;
269d38ceaf9SAlex Deucher 	if (vfct->VBIOSImageOffset + sizeof(VFCT_IMAGE_HEADER) > tbl_size) {
270d38ceaf9SAlex Deucher 		DRM_ERROR("ACPI VFCT table present but broken (too short #2)\n");
271d38ceaf9SAlex Deucher 		goto out_unmap;
272d38ceaf9SAlex Deucher 	}
273d38ceaf9SAlex Deucher 
274d38ceaf9SAlex Deucher 	vbios = (GOP_VBIOS_CONTENT *)((char *)hdr + vfct->VBIOSImageOffset);
275d38ceaf9SAlex Deucher 	vhdr = &vbios->VbiosHeader;
276d38ceaf9SAlex Deucher 	DRM_INFO("ACPI VFCT contains a BIOS for %02x:%02x.%d %04x:%04x, size %d\n",
277d38ceaf9SAlex Deucher 			vhdr->PCIBus, vhdr->PCIDevice, vhdr->PCIFunction,
278d38ceaf9SAlex Deucher 			vhdr->VendorID, vhdr->DeviceID, vhdr->ImageLength);
279d38ceaf9SAlex Deucher 
280d38ceaf9SAlex Deucher 	if (vhdr->PCIBus != adev->pdev->bus->number ||
281d38ceaf9SAlex Deucher 	    vhdr->PCIDevice != PCI_SLOT(adev->pdev->devfn) ||
282d38ceaf9SAlex Deucher 	    vhdr->PCIFunction != PCI_FUNC(adev->pdev->devfn) ||
283d38ceaf9SAlex Deucher 	    vhdr->VendorID != adev->pdev->vendor ||
284d38ceaf9SAlex Deucher 	    vhdr->DeviceID != adev->pdev->device) {
285d38ceaf9SAlex Deucher 		DRM_INFO("ACPI VFCT table is not for this card\n");
286d38ceaf9SAlex Deucher 		goto out_unmap;
287d38ceaf9SAlex Deucher 	}
288d38ceaf9SAlex Deucher 
289d38ceaf9SAlex Deucher 	if (vfct->VBIOSImageOffset + sizeof(VFCT_IMAGE_HEADER) + vhdr->ImageLength > tbl_size) {
290d38ceaf9SAlex Deucher 		DRM_ERROR("ACPI VFCT image truncated\n");
291d38ceaf9SAlex Deucher 		goto out_unmap;
292d38ceaf9SAlex Deucher 	}
293d38ceaf9SAlex Deucher 
294d38ceaf9SAlex Deucher 	adev->bios = kmemdup(&vbios->VbiosContent, vhdr->ImageLength, GFP_KERNEL);
295d38ceaf9SAlex Deucher 	ret = !!adev->bios;
296d38ceaf9SAlex Deucher 
297d38ceaf9SAlex Deucher out_unmap:
298d38ceaf9SAlex Deucher 	return ret;
299d38ceaf9SAlex Deucher }
300d38ceaf9SAlex Deucher #else
301d38ceaf9SAlex Deucher static inline bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)
302d38ceaf9SAlex Deucher {
303d38ceaf9SAlex Deucher 	return false;
304d38ceaf9SAlex Deucher }
305d38ceaf9SAlex Deucher #endif
306d38ceaf9SAlex Deucher 
307d38ceaf9SAlex Deucher bool amdgpu_get_bios(struct amdgpu_device *adev)
308d38ceaf9SAlex Deucher {
309d38ceaf9SAlex Deucher 	bool r;
310d38ceaf9SAlex Deucher 	uint16_t tmp;
311d38ceaf9SAlex Deucher 
312d38ceaf9SAlex Deucher 	r = amdgpu_atrm_get_bios(adev);
313d38ceaf9SAlex Deucher 	if (r == false)
314d38ceaf9SAlex Deucher 		r = amdgpu_acpi_vfct_bios(adev);
315d38ceaf9SAlex Deucher 	if (r == false)
316d38ceaf9SAlex Deucher 		r = igp_read_bios_from_vram(adev);
317d38ceaf9SAlex Deucher 	if (r == false)
318d38ceaf9SAlex Deucher 		r = amdgpu_read_bios(adev);
319d38ceaf9SAlex Deucher 	if (r == false) {
320d38ceaf9SAlex Deucher 		r = amdgpu_read_disabled_bios(adev);
321d38ceaf9SAlex Deucher 	}
322d38ceaf9SAlex Deucher 	if (r == false) {
323d38ceaf9SAlex Deucher 		r = amdgpu_read_platform_bios(adev);
324d38ceaf9SAlex Deucher 	}
325d38ceaf9SAlex Deucher 	if (r == false || adev->bios == NULL) {
326d38ceaf9SAlex Deucher 		DRM_ERROR("Unable to locate a BIOS ROM\n");
327d38ceaf9SAlex Deucher 		adev->bios = NULL;
328d38ceaf9SAlex Deucher 		return false;
329d38ceaf9SAlex Deucher 	}
330d38ceaf9SAlex Deucher 	if (adev->bios[0] != 0x55 || adev->bios[1] != 0xaa) {
331d38ceaf9SAlex Deucher 		printk("BIOS signature incorrect %x %x\n", adev->bios[0], adev->bios[1]);
332d38ceaf9SAlex Deucher 		goto free_bios;
333d38ceaf9SAlex Deucher 	}
334d38ceaf9SAlex Deucher 
335d38ceaf9SAlex Deucher 	tmp = RBIOS16(0x18);
336d38ceaf9SAlex Deucher 	if (RBIOS8(tmp + 0x14) != 0x0) {
337d38ceaf9SAlex Deucher 		DRM_INFO("Not an x86 BIOS ROM, not using.\n");
338d38ceaf9SAlex Deucher 		goto free_bios;
339d38ceaf9SAlex Deucher 	}
340d38ceaf9SAlex Deucher 
341d38ceaf9SAlex Deucher 	adev->bios_header_start = RBIOS16(0x48);
342d38ceaf9SAlex Deucher 	if (!adev->bios_header_start) {
343d38ceaf9SAlex Deucher 		goto free_bios;
344d38ceaf9SAlex Deucher 	}
345d38ceaf9SAlex Deucher 	tmp = adev->bios_header_start + 4;
346d38ceaf9SAlex Deucher 	if (!memcmp(adev->bios + tmp, "ATOM", 4) ||
347d38ceaf9SAlex Deucher 	    !memcmp(adev->bios + tmp, "MOTA", 4)) {
348d38ceaf9SAlex Deucher 		adev->is_atom_bios = true;
349d38ceaf9SAlex Deucher 	} else {
350d38ceaf9SAlex Deucher 		adev->is_atom_bios = false;
351d38ceaf9SAlex Deucher 	}
352d38ceaf9SAlex Deucher 
353d38ceaf9SAlex Deucher 	DRM_DEBUG("%sBIOS detected\n", adev->is_atom_bios ? "ATOM" : "COM");
354d38ceaf9SAlex Deucher 	return true;
355d38ceaf9SAlex Deucher free_bios:
356d38ceaf9SAlex Deucher 	kfree(adev->bios);
357d38ceaf9SAlex Deucher 	adev->bios = NULL;
358d38ceaf9SAlex Deucher 	return false;
359d38ceaf9SAlex Deucher }
360