xref: /dflybsd-src/sys/dev/drm/amd/amdgpu/amdgpu_bios.c (revision 789731325bde747251c28a37e0a00ed4efb88c46)
1b843c749SSergey Zigachev /*
2b843c749SSergey Zigachev  * Copyright 2008 Advanced Micro Devices, Inc.
3b843c749SSergey Zigachev  * Copyright 2008 Red Hat Inc.
4b843c749SSergey Zigachev  * Copyright 2009 Jerome Glisse.
5b843c749SSergey Zigachev  *
6b843c749SSergey Zigachev  * Permission is hereby granted, free of charge, to any person obtaining a
7b843c749SSergey Zigachev  * copy of this software and associated documentation files (the "Software"),
8b843c749SSergey Zigachev  * to deal in the Software without restriction, including without limitation
9b843c749SSergey Zigachev  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10b843c749SSergey Zigachev  * and/or sell copies of the Software, and to permit persons to whom the
11b843c749SSergey Zigachev  * Software is furnished to do so, subject to the following conditions:
12b843c749SSergey Zigachev  *
13b843c749SSergey Zigachev  * The above copyright notice and this permission notice shall be included in
14b843c749SSergey Zigachev  * all copies or substantial portions of the Software.
15b843c749SSergey Zigachev  *
16b843c749SSergey Zigachev  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17b843c749SSergey Zigachev  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18b843c749SSergey Zigachev  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19b843c749SSergey Zigachev  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
20b843c749SSergey Zigachev  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21b843c749SSergey Zigachev  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22b843c749SSergey Zigachev  * OTHER DEALINGS IN THE SOFTWARE.
23b843c749SSergey Zigachev  *
24b843c749SSergey Zigachev  * Authors: Dave Airlie
25b843c749SSergey Zigachev  *          Alex Deucher
26b843c749SSergey Zigachev  *          Jerome Glisse
27b843c749SSergey Zigachev  */
28b843c749SSergey Zigachev #include <drm/drmP.h>
29b843c749SSergey Zigachev #include "amdgpu.h"
30b843c749SSergey Zigachev #include "atom.h"
31b843c749SSergey Zigachev 
32b843c749SSergey Zigachev #include <linux/slab.h>
33b843c749SSergey Zigachev #include <linux/acpi.h>
34b843c749SSergey Zigachev /*
35b843c749SSergey Zigachev  * BIOS.
36b843c749SSergey Zigachev  */
37b843c749SSergey Zigachev 
38b843c749SSergey Zigachev #define AMD_VBIOS_SIGNATURE " 761295520"
39b843c749SSergey Zigachev #define AMD_VBIOS_SIGNATURE_OFFSET 0x30
40b843c749SSergey Zigachev #define AMD_VBIOS_SIGNATURE_SIZE sizeof(AMD_VBIOS_SIGNATURE)
41b843c749SSergey Zigachev #define AMD_VBIOS_SIGNATURE_END (AMD_VBIOS_SIGNATURE_OFFSET + AMD_VBIOS_SIGNATURE_SIZE)
42b843c749SSergey Zigachev #define AMD_IS_VALID_VBIOS(p) ((p)[0] == 0x55 && (p)[1] == 0xAA)
43b843c749SSergey Zigachev #define AMD_VBIOS_LENGTH(p) ((p)[2] << 9)
44b843c749SSergey Zigachev 
45b843c749SSergey Zigachev /* Check if current bios is an ATOM BIOS.
46b843c749SSergey Zigachev  * Return true if it is ATOM BIOS. Otherwise, return false.
47b843c749SSergey Zigachev  */
check_atom_bios(uint8_t * bios,size_t size)48b843c749SSergey Zigachev static bool check_atom_bios(uint8_t *bios, size_t size)
49b843c749SSergey Zigachev {
50b843c749SSergey Zigachev 	uint16_t tmp, bios_header_start;
51b843c749SSergey Zigachev 
52b843c749SSergey Zigachev 	if (!bios || size < 0x49) {
53b843c749SSergey Zigachev 		DRM_INFO("vbios mem is null or mem size is wrong\n");
54b843c749SSergey Zigachev 		return false;
55b843c749SSergey Zigachev 	}
56b843c749SSergey Zigachev 
57b843c749SSergey Zigachev 	if (!AMD_IS_VALID_VBIOS(bios)) {
58b843c749SSergey Zigachev 		DRM_INFO("BIOS signature incorrect %x %x\n", bios[0], bios[1]);
59b843c749SSergey Zigachev 		return false;
60b843c749SSergey Zigachev 	}
61b843c749SSergey Zigachev 
62b843c749SSergey Zigachev 	bios_header_start = bios[0x48] | (bios[0x49] << 8);
63b843c749SSergey Zigachev 	if (!bios_header_start) {
64b843c749SSergey Zigachev 		DRM_INFO("Can't locate bios header\n");
65b843c749SSergey Zigachev 		return false;
66b843c749SSergey Zigachev 	}
67b843c749SSergey Zigachev 
68b843c749SSergey Zigachev 	tmp = bios_header_start + 4;
69b843c749SSergey Zigachev 	if (size < tmp) {
70b843c749SSergey Zigachev 		DRM_INFO("BIOS header is broken\n");
71b843c749SSergey Zigachev 		return false;
72b843c749SSergey Zigachev 	}
73b843c749SSergey Zigachev 
74b843c749SSergey Zigachev 	if (!memcmp(bios + tmp, "ATOM", 4) ||
75b843c749SSergey Zigachev 	    !memcmp(bios + tmp, "MOTA", 4)) {
76b843c749SSergey Zigachev 		DRM_DEBUG("ATOMBIOS detected\n");
77b843c749SSergey Zigachev 		return true;
78b843c749SSergey Zigachev 	}
79b843c749SSergey Zigachev 
80b843c749SSergey Zigachev 	return false;
81b843c749SSergey Zigachev }
82b843c749SSergey Zigachev 
83b843c749SSergey Zigachev /* If you boot an IGP board with a discrete card as the primary,
84b843c749SSergey Zigachev  * the IGP rom is not accessible via the rom bar as the IGP rom is
85b843c749SSergey Zigachev  * part of the system bios.  On boot, the system bios puts a
86b843c749SSergey Zigachev  * copy of the igp rom at the start of vram if a discrete card is
87b843c749SSergey Zigachev  * present.
88b843c749SSergey Zigachev  */
igp_read_bios_from_vram(struct amdgpu_device * adev)89b843c749SSergey Zigachev static bool igp_read_bios_from_vram(struct amdgpu_device *adev)
90b843c749SSergey Zigachev {
91b843c749SSergey Zigachev 	uint8_t __iomem *bios;
92b843c749SSergey Zigachev 	resource_size_t vram_base;
93b843c749SSergey Zigachev 	resource_size_t size = 256 * 1024; /* ??? */
94b843c749SSergey Zigachev 
95b843c749SSergey Zigachev 	if (!(adev->flags & AMD_IS_APU))
96b843c749SSergey Zigachev 		if (amdgpu_device_need_post(adev))
97b843c749SSergey Zigachev 			return false;
98b843c749SSergey Zigachev 
99b843c749SSergey Zigachev 	adev->bios = NULL;
100b843c749SSergey Zigachev 	vram_base = pci_resource_start(adev->pdev, 0);
101b843c749SSergey Zigachev 	bios = ioremap_wc(vram_base, size);
102b843c749SSergey Zigachev 	if (!bios) {
103b843c749SSergey Zigachev 		return false;
104b843c749SSergey Zigachev 	}
105b843c749SSergey Zigachev 
106*78973132SSergey Zigachev 	adev->bios = kmalloc(size, M_DRM, GFP_KERNEL);
107b843c749SSergey Zigachev 	if (!adev->bios) {
108b843c749SSergey Zigachev 		iounmap(bios);
109b843c749SSergey Zigachev 		return false;
110b843c749SSergey Zigachev 	}
111b843c749SSergey Zigachev 	adev->bios_size = size;
112b843c749SSergey Zigachev 	memcpy_fromio(adev->bios, bios, size);
113b843c749SSergey Zigachev 	iounmap(bios);
114b843c749SSergey Zigachev 
115b843c749SSergey Zigachev 	if (!check_atom_bios(adev->bios, size)) {
116b843c749SSergey Zigachev 		kfree(adev->bios);
117b843c749SSergey Zigachev 		return false;
118b843c749SSergey Zigachev 	}
119b843c749SSergey Zigachev 
120b843c749SSergey Zigachev 	return true;
121b843c749SSergey Zigachev }
122b843c749SSergey Zigachev 
amdgpu_read_bios(struct amdgpu_device * adev)123b843c749SSergey Zigachev bool amdgpu_read_bios(struct amdgpu_device *adev)
124b843c749SSergey Zigachev {
125b843c749SSergey Zigachev 	uint8_t __iomem *bios;
126b843c749SSergey Zigachev 	size_t size;
127b843c749SSergey Zigachev 
128b843c749SSergey Zigachev 	adev->bios = NULL;
129b843c749SSergey Zigachev 	/* XXX: some cards may return 0 for rom size? ddx has a workaround */
130b843c749SSergey Zigachev 	bios = pci_map_rom(adev->pdev, &size);
131b843c749SSergey Zigachev 	if (!bios) {
132b843c749SSergey Zigachev 		return false;
133b843c749SSergey Zigachev 	}
134b843c749SSergey Zigachev 
135b843c749SSergey Zigachev 	adev->bios = kzalloc(size, GFP_KERNEL);
136b843c749SSergey Zigachev 	if (adev->bios == NULL) {
137b843c749SSergey Zigachev 		pci_unmap_rom(adev->pdev, bios);
138b843c749SSergey Zigachev 		return false;
139b843c749SSergey Zigachev 	}
140b843c749SSergey Zigachev 	adev->bios_size = size;
141b843c749SSergey Zigachev 	memcpy_fromio(adev->bios, bios, size);
142b843c749SSergey Zigachev 	pci_unmap_rom(adev->pdev, bios);
143b843c749SSergey Zigachev 
144b843c749SSergey Zigachev 	if (!check_atom_bios(adev->bios, size)) {
145b843c749SSergey Zigachev 		kfree(adev->bios);
146b843c749SSergey Zigachev 		return false;
147b843c749SSergey Zigachev 	}
148b843c749SSergey Zigachev 
149b843c749SSergey Zigachev 	return true;
150b843c749SSergey Zigachev }
151b843c749SSergey Zigachev 
amdgpu_read_bios_from_rom(struct amdgpu_device * adev)152b843c749SSergey Zigachev static bool amdgpu_read_bios_from_rom(struct amdgpu_device *adev)
153b843c749SSergey Zigachev {
154b843c749SSergey Zigachev 	u8 header[AMD_VBIOS_SIGNATURE_END+1] = {0};
155b843c749SSergey Zigachev 	int len;
156b843c749SSergey Zigachev 
157b843c749SSergey Zigachev 	if (!adev->asic_funcs->read_bios_from_rom)
158b843c749SSergey Zigachev 		return false;
159b843c749SSergey Zigachev 
160b843c749SSergey Zigachev 	/* validate VBIOS signature */
161b843c749SSergey Zigachev 	if (amdgpu_asic_read_bios_from_rom(adev, &header[0], sizeof(header)) == false)
162b843c749SSergey Zigachev 		return false;
163b843c749SSergey Zigachev 	header[AMD_VBIOS_SIGNATURE_END] = 0;
164b843c749SSergey Zigachev 
165b843c749SSergey Zigachev 	if ((!AMD_IS_VALID_VBIOS(header)) ||
166b843c749SSergey Zigachev 	    0 != memcmp((char *)&header[AMD_VBIOS_SIGNATURE_OFFSET],
167b843c749SSergey Zigachev 			AMD_VBIOS_SIGNATURE,
168b843c749SSergey Zigachev 			strlen(AMD_VBIOS_SIGNATURE)))
169b843c749SSergey Zigachev 		return false;
170b843c749SSergey Zigachev 
171b843c749SSergey Zigachev 	/* valid vbios, go on */
172b843c749SSergey Zigachev 	len = AMD_VBIOS_LENGTH(header);
173b843c749SSergey Zigachev 	len = ALIGN(len, 4);
174*78973132SSergey Zigachev 	adev->bios = kmalloc(len, M_DRM, GFP_KERNEL);
175b843c749SSergey Zigachev 	if (!adev->bios) {
176b843c749SSergey Zigachev 		DRM_ERROR("no memory to allocate for BIOS\n");
177b843c749SSergey Zigachev 		return false;
178b843c749SSergey Zigachev 	}
179b843c749SSergey Zigachev 	adev->bios_size = len;
180b843c749SSergey Zigachev 
181b843c749SSergey Zigachev 	/* read complete BIOS */
182b843c749SSergey Zigachev 	amdgpu_asic_read_bios_from_rom(adev, adev->bios, len);
183b843c749SSergey Zigachev 
184b843c749SSergey Zigachev 	if (!check_atom_bios(adev->bios, len)) {
185b843c749SSergey Zigachev 		kfree(adev->bios);
186b843c749SSergey Zigachev 		return false;
187b843c749SSergey Zigachev 	}
188b843c749SSergey Zigachev 
189b843c749SSergey Zigachev 	return true;
190b843c749SSergey Zigachev }
191b843c749SSergey Zigachev 
amdgpu_read_platform_bios(struct amdgpu_device * adev)192b843c749SSergey Zigachev static bool amdgpu_read_platform_bios(struct amdgpu_device *adev)
193b843c749SSergey Zigachev {
194*78973132SSergey Zigachev 	return false;
195*78973132SSergey Zigachev #if 0
196b843c749SSergey Zigachev 	phys_addr_t rom = adev->pdev->rom;
197b843c749SSergey Zigachev 	size_t romlen = adev->pdev->romlen;
198b843c749SSergey Zigachev 	void __iomem *bios;
199b843c749SSergey Zigachev 
200b843c749SSergey Zigachev 	adev->bios = NULL;
201b843c749SSergey Zigachev 
202b843c749SSergey Zigachev 	if (!rom || romlen == 0)
203b843c749SSergey Zigachev 		return false;
204b843c749SSergey Zigachev 
205b843c749SSergey Zigachev 	adev->bios = kzalloc(romlen, GFP_KERNEL);
206b843c749SSergey Zigachev 	if (!adev->bios)
207b843c749SSergey Zigachev 		return false;
208b843c749SSergey Zigachev 
209b843c749SSergey Zigachev 	bios = ioremap(rom, romlen);
210b843c749SSergey Zigachev 	if (!bios)
211b843c749SSergey Zigachev 		goto free_bios;
212b843c749SSergey Zigachev 
213b843c749SSergey Zigachev 	memcpy_fromio(adev->bios, bios, romlen);
214b843c749SSergey Zigachev 	iounmap(bios);
215b843c749SSergey Zigachev 
216b843c749SSergey Zigachev 	if (!check_atom_bios(adev->bios, romlen))
217b843c749SSergey Zigachev 		goto free_bios;
218b843c749SSergey Zigachev 
219b843c749SSergey Zigachev 	adev->bios_size = romlen;
220b843c749SSergey Zigachev 
221b843c749SSergey Zigachev 	return true;
222b843c749SSergey Zigachev free_bios:
223b843c749SSergey Zigachev 	kfree(adev->bios);
224b843c749SSergey Zigachev 	return false;
225*78973132SSergey Zigachev #endif
226b843c749SSergey Zigachev }
227b843c749SSergey Zigachev 
228b843c749SSergey Zigachev #ifdef CONFIG_ACPI
229b843c749SSergey Zigachev /* ATRM is used to get the BIOS on the discrete cards in
230b843c749SSergey Zigachev  * dual-gpu systems.
231b843c749SSergey Zigachev  */
232b843c749SSergey Zigachev /* retrieve the ROM in 4k blocks */
233b843c749SSergey Zigachev #define ATRM_BIOS_PAGE 4096
234b843c749SSergey Zigachev /**
235b843c749SSergey Zigachev  * amdgpu_atrm_call - fetch a chunk of the vbios
236b843c749SSergey Zigachev  *
237b843c749SSergey Zigachev  * @atrm_handle: acpi ATRM handle
238b843c749SSergey Zigachev  * @bios: vbios image pointer
239b843c749SSergey Zigachev  * @offset: offset of vbios image data to fetch
240b843c749SSergey Zigachev  * @len: length of vbios image data to fetch
241b843c749SSergey Zigachev  *
242b843c749SSergey Zigachev  * Executes ATRM to fetch a chunk of the discrete
243b843c749SSergey Zigachev  * vbios image on PX systems (all asics).
244b843c749SSergey Zigachev  * Returns the length of the buffer fetched.
245b843c749SSergey Zigachev  */
amdgpu_atrm_call(ACPI_HANDLE atrm_handle,uint8_t * bios,int offset,int len)246*78973132SSergey Zigachev static int amdgpu_atrm_call(ACPI_HANDLE atrm_handle, uint8_t *bios,
247b843c749SSergey Zigachev 			    int offset, int len)
248b843c749SSergey Zigachev {
249*78973132SSergey Zigachev 	ACPI_STATUS status;
250*78973132SSergey Zigachev 	ACPI_OBJECT atrm_arg_elements[2], *obj;
251*78973132SSergey Zigachev 	ACPI_OBJECT_LIST atrm_arg;
252*78973132SSergey Zigachev 	ACPI_BUFFER buffer = { ACPI_ALLOCATE_BUFFER, NULL};
253b843c749SSergey Zigachev 
254*78973132SSergey Zigachev 	atrm_arg.Count = 2;
255*78973132SSergey Zigachev 	atrm_arg.Pointer = &atrm_arg_elements[0];
256b843c749SSergey Zigachev 
257*78973132SSergey Zigachev 	atrm_arg_elements[0].Type = ACPI_TYPE_INTEGER;
258*78973132SSergey Zigachev 	atrm_arg_elements[0].Integer.Value = offset;
259b843c749SSergey Zigachev 
260*78973132SSergey Zigachev 	atrm_arg_elements[1].Type = ACPI_TYPE_INTEGER;
261*78973132SSergey Zigachev 	atrm_arg_elements[1].Integer.Value = len;
262b843c749SSergey Zigachev 
263*78973132SSergey Zigachev 	status = AcpiEvaluateObject(atrm_handle, NULL, &atrm_arg, &buffer);
264b843c749SSergey Zigachev 	if (ACPI_FAILURE(status)) {
265*78973132SSergey Zigachev 		printk("failed to evaluate ATRM got %s\n", AcpiFormatException(status));
266b843c749SSergey Zigachev 		return -ENODEV;
267b843c749SSergey Zigachev 	}
268b843c749SSergey Zigachev 
269*78973132SSergey Zigachev 	obj = (ACPI_OBJECT *)buffer.Pointer;
270*78973132SSergey Zigachev 	memcpy(bios+offset, obj->Buffer.Pointer, obj->Buffer.Length);
271*78973132SSergey Zigachev 	len = obj->Buffer.Length;
272*78973132SSergey Zigachev 	AcpiOsFree(buffer.Pointer);
273b843c749SSergey Zigachev 	return len;
274b843c749SSergey Zigachev }
275b843c749SSergey Zigachev 
amdgpu_atrm_get_bios(struct amdgpu_device * adev)276b843c749SSergey Zigachev static bool amdgpu_atrm_get_bios(struct amdgpu_device *adev)
277b843c749SSergey Zigachev {
278b843c749SSergey Zigachev 	int ret;
279b843c749SSergey Zigachev 	int size = 256 * 1024;
280b843c749SSergey Zigachev 	int i;
281*78973132SSergey Zigachev 	device_t dev;
282*78973132SSergey Zigachev 	ACPI_HANDLE dhandle, atrm_handle;
283*78973132SSergey Zigachev 	ACPI_STATUS status;
284b843c749SSergey Zigachev 	bool found = false;
285b843c749SSergey Zigachev 
286b843c749SSergey Zigachev 	/* ATRM is for the discrete card only */
287b843c749SSergey Zigachev 	if (adev->flags & AMD_IS_APU)
288b843c749SSergey Zigachev 		return false;
289b843c749SSergey Zigachev 
290*78973132SSergey Zigachev #if 0
291b843c749SSergey Zigachev 	while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
292*78973132SSergey Zigachev #endif
293*78973132SSergey Zigachev 	if ((dev = pci_find_class(PCIC_DISPLAY, PCIS_DISPLAY_VGA)) != NULL) {
294*78973132SSergey Zigachev 		DRM_INFO("%s: pci_find_class() found: %d:%d:%d:%d, vendor=%04x, device=%04x\n",
295*78973132SSergey Zigachev 		    __func__,
296*78973132SSergey Zigachev 		    pci_get_domain(dev),
297*78973132SSergey Zigachev 		    pci_get_bus(dev),
298*78973132SSergey Zigachev 		    pci_get_slot(dev),
299*78973132SSergey Zigachev 		    pci_get_function(dev),
300*78973132SSergey Zigachev 		    pci_get_vendor(dev),
301*78973132SSergey Zigachev 		    pci_get_device(dev));
302*78973132SSergey Zigachev 		DRM_INFO("%s: Get ACPI device handle\n", __func__);
303*78973132SSergey Zigachev 		dhandle = acpi_get_handle(dev);
304b843c749SSergey Zigachev 		if (!dhandle)
305*78973132SSergey Zigachev #ifndef __DragonFly__
306b843c749SSergey Zigachev  			continue;
307*78973132SSergey Zigachev #else
308*78973132SSergey Zigachev 			return false;
309*78973132SSergey Zigachev #endif
310b843c749SSergey Zigachev 
311*78973132SSergey Zigachev 		DRM_INFO("%s: Get ACPI handle for \"ATRM\"\n", __func__);
312*78973132SSergey Zigachev 		status = AcpiGetHandle(dhandle, "ATRM", &atrm_handle);
313b843c749SSergey Zigachev 		if (!ACPI_FAILURE(status)) {
314b843c749SSergey Zigachev 			found = true;
315*78973132SSergey Zigachev #if 0
316b843c749SSergey Zigachev 			break;
317*78973132SSergey Zigachev #endif
318*78973132SSergey Zigachev 		} else {
319*78973132SSergey Zigachev 			DRM_INFO("%s: Failed to get \"ATRM\" handle: %s\n",
320*78973132SSergey Zigachev 			    __func__, AcpiFormatException(status));
321b843c749SSergey Zigachev 		}
322b843c749SSergey Zigachev 	}
323b843c749SSergey Zigachev 
324*78973132SSergey Zigachev #if 0
325b843c749SSergey Zigachev 	if (!found) {
326b843c749SSergey Zigachev 		while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_OTHER << 8, pdev)) != NULL) {
327b843c749SSergey Zigachev 			dhandle = ACPI_HANDLE(&pdev->dev);
328b843c749SSergey Zigachev 			if (!dhandle)
329b843c749SSergey Zigachev 				continue;
330b843c749SSergey Zigachev 
331b843c749SSergey Zigachev 			status = acpi_get_handle(dhandle, "ATRM", &atrm_handle);
332b843c749SSergey Zigachev 			if (!ACPI_FAILURE(status)) {
333b843c749SSergey Zigachev 				found = true;
334b843c749SSergey Zigachev 				break;
335b843c749SSergey Zigachev 			}
336b843c749SSergey Zigachev 		}
337b843c749SSergey Zigachev 	}
338*78973132SSergey Zigachev #endif
339b843c749SSergey Zigachev 
340b843c749SSergey Zigachev 	if (!found)
341b843c749SSergey Zigachev 		return false;
342b843c749SSergey Zigachev 
343*78973132SSergey Zigachev 	adev->bios = kmalloc(size, M_DRM, GFP_KERNEL);
344b843c749SSergey Zigachev 	if (!adev->bios) {
345b843c749SSergey Zigachev 		DRM_ERROR("Unable to allocate bios\n");
346b843c749SSergey Zigachev 		return false;
347b843c749SSergey Zigachev 	}
348b843c749SSergey Zigachev 
349b843c749SSergey Zigachev 	for (i = 0; i < size / ATRM_BIOS_PAGE; i++) {
350b843c749SSergey Zigachev 		ret = amdgpu_atrm_call(atrm_handle,
351b843c749SSergey Zigachev 				       adev->bios,
352b843c749SSergey Zigachev 				       (i * ATRM_BIOS_PAGE),
353b843c749SSergey Zigachev 				       ATRM_BIOS_PAGE);
354b843c749SSergey Zigachev 		if (ret < ATRM_BIOS_PAGE)
355b843c749SSergey Zigachev 			break;
356b843c749SSergey Zigachev 	}
357b843c749SSergey Zigachev 
358b843c749SSergey Zigachev 	if (!check_atom_bios(adev->bios, size)) {
359b843c749SSergey Zigachev 		kfree(adev->bios);
360b843c749SSergey Zigachev 		return false;
361b843c749SSergey Zigachev 	}
362b843c749SSergey Zigachev 	adev->bios_size = size;
363b843c749SSergey Zigachev 	return true;
364b843c749SSergey Zigachev }
365b843c749SSergey Zigachev #else
366b843c749SSergey Zigachev static inline bool amdgpu_atrm_get_bios(struct amdgpu_device *adev)
367b843c749SSergey Zigachev {
368b843c749SSergey Zigachev 	return false;
369b843c749SSergey Zigachev }
370b843c749SSergey Zigachev #endif
371b843c749SSergey Zigachev 
372b843c749SSergey Zigachev static bool amdgpu_read_disabled_bios(struct amdgpu_device *adev)
373b843c749SSergey Zigachev {
374b843c749SSergey Zigachev 	if (adev->flags & AMD_IS_APU)
375b843c749SSergey Zigachev 		return igp_read_bios_from_vram(adev);
376b843c749SSergey Zigachev 	else
377b843c749SSergey Zigachev 		return amdgpu_asic_read_disabled_bios(adev);
378b843c749SSergey Zigachev }
379b843c749SSergey Zigachev 
380b843c749SSergey Zigachev #ifdef CONFIG_ACPI
381b843c749SSergey Zigachev static bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)
382b843c749SSergey Zigachev {
383*78973132SSergey Zigachev 	ACPI_TABLE_HEADER *hdr;
384*78973132SSergey Zigachev 	ACPI_SIZE tbl_size;
385b843c749SSergey Zigachev 	UEFI_ACPI_VFCT *vfct;
386b843c749SSergey Zigachev 	unsigned offset;
387*78973132SSergey Zigachev 	ACPI_STATUS status;
388b843c749SSergey Zigachev 
389*78973132SSergey Zigachev #ifndef __DragonFly__
390*78973132SSergey Zigachev  	if (!ACPI_SUCCESS(acpi_get_table_with_size("VFCT", 1, &hdr, &tbl_size)))
391b843c749SSergey Zigachev  		return false;
392*78973132SSergey Zigachev #else
393*78973132SSergey Zigachev 	status = AcpiGetTable("VFCT", 1, &hdr);
394*78973132SSergey Zigachev 	if (!ACPI_SUCCESS(status))
395*78973132SSergey Zigachev 		return false;
396*78973132SSergey Zigachev #endif
397*78973132SSergey Zigachev 	tbl_size = hdr->Length;
398b843c749SSergey Zigachev 	if (tbl_size < sizeof(UEFI_ACPI_VFCT)) {
399b843c749SSergey Zigachev 		DRM_ERROR("ACPI VFCT table present but broken (too short #1)\n");
400b843c749SSergey Zigachev 		return false;
401b843c749SSergey Zigachev 	}
402b843c749SSergey Zigachev 
403b843c749SSergey Zigachev 	vfct = (UEFI_ACPI_VFCT *)hdr;
404b843c749SSergey Zigachev 	offset = vfct->VBIOSImageOffset;
405b843c749SSergey Zigachev 
406b843c749SSergey Zigachev 	while (offset < tbl_size) {
407b843c749SSergey Zigachev 		GOP_VBIOS_CONTENT *vbios = (GOP_VBIOS_CONTENT *)((char *)hdr + offset);
408b843c749SSergey Zigachev 		VFCT_IMAGE_HEADER *vhdr = &vbios->VbiosHeader;
409b843c749SSergey Zigachev 
410b843c749SSergey Zigachev 		offset += sizeof(VFCT_IMAGE_HEADER);
411b843c749SSergey Zigachev 		if (offset > tbl_size) {
412b843c749SSergey Zigachev 			DRM_ERROR("ACPI VFCT image header truncated\n");
413b843c749SSergey Zigachev 			return false;
414b843c749SSergey Zigachev 		}
415b843c749SSergey Zigachev 
416b843c749SSergey Zigachev 		offset += vhdr->ImageLength;
417b843c749SSergey Zigachev 		if (offset > tbl_size) {
418b843c749SSergey Zigachev 			DRM_ERROR("ACPI VFCT image truncated\n");
419b843c749SSergey Zigachev 			return false;
420b843c749SSergey Zigachev 		}
421b843c749SSergey Zigachev 
422b843c749SSergey Zigachev 		if (vhdr->ImageLength &&
423b843c749SSergey Zigachev 		    vhdr->PCIBus == adev->pdev->bus->number &&
424b843c749SSergey Zigachev 		    vhdr->PCIDevice == PCI_SLOT(adev->pdev->devfn) &&
425b843c749SSergey Zigachev 		    vhdr->PCIFunction == PCI_FUNC(adev->pdev->devfn) &&
426b843c749SSergey Zigachev 		    vhdr->VendorID == adev->pdev->vendor &&
427b843c749SSergey Zigachev 		    vhdr->DeviceID == adev->pdev->device) {
428b843c749SSergey Zigachev 			adev->bios = kmemdup(&vbios->VbiosContent,
429b843c749SSergey Zigachev 					     vhdr->ImageLength,
430b843c749SSergey Zigachev 					     GFP_KERNEL);
431b843c749SSergey Zigachev 
432b843c749SSergey Zigachev 			if (!check_atom_bios(adev->bios, vhdr->ImageLength)) {
433b843c749SSergey Zigachev 				kfree(adev->bios);
434b843c749SSergey Zigachev 				return false;
435b843c749SSergey Zigachev 			}
436b843c749SSergey Zigachev 			adev->bios_size = vhdr->ImageLength;
437b843c749SSergey Zigachev 			return true;
438b843c749SSergey Zigachev 		}
439b843c749SSergey Zigachev 	}
440b843c749SSergey Zigachev 
441b843c749SSergey Zigachev 	DRM_ERROR("ACPI VFCT table present but broken (too short #2)\n");
442b843c749SSergey Zigachev 	return false;
443b843c749SSergey Zigachev }
444b843c749SSergey Zigachev #else
445b843c749SSergey Zigachev static inline bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)
446b843c749SSergey Zigachev {
447b843c749SSergey Zigachev 	return false;
448b843c749SSergey Zigachev }
449b843c749SSergey Zigachev #endif
450b843c749SSergey Zigachev 
451b843c749SSergey Zigachev bool amdgpu_get_bios(struct amdgpu_device *adev)
452b843c749SSergey Zigachev {
453b843c749SSergey Zigachev 	if (amdgpu_atrm_get_bios(adev))
454b843c749SSergey Zigachev 		goto success;
455b843c749SSergey Zigachev 
456b843c749SSergey Zigachev 	if (amdgpu_acpi_vfct_bios(adev))
457b843c749SSergey Zigachev 		goto success;
458b843c749SSergey Zigachev 
459b843c749SSergey Zigachev 	if (igp_read_bios_from_vram(adev))
460b843c749SSergey Zigachev 		goto success;
461b843c749SSergey Zigachev 
462b843c749SSergey Zigachev 	if (amdgpu_read_bios(adev))
463b843c749SSergey Zigachev 		goto success;
464b843c749SSergey Zigachev 
465b843c749SSergey Zigachev 	if (amdgpu_read_bios_from_rom(adev))
466b843c749SSergey Zigachev 		goto success;
467b843c749SSergey Zigachev 
468b843c749SSergey Zigachev 	if (amdgpu_read_disabled_bios(adev))
469b843c749SSergey Zigachev 		goto success;
470b843c749SSergey Zigachev 
471b843c749SSergey Zigachev 	if (amdgpu_read_platform_bios(adev))
472b843c749SSergey Zigachev 		goto success;
473b843c749SSergey Zigachev 
474b843c749SSergey Zigachev 	DRM_ERROR("Unable to locate a BIOS ROM\n");
475b843c749SSergey Zigachev 	return false;
476b843c749SSergey Zigachev 
477b843c749SSergey Zigachev success:
478b843c749SSergey Zigachev 	adev->is_atom_fw = (adev->asic_type >= CHIP_VEGA10) ? true : false;
479b843c749SSergey Zigachev 	return true;
480b843c749SSergey Zigachev }
481