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