| 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 |
|
| 29 | #include "amdgpu.h"
|
| 30 | #include "atom.h"
|
| 31 |
|
| 32 | #include <linux/device.h>
|
| 33 | #include <linux/pci.h>
|
| 34 | #include <linux/slab.h>
|
| 35 | #include <linux/acpi.h>
|
| 36 | #include <linux/vgaarb.h>
|
| 37 | |
| 38 | * BIOS.
|
| 39 |
|
| 40 |
|
| 41 | #define AMD_VBIOS_SIGNATURE " 761295520"
|
| 42 | #define AMD_VBIOS_SIGNATURE_OFFSET 0x30
|
| 43 | #define AMD_VBIOS_SIGNATURE_SIZE sizeof(AMD_VBIOS_SIGNATURE)
|
| 44 | #define AMD_VBIOS_SIGNATURE_END (AMD_VBIOS_SIGNATURE_OFFSET + AMD_VBIOS_SIGNATURE_SIZE)
|
| 45 | #define AMD_IS_VALID_VBIOS(p) ((p)[0] == 0x55 && (p)[1] == 0xAA)
|
| 46 | #define AMD_VBIOS_LENGTH(p) ((p)[2] << 9)
|
| 47 |
|
| 48 | |
| 49 | * Return true if it is ATOM BIOS. Otherwise, return false.
|
| 50 |
|
| 51 | static bool check_atom_bios(struct amdgpu_device *adev, size_t size)
|
| 52 | {
|
| 53 | uint16_t tmp, bios_header_start;
|
| 54 | uint8_t *bios = adev->bios;
|
| 55 |
|
| 56 | if (!bios || size < 0x49) {
|
| 57 | dev_dbg(adev->dev, "VBIOS mem is null or mem size is wrong\n");
|
| 58 | return false;
|
| 59 | }
|
| 60 |
|
| 61 | if (!AMD_IS_VALID_VBIOS(bios)) {
|
| 62 | dev_dbg(adev->dev, "VBIOS signature incorrect %x %x\n", bios[0],
|
| 63 | bios[1]);
|
| 64 | return false;
|
| 65 | }
|
| 66 |
|
| 67 | bios_header_start = bios[0x48] | (bios[0x49] << 8);
|
| 68 | if (!bios_header_start) {
|
| 69 | dev_dbg(adev->dev, "Can't locate VBIOS header\n");
|
| 70 | return false;
|
| 71 | }
|
| 72 |
|
| 73 | tmp = bios_header_start + 4;
|
| 74 | if (size < tmp) {
|
| 75 | dev_dbg(adev->dev, "VBIOS header is broken\n");
|
| 76 | return false;
|
| 77 | }
|
| 78 |
|
| 79 | if (!memcmp(bios + tmp, "ATOM", 4) ||
|
| 80 | !memcmp(bios + tmp, "MOTA", 4)) {
|
| 81 | dev_dbg(adev->dev, "ATOMBIOS detected\n");
|
| 82 | return true;
|
| 83 | }
|
| 84 |
|
| 85 | return false;
|
| 86 | }
|
| 87 |
|
| 88 | void amdgpu_bios_release(struct amdgpu_device *adev)
|
| 89 | {
|
| 90 | kfree(adev->bios);
|
| 91 | adev->bios = NULL;
|
| 92 | adev->bios_size = 0;
|
| 93 | }
|
| 94 |
|
| 95 | |
| 96 | * the IGP rom is not accessible via the rom bar as the IGP rom is
|
| 97 | * part of the system bios. On boot, the system bios puts a
|
| 98 | * copy of the igp rom at the start of vram if a discrete card is
|
| 99 | * present.
|
| 100 | * For SR-IOV, if dynamic critical region is not enabled,
|
| 101 | * the vbios image is also put at the start of VRAM in the VF.
|
| 102 |
|
| 103 | static bool amdgpu_read_bios_from_vram(struct amdgpu_device *adev)
|
| 104 | {
|
| 105 | uint8_t __iomem *bios = NULL;
|
| 106 | resource_size_t vram_base;
|
| 107 | u32 size = 256U * 1024U;
|
| 108 |
|
| 109 | if (!(adev->flags & AMD_IS_APU))
|
| 110 | if (amdgpu_device_need_post(adev))
|
| 111 | return false;
|
| 112 |
|
| 113 |
|
| 114 | if (pci_resource_len(adev->pdev, 0) == 0)
|
| 115 | return false;
|
| 116 |
|
| 117 | adev->bios = NULL;
|
| 118 | vram_base = pci_resource_start(adev->pdev, 0);
|
| 119 |
|
| 120 | adev->bios = kmalloc(size, GFP_KERNEL);
|
| 121 | if (!adev->bios)
|
| 122 | return false;
|
| 123 |
|
| 124 | |
| 125 | * the vbios image is put at a dynamic offset of VRAM in the VF.
|
| 126 | * If dynamic critical region is disabled, follow the existing logic as on baremetal.
|
| 127 |
|
| 128 | if (amdgpu_sriov_vf(adev) && adev->virt.is_dynamic_crit_regn_enabled) {
|
| 129 | if (amdgpu_virt_get_dynamic_data_info(adev,
|
| 130 | AMD_SRIOV_MSG_VBIOS_IMG_TABLE_ID, adev->bios, &size)) {
|
| 131 | amdgpu_bios_release(adev);
|
| 132 | return false;
|
| 133 | }
|
| 134 | } else {
|
| 135 | bios = ioremap_wc(vram_base, size);
|
| 136 | if (!bios) {
|
| 137 | amdgpu_bios_release(adev);
|
| 138 | return false;
|
| 139 | }
|
| 140 |
|
| 141 | memcpy_fromio(adev->bios, bios, size);
|
| 142 | iounmap(bios);
|
| 143 | }
|
| 144 |
|
| 145 | adev->bios_size = size;
|
| 146 |
|
| 147 | if (!check_atom_bios(adev, size)) {
|
| 148 | amdgpu_bios_release(adev);
|
| 149 | return false;
|
| 150 | }
|
| 151 |
|
| 152 | return true;
|
| 153 | }
|
| 154 |
|
| 155 | bool amdgpu_read_bios(struct amdgpu_device *adev)
|
| 156 | {
|
| 157 | uint8_t __iomem *bios;
|
| 158 | size_t size;
|
| 159 |
|
| 160 | adev->bios = NULL;
|
| 161 |
|
| 162 | bios = pci_map_rom(adev->pdev, &size);
|
| 163 | if (!bios)
|
| 164 | return false;
|
| 165 |
|
| 166 | adev->bios = kzalloc(size, GFP_KERNEL);
|
| 167 | if (adev->bios == NULL) {
|
| 168 | pci_unmap_rom(adev->pdev, bios);
|
| 169 | return false;
|
| 170 | }
|
| 171 | adev->bios_size = size;
|
| 172 | memcpy_fromio(adev->bios, bios, size);
|
| 173 | pci_unmap_rom(adev->pdev, bios);
|
| 174 |
|
| 175 | if (!check_atom_bios(adev, size)) {
|
| 176 | amdgpu_bios_release(adev);
|
| 177 | return false;
|
| 178 | }
|
| 179 |
|
| 180 | return true;
|
| 181 | }
|
| 182 |
|
| 183 | static bool amdgpu_read_bios_from_rom(struct amdgpu_device *adev)
|
| 184 | {
|
| 185 | u8 header[AMD_VBIOS_SIGNATURE_END+1] = {0};
|
| 186 | int len;
|
| 187 |
|
| 188 | if (!adev->asic_funcs || !adev->asic_funcs->read_bios_from_rom)
|
| 189 | return false;
|
| 190 |
|
| 191 |
|
| 192 | if (amdgpu_asic_read_bios_from_rom(adev, &header[0], sizeof(header)) == false)
|
| 193 | return false;
|
| 194 | header[AMD_VBIOS_SIGNATURE_END] = 0;
|
| 195 |
|
| 196 | if ((!AMD_IS_VALID_VBIOS(header)) ||
|
| 197 | memcmp((char *)&header[AMD_VBIOS_SIGNATURE_OFFSET],
|
| 198 | AMD_VBIOS_SIGNATURE,
|
| 199 | strlen(AMD_VBIOS_SIGNATURE)) != 0)
|
| 200 | return false;
|
| 201 |
|
| 202 |
|
| 203 | len = AMD_VBIOS_LENGTH(header);
|
| 204 | len = ALIGN(len, 4);
|
| 205 | adev->bios = kmalloc(len, GFP_KERNEL);
|
| 206 | if (!adev->bios) {
|
| 207 | DRM_ERROR("no memory to allocate for BIOS\n");
|
| 208 | return false;
|
| 209 | }
|
| 210 | adev->bios_size = len;
|
| 211 |
|
| 212 |
|
| 213 | amdgpu_asic_read_bios_from_rom(adev, adev->bios, len);
|
| 214 |
|
| 215 | if (!check_atom_bios(adev, len)) {
|
| 216 | amdgpu_bios_release(adev);
|
| 217 | return false;
|
| 218 | }
|
| 219 |
|
| 220 | return true;
|
| 221 | }
|
| 222 |
|
| 223 | static bool amdgpu_read_platform_bios(struct amdgpu_device *adev)
|
| 224 | {
|
| 225 | phys_addr_t rom = adev->pdev->rom;
|
| 226 | size_t romlen = adev->pdev->romlen;
|
| 227 | void __iomem *bios;
|
| 228 |
|
| 229 | adev->bios = NULL;
|
| 230 |
|
| 231 | if (!rom || romlen == 0)
|
| 232 | return false;
|
| 233 |
|
| 234 | adev->bios = kzalloc(romlen, GFP_KERNEL);
|
| 235 | if (!adev->bios)
|
| 236 | return false;
|
| 237 |
|
| 238 | bios = ioremap(rom, romlen);
|
| 239 | if (!bios)
|
| 240 | goto free_bios;
|
| 241 |
|
| 242 | memcpy_fromio(adev->bios, bios, romlen);
|
| 243 | iounmap(bios);
|
| 244 |
|
| 245 | if (!check_atom_bios(adev, romlen))
|
| 246 | goto free_bios;
|
| 247 |
|
| 248 | adev->bios_size = romlen;
|
| 249 |
|
| 250 | return true;
|
| 251 | free_bios:
|
| 252 | amdgpu_bios_release(adev);
|
| 253 |
|
| 254 | return false;
|
| 255 | }
|
| 256 |
|
| 257 | #ifdef CONFIG_ACPI
|
| 258 | |
| 259 | * dual-gpu systems.
|
| 260 |
|
| 261 |
|
| 262 | #define ATRM_BIOS_PAGE 4096
|
| 263 | |
| 264 | * amdgpu_atrm_call - fetch a chunk of the vbios
|
| 265 | *
|
| 266 | * @atrm_handle: acpi ATRM handle
|
| 267 | * @bios: vbios image pointer
|
| 268 | * @offset: offset of vbios image data to fetch
|
| 269 | * @len: length of vbios image data to fetch
|
| 270 | *
|
| 271 | * Executes ATRM to fetch a chunk of the discrete
|
| 272 | * vbios image on PX systems (all asics).
|
| 273 | * Returns the length of the buffer fetched.
|
| 274 |
|
| 275 | static int amdgpu_atrm_call(acpi_handle atrm_handle, uint8_t *bios,
|
| 276 | int offset, int len)
|
| 277 | {
|
| 278 | acpi_status status;
|
| 279 | union acpi_object atrm_arg_elements[2], *obj;
|
| 280 | struct acpi_object_list atrm_arg;
|
| 281 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL};
|
| 282 |
|
| 283 | atrm_arg.count = 2;
|
| 284 | atrm_arg.pointer = &atrm_arg_elements[0];
|
| 285 |
|
| 286 | atrm_arg_elements[0].type = ACPI_TYPE_INTEGER;
|
| 287 | atrm_arg_elements[0].integer.value = offset;
|
| 288 |
|
| 289 | atrm_arg_elements[1].type = ACPI_TYPE_INTEGER;
|
| 290 | atrm_arg_elements[1].integer.value = len;
|
| 291 |
|
| 292 | status = acpi_evaluate_object(atrm_handle, NULL, &atrm_arg, &buffer);
|
| 293 | if (ACPI_FAILURE(status)) {
|
| 294 | DRM_ERROR("failed to evaluate ATRM got %s\n", acpi_format_exception(status));
|
| 295 | return -ENODEV;
|
| 296 | }
|
| 297 |
|
| 298 | obj = (union acpi_object *)buffer.pointer;
|
| 299 | if (!obj || obj->type != ACPI_TYPE_BUFFER) {
|
| 300 | DRM_ERROR("ATRM returned an invalid object\n");
|
| 301 | kfree(buffer.pointer);
|
| 302 | return -EINVAL;
|
| 303 | }
|
| 304 |
|
| 305 | len = min_t(size_t, obj->buffer.length, len);
|
| 306 | memcpy(bios+offset, obj->buffer.pointer, len);
|
| 307 | kfree(buffer.pointer);
|
| 308 | return len;
|
| 309 | }
|
| 310 |
|
| 311 | static bool amdgpu_atrm_get_bios(struct amdgpu_device *adev)
|
| 312 | {
|
| 313 | int ret;
|
| 314 | int size = 256 * 1024;
|
| 315 | int i;
|
| 316 | struct pci_dev *pdev = NULL;
|
| 317 | acpi_handle dhandle, atrm_handle;
|
| 318 | acpi_status status;
|
| 319 | bool found = false;
|
| 320 |
|
| 321 |
|
| 322 | if (dev_is_removable(&adev->pdev->dev))
|
| 323 | return false;
|
| 324 |
|
| 325 | while ((pdev = pci_get_base_class(PCI_BASE_CLASS_DISPLAY, pdev))) {
|
| 326 | if ((pdev->class != PCI_CLASS_DISPLAY_VGA << 8) &&
|
| 327 | (pdev->class != PCI_CLASS_DISPLAY_OTHER << 8))
|
| 328 | continue;
|
| 329 |
|
| 330 | dhandle = ACPI_HANDLE(&pdev->dev);
|
| 331 | if (!dhandle)
|
| 332 | continue;
|
| 333 |
|
| 334 | status = acpi_get_handle(dhandle, "ATRM", &atrm_handle);
|
| 335 | if (ACPI_SUCCESS(status)) {
|
| 336 | found = true;
|
| 337 | break;
|
| 338 | }
|
| 339 | }
|
| 340 |
|
| 341 | if (!found)
|
| 342 | return false;
|
| 343 | pci_dev_put(pdev);
|
| 344 |
|
| 345 | adev->bios = kmalloc(size, GFP_KERNEL);
|
| 346 | if (!adev->bios) {
|
| 347 | dev_err(adev->dev, "Unable to allocate bios\n");
|
| 348 | return false;
|
| 349 | }
|
| 350 |
|
| 351 | for (i = 0; i < size / ATRM_BIOS_PAGE; i++) {
|
| 352 | ret = amdgpu_atrm_call(atrm_handle,
|
| 353 | adev->bios,
|
| 354 | (i * ATRM_BIOS_PAGE),
|
| 355 | ATRM_BIOS_PAGE);
|
| 356 | if (ret < ATRM_BIOS_PAGE)
|
| 357 | break;
|
| 358 | }
|
| 359 |
|
| 360 | if (!check_atom_bios(adev, size)) {
|
| 361 | amdgpu_bios_release(adev);
|
| 362 | return false;
|
| 363 | }
|
| 364 | adev->bios_size = size;
|
| 365 | return true;
|
| 366 | }
|
| 367 | #else
|
| 368 | static inline bool amdgpu_atrm_get_bios(struct amdgpu_device *adev)
|
| 369 | {
|
| 370 | return false;
|
| 371 | }
|
| 372 | #endif
|
| 373 |
|
| 374 | static bool amdgpu_read_disabled_bios(struct amdgpu_device *adev)
|
| 375 | {
|
| 376 | return (!adev->asic_funcs || !adev->asic_funcs->read_disabled_bios) ?
|
| 377 | false : amdgpu_asic_read_disabled_bios(adev);
|
| 378 | }
|
| 379 |
|
| 380 | #ifdef CONFIG_ACPI
|
| 381 | |
| 382 | * amdgpu_acpi_vfct_match() - Check if a VFCT entry matches the device
|
| 383 | * @adev: AMDGPU device
|
| 384 | * @vhdr: VFCT image header to check
|
| 385 | *
|
| 386 | * VFCT entries contain the PCI bus number as recorded during BIOS POST.
|
| 387 | * On systems where the kernel renumbers PCI buses (e.g. pci=realloc or
|
| 388 | * resource conflicts), the runtime bus number may differ from the POST
|
| 389 | * value. Match by device identity (vendor + device + function) and use
|
| 390 | * the bus number as a preference: exact bus match is preferred, but when
|
| 391 | * the bus numbers disagree we accept the entry if the device identity
|
| 392 | * matches.
|
| 393 | *
|
| 394 | * Returns: 0 on match, -ENODEV on no match
|
| 395 |
|
| 396 | static int amdgpu_acpi_vfct_match(struct amdgpu_device *adev,
|
| 397 | VFCT_IMAGE_HEADER *vhdr)
|
| 398 | {
|
| 399 |
|
| 400 | if (vhdr->VendorID != adev->pdev->vendor ||
|
| 401 | vhdr->DeviceID != adev->pdev->device)
|
| 402 | return -ENODEV;
|
| 403 |
|
| 404 | if (vhdr->PCIDevice != PCI_SLOT(adev->pdev->devfn) ||
|
| 405 | vhdr->PCIFunction != PCI_FUNC(adev->pdev->devfn))
|
| 406 | return -ENODEV;
|
| 407 |
|
| 408 |
|
| 409 | if (vhdr->PCIBus == adev->pdev->bus->number)
|
| 410 | return 0;
|
| 411 |
|
| 412 |
|
| 413 | dev_notice(adev->dev,
|
| 414 | "VFCT bus number mismatch: table %u != runtime %u, matching by device identity (vendor 0x%04x device 0x%04x)\n",
|
| 415 | vhdr->PCIBus, adev->pdev->bus->number,
|
| 416 | adev->pdev->vendor, adev->pdev->device);
|
| 417 | return 0;
|
| 418 | }
|
| 419 |
|
| 420 | static bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)
|
| 421 | {
|
| 422 | struct acpi_table_header *hdr;
|
| 423 | acpi_size tbl_size;
|
| 424 | UEFI_ACPI_VFCT *vfct;
|
| 425 | unsigned int offset;
|
| 426 | bool r = false;
|
| 427 |
|
| 428 | if (!ACPI_SUCCESS(acpi_get_table("VFCT", 1, &hdr)))
|
| 429 | return false;
|
| 430 | tbl_size = hdr->length;
|
| 431 | if (tbl_size < sizeof(UEFI_ACPI_VFCT)) {
|
| 432 | dev_info(adev->dev, "ACPI VFCT table present but broken (too short #1),skipping\n");
|
| 433 | goto out;
|
| 434 | }
|
| 435 |
|
| 436 | vfct = (UEFI_ACPI_VFCT *)hdr;
|
| 437 | offset = vfct->VBIOSImageOffset;
|
| 438 |
|
| 439 | while (offset < tbl_size) {
|
| 440 | GOP_VBIOS_CONTENT *vbios = (GOP_VBIOS_CONTENT *)((char *)hdr + offset);
|
| 441 | VFCT_IMAGE_HEADER *vhdr = &vbios->VbiosHeader;
|
| 442 |
|
| 443 | offset += sizeof(VFCT_IMAGE_HEADER);
|
| 444 | if (offset > tbl_size) {
|
| 445 | dev_info(adev->dev, "ACPI VFCT image header truncated,skipping\n");
|
| 446 | goto out;
|
| 447 | }
|
| 448 |
|
| 449 | offset += vhdr->ImageLength;
|
| 450 | if (offset > tbl_size) {
|
| 451 | dev_info(adev->dev, "ACPI VFCT image truncated,skipping\n");
|
| 452 | goto out;
|
| 453 | }
|
| 454 |
|
| 455 | if (vhdr->ImageLength &&
|
| 456 | !amdgpu_acpi_vfct_match(adev, vhdr)) {
|
| 457 | adev->bios = kmemdup(&vbios->VbiosContent,
|
| 458 | vhdr->ImageLength,
|
| 459 | GFP_KERNEL);
|
| 460 |
|
| 461 | if (!check_atom_bios(adev, vhdr->ImageLength)) {
|
| 462 | amdgpu_bios_release(adev);
|
| 463 | goto out;
|
| 464 | }
|
| 465 | adev->bios_size = vhdr->ImageLength;
|
| 466 | r = true;
|
| 467 | goto out;
|
| 468 | }
|
| 469 | }
|
| 470 |
|
| 471 | dev_info(adev->dev, "ACPI VFCT table present but broken (too short #2),skipping\n");
|
| 472 |
|
| 473 | out:
|
| 474 | acpi_put_table(hdr);
|
| 475 | return r;
|
| 476 | }
|
| 477 | #else
|
| 478 | static inline bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)
|
| 479 | {
|
| 480 | return false;
|
| 481 | }
|
| 482 | #endif
|
| 483 |
|
| 484 | static bool amdgpu_get_bios_apu(struct amdgpu_device *adev)
|
| 485 | {
|
| 486 | if (amdgpu_acpi_vfct_bios(adev)) {
|
| 487 | dev_info(adev->dev, "Fetched VBIOS from VFCT\n");
|
| 488 | goto success;
|
| 489 | }
|
| 490 |
|
| 491 | if (amdgpu_read_bios_from_vram(adev)) {
|
| 492 | dev_info(adev->dev, "Fetched VBIOS from VRAM BAR\n");
|
| 493 | goto success;
|
| 494 | }
|
| 495 |
|
| 496 | if (amdgpu_read_bios(adev)) {
|
| 497 | dev_info(adev->dev, "Fetched VBIOS from ROM BAR\n");
|
| 498 | goto success;
|
| 499 | }
|
| 500 |
|
| 501 | if (amdgpu_read_platform_bios(adev)) {
|
| 502 | dev_info(adev->dev, "Fetched VBIOS from platform\n");
|
| 503 | goto success;
|
| 504 | }
|
| 505 |
|
| 506 | dev_err(adev->dev, "Unable to locate a BIOS ROM\n");
|
| 507 | return false;
|
| 508 |
|
| 509 | success:
|
| 510 | return true;
|
| 511 | }
|
| 512 |
|
| 513 | static bool amdgpu_prefer_rom_resource(struct amdgpu_device *adev)
|
| 514 | {
|
| 515 | struct resource *res = &adev->pdev->resource[PCI_ROM_RESOURCE];
|
| 516 |
|
| 517 | return (res->flags & IORESOURCE_ROM_SHADOW) ||
|
| 518 | adev->pdev == vga_default_device();
|
| 519 | }
|
| 520 |
|
| 521 | static bool amdgpu_get_bios_dgpu(struct amdgpu_device *adev)
|
| 522 | {
|
| 523 | if (amdgpu_atrm_get_bios(adev)) {
|
| 524 | dev_info(adev->dev, "Fetched VBIOS from ATRM\n");
|
| 525 | goto success;
|
| 526 | }
|
| 527 |
|
| 528 | if (amdgpu_acpi_vfct_bios(adev)) {
|
| 529 | dev_info(adev->dev, "Fetched VBIOS from VFCT\n");
|
| 530 | goto success;
|
| 531 | }
|
| 532 |
|
| 533 |
|
| 534 | if (amdgpu_read_bios_from_vram(adev)) {
|
| 535 | dev_info(adev->dev, "Fetched VBIOS from VRAM BAR\n");
|
| 536 | goto success;
|
| 537 | }
|
| 538 |
|
| 539 | if (amdgpu_prefer_rom_resource(adev)) {
|
| 540 | if (amdgpu_read_bios(adev)) {
|
| 541 | dev_info(adev->dev, "Fetched VBIOS from ROM BAR\n");
|
| 542 | goto success;
|
| 543 | }
|
| 544 |
|
| 545 | if (amdgpu_read_platform_bios(adev)) {
|
| 546 | dev_info(adev->dev, "Fetched VBIOS from platform\n");
|
| 547 | goto success;
|
| 548 | }
|
| 549 |
|
| 550 | } else {
|
| 551 | if (amdgpu_read_platform_bios(adev)) {
|
| 552 | dev_info(adev->dev, "Fetched VBIOS from platform\n");
|
| 553 | goto success;
|
| 554 | }
|
| 555 |
|
| 556 | if (amdgpu_read_bios(adev)) {
|
| 557 | dev_info(adev->dev, "Fetched VBIOS from ROM BAR\n");
|
| 558 | goto success;
|
| 559 | }
|
| 560 | }
|
| 561 |
|
| 562 | if (amdgpu_read_bios_from_rom(adev)) {
|
| 563 | dev_info(adev->dev, "Fetched VBIOS from ROM\n");
|
| 564 | goto success;
|
| 565 | }
|
| 566 |
|
| 567 | if (amdgpu_read_disabled_bios(adev)) {
|
| 568 | dev_info(adev->dev, "Fetched VBIOS from disabled ROM BAR\n");
|
| 569 | goto success;
|
| 570 | }
|
| 571 |
|
| 572 | dev_err(adev->dev, "Unable to locate a BIOS ROM\n");
|
| 573 | return false;
|
| 574 |
|
| 575 | success:
|
| 576 | return true;
|
| 577 | }
|
| 578 |
|
| 579 | bool amdgpu_get_bios(struct amdgpu_device *adev)
|
| 580 | {
|
| 581 | bool found;
|
| 582 |
|
| 583 | if (adev->flags & AMD_IS_APU)
|
| 584 | found = amdgpu_get_bios_apu(adev);
|
| 585 | else
|
| 586 | found = amdgpu_get_bios_dgpu(adev);
|
| 587 |
|
| 588 | if (found)
|
| 589 | adev->is_atom_fw = adev->asic_type >= CHIP_VEGA10;
|
| 590 |
|
| 591 | return found;
|
| 592 | }
|
| 593 |
|
| 594 |
|
| 595 | bool amdgpu_soc15_read_bios_from_rom(struct amdgpu_device *adev,
|
| 596 | u8 *bios, u32 length_bytes)
|
| 597 | {
|
| 598 | u32 *dw_ptr;
|
| 599 | u32 i, length_dw;
|
| 600 | u32 rom_offset;
|
| 601 | u32 rom_index_offset;
|
| 602 | u32 rom_data_offset;
|
| 603 |
|
| 604 | if (bios == NULL)
|
| 605 | return false;
|
| 606 | if (length_bytes == 0)
|
| 607 | return false;
|
| 608 |
|
| 609 | if (adev->flags & AMD_IS_APU)
|
| 610 | return false;
|
| 611 | if (!adev->smuio.funcs ||
|
| 612 | !adev->smuio.funcs->get_rom_index_offset ||
|
| 613 | !adev->smuio.funcs->get_rom_data_offset)
|
| 614 | return false;
|
| 615 |
|
| 616 | dw_ptr = (u32 *)bios;
|
| 617 | length_dw = ALIGN(length_bytes, 4) / 4;
|
| 618 |
|
| 619 | rom_index_offset =
|
| 620 | adev->smuio.funcs->get_rom_index_offset(adev);
|
| 621 | rom_data_offset =
|
| 622 | adev->smuio.funcs->get_rom_data_offset(adev);
|
| 623 |
|
| 624 | if (adev->nbio.funcs &&
|
| 625 | adev->nbio.funcs->get_rom_offset) {
|
| 626 | rom_offset = adev->nbio.funcs->get_rom_offset(adev);
|
| 627 | rom_offset = rom_offset << 17;
|
| 628 | } else {
|
| 629 | rom_offset = 0;
|
| 630 | }
|
| 631 |
|
| 632 |
|
| 633 | WREG32(rom_index_offset, rom_offset);
|
| 634 |
|
| 635 | for (i = 0; i < length_dw; i++)
|
| 636 | dw_ptr[i] = RREG32(rom_data_offset);
|
| 637 |
|
| 638 | return true;
|
| 639 | }
|