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/slab.h> 33d38ceaf9SAlex Deucher #include <linux/acpi.h> 34d38ceaf9SAlex Deucher /* 35d38ceaf9SAlex Deucher * BIOS. 36d38ceaf9SAlex Deucher */ 37d38ceaf9SAlex Deucher 38f930b2e8Smonk.liu #define AMD_VBIOS_SIGNATURE " 761295520" 39f930b2e8Smonk.liu #define AMD_VBIOS_SIGNATURE_OFFSET 0x30 40f930b2e8Smonk.liu #define AMD_VBIOS_SIGNATURE_SIZE sizeof(AMD_VBIOS_SIGNATURE) 41f930b2e8Smonk.liu #define AMD_VBIOS_SIGNATURE_END (AMD_VBIOS_SIGNATURE_OFFSET + AMD_VBIOS_SIGNATURE_SIZE) 42f930b2e8Smonk.liu #define AMD_IS_VALID_VBIOS(p) ((p)[0] == 0x55 && (p)[1] == 0xAA) 43f930b2e8Smonk.liu #define AMD_VBIOS_LENGTH(p) ((p)[2] << 9) 44f930b2e8Smonk.liu 45919db4c1SKen Xue /* Check if current bios is an ATOM BIOS. 46919db4c1SKen Xue * Return true if it is ATOM BIOS. Otherwise, return false. 47919db4c1SKen Xue */ 48919db4c1SKen Xue static bool check_atom_bios(uint8_t *bios, size_t size) 49919db4c1SKen Xue { 50919db4c1SKen Xue uint16_t tmp, bios_header_start; 51919db4c1SKen Xue 52919db4c1SKen Xue if (!bios || size < 0x49) { 53919db4c1SKen Xue DRM_INFO("vbios mem is null or mem size is wrong\n"); 54919db4c1SKen Xue return false; 55919db4c1SKen Xue } 56919db4c1SKen Xue 57919db4c1SKen Xue if (!AMD_IS_VALID_VBIOS(bios)) { 58919db4c1SKen Xue DRM_INFO("BIOS signature incorrect %x %x\n", bios[0], bios[1]); 59919db4c1SKen Xue return false; 60919db4c1SKen Xue } 61919db4c1SKen Xue 62919db4c1SKen Xue tmp = bios[0x18] | (bios[0x19] << 8); 63919db4c1SKen Xue if (bios[tmp + 0x14] != 0x0) { 64919db4c1SKen Xue DRM_INFO("Not an x86 BIOS ROM\n"); 65919db4c1SKen Xue return false; 66919db4c1SKen Xue } 67919db4c1SKen Xue 68919db4c1SKen Xue bios_header_start = bios[0x48] | (bios[0x49] << 8); 69919db4c1SKen Xue if (!bios_header_start) { 70919db4c1SKen Xue DRM_INFO("Can't locate bios header\n"); 71919db4c1SKen Xue return false; 72919db4c1SKen Xue } 73919db4c1SKen Xue 74919db4c1SKen Xue tmp = bios_header_start + 4; 75919db4c1SKen Xue if (size < tmp) { 76919db4c1SKen Xue DRM_INFO("BIOS header is broken\n"); 77919db4c1SKen Xue return false; 78919db4c1SKen Xue } 79919db4c1SKen Xue 80919db4c1SKen Xue if (!memcmp(bios + tmp, "ATOM", 4) || 81919db4c1SKen Xue !memcmp(bios + tmp, "MOTA", 4)) { 82919db4c1SKen Xue DRM_DEBUG("ATOMBIOS detected\n"); 83919db4c1SKen Xue return true; 84919db4c1SKen Xue } 85919db4c1SKen Xue 86919db4c1SKen Xue return false; 87919db4c1SKen Xue } 88919db4c1SKen Xue 890cdd5005SAlex Deucher static bool is_atom_fw(uint8_t *bios) 900cdd5005SAlex Deucher { 910cdd5005SAlex Deucher uint16_t bios_header_start = bios[0x48] | (bios[0x49] << 8); 920cdd5005SAlex Deucher uint8_t frev = bios[bios_header_start + 2]; 930cdd5005SAlex Deucher uint8_t crev = bios[bios_header_start + 3]; 940cdd5005SAlex Deucher 950cdd5005SAlex Deucher if ((frev < 3) || 960cdd5005SAlex Deucher ((frev == 3) && (crev < 3))) 970cdd5005SAlex Deucher return false; 980cdd5005SAlex Deucher 990cdd5005SAlex Deucher return true; 1000cdd5005SAlex Deucher } 101919db4c1SKen Xue 102d38ceaf9SAlex Deucher /* If you boot an IGP board with a discrete card as the primary, 103d38ceaf9SAlex Deucher * the IGP rom is not accessible via the rom bar as the IGP rom is 104d38ceaf9SAlex Deucher * part of the system bios. On boot, the system bios puts a 105d38ceaf9SAlex Deucher * copy of the igp rom at the start of vram if a discrete card is 106d38ceaf9SAlex Deucher * present. 107d38ceaf9SAlex Deucher */ 108d38ceaf9SAlex Deucher static bool igp_read_bios_from_vram(struct amdgpu_device *adev) 109d38ceaf9SAlex Deucher { 110d38ceaf9SAlex Deucher uint8_t __iomem *bios; 111d38ceaf9SAlex Deucher resource_size_t vram_base; 112d38ceaf9SAlex Deucher resource_size_t size = 256 * 1024; /* ??? */ 113d38ceaf9SAlex Deucher 1142f7d10b3SJammy Zhou if (!(adev->flags & AMD_IS_APU)) 115c836fec5SJim Qu if (amdgpu_need_post(adev)) 116d38ceaf9SAlex Deucher return false; 117d38ceaf9SAlex Deucher 118d38ceaf9SAlex Deucher adev->bios = NULL; 119d38ceaf9SAlex Deucher vram_base = pci_resource_start(adev->pdev, 0); 120d38ceaf9SAlex Deucher bios = ioremap(vram_base, size); 121d38ceaf9SAlex Deucher if (!bios) { 122d38ceaf9SAlex Deucher return false; 123d38ceaf9SAlex Deucher } 124d38ceaf9SAlex Deucher 125d38ceaf9SAlex Deucher adev->bios = kmalloc(size, GFP_KERNEL); 1263f12325aSRavikant B Sharma if (!adev->bios) { 127d38ceaf9SAlex Deucher iounmap(bios); 128d38ceaf9SAlex Deucher return false; 129d38ceaf9SAlex Deucher } 130a9f5db9cSEvan Quan adev->bios_size = size; 131d38ceaf9SAlex Deucher memcpy_fromio(adev->bios, bios, size); 132d38ceaf9SAlex Deucher iounmap(bios); 133919db4c1SKen Xue 134919db4c1SKen Xue if (!check_atom_bios(adev->bios, size)) { 135919db4c1SKen Xue kfree(adev->bios); 136919db4c1SKen Xue return false; 137919db4c1SKen Xue } 138919db4c1SKen Xue 139d38ceaf9SAlex Deucher return true; 140d38ceaf9SAlex Deucher } 141d38ceaf9SAlex Deucher 142d38ceaf9SAlex Deucher bool amdgpu_read_bios(struct amdgpu_device *adev) 143d38ceaf9SAlex Deucher { 144919db4c1SKen Xue uint8_t __iomem *bios; 145d38ceaf9SAlex Deucher size_t size; 146d38ceaf9SAlex Deucher 147d38ceaf9SAlex Deucher adev->bios = NULL; 148d38ceaf9SAlex Deucher /* XXX: some cards may return 0 for rom size? ddx has a workaround */ 149d38ceaf9SAlex Deucher bios = pci_map_rom(adev->pdev, &size); 150d38ceaf9SAlex Deucher if (!bios) { 151d38ceaf9SAlex Deucher return false; 152d38ceaf9SAlex Deucher } 153d38ceaf9SAlex Deucher 15418da4340SAlex Deucher adev->bios = kzalloc(size, GFP_KERNEL); 155d38ceaf9SAlex Deucher if (adev->bios == NULL) { 156d38ceaf9SAlex Deucher pci_unmap_rom(adev->pdev, bios); 157d38ceaf9SAlex Deucher return false; 158d38ceaf9SAlex Deucher } 159a9f5db9cSEvan Quan adev->bios_size = size; 16018da4340SAlex Deucher memcpy_fromio(adev->bios, bios, size); 161d38ceaf9SAlex Deucher pci_unmap_rom(adev->pdev, bios); 162919db4c1SKen Xue 163919db4c1SKen Xue if (!check_atom_bios(adev->bios, size)) { 164919db4c1SKen Xue kfree(adev->bios); 165919db4c1SKen Xue return false; 166919db4c1SKen Xue } 167919db4c1SKen Xue 168d38ceaf9SAlex Deucher return true; 169d38ceaf9SAlex Deucher } 170d38ceaf9SAlex Deucher 171f930b2e8Smonk.liu static bool amdgpu_read_bios_from_rom(struct amdgpu_device *adev) 172f930b2e8Smonk.liu { 173f930b2e8Smonk.liu u8 header[AMD_VBIOS_SIGNATURE_END+1] = {0}; 174f930b2e8Smonk.liu int len; 175f930b2e8Smonk.liu 176f930b2e8Smonk.liu if (!adev->asic_funcs->read_bios_from_rom) 177f930b2e8Smonk.liu return false; 178f930b2e8Smonk.liu 179f930b2e8Smonk.liu /* validate VBIOS signature */ 180f930b2e8Smonk.liu if (amdgpu_asic_read_bios_from_rom(adev, &header[0], sizeof(header)) == false) 181f930b2e8Smonk.liu return false; 182f930b2e8Smonk.liu header[AMD_VBIOS_SIGNATURE_END] = 0; 183f930b2e8Smonk.liu 184f930b2e8Smonk.liu if ((!AMD_IS_VALID_VBIOS(header)) || 185f930b2e8Smonk.liu 0 != memcmp((char *)&header[AMD_VBIOS_SIGNATURE_OFFSET], 186f930b2e8Smonk.liu AMD_VBIOS_SIGNATURE, 187f930b2e8Smonk.liu strlen(AMD_VBIOS_SIGNATURE))) 188f930b2e8Smonk.liu return false; 189f930b2e8Smonk.liu 190f930b2e8Smonk.liu /* valid vbios, go on */ 191f930b2e8Smonk.liu len = AMD_VBIOS_LENGTH(header); 192f930b2e8Smonk.liu len = ALIGN(len, 4); 193f930b2e8Smonk.liu adev->bios = kmalloc(len, GFP_KERNEL); 194f930b2e8Smonk.liu if (!adev->bios) { 195f930b2e8Smonk.liu DRM_ERROR("no memory to allocate for BIOS\n"); 196f930b2e8Smonk.liu return false; 197f930b2e8Smonk.liu } 198a9f5db9cSEvan Quan adev->bios_size = len; 199f930b2e8Smonk.liu 200f930b2e8Smonk.liu /* read complete BIOS */ 201919db4c1SKen Xue amdgpu_asic_read_bios_from_rom(adev, adev->bios, len); 202919db4c1SKen Xue 203919db4c1SKen Xue if (!check_atom_bios(adev->bios, len)) { 204919db4c1SKen Xue kfree(adev->bios); 205919db4c1SKen Xue return false; 206919db4c1SKen Xue } 207919db4c1SKen Xue 208919db4c1SKen Xue return true; 209f930b2e8Smonk.liu } 210f930b2e8Smonk.liu 211d38ceaf9SAlex Deucher static bool amdgpu_read_platform_bios(struct amdgpu_device *adev) 212d38ceaf9SAlex Deucher { 213d38ceaf9SAlex Deucher uint8_t __iomem *bios; 214d38ceaf9SAlex Deucher size_t size; 215d38ceaf9SAlex Deucher 216d38ceaf9SAlex Deucher adev->bios = NULL; 217d38ceaf9SAlex Deucher 218d38ceaf9SAlex Deucher bios = pci_platform_rom(adev->pdev, &size); 219d38ceaf9SAlex Deucher if (!bios) { 220d38ceaf9SAlex Deucher return false; 221d38ceaf9SAlex Deucher } 222d38ceaf9SAlex Deucher 223919db4c1SKen Xue adev->bios = kzalloc(size, GFP_KERNEL); 224919db4c1SKen Xue if (adev->bios == NULL) 225919db4c1SKen Xue return false; 226919db4c1SKen Xue 227919db4c1SKen Xue memcpy_fromio(adev->bios, bios, size); 228919db4c1SKen Xue 229919db4c1SKen Xue if (!check_atom_bios(adev->bios, size)) { 230919db4c1SKen Xue kfree(adev->bios); 231d38ceaf9SAlex Deucher return false; 232d38ceaf9SAlex Deucher } 233919db4c1SKen Xue 234a9f5db9cSEvan Quan adev->bios_size = size; 235d38ceaf9SAlex Deucher 236d38ceaf9SAlex Deucher return true; 237d38ceaf9SAlex Deucher } 238d38ceaf9SAlex Deucher 239d38ceaf9SAlex Deucher #ifdef CONFIG_ACPI 240d38ceaf9SAlex Deucher /* ATRM is used to get the BIOS on the discrete cards in 241d38ceaf9SAlex Deucher * dual-gpu systems. 242d38ceaf9SAlex Deucher */ 243d38ceaf9SAlex Deucher /* retrieve the ROM in 4k blocks */ 244d38ceaf9SAlex Deucher #define ATRM_BIOS_PAGE 4096 245d38ceaf9SAlex Deucher /** 246d38ceaf9SAlex Deucher * amdgpu_atrm_call - fetch a chunk of the vbios 247d38ceaf9SAlex Deucher * 248d38ceaf9SAlex Deucher * @atrm_handle: acpi ATRM handle 249d38ceaf9SAlex Deucher * @bios: vbios image pointer 250d38ceaf9SAlex Deucher * @offset: offset of vbios image data to fetch 251d38ceaf9SAlex Deucher * @len: length of vbios image data to fetch 252d38ceaf9SAlex Deucher * 253d38ceaf9SAlex Deucher * Executes ATRM to fetch a chunk of the discrete 254d38ceaf9SAlex Deucher * vbios image on PX systems (all asics). 255d38ceaf9SAlex Deucher * Returns the length of the buffer fetched. 256d38ceaf9SAlex Deucher */ 257d38ceaf9SAlex Deucher static int amdgpu_atrm_call(acpi_handle atrm_handle, uint8_t *bios, 258d38ceaf9SAlex Deucher int offset, int len) 259d38ceaf9SAlex Deucher { 260d38ceaf9SAlex Deucher acpi_status status; 261d38ceaf9SAlex Deucher union acpi_object atrm_arg_elements[2], *obj; 262d38ceaf9SAlex Deucher struct acpi_object_list atrm_arg; 263d38ceaf9SAlex Deucher struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL}; 264d38ceaf9SAlex Deucher 265d38ceaf9SAlex Deucher atrm_arg.count = 2; 266d38ceaf9SAlex Deucher atrm_arg.pointer = &atrm_arg_elements[0]; 267d38ceaf9SAlex Deucher 268d38ceaf9SAlex Deucher atrm_arg_elements[0].type = ACPI_TYPE_INTEGER; 269d38ceaf9SAlex Deucher atrm_arg_elements[0].integer.value = offset; 270d38ceaf9SAlex Deucher 271d38ceaf9SAlex Deucher atrm_arg_elements[1].type = ACPI_TYPE_INTEGER; 272d38ceaf9SAlex Deucher atrm_arg_elements[1].integer.value = len; 273d38ceaf9SAlex Deucher 274d38ceaf9SAlex Deucher status = acpi_evaluate_object(atrm_handle, NULL, &atrm_arg, &buffer); 275d38ceaf9SAlex Deucher if (ACPI_FAILURE(status)) { 276d38ceaf9SAlex Deucher printk("failed to evaluate ATRM got %s\n", acpi_format_exception(status)); 277d38ceaf9SAlex Deucher return -ENODEV; 278d38ceaf9SAlex Deucher } 279d38ceaf9SAlex Deucher 280d38ceaf9SAlex Deucher obj = (union acpi_object *)buffer.pointer; 281d38ceaf9SAlex Deucher memcpy(bios+offset, obj->buffer.pointer, obj->buffer.length); 282d38ceaf9SAlex Deucher len = obj->buffer.length; 283d38ceaf9SAlex Deucher kfree(buffer.pointer); 284d38ceaf9SAlex Deucher return len; 285d38ceaf9SAlex Deucher } 286d38ceaf9SAlex Deucher 287d38ceaf9SAlex Deucher static bool amdgpu_atrm_get_bios(struct amdgpu_device *adev) 288d38ceaf9SAlex Deucher { 289d38ceaf9SAlex Deucher int ret; 290d38ceaf9SAlex Deucher int size = 256 * 1024; 291d38ceaf9SAlex Deucher int i; 292d38ceaf9SAlex Deucher struct pci_dev *pdev = NULL; 293d38ceaf9SAlex Deucher acpi_handle dhandle, atrm_handle; 294d38ceaf9SAlex Deucher acpi_status status; 295d38ceaf9SAlex Deucher bool found = false; 296d38ceaf9SAlex Deucher 297d38ceaf9SAlex Deucher /* ATRM is for the discrete card only */ 2982f7d10b3SJammy Zhou if (adev->flags & AMD_IS_APU) 299d38ceaf9SAlex Deucher return false; 300d38ceaf9SAlex Deucher 301d38ceaf9SAlex Deucher while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) { 302d38ceaf9SAlex Deucher dhandle = ACPI_HANDLE(&pdev->dev); 303d38ceaf9SAlex Deucher if (!dhandle) 304d38ceaf9SAlex Deucher continue; 305d38ceaf9SAlex Deucher 306d38ceaf9SAlex Deucher status = acpi_get_handle(dhandle, "ATRM", &atrm_handle); 307d38ceaf9SAlex Deucher if (!ACPI_FAILURE(status)) { 308d38ceaf9SAlex Deucher found = true; 309d38ceaf9SAlex Deucher break; 310d38ceaf9SAlex Deucher } 311d38ceaf9SAlex Deucher } 312d38ceaf9SAlex Deucher 313d38ceaf9SAlex Deucher if (!found) { 314d38ceaf9SAlex Deucher while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_OTHER << 8, pdev)) != NULL) { 315d38ceaf9SAlex Deucher dhandle = ACPI_HANDLE(&pdev->dev); 316d38ceaf9SAlex Deucher if (!dhandle) 317d38ceaf9SAlex Deucher continue; 318d38ceaf9SAlex Deucher 319d38ceaf9SAlex Deucher status = acpi_get_handle(dhandle, "ATRM", &atrm_handle); 320d38ceaf9SAlex Deucher if (!ACPI_FAILURE(status)) { 321d38ceaf9SAlex Deucher found = true; 322d38ceaf9SAlex Deucher break; 323d38ceaf9SAlex Deucher } 324d38ceaf9SAlex Deucher } 325d38ceaf9SAlex Deucher } 326d38ceaf9SAlex Deucher 327d38ceaf9SAlex Deucher if (!found) 328d38ceaf9SAlex Deucher return false; 329d38ceaf9SAlex Deucher 330d38ceaf9SAlex Deucher adev->bios = kmalloc(size, GFP_KERNEL); 331d38ceaf9SAlex Deucher if (!adev->bios) { 332d38ceaf9SAlex Deucher DRM_ERROR("Unable to allocate bios\n"); 333d38ceaf9SAlex Deucher return false; 334d38ceaf9SAlex Deucher } 335d38ceaf9SAlex Deucher 336d38ceaf9SAlex Deucher for (i = 0; i < size / ATRM_BIOS_PAGE; i++) { 337d38ceaf9SAlex Deucher ret = amdgpu_atrm_call(atrm_handle, 338d38ceaf9SAlex Deucher adev->bios, 339d38ceaf9SAlex Deucher (i * ATRM_BIOS_PAGE), 340d38ceaf9SAlex Deucher ATRM_BIOS_PAGE); 341d38ceaf9SAlex Deucher if (ret < ATRM_BIOS_PAGE) 342d38ceaf9SAlex Deucher break; 343d38ceaf9SAlex Deucher } 344d38ceaf9SAlex Deucher 345919db4c1SKen Xue if (!check_atom_bios(adev->bios, size)) { 346d38ceaf9SAlex Deucher kfree(adev->bios); 347d38ceaf9SAlex Deucher return false; 348d38ceaf9SAlex Deucher } 349a9f5db9cSEvan Quan adev->bios_size = size; 350d38ceaf9SAlex Deucher return true; 351d38ceaf9SAlex Deucher } 352d38ceaf9SAlex Deucher #else 353d38ceaf9SAlex Deucher static inline bool amdgpu_atrm_get_bios(struct amdgpu_device *adev) 354d38ceaf9SAlex Deucher { 355d38ceaf9SAlex Deucher return false; 356d38ceaf9SAlex Deucher } 357d38ceaf9SAlex Deucher #endif 358d38ceaf9SAlex Deucher 359d38ceaf9SAlex Deucher static bool amdgpu_read_disabled_bios(struct amdgpu_device *adev) 360d38ceaf9SAlex Deucher { 3612f7d10b3SJammy Zhou if (adev->flags & AMD_IS_APU) 362d38ceaf9SAlex Deucher return igp_read_bios_from_vram(adev); 363d38ceaf9SAlex Deucher else 364d38ceaf9SAlex Deucher return amdgpu_asic_read_disabled_bios(adev); 365d38ceaf9SAlex Deucher } 366d38ceaf9SAlex Deucher 367d38ceaf9SAlex Deucher #ifdef CONFIG_ACPI 368d38ceaf9SAlex Deucher static bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev) 369d38ceaf9SAlex Deucher { 370d38ceaf9SAlex Deucher struct acpi_table_header *hdr; 371d38ceaf9SAlex Deucher acpi_size tbl_size; 372d38ceaf9SAlex Deucher UEFI_ACPI_VFCT *vfct; 37317ed9be8SAlex Deucher unsigned offset; 374d38ceaf9SAlex Deucher 3756b11d1d6SLv Zheng if (!ACPI_SUCCESS(acpi_get_table("VFCT", 1, &hdr))) 376d38ceaf9SAlex Deucher return false; 3776b11d1d6SLv Zheng tbl_size = hdr->length; 378d38ceaf9SAlex Deucher if (tbl_size < sizeof(UEFI_ACPI_VFCT)) { 379d38ceaf9SAlex Deucher DRM_ERROR("ACPI VFCT table present but broken (too short #1)\n"); 380919db4c1SKen Xue return false; 381d38ceaf9SAlex Deucher } 382d38ceaf9SAlex Deucher 383d38ceaf9SAlex Deucher vfct = (UEFI_ACPI_VFCT *)hdr; 38417ed9be8SAlex Deucher offset = vfct->VBIOSImageOffset; 38517ed9be8SAlex Deucher 38617ed9be8SAlex Deucher while (offset < tbl_size) { 38717ed9be8SAlex Deucher GOP_VBIOS_CONTENT *vbios = (GOP_VBIOS_CONTENT *)((char *)hdr + offset); 38817ed9be8SAlex Deucher VFCT_IMAGE_HEADER *vhdr = &vbios->VbiosHeader; 38917ed9be8SAlex Deucher 39017ed9be8SAlex Deucher offset += sizeof(VFCT_IMAGE_HEADER); 39117ed9be8SAlex Deucher if (offset > tbl_size) { 39217ed9be8SAlex Deucher DRM_ERROR("ACPI VFCT image header truncated\n"); 393919db4c1SKen Xue return false; 394d38ceaf9SAlex Deucher } 395d38ceaf9SAlex Deucher 39617ed9be8SAlex Deucher offset += vhdr->ImageLength; 39717ed9be8SAlex Deucher if (offset > tbl_size) { 398d38ceaf9SAlex Deucher DRM_ERROR("ACPI VFCT image truncated\n"); 399919db4c1SKen Xue return false; 400d38ceaf9SAlex Deucher } 401d38ceaf9SAlex Deucher 40217ed9be8SAlex Deucher if (vhdr->ImageLength && 40317ed9be8SAlex Deucher vhdr->PCIBus == adev->pdev->bus->number && 40417ed9be8SAlex Deucher vhdr->PCIDevice == PCI_SLOT(adev->pdev->devfn) && 40517ed9be8SAlex Deucher vhdr->PCIFunction == PCI_FUNC(adev->pdev->devfn) && 40617ed9be8SAlex Deucher vhdr->VendorID == adev->pdev->vendor && 40717ed9be8SAlex Deucher vhdr->DeviceID == adev->pdev->device) { 408919db4c1SKen Xue adev->bios = kmemdup(&vbios->VbiosContent, 409919db4c1SKen Xue vhdr->ImageLength, 410919db4c1SKen Xue GFP_KERNEL); 411d38ceaf9SAlex Deucher 412919db4c1SKen Xue if (!check_atom_bios(adev->bios, vhdr->ImageLength)) { 413919db4c1SKen Xue kfree(adev->bios); 414919db4c1SKen Xue return false; 415919db4c1SKen Xue } 416919db4c1SKen Xue adev->bios_size = vhdr->ImageLength; 417919db4c1SKen Xue return true; 418d38ceaf9SAlex Deucher } 41917ed9be8SAlex Deucher } 42017ed9be8SAlex Deucher 42117ed9be8SAlex Deucher DRM_ERROR("ACPI VFCT table present but broken (too short #2)\n"); 42217ed9be8SAlex Deucher return false; 42317ed9be8SAlex Deucher } 424d38ceaf9SAlex Deucher #else 425d38ceaf9SAlex Deucher static inline bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev) 426d38ceaf9SAlex Deucher { 427d38ceaf9SAlex Deucher return false; 428d38ceaf9SAlex Deucher } 429d38ceaf9SAlex Deucher #endif 430d38ceaf9SAlex Deucher 431d38ceaf9SAlex Deucher bool amdgpu_get_bios(struct amdgpu_device *adev) 432d38ceaf9SAlex Deucher { 433919db4c1SKen Xue if (amdgpu_atrm_get_bios(adev)) 4340cdd5005SAlex Deucher goto success; 435919db4c1SKen Xue 436919db4c1SKen Xue if (amdgpu_acpi_vfct_bios(adev)) 4370cdd5005SAlex Deucher goto success; 438919db4c1SKen Xue 439919db4c1SKen Xue if (igp_read_bios_from_vram(adev)) 4400cdd5005SAlex Deucher goto success; 441919db4c1SKen Xue 442919db4c1SKen Xue if (amdgpu_read_bios(adev)) 4430cdd5005SAlex Deucher goto success; 444919db4c1SKen Xue 445919db4c1SKen Xue if (amdgpu_read_bios_from_rom(adev)) 4460cdd5005SAlex Deucher goto success; 447919db4c1SKen Xue 448919db4c1SKen Xue if (amdgpu_read_disabled_bios(adev)) 4490cdd5005SAlex Deucher goto success; 450919db4c1SKen Xue 451919db4c1SKen Xue if (amdgpu_read_platform_bios(adev)) 4520cdd5005SAlex Deucher goto success; 453919db4c1SKen Xue 454919db4c1SKen Xue DRM_ERROR("Unable to locate a BIOS ROM\n"); 455d38ceaf9SAlex Deucher return false; 4560cdd5005SAlex Deucher 4570cdd5005SAlex Deucher success: 4580cdd5005SAlex Deucher adev->is_atom_fw = is_atom_fw(adev->bios); 4590cdd5005SAlex Deucher return true; 460d38ceaf9SAlex Deucher } 461