1*e4a2ed4fSriastradh /* $NetBSD: amdgpu_bios.c,v 1.6 2022/02/27 14:23:24 riastradh Exp $ */
2efa246c0Sriastradh
3efa246c0Sriastradh /*
4efa246c0Sriastradh * Copyright 2008 Advanced Micro Devices, Inc.
5efa246c0Sriastradh * Copyright 2008 Red Hat Inc.
6efa246c0Sriastradh * Copyright 2009 Jerome Glisse.
7efa246c0Sriastradh *
8efa246c0Sriastradh * Permission is hereby granted, free of charge, to any person obtaining a
9efa246c0Sriastradh * copy of this software and associated documentation files (the "Software"),
10efa246c0Sriastradh * to deal in the Software without restriction, including without limitation
11efa246c0Sriastradh * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12efa246c0Sriastradh * and/or sell copies of the Software, and to permit persons to whom the
13efa246c0Sriastradh * Software is furnished to do so, subject to the following conditions:
14efa246c0Sriastradh *
15efa246c0Sriastradh * The above copyright notice and this permission notice shall be included in
16efa246c0Sriastradh * all copies or substantial portions of the Software.
17efa246c0Sriastradh *
18efa246c0Sriastradh * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19efa246c0Sriastradh * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20efa246c0Sriastradh * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21efa246c0Sriastradh * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
22efa246c0Sriastradh * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
23efa246c0Sriastradh * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24efa246c0Sriastradh * OTHER DEALINGS IN THE SOFTWARE.
25efa246c0Sriastradh *
26efa246c0Sriastradh * Authors: Dave Airlie
27efa246c0Sriastradh * Alex Deucher
28efa246c0Sriastradh * Jerome Glisse
29efa246c0Sriastradh */
30efa246c0Sriastradh
3141ec0267Sriastradh #include <sys/cdefs.h>
32*e4a2ed4fSriastradh __KERNEL_RCSID(0, "$NetBSD: amdgpu_bios.c,v 1.6 2022/02/27 14:23:24 riastradh Exp $");
3341ec0267Sriastradh
34efa246c0Sriastradh #include "amdgpu.h"
35efa246c0Sriastradh #include "atom.h"
36efa246c0Sriastradh
3741ec0267Sriastradh #include <linux/pci.h>
38efa246c0Sriastradh #include <linux/slab.h>
39efa246c0Sriastradh #include <linux/acpi.h>
40e4a580baSriastradh
41e4a580baSriastradh #include <linux/nbsd-namespace.h>
42*e4a2ed4fSriastradh #include <linux/nbsd-namespace-acpi.h>
43e4a580baSriastradh
44efa246c0Sriastradh /*
45efa246c0Sriastradh * BIOS.
46efa246c0Sriastradh */
47efa246c0Sriastradh
4841ec0267Sriastradh #define AMD_VBIOS_SIGNATURE " 761295520"
4941ec0267Sriastradh #define AMD_VBIOS_SIGNATURE_OFFSET 0x30
5041ec0267Sriastradh #define AMD_VBIOS_SIGNATURE_SIZE sizeof(AMD_VBIOS_SIGNATURE)
5141ec0267Sriastradh #define AMD_VBIOS_SIGNATURE_END (AMD_VBIOS_SIGNATURE_OFFSET + AMD_VBIOS_SIGNATURE_SIZE)
5241ec0267Sriastradh #define AMD_IS_VALID_VBIOS(p) ((p)[0] == 0x55 && (p)[1] == 0xAA)
5341ec0267Sriastradh #define AMD_VBIOS_LENGTH(p) ((p)[2] << 9)
5441ec0267Sriastradh
5541ec0267Sriastradh /* Check if current bios is an ATOM BIOS.
5641ec0267Sriastradh * Return true if it is ATOM BIOS. Otherwise, return false.
5741ec0267Sriastradh */
check_atom_bios(uint8_t * bios,size_t size)5841ec0267Sriastradh static bool check_atom_bios(uint8_t *bios, size_t size)
5941ec0267Sriastradh {
6041ec0267Sriastradh uint16_t tmp, bios_header_start;
6141ec0267Sriastradh
6241ec0267Sriastradh if (!bios || size < 0x49) {
6341ec0267Sriastradh DRM_INFO("vbios mem is null or mem size is wrong\n");
6441ec0267Sriastradh return false;
6541ec0267Sriastradh }
6641ec0267Sriastradh
6741ec0267Sriastradh if (!AMD_IS_VALID_VBIOS(bios)) {
6841ec0267Sriastradh DRM_INFO("BIOS signature incorrect %x %x\n", bios[0], bios[1]);
6941ec0267Sriastradh return false;
7041ec0267Sriastradh }
7141ec0267Sriastradh
7241ec0267Sriastradh bios_header_start = bios[0x48] | (bios[0x49] << 8);
7341ec0267Sriastradh if (!bios_header_start) {
7441ec0267Sriastradh DRM_INFO("Can't locate bios header\n");
7541ec0267Sriastradh return false;
7641ec0267Sriastradh }
7741ec0267Sriastradh
7841ec0267Sriastradh tmp = bios_header_start + 4;
7941ec0267Sriastradh if (size < tmp) {
8041ec0267Sriastradh DRM_INFO("BIOS header is broken\n");
8141ec0267Sriastradh return false;
8241ec0267Sriastradh }
8341ec0267Sriastradh
8441ec0267Sriastradh if (!memcmp(bios + tmp, "ATOM", 4) ||
8541ec0267Sriastradh !memcmp(bios + tmp, "MOTA", 4)) {
8641ec0267Sriastradh DRM_DEBUG("ATOMBIOS detected\n");
8741ec0267Sriastradh return true;
8841ec0267Sriastradh }
8941ec0267Sriastradh
9041ec0267Sriastradh return false;
9141ec0267Sriastradh }
9241ec0267Sriastradh
93efa246c0Sriastradh /* If you boot an IGP board with a discrete card as the primary,
94efa246c0Sriastradh * the IGP rom is not accessible via the rom bar as the IGP rom is
95efa246c0Sriastradh * part of the system bios. On boot, the system bios puts a
96efa246c0Sriastradh * copy of the igp rom at the start of vram if a discrete card is
97efa246c0Sriastradh * present.
98efa246c0Sriastradh */
igp_read_bios_from_vram(struct amdgpu_device * adev)99efa246c0Sriastradh static bool igp_read_bios_from_vram(struct amdgpu_device *adev)
100efa246c0Sriastradh {
1010d50c49dSriastradh #ifdef __NetBSD__
1020d50c49dSriastradh bus_space_tag_t bst;
1030d50c49dSriastradh bus_space_handle_t bsh;
1040d50c49dSriastradh bus_size_t size;
1050d50c49dSriastradh #else
106efa246c0Sriastradh uint8_t __iomem *bios;
107efa246c0Sriastradh resource_size_t vram_base;
108efa246c0Sriastradh resource_size_t size = 256 * 1024; /* ??? */
1090d50c49dSriastradh #endif
110efa246c0Sriastradh
111efa246c0Sriastradh if (!(adev->flags & AMD_IS_APU))
11241ec0267Sriastradh if (amdgpu_device_need_post(adev))
113efa246c0Sriastradh return false;
114efa246c0Sriastradh
115efa246c0Sriastradh adev->bios = NULL;
1160d50c49dSriastradh #ifdef __NetBSD__
1170d50c49dSriastradh if (pci_mapreg_map(&adev->pdev->pd_pa, PCI_BAR(0),
1180d50c49dSriastradh /* XXX Dunno what type to expect here; fill me in... */
1190d50c49dSriastradh pci_mapreg_type(adev->pdev->pd_pa.pa_pc,
1200d50c49dSriastradh adev->pdev->pd_pa.pa_tag, PCI_BAR(0)),
1210d50c49dSriastradh 0, &bst, &bsh, NULL, &size))
1220d50c49dSriastradh return false;
1230d50c49dSriastradh if ((size == 0) ||
1240d50c49dSriastradh (size < 256 * 1024) ||
1250d50c49dSriastradh (bus_space_read_1(bst, bsh, 0) != 0x55) ||
1260d50c49dSriastradh (bus_space_read_1(bst, bsh, 1) != 0xaa) ||
1270d50c49dSriastradh ((adev->bios = kmalloc(size, GFP_KERNEL)) == NULL)) {
1280d50c49dSriastradh bus_space_unmap(bst, bsh, size);
1290d50c49dSriastradh return false;
1300d50c49dSriastradh }
1310d50c49dSriastradh bus_space_read_region_1(bst, bsh, 0, adev->bios, size);
1320d50c49dSriastradh bus_space_unmap(bst, bsh, size);
1330d50c49dSriastradh #else
134efa246c0Sriastradh vram_base = pci_resource_start(adev->pdev, 0);
13541ec0267Sriastradh bios = ioremap_wc(vram_base, size);
136efa246c0Sriastradh if (!bios) {
137efa246c0Sriastradh return false;
138efa246c0Sriastradh }
139efa246c0Sriastradh
140efa246c0Sriastradh adev->bios = kmalloc(size, GFP_KERNEL);
14141ec0267Sriastradh if (!adev->bios) {
142efa246c0Sriastradh iounmap(bios);
143efa246c0Sriastradh return false;
144efa246c0Sriastradh }
14541ec0267Sriastradh adev->bios_size = size;
146efa246c0Sriastradh memcpy_fromio(adev->bios, bios, size);
147efa246c0Sriastradh iounmap(bios);
1480d50c49dSriastradh #endif
14941ec0267Sriastradh
15041ec0267Sriastradh if (!check_atom_bios(adev->bios, size)) {
15141ec0267Sriastradh kfree(adev->bios);
15241ec0267Sriastradh return false;
15341ec0267Sriastradh }
15441ec0267Sriastradh
155efa246c0Sriastradh return true;
156efa246c0Sriastradh }
157efa246c0Sriastradh
1580d50c49dSriastradh #ifdef __NetBSD__
1590d50c49dSriastradh # define __iomem __pci_rom_iomem
1600d50c49dSriastradh #endif
1610d50c49dSriastradh
amdgpu_read_bios(struct amdgpu_device * adev)162efa246c0Sriastradh bool amdgpu_read_bios(struct amdgpu_device *adev)
163efa246c0Sriastradh {
16441ec0267Sriastradh uint8_t __iomem *bios;
165efa246c0Sriastradh size_t size;
166efa246c0Sriastradh
167efa246c0Sriastradh adev->bios = NULL;
168efa246c0Sriastradh /* XXX: some cards may return 0 for rom size? ddx has a workaround */
169efa246c0Sriastradh bios = pci_map_rom(adev->pdev, &size);
170efa246c0Sriastradh if (!bios) {
171efa246c0Sriastradh return false;
172efa246c0Sriastradh }
173efa246c0Sriastradh
174efa246c0Sriastradh adev->bios = kzalloc(size, GFP_KERNEL);
175efa246c0Sriastradh if (adev->bios == NULL) {
176efa246c0Sriastradh pci_unmap_rom(adev->pdev, bios);
177efa246c0Sriastradh return false;
178efa246c0Sriastradh }
17941ec0267Sriastradh adev->bios_size = size;
180efa246c0Sriastradh memcpy_fromio(adev->bios, bios, size);
181efa246c0Sriastradh pci_unmap_rom(adev->pdev, bios);
18241ec0267Sriastradh
18341ec0267Sriastradh if (!check_atom_bios(adev->bios, size)) {
18441ec0267Sriastradh kfree(adev->bios);
18541ec0267Sriastradh return false;
18641ec0267Sriastradh }
18741ec0267Sriastradh
18841ec0267Sriastradh return true;
18941ec0267Sriastradh }
19041ec0267Sriastradh
amdgpu_read_bios_from_rom(struct amdgpu_device * adev)19141ec0267Sriastradh static bool amdgpu_read_bios_from_rom(struct amdgpu_device *adev)
19241ec0267Sriastradh {
19341ec0267Sriastradh u8 header[AMD_VBIOS_SIGNATURE_END+1] = {0};
19441ec0267Sriastradh int len;
19541ec0267Sriastradh
19641ec0267Sriastradh if (!adev->asic_funcs->read_bios_from_rom)
19741ec0267Sriastradh return false;
19841ec0267Sriastradh
19941ec0267Sriastradh /* validate VBIOS signature */
20041ec0267Sriastradh if (amdgpu_asic_read_bios_from_rom(adev, &header[0], sizeof(header)) == false)
20141ec0267Sriastradh return false;
20241ec0267Sriastradh header[AMD_VBIOS_SIGNATURE_END] = 0;
20341ec0267Sriastradh
20441ec0267Sriastradh if ((!AMD_IS_VALID_VBIOS(header)) ||
20541ec0267Sriastradh 0 != memcmp((char *)&header[AMD_VBIOS_SIGNATURE_OFFSET],
20641ec0267Sriastradh AMD_VBIOS_SIGNATURE,
20741ec0267Sriastradh strlen(AMD_VBIOS_SIGNATURE)))
20841ec0267Sriastradh return false;
20941ec0267Sriastradh
21041ec0267Sriastradh /* valid vbios, go on */
21141ec0267Sriastradh len = AMD_VBIOS_LENGTH(header);
21241ec0267Sriastradh len = ALIGN(len, 4);
21341ec0267Sriastradh adev->bios = kmalloc(len, GFP_KERNEL);
21441ec0267Sriastradh if (!adev->bios) {
21541ec0267Sriastradh DRM_ERROR("no memory to allocate for BIOS\n");
21641ec0267Sriastradh return false;
21741ec0267Sriastradh }
21841ec0267Sriastradh adev->bios_size = len;
21941ec0267Sriastradh
22041ec0267Sriastradh /* read complete BIOS */
22141ec0267Sriastradh amdgpu_asic_read_bios_from_rom(adev, adev->bios, len);
22241ec0267Sriastradh
22341ec0267Sriastradh if (!check_atom_bios(adev->bios, len)) {
22441ec0267Sriastradh kfree(adev->bios);
22541ec0267Sriastradh return false;
22641ec0267Sriastradh }
22741ec0267Sriastradh
228efa246c0Sriastradh return true;
229efa246c0Sriastradh }
230efa246c0Sriastradh
2310d50c49dSriastradh #ifdef __NetBSD__
2320d50c49dSriastradh # undef __iomem
2330d50c49dSriastradh #endif
2340d50c49dSriastradh
amdgpu_read_platform_bios(struct amdgpu_device * adev)235efa246c0Sriastradh static bool amdgpu_read_platform_bios(struct amdgpu_device *adev)
236efa246c0Sriastradh {
2370d50c49dSriastradh #ifdef __NetBSD__ /* XXX amdgpu platform bios */
2380d50c49dSriastradh return false;
2390d50c49dSriastradh #else
240efa246c0Sriastradh uint8_t __iomem *bios;
241efa246c0Sriastradh size_t size;
242efa246c0Sriastradh
243efa246c0Sriastradh adev->bios = NULL;
244efa246c0Sriastradh
245efa246c0Sriastradh bios = pci_platform_rom(adev->pdev, &size);
246efa246c0Sriastradh if (!bios) {
247efa246c0Sriastradh return false;
248efa246c0Sriastradh }
249efa246c0Sriastradh
25041ec0267Sriastradh adev->bios = kzalloc(size, GFP_KERNEL);
25141ec0267Sriastradh if (adev->bios == NULL)
25241ec0267Sriastradh return false;
25341ec0267Sriastradh
25441ec0267Sriastradh memcpy_fromio(adev->bios, bios, size);
25541ec0267Sriastradh
25641ec0267Sriastradh if (!check_atom_bios(adev->bios, size)) {
25741ec0267Sriastradh kfree(adev->bios);
258efa246c0Sriastradh return false;
259efa246c0Sriastradh }
26041ec0267Sriastradh
26141ec0267Sriastradh adev->bios_size = size;
262efa246c0Sriastradh
263efa246c0Sriastradh return true;
2640d50c49dSriastradh #endif /* __NetBSD__ */
265efa246c0Sriastradh }
266efa246c0Sriastradh
2670d50c49dSriastradh /* XXX amdgpu acpi */
268efa246c0Sriastradh #ifdef CONFIG_ACPI
269efa246c0Sriastradh /* ATRM is used to get the BIOS on the discrete cards in
270efa246c0Sriastradh * dual-gpu systems.
271efa246c0Sriastradh */
272efa246c0Sriastradh /* retrieve the ROM in 4k blocks */
273efa246c0Sriastradh #define ATRM_BIOS_PAGE 4096
274efa246c0Sriastradh /**
275efa246c0Sriastradh * amdgpu_atrm_call - fetch a chunk of the vbios
276efa246c0Sriastradh *
277efa246c0Sriastradh * @atrm_handle: acpi ATRM handle
278efa246c0Sriastradh * @bios: vbios image pointer
279efa246c0Sriastradh * @offset: offset of vbios image data to fetch
280efa246c0Sriastradh * @len: length of vbios image data to fetch
281efa246c0Sriastradh *
282efa246c0Sriastradh * Executes ATRM to fetch a chunk of the discrete
283efa246c0Sriastradh * vbios image on PX systems (all asics).
284efa246c0Sriastradh * Returns the length of the buffer fetched.
285efa246c0Sriastradh */
amdgpu_atrm_call(acpi_handle atrm_handle,uint8_t * bios,int offset,int len)286efa246c0Sriastradh static int amdgpu_atrm_call(acpi_handle atrm_handle, uint8_t *bios,
287efa246c0Sriastradh int offset, int len)
288efa246c0Sriastradh {
289efa246c0Sriastradh acpi_status status;
290efa246c0Sriastradh union acpi_object atrm_arg_elements[2], *obj;
291efa246c0Sriastradh struct acpi_object_list atrm_arg;
292efa246c0Sriastradh struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL};
293efa246c0Sriastradh
294efa246c0Sriastradh atrm_arg.count = 2;
295efa246c0Sriastradh atrm_arg.pointer = &atrm_arg_elements[0];
296efa246c0Sriastradh
297efa246c0Sriastradh atrm_arg_elements[0].type = ACPI_TYPE_INTEGER;
298efa246c0Sriastradh atrm_arg_elements[0].integer.value = offset;
299efa246c0Sriastradh
300efa246c0Sriastradh atrm_arg_elements[1].type = ACPI_TYPE_INTEGER;
301efa246c0Sriastradh atrm_arg_elements[1].integer.value = len;
302efa246c0Sriastradh
303efa246c0Sriastradh status = acpi_evaluate_object(atrm_handle, NULL, &atrm_arg, &buffer);
304efa246c0Sriastradh if (ACPI_FAILURE(status)) {
305efa246c0Sriastradh printk("failed to evaluate ATRM got %s\n", acpi_format_exception(status));
306efa246c0Sriastradh return -ENODEV;
307efa246c0Sriastradh }
308efa246c0Sriastradh
309efa246c0Sriastradh obj = (union acpi_object *)buffer.pointer;
310efa246c0Sriastradh memcpy(bios+offset, obj->buffer.pointer, obj->buffer.length);
311efa246c0Sriastradh len = obj->buffer.length;
312efa246c0Sriastradh kfree(buffer.pointer);
313efa246c0Sriastradh return len;
314efa246c0Sriastradh }
315efa246c0Sriastradh
amdgpu_atrm_get_bios(struct amdgpu_device * adev)316efa246c0Sriastradh static bool amdgpu_atrm_get_bios(struct amdgpu_device *adev)
317efa246c0Sriastradh {
318efa246c0Sriastradh int ret;
319efa246c0Sriastradh int size = 256 * 1024;
320efa246c0Sriastradh int i;
321efa246c0Sriastradh struct pci_dev *pdev = NULL;
322efa246c0Sriastradh acpi_handle dhandle, atrm_handle;
323efa246c0Sriastradh acpi_status status;
324efa246c0Sriastradh bool found = false;
325efa246c0Sriastradh
326efa246c0Sriastradh /* ATRM is for the discrete card only */
327efa246c0Sriastradh if (adev->flags & AMD_IS_APU)
328efa246c0Sriastradh return false;
329efa246c0Sriastradh
330efa246c0Sriastradh while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
331*e4a2ed4fSriastradh #ifdef __NetBSD__
332*e4a2ed4fSriastradh dhandle = (pdev->pd_ad ? pdev->pd_ad->ad_handle : NULL);
333*e4a2ed4fSriastradh #else
334efa246c0Sriastradh dhandle = ACPI_HANDLE(&pdev->dev);
335*e4a2ed4fSriastradh #endif
336efa246c0Sriastradh if (!dhandle)
337efa246c0Sriastradh continue;
338efa246c0Sriastradh
339efa246c0Sriastradh status = acpi_get_handle(dhandle, "ATRM", &atrm_handle);
340efa246c0Sriastradh if (!ACPI_FAILURE(status)) {
341efa246c0Sriastradh found = true;
342efa246c0Sriastradh break;
343efa246c0Sriastradh }
344efa246c0Sriastradh }
345efa246c0Sriastradh
346efa246c0Sriastradh if (!found) {
347efa246c0Sriastradh while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_OTHER << 8, pdev)) != NULL) {
348*e4a2ed4fSriastradh #ifdef __NetBSD__
349*e4a2ed4fSriastradh dhandle = (pdev->pd_ad ? pdev->pd_ad->ad_handle
350*e4a2ed4fSriastradh : NULL);
351*e4a2ed4fSriastradh #else
352efa246c0Sriastradh dhandle = ACPI_HANDLE(&pdev->dev);
353*e4a2ed4fSriastradh #endif
354efa246c0Sriastradh if (!dhandle)
355efa246c0Sriastradh continue;
356efa246c0Sriastradh
357efa246c0Sriastradh status = acpi_get_handle(dhandle, "ATRM", &atrm_handle);
358efa246c0Sriastradh if (!ACPI_FAILURE(status)) {
359efa246c0Sriastradh found = true;
360efa246c0Sriastradh break;
361efa246c0Sriastradh }
362efa246c0Sriastradh }
363efa246c0Sriastradh }
364efa246c0Sriastradh
365efa246c0Sriastradh if (!found)
366efa246c0Sriastradh return false;
367efa246c0Sriastradh
368efa246c0Sriastradh adev->bios = kmalloc(size, GFP_KERNEL);
369efa246c0Sriastradh if (!adev->bios) {
370efa246c0Sriastradh DRM_ERROR("Unable to allocate bios\n");
371efa246c0Sriastradh return false;
372efa246c0Sriastradh }
373efa246c0Sriastradh
374efa246c0Sriastradh for (i = 0; i < size / ATRM_BIOS_PAGE; i++) {
375efa246c0Sriastradh ret = amdgpu_atrm_call(atrm_handle,
376efa246c0Sriastradh adev->bios,
377efa246c0Sriastradh (i * ATRM_BIOS_PAGE),
378efa246c0Sriastradh ATRM_BIOS_PAGE);
379efa246c0Sriastradh if (ret < ATRM_BIOS_PAGE)
380efa246c0Sriastradh break;
381efa246c0Sriastradh }
382efa246c0Sriastradh
38341ec0267Sriastradh if (!check_atom_bios(adev->bios, size)) {
384efa246c0Sriastradh kfree(adev->bios);
385efa246c0Sriastradh return false;
386efa246c0Sriastradh }
38741ec0267Sriastradh adev->bios_size = size;
388efa246c0Sriastradh return true;
389efa246c0Sriastradh }
390efa246c0Sriastradh #else
amdgpu_atrm_get_bios(struct amdgpu_device * adev)391efa246c0Sriastradh static inline bool amdgpu_atrm_get_bios(struct amdgpu_device *adev)
392efa246c0Sriastradh {
393efa246c0Sriastradh return false;
394efa246c0Sriastradh }
395efa246c0Sriastradh #endif
396efa246c0Sriastradh
amdgpu_read_disabled_bios(struct amdgpu_device * adev)397efa246c0Sriastradh static bool amdgpu_read_disabled_bios(struct amdgpu_device *adev)
398efa246c0Sriastradh {
399efa246c0Sriastradh if (adev->flags & AMD_IS_APU)
400efa246c0Sriastradh return igp_read_bios_from_vram(adev);
401efa246c0Sriastradh else
402efa246c0Sriastradh return amdgpu_asic_read_disabled_bios(adev);
403efa246c0Sriastradh }
404efa246c0Sriastradh
405efa246c0Sriastradh #ifdef CONFIG_ACPI
amdgpu_acpi_vfct_bios(struct amdgpu_device * adev)406efa246c0Sriastradh static bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)
407efa246c0Sriastradh {
408efa246c0Sriastradh struct acpi_table_header *hdr;
409efa246c0Sriastradh acpi_size tbl_size;
410efa246c0Sriastradh UEFI_ACPI_VFCT *vfct;
41141ec0267Sriastradh unsigned offset;
412efa246c0Sriastradh
41341ec0267Sriastradh if (!ACPI_SUCCESS(acpi_get_table("VFCT", 1, &hdr)))
414efa246c0Sriastradh return false;
41541ec0267Sriastradh tbl_size = hdr->length;
416efa246c0Sriastradh if (tbl_size < sizeof(UEFI_ACPI_VFCT)) {
417efa246c0Sriastradh DRM_ERROR("ACPI VFCT table present but broken (too short #1)\n");
41841ec0267Sriastradh return false;
419efa246c0Sriastradh }
420efa246c0Sriastradh
421efa246c0Sriastradh vfct = (UEFI_ACPI_VFCT *)hdr;
42241ec0267Sriastradh offset = vfct->VBIOSImageOffset;
42341ec0267Sriastradh
42441ec0267Sriastradh while (offset < tbl_size) {
42541ec0267Sriastradh GOP_VBIOS_CONTENT *vbios = (GOP_VBIOS_CONTENT *)((char *)hdr + offset);
42641ec0267Sriastradh VFCT_IMAGE_HEADER *vhdr = &vbios->VbiosHeader;
42741ec0267Sriastradh
42841ec0267Sriastradh offset += sizeof(VFCT_IMAGE_HEADER);
42941ec0267Sriastradh if (offset > tbl_size) {
43041ec0267Sriastradh DRM_ERROR("ACPI VFCT image header truncated\n");
43141ec0267Sriastradh return false;
432efa246c0Sriastradh }
433efa246c0Sriastradh
43441ec0267Sriastradh offset += vhdr->ImageLength;
43541ec0267Sriastradh if (offset > tbl_size) {
436efa246c0Sriastradh DRM_ERROR("ACPI VFCT image truncated\n");
43741ec0267Sriastradh return false;
438efa246c0Sriastradh }
439efa246c0Sriastradh
44041ec0267Sriastradh if (vhdr->ImageLength &&
44141ec0267Sriastradh vhdr->PCIBus == adev->pdev->bus->number &&
44241ec0267Sriastradh vhdr->PCIDevice == PCI_SLOT(adev->pdev->devfn) &&
44341ec0267Sriastradh vhdr->PCIFunction == PCI_FUNC(adev->pdev->devfn) &&
44441ec0267Sriastradh vhdr->VendorID == adev->pdev->vendor &&
44541ec0267Sriastradh vhdr->DeviceID == adev->pdev->device) {
44641ec0267Sriastradh adev->bios = kmemdup(&vbios->VbiosContent,
44741ec0267Sriastradh vhdr->ImageLength,
44841ec0267Sriastradh GFP_KERNEL);
449efa246c0Sriastradh
45041ec0267Sriastradh if (!check_atom_bios(adev->bios, vhdr->ImageLength)) {
45141ec0267Sriastradh kfree(adev->bios);
45241ec0267Sriastradh return false;
45341ec0267Sriastradh }
45441ec0267Sriastradh adev->bios_size = vhdr->ImageLength;
45541ec0267Sriastradh return true;
45641ec0267Sriastradh }
45741ec0267Sriastradh }
45841ec0267Sriastradh
45941ec0267Sriastradh DRM_ERROR("ACPI VFCT table present but broken (too short #2)\n");
46041ec0267Sriastradh return false;
461efa246c0Sriastradh }
462efa246c0Sriastradh #else
amdgpu_acpi_vfct_bios(struct amdgpu_device * adev)463efa246c0Sriastradh static inline bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)
464efa246c0Sriastradh {
465efa246c0Sriastradh return false;
466efa246c0Sriastradh }
467efa246c0Sriastradh #endif
468efa246c0Sriastradh
amdgpu_get_bios(struct amdgpu_device * adev)469efa246c0Sriastradh bool amdgpu_get_bios(struct amdgpu_device *adev)
470efa246c0Sriastradh {
47141ec0267Sriastradh if (amdgpu_atrm_get_bios(adev))
47241ec0267Sriastradh goto success;
473efa246c0Sriastradh
47441ec0267Sriastradh if (amdgpu_acpi_vfct_bios(adev))
47541ec0267Sriastradh goto success;
47641ec0267Sriastradh
47741ec0267Sriastradh if (igp_read_bios_from_vram(adev))
47841ec0267Sriastradh goto success;
47941ec0267Sriastradh
48041ec0267Sriastradh if (amdgpu_read_bios(adev))
48141ec0267Sriastradh goto success;
48241ec0267Sriastradh
48341ec0267Sriastradh if (amdgpu_read_bios_from_rom(adev))
48441ec0267Sriastradh goto success;
48541ec0267Sriastradh
48641ec0267Sriastradh if (amdgpu_read_disabled_bios(adev))
48741ec0267Sriastradh goto success;
48841ec0267Sriastradh
48941ec0267Sriastradh if (amdgpu_read_platform_bios(adev))
49041ec0267Sriastradh goto success;
49141ec0267Sriastradh
492efa246c0Sriastradh DRM_ERROR("Unable to locate a BIOS ROM\n");
493efa246c0Sriastradh return false;
494efa246c0Sriastradh
49541ec0267Sriastradh success:
49641ec0267Sriastradh adev->is_atom_fw = (adev->asic_type >= CHIP_VEGA10) ? true : false;
497efa246c0Sriastradh return true;
498efa246c0Sriastradh }
499