162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright 2008 Advanced Micro Devices, Inc.
362306a36Sopenharmony_ci * Copyright 2008 Red Hat Inc.
462306a36Sopenharmony_ci * Copyright 2009 Jerome Glisse.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
762306a36Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
862306a36Sopenharmony_ci * to deal in the Software without restriction, including without limitation
962306a36Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1062306a36Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
1162306a36Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
1262306a36Sopenharmony_ci *
1362306a36Sopenharmony_ci * The above copyright notice and this permission notice shall be included in
1462306a36Sopenharmony_ci * all copies or substantial portions of the Software.
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1762306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1862306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1962306a36Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
2062306a36Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
2162306a36Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2262306a36Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE.
2362306a36Sopenharmony_ci *
2462306a36Sopenharmony_ci * Authors: Dave Airlie
2562306a36Sopenharmony_ci *          Alex Deucher
2662306a36Sopenharmony_ci *          Jerome Glisse
2762306a36Sopenharmony_ci */
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#include <linux/acpi.h>
3062306a36Sopenharmony_ci#include <linux/pci.h>
3162306a36Sopenharmony_ci#include <linux/slab.h>
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#include <drm/drm_device.h>
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#include "atom.h"
3662306a36Sopenharmony_ci#include "radeon.h"
3762306a36Sopenharmony_ci#include "radeon_reg.h"
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci/*
4062306a36Sopenharmony_ci * BIOS.
4162306a36Sopenharmony_ci */
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci/* If you boot an IGP board with a discrete card as the primary,
4462306a36Sopenharmony_ci * the IGP rom is not accessible via the rom bar as the IGP rom is
4562306a36Sopenharmony_ci * part of the system bios.  On boot, the system bios puts a
4662306a36Sopenharmony_ci * copy of the igp rom at the start of vram if a discrete card is
4762306a36Sopenharmony_ci * present.
4862306a36Sopenharmony_ci */
4962306a36Sopenharmony_cistatic bool igp_read_bios_from_vram(struct radeon_device *rdev)
5062306a36Sopenharmony_ci{
5162306a36Sopenharmony_ci	uint8_t __iomem *bios;
5262306a36Sopenharmony_ci	resource_size_t vram_base;
5362306a36Sopenharmony_ci	resource_size_t size = 256 * 1024; /* ??? */
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	if (!(rdev->flags & RADEON_IS_IGP))
5662306a36Sopenharmony_ci		if (!radeon_card_posted(rdev))
5762306a36Sopenharmony_ci			return false;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	rdev->bios = NULL;
6062306a36Sopenharmony_ci	vram_base = pci_resource_start(rdev->pdev, 0);
6162306a36Sopenharmony_ci	bios = ioremap(vram_base, size);
6262306a36Sopenharmony_ci	if (!bios) {
6362306a36Sopenharmony_ci		return false;
6462306a36Sopenharmony_ci	}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	if (size == 0 || bios[0] != 0x55 || bios[1] != 0xaa) {
6762306a36Sopenharmony_ci		iounmap(bios);
6862306a36Sopenharmony_ci		return false;
6962306a36Sopenharmony_ci	}
7062306a36Sopenharmony_ci	rdev->bios = kmalloc(size, GFP_KERNEL);
7162306a36Sopenharmony_ci	if (rdev->bios == NULL) {
7262306a36Sopenharmony_ci		iounmap(bios);
7362306a36Sopenharmony_ci		return false;
7462306a36Sopenharmony_ci	}
7562306a36Sopenharmony_ci	memcpy_fromio(rdev->bios, bios, size);
7662306a36Sopenharmony_ci	iounmap(bios);
7762306a36Sopenharmony_ci	return true;
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cistatic bool radeon_read_bios(struct radeon_device *rdev)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	uint8_t __iomem *bios, val1, val2;
8362306a36Sopenharmony_ci	size_t size;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	rdev->bios = NULL;
8662306a36Sopenharmony_ci	/* XXX: some cards may return 0 for rom size? ddx has a workaround */
8762306a36Sopenharmony_ci	bios = pci_map_rom(rdev->pdev, &size);
8862306a36Sopenharmony_ci	if (!bios) {
8962306a36Sopenharmony_ci		return false;
9062306a36Sopenharmony_ci	}
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	val1 = readb(&bios[0]);
9362306a36Sopenharmony_ci	val2 = readb(&bios[1]);
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	if (size == 0 || val1 != 0x55 || val2 != 0xaa) {
9662306a36Sopenharmony_ci		pci_unmap_rom(rdev->pdev, bios);
9762306a36Sopenharmony_ci		return false;
9862306a36Sopenharmony_ci	}
9962306a36Sopenharmony_ci	rdev->bios = kzalloc(size, GFP_KERNEL);
10062306a36Sopenharmony_ci	if (rdev->bios == NULL) {
10162306a36Sopenharmony_ci		pci_unmap_rom(rdev->pdev, bios);
10262306a36Sopenharmony_ci		return false;
10362306a36Sopenharmony_ci	}
10462306a36Sopenharmony_ci	memcpy_fromio(rdev->bios, bios, size);
10562306a36Sopenharmony_ci	pci_unmap_rom(rdev->pdev, bios);
10662306a36Sopenharmony_ci	return true;
10762306a36Sopenharmony_ci}
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_cistatic bool radeon_read_platform_bios(struct radeon_device *rdev)
11062306a36Sopenharmony_ci{
11162306a36Sopenharmony_ci	phys_addr_t rom = rdev->pdev->rom;
11262306a36Sopenharmony_ci	size_t romlen = rdev->pdev->romlen;
11362306a36Sopenharmony_ci	void __iomem *bios;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	rdev->bios = NULL;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	if (!rom || romlen == 0)
11862306a36Sopenharmony_ci		return false;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	rdev->bios = kzalloc(romlen, GFP_KERNEL);
12162306a36Sopenharmony_ci	if (!rdev->bios)
12262306a36Sopenharmony_ci		return false;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	bios = ioremap(rom, romlen);
12562306a36Sopenharmony_ci	if (!bios)
12662306a36Sopenharmony_ci		goto free_bios;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	memcpy_fromio(rdev->bios, bios, romlen);
12962306a36Sopenharmony_ci	iounmap(bios);
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	if (rdev->bios[0] != 0x55 || rdev->bios[1] != 0xaa)
13262306a36Sopenharmony_ci		goto free_bios;
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	return true;
13562306a36Sopenharmony_cifree_bios:
13662306a36Sopenharmony_ci	kfree(rdev->bios);
13762306a36Sopenharmony_ci	return false;
13862306a36Sopenharmony_ci}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci#ifdef CONFIG_ACPI
14162306a36Sopenharmony_ci/* ATRM is used to get the BIOS on the discrete cards in
14262306a36Sopenharmony_ci * dual-gpu systems.
14362306a36Sopenharmony_ci */
14462306a36Sopenharmony_ci/* retrieve the ROM in 4k blocks */
14562306a36Sopenharmony_ci#define ATRM_BIOS_PAGE 4096
14662306a36Sopenharmony_ci/**
14762306a36Sopenharmony_ci * radeon_atrm_call - fetch a chunk of the vbios
14862306a36Sopenharmony_ci *
14962306a36Sopenharmony_ci * @atrm_handle: acpi ATRM handle
15062306a36Sopenharmony_ci * @bios: vbios image pointer
15162306a36Sopenharmony_ci * @offset: offset of vbios image data to fetch
15262306a36Sopenharmony_ci * @len: length of vbios image data to fetch
15362306a36Sopenharmony_ci *
15462306a36Sopenharmony_ci * Executes ATRM to fetch a chunk of the discrete
15562306a36Sopenharmony_ci * vbios image on PX systems (all asics).
15662306a36Sopenharmony_ci * Returns the length of the buffer fetched.
15762306a36Sopenharmony_ci */
15862306a36Sopenharmony_cistatic int radeon_atrm_call(acpi_handle atrm_handle, uint8_t *bios,
15962306a36Sopenharmony_ci			    int offset, int len)
16062306a36Sopenharmony_ci{
16162306a36Sopenharmony_ci	acpi_status status;
16262306a36Sopenharmony_ci	union acpi_object atrm_arg_elements[2], *obj;
16362306a36Sopenharmony_ci	struct acpi_object_list atrm_arg;
16462306a36Sopenharmony_ci	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL};
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	atrm_arg.count = 2;
16762306a36Sopenharmony_ci	atrm_arg.pointer = &atrm_arg_elements[0];
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	atrm_arg_elements[0].type = ACPI_TYPE_INTEGER;
17062306a36Sopenharmony_ci	atrm_arg_elements[0].integer.value = offset;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	atrm_arg_elements[1].type = ACPI_TYPE_INTEGER;
17362306a36Sopenharmony_ci	atrm_arg_elements[1].integer.value = len;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	status = acpi_evaluate_object(atrm_handle, NULL, &atrm_arg, &buffer);
17662306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
17762306a36Sopenharmony_ci		printk("failed to evaluate ATRM got %s\n", acpi_format_exception(status));
17862306a36Sopenharmony_ci		return -ENODEV;
17962306a36Sopenharmony_ci	}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	obj = (union acpi_object *)buffer.pointer;
18262306a36Sopenharmony_ci	memcpy(bios+offset, obj->buffer.pointer, obj->buffer.length);
18362306a36Sopenharmony_ci	len = obj->buffer.length;
18462306a36Sopenharmony_ci	kfree(buffer.pointer);
18562306a36Sopenharmony_ci	return len;
18662306a36Sopenharmony_ci}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_cistatic bool radeon_atrm_get_bios(struct radeon_device *rdev)
18962306a36Sopenharmony_ci{
19062306a36Sopenharmony_ci	int ret;
19162306a36Sopenharmony_ci	int size = 256 * 1024;
19262306a36Sopenharmony_ci	int i;
19362306a36Sopenharmony_ci	struct pci_dev *pdev = NULL;
19462306a36Sopenharmony_ci	acpi_handle dhandle, atrm_handle;
19562306a36Sopenharmony_ci	acpi_status status;
19662306a36Sopenharmony_ci	bool found = false;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	/* ATRM is for the discrete card only */
19962306a36Sopenharmony_ci	if (rdev->flags & RADEON_IS_IGP)
20062306a36Sopenharmony_ci		return false;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
20362306a36Sopenharmony_ci		dhandle = ACPI_HANDLE(&pdev->dev);
20462306a36Sopenharmony_ci		if (!dhandle)
20562306a36Sopenharmony_ci			continue;
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci		status = acpi_get_handle(dhandle, "ATRM", &atrm_handle);
20862306a36Sopenharmony_ci		if (ACPI_SUCCESS(status)) {
20962306a36Sopenharmony_ci			found = true;
21062306a36Sopenharmony_ci			break;
21162306a36Sopenharmony_ci		}
21262306a36Sopenharmony_ci	}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	if (!found) {
21562306a36Sopenharmony_ci		while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_OTHER << 8, pdev)) != NULL) {
21662306a36Sopenharmony_ci			dhandle = ACPI_HANDLE(&pdev->dev);
21762306a36Sopenharmony_ci			if (!dhandle)
21862306a36Sopenharmony_ci				continue;
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci			status = acpi_get_handle(dhandle, "ATRM", &atrm_handle);
22162306a36Sopenharmony_ci			if (ACPI_SUCCESS(status)) {
22262306a36Sopenharmony_ci				found = true;
22362306a36Sopenharmony_ci				break;
22462306a36Sopenharmony_ci			}
22562306a36Sopenharmony_ci		}
22662306a36Sopenharmony_ci	}
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	if (!found)
22962306a36Sopenharmony_ci		return false;
23062306a36Sopenharmony_ci	pci_dev_put(pdev);
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	rdev->bios = kmalloc(size, GFP_KERNEL);
23362306a36Sopenharmony_ci	if (!rdev->bios) {
23462306a36Sopenharmony_ci		DRM_ERROR("Unable to allocate bios\n");
23562306a36Sopenharmony_ci		return false;
23662306a36Sopenharmony_ci	}
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	for (i = 0; i < size / ATRM_BIOS_PAGE; i++) {
23962306a36Sopenharmony_ci		ret = radeon_atrm_call(atrm_handle,
24062306a36Sopenharmony_ci				       rdev->bios,
24162306a36Sopenharmony_ci				       (i * ATRM_BIOS_PAGE),
24262306a36Sopenharmony_ci				       ATRM_BIOS_PAGE);
24362306a36Sopenharmony_ci		if (ret < ATRM_BIOS_PAGE)
24462306a36Sopenharmony_ci			break;
24562306a36Sopenharmony_ci	}
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	if (i == 0 || rdev->bios[0] != 0x55 || rdev->bios[1] != 0xaa) {
24862306a36Sopenharmony_ci		kfree(rdev->bios);
24962306a36Sopenharmony_ci		return false;
25062306a36Sopenharmony_ci	}
25162306a36Sopenharmony_ci	return true;
25262306a36Sopenharmony_ci}
25362306a36Sopenharmony_ci#else
25462306a36Sopenharmony_cistatic inline bool radeon_atrm_get_bios(struct radeon_device *rdev)
25562306a36Sopenharmony_ci{
25662306a36Sopenharmony_ci	return false;
25762306a36Sopenharmony_ci}
25862306a36Sopenharmony_ci#endif
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_cistatic bool ni_read_disabled_bios(struct radeon_device *rdev)
26162306a36Sopenharmony_ci{
26262306a36Sopenharmony_ci	u32 bus_cntl;
26362306a36Sopenharmony_ci	u32 d1vga_control;
26462306a36Sopenharmony_ci	u32 d2vga_control;
26562306a36Sopenharmony_ci	u32 vga_render_control;
26662306a36Sopenharmony_ci	u32 rom_cntl;
26762306a36Sopenharmony_ci	bool r;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	bus_cntl = RREG32(R600_BUS_CNTL);
27062306a36Sopenharmony_ci	d1vga_control = RREG32(AVIVO_D1VGA_CONTROL);
27162306a36Sopenharmony_ci	d2vga_control = RREG32(AVIVO_D2VGA_CONTROL);
27262306a36Sopenharmony_ci	vga_render_control = RREG32(AVIVO_VGA_RENDER_CONTROL);
27362306a36Sopenharmony_ci	rom_cntl = RREG32(R600_ROM_CNTL);
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	/* enable the rom */
27662306a36Sopenharmony_ci	WREG32(R600_BUS_CNTL, (bus_cntl & ~R600_BIOS_ROM_DIS));
27762306a36Sopenharmony_ci	if (!ASIC_IS_NODCE(rdev)) {
27862306a36Sopenharmony_ci		/* Disable VGA mode */
27962306a36Sopenharmony_ci		WREG32(AVIVO_D1VGA_CONTROL,
28062306a36Sopenharmony_ci		       (d1vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE |
28162306a36Sopenharmony_ci					  AVIVO_DVGA_CONTROL_TIMING_SELECT)));
28262306a36Sopenharmony_ci		WREG32(AVIVO_D2VGA_CONTROL,
28362306a36Sopenharmony_ci		       (d2vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE |
28462306a36Sopenharmony_ci					  AVIVO_DVGA_CONTROL_TIMING_SELECT)));
28562306a36Sopenharmony_ci		WREG32(AVIVO_VGA_RENDER_CONTROL,
28662306a36Sopenharmony_ci		       (vga_render_control & ~AVIVO_VGA_VSTATUS_CNTL_MASK));
28762306a36Sopenharmony_ci	}
28862306a36Sopenharmony_ci	WREG32(R600_ROM_CNTL, rom_cntl | R600_SCK_OVERWRITE);
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	r = radeon_read_bios(rdev);
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	/* restore regs */
29362306a36Sopenharmony_ci	WREG32(R600_BUS_CNTL, bus_cntl);
29462306a36Sopenharmony_ci	if (!ASIC_IS_NODCE(rdev)) {
29562306a36Sopenharmony_ci		WREG32(AVIVO_D1VGA_CONTROL, d1vga_control);
29662306a36Sopenharmony_ci		WREG32(AVIVO_D2VGA_CONTROL, d2vga_control);
29762306a36Sopenharmony_ci		WREG32(AVIVO_VGA_RENDER_CONTROL, vga_render_control);
29862306a36Sopenharmony_ci	}
29962306a36Sopenharmony_ci	WREG32(R600_ROM_CNTL, rom_cntl);
30062306a36Sopenharmony_ci	return r;
30162306a36Sopenharmony_ci}
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_cistatic bool r700_read_disabled_bios(struct radeon_device *rdev)
30462306a36Sopenharmony_ci{
30562306a36Sopenharmony_ci	uint32_t viph_control;
30662306a36Sopenharmony_ci	uint32_t bus_cntl;
30762306a36Sopenharmony_ci	uint32_t d1vga_control;
30862306a36Sopenharmony_ci	uint32_t d2vga_control;
30962306a36Sopenharmony_ci	uint32_t vga_render_control;
31062306a36Sopenharmony_ci	uint32_t rom_cntl;
31162306a36Sopenharmony_ci	uint32_t cg_spll_func_cntl = 0;
31262306a36Sopenharmony_ci	uint32_t cg_spll_status;
31362306a36Sopenharmony_ci	bool r;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	viph_control = RREG32(RADEON_VIPH_CONTROL);
31662306a36Sopenharmony_ci	bus_cntl = RREG32(R600_BUS_CNTL);
31762306a36Sopenharmony_ci	d1vga_control = RREG32(AVIVO_D1VGA_CONTROL);
31862306a36Sopenharmony_ci	d2vga_control = RREG32(AVIVO_D2VGA_CONTROL);
31962306a36Sopenharmony_ci	vga_render_control = RREG32(AVIVO_VGA_RENDER_CONTROL);
32062306a36Sopenharmony_ci	rom_cntl = RREG32(R600_ROM_CNTL);
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	/* disable VIP */
32362306a36Sopenharmony_ci	WREG32(RADEON_VIPH_CONTROL, (viph_control & ~RADEON_VIPH_EN));
32462306a36Sopenharmony_ci	/* enable the rom */
32562306a36Sopenharmony_ci	WREG32(R600_BUS_CNTL, (bus_cntl & ~R600_BIOS_ROM_DIS));
32662306a36Sopenharmony_ci	/* Disable VGA mode */
32762306a36Sopenharmony_ci	WREG32(AVIVO_D1VGA_CONTROL,
32862306a36Sopenharmony_ci	       (d1vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE |
32962306a36Sopenharmony_ci		AVIVO_DVGA_CONTROL_TIMING_SELECT)));
33062306a36Sopenharmony_ci	WREG32(AVIVO_D2VGA_CONTROL,
33162306a36Sopenharmony_ci	       (d2vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE |
33262306a36Sopenharmony_ci		AVIVO_DVGA_CONTROL_TIMING_SELECT)));
33362306a36Sopenharmony_ci	WREG32(AVIVO_VGA_RENDER_CONTROL,
33462306a36Sopenharmony_ci	       (vga_render_control & ~AVIVO_VGA_VSTATUS_CNTL_MASK));
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	if (rdev->family == CHIP_RV730) {
33762306a36Sopenharmony_ci		cg_spll_func_cntl = RREG32(R600_CG_SPLL_FUNC_CNTL);
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci		/* enable bypass mode */
34062306a36Sopenharmony_ci		WREG32(R600_CG_SPLL_FUNC_CNTL, (cg_spll_func_cntl |
34162306a36Sopenharmony_ci						R600_SPLL_BYPASS_EN));
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci		/* wait for SPLL_CHG_STATUS to change to 1 */
34462306a36Sopenharmony_ci		cg_spll_status = 0;
34562306a36Sopenharmony_ci		while (!(cg_spll_status & R600_SPLL_CHG_STATUS))
34662306a36Sopenharmony_ci			cg_spll_status = RREG32(R600_CG_SPLL_STATUS);
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci		WREG32(R600_ROM_CNTL, (rom_cntl & ~R600_SCK_OVERWRITE));
34962306a36Sopenharmony_ci	} else
35062306a36Sopenharmony_ci		WREG32(R600_ROM_CNTL, (rom_cntl | R600_SCK_OVERWRITE));
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	r = radeon_read_bios(rdev);
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	/* restore regs */
35562306a36Sopenharmony_ci	if (rdev->family == CHIP_RV730) {
35662306a36Sopenharmony_ci		WREG32(R600_CG_SPLL_FUNC_CNTL, cg_spll_func_cntl);
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci		/* wait for SPLL_CHG_STATUS to change to 1 */
35962306a36Sopenharmony_ci		cg_spll_status = 0;
36062306a36Sopenharmony_ci		while (!(cg_spll_status & R600_SPLL_CHG_STATUS))
36162306a36Sopenharmony_ci			cg_spll_status = RREG32(R600_CG_SPLL_STATUS);
36262306a36Sopenharmony_ci	}
36362306a36Sopenharmony_ci	WREG32(RADEON_VIPH_CONTROL, viph_control);
36462306a36Sopenharmony_ci	WREG32(R600_BUS_CNTL, bus_cntl);
36562306a36Sopenharmony_ci	WREG32(AVIVO_D1VGA_CONTROL, d1vga_control);
36662306a36Sopenharmony_ci	WREG32(AVIVO_D2VGA_CONTROL, d2vga_control);
36762306a36Sopenharmony_ci	WREG32(AVIVO_VGA_RENDER_CONTROL, vga_render_control);
36862306a36Sopenharmony_ci	WREG32(R600_ROM_CNTL, rom_cntl);
36962306a36Sopenharmony_ci	return r;
37062306a36Sopenharmony_ci}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_cistatic bool r600_read_disabled_bios(struct radeon_device *rdev)
37362306a36Sopenharmony_ci{
37462306a36Sopenharmony_ci	uint32_t viph_control;
37562306a36Sopenharmony_ci	uint32_t bus_cntl;
37662306a36Sopenharmony_ci	uint32_t d1vga_control;
37762306a36Sopenharmony_ci	uint32_t d2vga_control;
37862306a36Sopenharmony_ci	uint32_t vga_render_control;
37962306a36Sopenharmony_ci	uint32_t rom_cntl;
38062306a36Sopenharmony_ci	uint32_t general_pwrmgt;
38162306a36Sopenharmony_ci	uint32_t low_vid_lower_gpio_cntl;
38262306a36Sopenharmony_ci	uint32_t medium_vid_lower_gpio_cntl;
38362306a36Sopenharmony_ci	uint32_t high_vid_lower_gpio_cntl;
38462306a36Sopenharmony_ci	uint32_t ctxsw_vid_lower_gpio_cntl;
38562306a36Sopenharmony_ci	uint32_t lower_gpio_enable;
38662306a36Sopenharmony_ci	bool r;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	viph_control = RREG32(RADEON_VIPH_CONTROL);
38962306a36Sopenharmony_ci	bus_cntl = RREG32(R600_BUS_CNTL);
39062306a36Sopenharmony_ci	d1vga_control = RREG32(AVIVO_D1VGA_CONTROL);
39162306a36Sopenharmony_ci	d2vga_control = RREG32(AVIVO_D2VGA_CONTROL);
39262306a36Sopenharmony_ci	vga_render_control = RREG32(AVIVO_VGA_RENDER_CONTROL);
39362306a36Sopenharmony_ci	rom_cntl = RREG32(R600_ROM_CNTL);
39462306a36Sopenharmony_ci	general_pwrmgt = RREG32(R600_GENERAL_PWRMGT);
39562306a36Sopenharmony_ci	low_vid_lower_gpio_cntl = RREG32(R600_LOW_VID_LOWER_GPIO_CNTL);
39662306a36Sopenharmony_ci	medium_vid_lower_gpio_cntl = RREG32(R600_MEDIUM_VID_LOWER_GPIO_CNTL);
39762306a36Sopenharmony_ci	high_vid_lower_gpio_cntl = RREG32(R600_HIGH_VID_LOWER_GPIO_CNTL);
39862306a36Sopenharmony_ci	ctxsw_vid_lower_gpio_cntl = RREG32(R600_CTXSW_VID_LOWER_GPIO_CNTL);
39962306a36Sopenharmony_ci	lower_gpio_enable = RREG32(R600_LOWER_GPIO_ENABLE);
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	/* disable VIP */
40262306a36Sopenharmony_ci	WREG32(RADEON_VIPH_CONTROL, (viph_control & ~RADEON_VIPH_EN));
40362306a36Sopenharmony_ci	/* enable the rom */
40462306a36Sopenharmony_ci	WREG32(R600_BUS_CNTL, (bus_cntl & ~R600_BIOS_ROM_DIS));
40562306a36Sopenharmony_ci	/* Disable VGA mode */
40662306a36Sopenharmony_ci	WREG32(AVIVO_D1VGA_CONTROL,
40762306a36Sopenharmony_ci	       (d1vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE |
40862306a36Sopenharmony_ci		AVIVO_DVGA_CONTROL_TIMING_SELECT)));
40962306a36Sopenharmony_ci	WREG32(AVIVO_D2VGA_CONTROL,
41062306a36Sopenharmony_ci	       (d2vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE |
41162306a36Sopenharmony_ci		AVIVO_DVGA_CONTROL_TIMING_SELECT)));
41262306a36Sopenharmony_ci	WREG32(AVIVO_VGA_RENDER_CONTROL,
41362306a36Sopenharmony_ci	       (vga_render_control & ~AVIVO_VGA_VSTATUS_CNTL_MASK));
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	WREG32(R600_ROM_CNTL,
41662306a36Sopenharmony_ci	       ((rom_cntl & ~R600_SCK_PRESCALE_CRYSTAL_CLK_MASK) |
41762306a36Sopenharmony_ci		(1 << R600_SCK_PRESCALE_CRYSTAL_CLK_SHIFT) |
41862306a36Sopenharmony_ci		R600_SCK_OVERWRITE));
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	WREG32(R600_GENERAL_PWRMGT, (general_pwrmgt & ~R600_OPEN_DRAIN_PADS));
42162306a36Sopenharmony_ci	WREG32(R600_LOW_VID_LOWER_GPIO_CNTL,
42262306a36Sopenharmony_ci	       (low_vid_lower_gpio_cntl & ~0x400));
42362306a36Sopenharmony_ci	WREG32(R600_MEDIUM_VID_LOWER_GPIO_CNTL,
42462306a36Sopenharmony_ci	       (medium_vid_lower_gpio_cntl & ~0x400));
42562306a36Sopenharmony_ci	WREG32(R600_HIGH_VID_LOWER_GPIO_CNTL,
42662306a36Sopenharmony_ci	       (high_vid_lower_gpio_cntl & ~0x400));
42762306a36Sopenharmony_ci	WREG32(R600_CTXSW_VID_LOWER_GPIO_CNTL,
42862306a36Sopenharmony_ci	       (ctxsw_vid_lower_gpio_cntl & ~0x400));
42962306a36Sopenharmony_ci	WREG32(R600_LOWER_GPIO_ENABLE, (lower_gpio_enable | 0x400));
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	r = radeon_read_bios(rdev);
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	/* restore regs */
43462306a36Sopenharmony_ci	WREG32(RADEON_VIPH_CONTROL, viph_control);
43562306a36Sopenharmony_ci	WREG32(R600_BUS_CNTL, bus_cntl);
43662306a36Sopenharmony_ci	WREG32(AVIVO_D1VGA_CONTROL, d1vga_control);
43762306a36Sopenharmony_ci	WREG32(AVIVO_D2VGA_CONTROL, d2vga_control);
43862306a36Sopenharmony_ci	WREG32(AVIVO_VGA_RENDER_CONTROL, vga_render_control);
43962306a36Sopenharmony_ci	WREG32(R600_ROM_CNTL, rom_cntl);
44062306a36Sopenharmony_ci	WREG32(R600_GENERAL_PWRMGT, general_pwrmgt);
44162306a36Sopenharmony_ci	WREG32(R600_LOW_VID_LOWER_GPIO_CNTL, low_vid_lower_gpio_cntl);
44262306a36Sopenharmony_ci	WREG32(R600_MEDIUM_VID_LOWER_GPIO_CNTL, medium_vid_lower_gpio_cntl);
44362306a36Sopenharmony_ci	WREG32(R600_HIGH_VID_LOWER_GPIO_CNTL, high_vid_lower_gpio_cntl);
44462306a36Sopenharmony_ci	WREG32(R600_CTXSW_VID_LOWER_GPIO_CNTL, ctxsw_vid_lower_gpio_cntl);
44562306a36Sopenharmony_ci	WREG32(R600_LOWER_GPIO_ENABLE, lower_gpio_enable);
44662306a36Sopenharmony_ci	return r;
44762306a36Sopenharmony_ci}
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_cistatic bool avivo_read_disabled_bios(struct radeon_device *rdev)
45062306a36Sopenharmony_ci{
45162306a36Sopenharmony_ci	uint32_t seprom_cntl1;
45262306a36Sopenharmony_ci	uint32_t viph_control;
45362306a36Sopenharmony_ci	uint32_t bus_cntl;
45462306a36Sopenharmony_ci	uint32_t d1vga_control;
45562306a36Sopenharmony_ci	uint32_t d2vga_control;
45662306a36Sopenharmony_ci	uint32_t vga_render_control;
45762306a36Sopenharmony_ci	uint32_t gpiopad_a;
45862306a36Sopenharmony_ci	uint32_t gpiopad_en;
45962306a36Sopenharmony_ci	uint32_t gpiopad_mask;
46062306a36Sopenharmony_ci	bool r;
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	seprom_cntl1 = RREG32(RADEON_SEPROM_CNTL1);
46362306a36Sopenharmony_ci	viph_control = RREG32(RADEON_VIPH_CONTROL);
46462306a36Sopenharmony_ci	bus_cntl = RREG32(RV370_BUS_CNTL);
46562306a36Sopenharmony_ci	d1vga_control = RREG32(AVIVO_D1VGA_CONTROL);
46662306a36Sopenharmony_ci	d2vga_control = RREG32(AVIVO_D2VGA_CONTROL);
46762306a36Sopenharmony_ci	vga_render_control = RREG32(AVIVO_VGA_RENDER_CONTROL);
46862306a36Sopenharmony_ci	gpiopad_a = RREG32(RADEON_GPIOPAD_A);
46962306a36Sopenharmony_ci	gpiopad_en = RREG32(RADEON_GPIOPAD_EN);
47062306a36Sopenharmony_ci	gpiopad_mask = RREG32(RADEON_GPIOPAD_MASK);
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	WREG32(RADEON_SEPROM_CNTL1,
47362306a36Sopenharmony_ci	       ((seprom_cntl1 & ~RADEON_SCK_PRESCALE_MASK) |
47462306a36Sopenharmony_ci		(0xc << RADEON_SCK_PRESCALE_SHIFT)));
47562306a36Sopenharmony_ci	WREG32(RADEON_GPIOPAD_A, 0);
47662306a36Sopenharmony_ci	WREG32(RADEON_GPIOPAD_EN, 0);
47762306a36Sopenharmony_ci	WREG32(RADEON_GPIOPAD_MASK, 0);
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	/* disable VIP */
48062306a36Sopenharmony_ci	WREG32(RADEON_VIPH_CONTROL, (viph_control & ~RADEON_VIPH_EN));
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	/* enable the rom */
48362306a36Sopenharmony_ci	WREG32(RV370_BUS_CNTL, (bus_cntl & ~RV370_BUS_BIOS_DIS_ROM));
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	/* Disable VGA mode */
48662306a36Sopenharmony_ci	WREG32(AVIVO_D1VGA_CONTROL,
48762306a36Sopenharmony_ci	       (d1vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE |
48862306a36Sopenharmony_ci		AVIVO_DVGA_CONTROL_TIMING_SELECT)));
48962306a36Sopenharmony_ci	WREG32(AVIVO_D2VGA_CONTROL,
49062306a36Sopenharmony_ci	       (d2vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE |
49162306a36Sopenharmony_ci		AVIVO_DVGA_CONTROL_TIMING_SELECT)));
49262306a36Sopenharmony_ci	WREG32(AVIVO_VGA_RENDER_CONTROL,
49362306a36Sopenharmony_ci	       (vga_render_control & ~AVIVO_VGA_VSTATUS_CNTL_MASK));
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	r = radeon_read_bios(rdev);
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	/* restore regs */
49862306a36Sopenharmony_ci	WREG32(RADEON_SEPROM_CNTL1, seprom_cntl1);
49962306a36Sopenharmony_ci	WREG32(RADEON_VIPH_CONTROL, viph_control);
50062306a36Sopenharmony_ci	WREG32(RV370_BUS_CNTL, bus_cntl);
50162306a36Sopenharmony_ci	WREG32(AVIVO_D1VGA_CONTROL, d1vga_control);
50262306a36Sopenharmony_ci	WREG32(AVIVO_D2VGA_CONTROL, d2vga_control);
50362306a36Sopenharmony_ci	WREG32(AVIVO_VGA_RENDER_CONTROL, vga_render_control);
50462306a36Sopenharmony_ci	WREG32(RADEON_GPIOPAD_A, gpiopad_a);
50562306a36Sopenharmony_ci	WREG32(RADEON_GPIOPAD_EN, gpiopad_en);
50662306a36Sopenharmony_ci	WREG32(RADEON_GPIOPAD_MASK, gpiopad_mask);
50762306a36Sopenharmony_ci	return r;
50862306a36Sopenharmony_ci}
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_cistatic bool legacy_read_disabled_bios(struct radeon_device *rdev)
51162306a36Sopenharmony_ci{
51262306a36Sopenharmony_ci	uint32_t seprom_cntl1;
51362306a36Sopenharmony_ci	uint32_t viph_control;
51462306a36Sopenharmony_ci	uint32_t bus_cntl;
51562306a36Sopenharmony_ci	uint32_t crtc_gen_cntl;
51662306a36Sopenharmony_ci	uint32_t crtc2_gen_cntl;
51762306a36Sopenharmony_ci	uint32_t crtc_ext_cntl;
51862306a36Sopenharmony_ci	uint32_t fp2_gen_cntl;
51962306a36Sopenharmony_ci	bool r;
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	seprom_cntl1 = RREG32(RADEON_SEPROM_CNTL1);
52262306a36Sopenharmony_ci	viph_control = RREG32(RADEON_VIPH_CONTROL);
52362306a36Sopenharmony_ci	if (rdev->flags & RADEON_IS_PCIE)
52462306a36Sopenharmony_ci		bus_cntl = RREG32(RV370_BUS_CNTL);
52562306a36Sopenharmony_ci	else
52662306a36Sopenharmony_ci		bus_cntl = RREG32(RADEON_BUS_CNTL);
52762306a36Sopenharmony_ci	crtc_gen_cntl = RREG32(RADEON_CRTC_GEN_CNTL);
52862306a36Sopenharmony_ci	crtc2_gen_cntl = 0;
52962306a36Sopenharmony_ci	crtc_ext_cntl = RREG32(RADEON_CRTC_EXT_CNTL);
53062306a36Sopenharmony_ci	fp2_gen_cntl = 0;
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	if (rdev->pdev->device == PCI_DEVICE_ID_ATI_RADEON_QY) {
53362306a36Sopenharmony_ci		fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL);
53462306a36Sopenharmony_ci	}
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	if (!(rdev->flags & RADEON_SINGLE_CRTC)) {
53762306a36Sopenharmony_ci		crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL);
53862306a36Sopenharmony_ci	}
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	WREG32(RADEON_SEPROM_CNTL1,
54162306a36Sopenharmony_ci	       ((seprom_cntl1 & ~RADEON_SCK_PRESCALE_MASK) |
54262306a36Sopenharmony_ci		(0xc << RADEON_SCK_PRESCALE_SHIFT)));
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	/* disable VIP */
54562306a36Sopenharmony_ci	WREG32(RADEON_VIPH_CONTROL, (viph_control & ~RADEON_VIPH_EN));
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	/* enable the rom */
54862306a36Sopenharmony_ci	if (rdev->flags & RADEON_IS_PCIE)
54962306a36Sopenharmony_ci		WREG32(RV370_BUS_CNTL, (bus_cntl & ~RV370_BUS_BIOS_DIS_ROM));
55062306a36Sopenharmony_ci	else
55162306a36Sopenharmony_ci		WREG32(RADEON_BUS_CNTL, (bus_cntl & ~RADEON_BUS_BIOS_DIS_ROM));
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	/* Turn off mem requests and CRTC for both controllers */
55462306a36Sopenharmony_ci	WREG32(RADEON_CRTC_GEN_CNTL,
55562306a36Sopenharmony_ci	       ((crtc_gen_cntl & ~RADEON_CRTC_EN) |
55662306a36Sopenharmony_ci		(RADEON_CRTC_DISP_REQ_EN_B |
55762306a36Sopenharmony_ci		 RADEON_CRTC_EXT_DISP_EN)));
55862306a36Sopenharmony_ci	if (!(rdev->flags & RADEON_SINGLE_CRTC)) {
55962306a36Sopenharmony_ci		WREG32(RADEON_CRTC2_GEN_CNTL,
56062306a36Sopenharmony_ci		       ((crtc2_gen_cntl & ~RADEON_CRTC2_EN) |
56162306a36Sopenharmony_ci			RADEON_CRTC2_DISP_REQ_EN_B));
56262306a36Sopenharmony_ci	}
56362306a36Sopenharmony_ci	/* Turn off CRTC */
56462306a36Sopenharmony_ci	WREG32(RADEON_CRTC_EXT_CNTL,
56562306a36Sopenharmony_ci	       ((crtc_ext_cntl & ~RADEON_CRTC_CRT_ON) |
56662306a36Sopenharmony_ci		(RADEON_CRTC_SYNC_TRISTAT |
56762306a36Sopenharmony_ci		 RADEON_CRTC_DISPLAY_DIS)));
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	if (rdev->pdev->device == PCI_DEVICE_ID_ATI_RADEON_QY) {
57062306a36Sopenharmony_ci		WREG32(RADEON_FP2_GEN_CNTL, (fp2_gen_cntl & ~RADEON_FP2_ON));
57162306a36Sopenharmony_ci	}
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	r = radeon_read_bios(rdev);
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	/* restore regs */
57662306a36Sopenharmony_ci	WREG32(RADEON_SEPROM_CNTL1, seprom_cntl1);
57762306a36Sopenharmony_ci	WREG32(RADEON_VIPH_CONTROL, viph_control);
57862306a36Sopenharmony_ci	if (rdev->flags & RADEON_IS_PCIE)
57962306a36Sopenharmony_ci		WREG32(RV370_BUS_CNTL, bus_cntl);
58062306a36Sopenharmony_ci	else
58162306a36Sopenharmony_ci		WREG32(RADEON_BUS_CNTL, bus_cntl);
58262306a36Sopenharmony_ci	WREG32(RADEON_CRTC_GEN_CNTL, crtc_gen_cntl);
58362306a36Sopenharmony_ci	if (!(rdev->flags & RADEON_SINGLE_CRTC)) {
58462306a36Sopenharmony_ci		WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl);
58562306a36Sopenharmony_ci	}
58662306a36Sopenharmony_ci	WREG32(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl);
58762306a36Sopenharmony_ci	if (rdev->pdev->device == PCI_DEVICE_ID_ATI_RADEON_QY) {
58862306a36Sopenharmony_ci		WREG32(RADEON_FP2_GEN_CNTL, fp2_gen_cntl);
58962306a36Sopenharmony_ci	}
59062306a36Sopenharmony_ci	return r;
59162306a36Sopenharmony_ci}
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_cistatic bool radeon_read_disabled_bios(struct radeon_device *rdev)
59462306a36Sopenharmony_ci{
59562306a36Sopenharmony_ci	if (rdev->flags & RADEON_IS_IGP)
59662306a36Sopenharmony_ci		return igp_read_bios_from_vram(rdev);
59762306a36Sopenharmony_ci	else if (rdev->family >= CHIP_BARTS)
59862306a36Sopenharmony_ci		return ni_read_disabled_bios(rdev);
59962306a36Sopenharmony_ci	else if (rdev->family >= CHIP_RV770)
60062306a36Sopenharmony_ci		return r700_read_disabled_bios(rdev);
60162306a36Sopenharmony_ci	else if (rdev->family >= CHIP_R600)
60262306a36Sopenharmony_ci		return r600_read_disabled_bios(rdev);
60362306a36Sopenharmony_ci	else if (rdev->family >= CHIP_RS600)
60462306a36Sopenharmony_ci		return avivo_read_disabled_bios(rdev);
60562306a36Sopenharmony_ci	else
60662306a36Sopenharmony_ci		return legacy_read_disabled_bios(rdev);
60762306a36Sopenharmony_ci}
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci#ifdef CONFIG_ACPI
61062306a36Sopenharmony_cistatic bool radeon_acpi_vfct_bios(struct radeon_device *rdev)
61162306a36Sopenharmony_ci{
61262306a36Sopenharmony_ci	struct acpi_table_header *hdr;
61362306a36Sopenharmony_ci	acpi_size tbl_size;
61462306a36Sopenharmony_ci	UEFI_ACPI_VFCT *vfct;
61562306a36Sopenharmony_ci	unsigned offset;
61662306a36Sopenharmony_ci	bool r = false;
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	if (!ACPI_SUCCESS(acpi_get_table("VFCT", 1, &hdr)))
61962306a36Sopenharmony_ci		return false;
62062306a36Sopenharmony_ci	tbl_size = hdr->length;
62162306a36Sopenharmony_ci	if (tbl_size < sizeof(UEFI_ACPI_VFCT)) {
62262306a36Sopenharmony_ci		DRM_ERROR("ACPI VFCT table present but broken (too short #1)\n");
62362306a36Sopenharmony_ci		goto out;
62462306a36Sopenharmony_ci	}
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	vfct = (UEFI_ACPI_VFCT *)hdr;
62762306a36Sopenharmony_ci	offset = vfct->VBIOSImageOffset;
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	while (offset < tbl_size) {
63062306a36Sopenharmony_ci		GOP_VBIOS_CONTENT *vbios = (GOP_VBIOS_CONTENT *)((char *)hdr + offset);
63162306a36Sopenharmony_ci		VFCT_IMAGE_HEADER *vhdr = &vbios->VbiosHeader;
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci		offset += sizeof(VFCT_IMAGE_HEADER);
63462306a36Sopenharmony_ci		if (offset > tbl_size) {
63562306a36Sopenharmony_ci			DRM_ERROR("ACPI VFCT image header truncated\n");
63662306a36Sopenharmony_ci			goto out;
63762306a36Sopenharmony_ci		}
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci		offset += vhdr->ImageLength;
64062306a36Sopenharmony_ci		if (offset > tbl_size) {
64162306a36Sopenharmony_ci			DRM_ERROR("ACPI VFCT image truncated\n");
64262306a36Sopenharmony_ci			goto out;
64362306a36Sopenharmony_ci		}
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci		if (vhdr->ImageLength &&
64662306a36Sopenharmony_ci		    vhdr->PCIBus == rdev->pdev->bus->number &&
64762306a36Sopenharmony_ci		    vhdr->PCIDevice == PCI_SLOT(rdev->pdev->devfn) &&
64862306a36Sopenharmony_ci		    vhdr->PCIFunction == PCI_FUNC(rdev->pdev->devfn) &&
64962306a36Sopenharmony_ci		    vhdr->VendorID == rdev->pdev->vendor &&
65062306a36Sopenharmony_ci		    vhdr->DeviceID == rdev->pdev->device) {
65162306a36Sopenharmony_ci			rdev->bios = kmemdup(&vbios->VbiosContent,
65262306a36Sopenharmony_ci					     vhdr->ImageLength,
65362306a36Sopenharmony_ci					     GFP_KERNEL);
65462306a36Sopenharmony_ci			if (rdev->bios)
65562306a36Sopenharmony_ci				r = true;
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci			goto out;
65862306a36Sopenharmony_ci		}
65962306a36Sopenharmony_ci	}
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	DRM_ERROR("ACPI VFCT table present but broken (too short #2)\n");
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ciout:
66462306a36Sopenharmony_ci	acpi_put_table(hdr);
66562306a36Sopenharmony_ci	return r;
66662306a36Sopenharmony_ci}
66762306a36Sopenharmony_ci#else
66862306a36Sopenharmony_cistatic inline bool radeon_acpi_vfct_bios(struct radeon_device *rdev)
66962306a36Sopenharmony_ci{
67062306a36Sopenharmony_ci	return false;
67162306a36Sopenharmony_ci}
67262306a36Sopenharmony_ci#endif
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_cibool radeon_get_bios(struct radeon_device *rdev)
67562306a36Sopenharmony_ci{
67662306a36Sopenharmony_ci	bool r;
67762306a36Sopenharmony_ci	uint16_t tmp;
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	r = radeon_atrm_get_bios(rdev);
68062306a36Sopenharmony_ci	if (!r)
68162306a36Sopenharmony_ci		r = radeon_acpi_vfct_bios(rdev);
68262306a36Sopenharmony_ci	if (!r)
68362306a36Sopenharmony_ci		r = igp_read_bios_from_vram(rdev);
68462306a36Sopenharmony_ci	if (!r)
68562306a36Sopenharmony_ci		r = radeon_read_bios(rdev);
68662306a36Sopenharmony_ci	if (!r)
68762306a36Sopenharmony_ci		r = radeon_read_disabled_bios(rdev);
68862306a36Sopenharmony_ci	if (!r)
68962306a36Sopenharmony_ci		r = radeon_read_platform_bios(rdev);
69062306a36Sopenharmony_ci	if (!r || rdev->bios == NULL) {
69162306a36Sopenharmony_ci		DRM_ERROR("Unable to locate a BIOS ROM\n");
69262306a36Sopenharmony_ci		rdev->bios = NULL;
69362306a36Sopenharmony_ci		return false;
69462306a36Sopenharmony_ci	}
69562306a36Sopenharmony_ci	if (rdev->bios[0] != 0x55 || rdev->bios[1] != 0xaa) {
69662306a36Sopenharmony_ci		printk("BIOS signature incorrect %x %x\n", rdev->bios[0], rdev->bios[1]);
69762306a36Sopenharmony_ci		goto free_bios;
69862306a36Sopenharmony_ci	}
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	tmp = RBIOS16(0x18);
70162306a36Sopenharmony_ci	if (RBIOS8(tmp + 0x14) != 0x0) {
70262306a36Sopenharmony_ci		DRM_INFO("Not an x86 BIOS ROM, not using.\n");
70362306a36Sopenharmony_ci		goto free_bios;
70462306a36Sopenharmony_ci	}
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	rdev->bios_header_start = RBIOS16(0x48);
70762306a36Sopenharmony_ci	if (!rdev->bios_header_start) {
70862306a36Sopenharmony_ci		goto free_bios;
70962306a36Sopenharmony_ci	}
71062306a36Sopenharmony_ci	tmp = rdev->bios_header_start + 4;
71162306a36Sopenharmony_ci	if (!memcmp(rdev->bios + tmp, "ATOM", 4) ||
71262306a36Sopenharmony_ci	    !memcmp(rdev->bios + tmp, "MOTA", 4)) {
71362306a36Sopenharmony_ci		rdev->is_atom_bios = true;
71462306a36Sopenharmony_ci	} else {
71562306a36Sopenharmony_ci		rdev->is_atom_bios = false;
71662306a36Sopenharmony_ci	}
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci	DRM_DEBUG("%sBIOS detected\n", rdev->is_atom_bios ? "ATOM" : "COM");
71962306a36Sopenharmony_ci	return true;
72062306a36Sopenharmony_cifree_bios:
72162306a36Sopenharmony_ci	kfree(rdev->bios);
72262306a36Sopenharmony_ci	rdev->bios = NULL;
72362306a36Sopenharmony_ci	return false;
72462306a36Sopenharmony_ci}
725