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