brintos

brintos / linux-shallow public Read only

0
0
Text · 13.1 KiB · 45affc0 Raw
546 lines · c
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 a7 * copy of this software and associated documentation files (the "Software"),8 * to deal in the Software without restriction, including without limitation9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,10 * and/or sell copies of the Software, and to permit persons to whom the11 * Software is furnished to do so, subject to the following conditions:12 *13 * The above copyright notice and this permission notice shall be included in14 * all copies or substantial portions of the Software.15 *16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL19 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR20 * 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 OR22 * OTHER DEALINGS IN THE SOFTWARE.23 *24 * Authors: Dave Airlie25 *          Alex Deucher26 *          Jerome Glisse27 */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/*37 * BIOS.38 */39 40#define AMD_VBIOS_SIGNATURE " 761295520"41#define AMD_VBIOS_SIGNATURE_OFFSET 0x3042#define AMD_VBIOS_SIGNATURE_SIZE sizeof(AMD_VBIOS_SIGNATURE)43#define AMD_VBIOS_SIGNATURE_END (AMD_VBIOS_SIGNATURE_OFFSET + AMD_VBIOS_SIGNATURE_SIZE)44#define AMD_IS_VALID_VBIOS(p) ((p)[0] == 0x55 && (p)[1] == 0xAA)45#define AMD_VBIOS_LENGTH(p) ((p)[2] << 9)46 47/* Check if current bios is an ATOM BIOS.48 * Return true if it is ATOM BIOS. Otherwise, return false.49 */50static bool check_atom_bios(uint8_t *bios, size_t size)51{52	uint16_t tmp, bios_header_start;53 54	if (!bios || size < 0x49) {55		DRM_INFO("vbios mem is null or mem size is wrong\n");56		return false;57	}58 59	if (!AMD_IS_VALID_VBIOS(bios)) {60		DRM_INFO("BIOS signature incorrect %x %x\n", bios[0], bios[1]);61		return false;62	}63 64	bios_header_start = bios[0x48] | (bios[0x49] << 8);65	if (!bios_header_start) {66		DRM_INFO("Can't locate bios header\n");67		return false;68	}69 70	tmp = bios_header_start + 4;71	if (size < tmp) {72		DRM_INFO("BIOS header is broken\n");73		return false;74	}75 76	if (!memcmp(bios + tmp, "ATOM", 4) ||77	    !memcmp(bios + tmp, "MOTA", 4)) {78		DRM_DEBUG("ATOMBIOS detected\n");79		return true;80	}81 82	return false;83}84 85/* If you boot an IGP board with a discrete card as the primary,86 * the IGP rom is not accessible via the rom bar as the IGP rom is87 * part of the system bios.  On boot, the system bios puts a88 * copy of the igp rom at the start of vram if a discrete card is89 * present.90 * For SR-IOV, the vbios image is also put in VRAM in the VF.91 */92static bool amdgpu_read_bios_from_vram(struct amdgpu_device *adev)93{94	uint8_t __iomem *bios;95	resource_size_t vram_base;96	resource_size_t size = 256 * 1024; /* ??? */97 98	if (!(adev->flags & AMD_IS_APU))99		if (amdgpu_device_need_post(adev))100			return false;101 102	/* FB BAR not enabled */103	if (pci_resource_len(adev->pdev, 0) == 0)104		return false;105 106	adev->bios = NULL;107	vram_base = pci_resource_start(adev->pdev, 0);108	bios = ioremap_wc(vram_base, size);109	if (!bios)110		return false;111 112	adev->bios = kmalloc(size, GFP_KERNEL);113	if (!adev->bios) {114		iounmap(bios);115		return false;116	}117	adev->bios_size = size;118	memcpy_fromio(adev->bios, bios, size);119	iounmap(bios);120 121	if (!check_atom_bios(adev->bios, size)) {122		kfree(adev->bios);123		return false;124	}125 126	return true;127}128 129bool amdgpu_read_bios(struct amdgpu_device *adev)130{131	uint8_t __iomem *bios;132	size_t size;133 134	adev->bios = NULL;135	/* XXX: some cards may return 0 for rom size? ddx has a workaround */136	bios = pci_map_rom(adev->pdev, &size);137	if (!bios)138		return false;139 140	adev->bios = kzalloc(size, GFP_KERNEL);141	if (adev->bios == NULL) {142		pci_unmap_rom(adev->pdev, bios);143		return false;144	}145	adev->bios_size = size;146	memcpy_fromio(adev->bios, bios, size);147	pci_unmap_rom(adev->pdev, bios);148 149	if (!check_atom_bios(adev->bios, size)) {150		kfree(adev->bios);151		return false;152	}153 154	return true;155}156 157static bool amdgpu_read_bios_from_rom(struct amdgpu_device *adev)158{159	u8 header[AMD_VBIOS_SIGNATURE_END+1] = {0};160	int len;161 162	if (!adev->asic_funcs || !adev->asic_funcs->read_bios_from_rom)163		return false;164 165	/* validate VBIOS signature */166	if (amdgpu_asic_read_bios_from_rom(adev, &header[0], sizeof(header)) == false)167		return false;168	header[AMD_VBIOS_SIGNATURE_END] = 0;169 170	if ((!AMD_IS_VALID_VBIOS(header)) ||171		memcmp((char *)&header[AMD_VBIOS_SIGNATURE_OFFSET],172		       AMD_VBIOS_SIGNATURE,173		       strlen(AMD_VBIOS_SIGNATURE)) != 0)174		return false;175 176	/* valid vbios, go on */177	len = AMD_VBIOS_LENGTH(header);178	len = ALIGN(len, 4);179	adev->bios = kmalloc(len, GFP_KERNEL);180	if (!adev->bios) {181		DRM_ERROR("no memory to allocate for BIOS\n");182		return false;183	}184	adev->bios_size = len;185 186	/* read complete BIOS */187	amdgpu_asic_read_bios_from_rom(adev, adev->bios, len);188 189	if (!check_atom_bios(adev->bios, len)) {190		kfree(adev->bios);191		return false;192	}193 194	return true;195}196 197static bool amdgpu_read_platform_bios(struct amdgpu_device *adev)198{199	phys_addr_t rom = adev->pdev->rom;200	size_t romlen = adev->pdev->romlen;201	void __iomem *bios;202 203	adev->bios = NULL;204 205	if (!rom || romlen == 0)206		return false;207 208	adev->bios = kzalloc(romlen, GFP_KERNEL);209	if (!adev->bios)210		return false;211 212	bios = ioremap(rom, romlen);213	if (!bios)214		goto free_bios;215 216	memcpy_fromio(adev->bios, bios, romlen);217	iounmap(bios);218 219	if (!check_atom_bios(adev->bios, romlen))220		goto free_bios;221 222	adev->bios_size = romlen;223 224	return true;225free_bios:226	kfree(adev->bios);227	return false;228}229 230#ifdef CONFIG_ACPI231/* ATRM is used to get the BIOS on the discrete cards in232 * dual-gpu systems.233 */234/* retrieve the ROM in 4k blocks */235#define ATRM_BIOS_PAGE 4096236/**237 * amdgpu_atrm_call - fetch a chunk of the vbios238 *239 * @atrm_handle: acpi ATRM handle240 * @bios: vbios image pointer241 * @offset: offset of vbios image data to fetch242 * @len: length of vbios image data to fetch243 *244 * Executes ATRM to fetch a chunk of the discrete245 * vbios image on PX systems (all asics).246 * Returns the length of the buffer fetched.247 */248static int amdgpu_atrm_call(acpi_handle atrm_handle, uint8_t *bios,249			    int offset, int len)250{251	acpi_status status;252	union acpi_object atrm_arg_elements[2], *obj;253	struct acpi_object_list atrm_arg;254	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL};255 256	atrm_arg.count = 2;257	atrm_arg.pointer = &atrm_arg_elements[0];258 259	atrm_arg_elements[0].type = ACPI_TYPE_INTEGER;260	atrm_arg_elements[0].integer.value = offset;261 262	atrm_arg_elements[1].type = ACPI_TYPE_INTEGER;263	atrm_arg_elements[1].integer.value = len;264 265	status = acpi_evaluate_object(atrm_handle, NULL, &atrm_arg, &buffer);266	if (ACPI_FAILURE(status)) {267		DRM_ERROR("failed to evaluate ATRM got %s\n", acpi_format_exception(status));268		return -ENODEV;269	}270 271	obj = (union acpi_object *)buffer.pointer;272	memcpy(bios+offset, obj->buffer.pointer, obj->buffer.length);273	len = obj->buffer.length;274	kfree(buffer.pointer);275	return len;276}277 278static bool amdgpu_atrm_get_bios(struct amdgpu_device *adev)279{280	int ret;281	int size = 256 * 1024;282	int i;283	struct pci_dev *pdev = NULL;284	acpi_handle dhandle, atrm_handle;285	acpi_status status;286	bool found = false;287 288	/* ATRM is for on-platform devices only */289	if (dev_is_removable(&adev->pdev->dev))290		return false;291 292	while ((pdev = pci_get_base_class(PCI_BASE_CLASS_DISPLAY, pdev))) {293		if ((pdev->class != PCI_CLASS_DISPLAY_VGA << 8) &&294		    (pdev->class != PCI_CLASS_DISPLAY_OTHER << 8))295			continue;296 297		dhandle = ACPI_HANDLE(&pdev->dev);298		if (!dhandle)299			continue;300 301		status = acpi_get_handle(dhandle, "ATRM", &atrm_handle);302		if (ACPI_SUCCESS(status)) {303			found = true;304			break;305		}306	}307 308	if (!found)309		return false;310	pci_dev_put(pdev);311 312	adev->bios = kmalloc(size, GFP_KERNEL);313	if (!adev->bios) {314		dev_err(adev->dev, "Unable to allocate bios\n");315		return false;316	}317 318	for (i = 0; i < size / ATRM_BIOS_PAGE; i++) {319		ret = amdgpu_atrm_call(atrm_handle,320				       adev->bios,321				       (i * ATRM_BIOS_PAGE),322				       ATRM_BIOS_PAGE);323		if (ret < ATRM_BIOS_PAGE)324			break;325	}326 327	if (!check_atom_bios(adev->bios, size)) {328		kfree(adev->bios);329		return false;330	}331	adev->bios_size = size;332	return true;333}334#else335static inline bool amdgpu_atrm_get_bios(struct amdgpu_device *adev)336{337	return false;338}339#endif340 341static bool amdgpu_read_disabled_bios(struct amdgpu_device *adev)342{343	return (!adev->asic_funcs || !adev->asic_funcs->read_disabled_bios) ?344		false : amdgpu_asic_read_disabled_bios(adev);345}346 347#ifdef CONFIG_ACPI348static bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)349{350	struct acpi_table_header *hdr;351	acpi_size tbl_size;352	UEFI_ACPI_VFCT *vfct;353	unsigned int offset;354 355	if (!ACPI_SUCCESS(acpi_get_table("VFCT", 1, &hdr)))356		return false;357	tbl_size = hdr->length;358	if (tbl_size < sizeof(UEFI_ACPI_VFCT)) {359		dev_info(adev->dev, "ACPI VFCT table present but broken (too short #1),skipping\n");360		return false;361	}362 363	vfct = (UEFI_ACPI_VFCT *)hdr;364	offset = vfct->VBIOSImageOffset;365 366	while (offset < tbl_size) {367		GOP_VBIOS_CONTENT *vbios = (GOP_VBIOS_CONTENT *)((char *)hdr + offset);368		VFCT_IMAGE_HEADER *vhdr = &vbios->VbiosHeader;369 370		offset += sizeof(VFCT_IMAGE_HEADER);371		if (offset > tbl_size) {372			dev_info(adev->dev, "ACPI VFCT image header truncated,skipping\n");373			return false;374		}375 376		offset += vhdr->ImageLength;377		if (offset > tbl_size) {378			dev_info(adev->dev, "ACPI VFCT image truncated,skipping\n");379			return false;380		}381 382		if (vhdr->ImageLength &&383		    vhdr->PCIBus == adev->pdev->bus->number &&384		    vhdr->PCIDevice == PCI_SLOT(adev->pdev->devfn) &&385		    vhdr->PCIFunction == PCI_FUNC(adev->pdev->devfn) &&386		    vhdr->VendorID == adev->pdev->vendor &&387		    vhdr->DeviceID == adev->pdev->device) {388			adev->bios = kmemdup(&vbios->VbiosContent,389					     vhdr->ImageLength,390					     GFP_KERNEL);391 392			if (!check_atom_bios(adev->bios, vhdr->ImageLength)) {393				kfree(adev->bios);394				return false;395			}396			adev->bios_size = vhdr->ImageLength;397			return true;398		}399	}400 401	dev_info(adev->dev, "ACPI VFCT table present but broken (too short #2),skipping\n");402	return false;403}404#else405static inline bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)406{407	return false;408}409#endif410 411static bool amdgpu_get_bios_apu(struct amdgpu_device *adev)412{413	if (amdgpu_acpi_vfct_bios(adev)) {414		dev_info(adev->dev, "Fetched VBIOS from VFCT\n");415		goto success;416	}417 418	if (amdgpu_read_bios_from_vram(adev)) {419		dev_info(adev->dev, "Fetched VBIOS from VRAM BAR\n");420		goto success;421	}422 423	if (amdgpu_read_bios(adev)) {424		dev_info(adev->dev, "Fetched VBIOS from ROM BAR\n");425		goto success;426	}427 428	if (amdgpu_read_platform_bios(adev)) {429		dev_info(adev->dev, "Fetched VBIOS from platform\n");430		goto success;431	}432 433	dev_err(adev->dev, "Unable to locate a BIOS ROM\n");434	return false;435 436success:437	return true;438}439 440static bool amdgpu_get_bios_dgpu(struct amdgpu_device *adev)441{442	if (amdgpu_atrm_get_bios(adev)) {443		dev_info(adev->dev, "Fetched VBIOS from ATRM\n");444		goto success;445	}446 447	if (amdgpu_acpi_vfct_bios(adev)) {448		dev_info(adev->dev, "Fetched VBIOS from VFCT\n");449		goto success;450	}451 452	/* this is required for SR-IOV */453	if (amdgpu_read_bios_from_vram(adev)) {454		dev_info(adev->dev, "Fetched VBIOS from VRAM BAR\n");455		goto success;456	}457 458	if (amdgpu_read_platform_bios(adev)) {459		dev_info(adev->dev, "Fetched VBIOS from platform\n");460		goto success;461	}462 463	if (amdgpu_read_bios(adev)) {464		dev_info(adev->dev, "Fetched VBIOS from ROM BAR\n");465		goto success;466	}467 468	if (amdgpu_read_bios_from_rom(adev)) {469		dev_info(adev->dev, "Fetched VBIOS from ROM\n");470		goto success;471	}472 473	if (amdgpu_read_disabled_bios(adev)) {474		dev_info(adev->dev, "Fetched VBIOS from disabled ROM BAR\n");475		goto success;476	}477 478	dev_err(adev->dev, "Unable to locate a BIOS ROM\n");479	return false;480 481success:482	return true;483}484 485bool amdgpu_get_bios(struct amdgpu_device *adev)486{487	bool found;488 489	if (adev->flags & AMD_IS_APU)490		found = amdgpu_get_bios_apu(adev);491	else492		found = amdgpu_get_bios_dgpu(adev);493 494	if (found)495		adev->is_atom_fw = adev->asic_type >= CHIP_VEGA10;496 497	return found;498}499 500/* helper function for soc15 and onwards to read bios from rom */501bool amdgpu_soc15_read_bios_from_rom(struct amdgpu_device *adev,502				     u8 *bios, u32 length_bytes)503{504	u32 *dw_ptr;505	u32 i, length_dw;506	u32 rom_offset;507	u32 rom_index_offset;508	u32 rom_data_offset;509 510	if (bios == NULL)511		return false;512	if (length_bytes == 0)513		return false;514	/* APU vbios image is part of sbios image */515	if (adev->flags & AMD_IS_APU)516		return false;517	if (!adev->smuio.funcs ||518	    !adev->smuio.funcs->get_rom_index_offset ||519	    !adev->smuio.funcs->get_rom_data_offset)520		return false;521 522	dw_ptr = (u32 *)bios;523	length_dw = ALIGN(length_bytes, 4) / 4;524 525	rom_index_offset =526		adev->smuio.funcs->get_rom_index_offset(adev);527	rom_data_offset =528		adev->smuio.funcs->get_rom_data_offset(adev);529 530	if (adev->nbio.funcs &&531	    adev->nbio.funcs->get_rom_offset) {532		rom_offset = adev->nbio.funcs->get_rom_offset(adev);533		rom_offset = rom_offset << 17;534	} else {535		rom_offset = 0;536	}537 538	/* set rom index to rom_offset */539	WREG32(rom_index_offset, rom_offset);540	/* read out the rom data */541	for (i = 0; i < length_dw; i++)542		dw_ptr[i] = RREG32(rom_data_offset);543 544	return true;545}546