/*
 * Copyright 2006-2011, Haiku, Inc. All Rights Reserved.
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *		Axel Dörfler, axeld@pinc-software.de
 *		Clemens Zeidler, haiku@clemens-zeidler.de
 *		Fredrik Holmqvis, fredrik.holmqvist@gmail.com
 *		Alexander von Gluck, kallisti5@unixzen.com
 */
 
 
#include "radeon_hd.h"
#include "sensors.h"
 
#include "AreaKeeper.h"
#include "driver.h"
#include "utility.h"
 
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
 
#include <boot_item.h>
#include <driver_settings.h>
#include <util/kernel_cpp.h>
#include <vm/vm.h>
 
 
#define TRACE_DEVICE
#ifdef TRACE_DEVICE
#	define TRACE(x...) dprintf("radeon_hd: " x)
#else
#	define TRACE(x) ;
#endif
 
#define ERROR(x...) dprintf("radeon_hd: " x)
 
 
//	#pragma mark -
 
 
status_t
mapAtomBIOS(radeon_info &info, uint32 romBase, uint32 romSize)
{
	TRACE("%s: seeking AtomBIOS @ 0x%" B_PRIX32 " [size: 0x%" B_PRIX32 "]\n",
		__func__, romBase, romSize);
 
	uint8* rom;
 
	// attempt to access area specified
	area_id testArea = map_physical_memory("radeon hd rom probe",
		romBase, romSize, B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA,
		(void**)&rom);
 
	if (testArea < 0) {
		ERROR("%s: couldn't map potential rom @ 0x%" B_PRIX32
			"\n", __func__, romBase);
		return B_NO_MEMORY;
	}
 
	// check for valid BIOS signature
	if (rom[0] != 0x55 || rom[1] != 0xAA) {
		uint16 id = rom[0] + (rom[1] << 8);
		TRACE("%s: BIOS signature incorrect @ 0x%" B_PRIX32 " (%X)\n",
			__func__, romBase, id);
		delete_area(testArea);
		return B_ERROR;
	}
 
	// see if valid AtomBIOS rom
	uint16 romHeader = RADEON_BIOS16(rom, 0x48);
	bool romValid = !memcmp(&rom[romHeader + 4], "ATOM", 4)
		|| !memcmp(&rom[romHeader + 4], "MOTA", 4);
 
	if (romValid == false) {
		// FAIL : a PCI VGA bios but not AtomBIOS
		uint16 id = rom[0] + (rom[1] << 8);
		TRACE("%s: not AtomBIOS rom at 0x%" B_PRIX32 "(%X)\n",
			__func__, romBase, id);
		delete_area(testArea);
		return B_ERROR;
	}
 
	info.rom_area = create_area("radeon hd AtomBIOS",
		(void**)&info.atom_buffer, B_ANY_KERNEL_ADDRESS,
		romSize, B_NO_LOCK,
		B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_USER_CLONEABLE_AREA);
 
	if (info.rom_area < 0) {
		ERROR("%s: unable to map kernel AtomBIOS space!\n",
			__func__);
		delete_area(testArea);
		return B_NO_MEMORY;
	}
 
	memset((void*)info.atom_buffer, 0, romSize);
		// Prevent unknown code execution by AtomBIOS parser
	memcpy(info.atom_buffer, (void*)rom, romSize);
		// Copy AtomBIOS to kernel area
 
	// validate copied rom is valid
	romHeader = RADEON_BIOS16(info.atom_buffer, 0x48);
	romValid = !memcmp(&info.atom_buffer[romHeader + 4], "ATOM", 4)
		|| !memcmp(&info.atom_buffer[romHeader + 4], "MOTA", 4);
 
	if (romValid == true) {
		set_area_protection(info.rom_area,
			B_KERNEL_READ_AREA | B_USER_CLONEABLE_AREA);
		ERROR("%s: AtomBIOS verified and locked\n", __func__);
	} else
		ERROR("%s: AtomBIOS memcpy failed!\n", __func__);
 
	delete_area(testArea);
	return romValid ? B_OK : B_ERROR;
}
 
 
static status_t
radeon_hd_getbios(radeon_info &info)
{
	TRACE("card(%ld): %s: called\n", info.id, __func__);
 
	uint32 romBase = 0;
	uint32 romSize = 0;
	uint32 romMethod = 0;
 
	status_t mapResult = B_ERROR;
 
	// first we try to find the AtomBIOS rom via various methods
	for (romMethod = 0; romMethod < 3; romMethod++) {
		switch(romMethod) {
			case 0:
				// TODO: *** New ACPI method
				ERROR("%s: ACPI ATRM AtomBIOS TODO\n", __func__);
				break;
			case 1:
				// *** Discreet card on IGP, check PCI BAR 0
				// On post, the bios puts a copy of the IGP
				// AtomBIOS at the start of the video ram
				romBase = info.pci->u.h0.base_registers[PCI_BAR_FB];
				romSize = 256 * 1024;
 
				if (romBase == 0 || romSize == 0) {
					ERROR("%s: No base found at PCI FB BAR\n", __func__);
				} else {
					mapResult = mapAtomBIOS(info, romBase, romSize);
				}
				break;
			case 2:
			{
				// *** PCI ROM BAR
				// Enable ROM decoding for PCI BAR rom
				uint32 pciConfig = get_pci_config(info.pci, PCI_rom_base, 4);
				pciConfig |= PCI_rom_enable;
				set_pci_config(info.pci, PCI_rom_base, 4, pciConfig);
 
				uint32 flags = get_pci_config(info.pci, PCI_rom_base, 4);
				if ((flags & PCI_rom_enable) != 0)
					TRACE("%s: PCI ROM decode enabled\n", __func__);
 
				romBase = info.pci->u.h0.rom_base;
				romSize = info.pci->u.h0.rom_size;
 
				if (romBase == 0 || romSize == 0) {
					ERROR("%s: No base found at PCI ROM BAR\n", __func__);
				} else {
					mapResult = mapAtomBIOS(info, romBase, romSize);
				}
 
				// Disable ROM decoding
				pciConfig &= ~PCI_rom_enable;
				set_pci_config(info.pci, PCI_rom_base, 4, pciConfig);
				break;
			}
		}
 
		if (mapResult == B_OK) {
			ERROR("%s: AtomBIOS found using active method %" B_PRIu32
				" at 0x%" B_PRIX32 "\n", __func__, romMethod, romBase);
			break;
		} else {
			ERROR("%s: AtomBIOS not found using active method %" B_PRIu32
				" at 0x%" B_PRIX32 "\n", __func__, romMethod, romBase);
		}
	}
 
	if (mapResult == B_OK) {
		info.shared_info->rom_phys = romBase;
		info.shared_info->rom_size = romSize;
	} else
		ERROR("%s: Active AtomBIOS search failed.\n", __func__);
 
	return mapResult;
}
 
 
static status_t
radeon_hd_getbios_ni(radeon_info &info)
{
	TRACE("card(%ld): %s: called\n", info.id, __func__);
	uint32 bus_cntl = read32(info.registers + R600_BUS_CNTL);
	uint32 d1vga_control = read32(info.registers + AVIVO_D1VGA_CONTROL);
	uint32 d2vga_control = read32(info.registers + AVIVO_D2VGA_CONTROL);
	uint32 vga_render_control
		= read32(info.registers + AVIVO_VGA_RENDER_CONTROL);
	uint32 rom_cntl = read32(info.registers + R600_ROM_CNTL);
 
	// enable the rom
	write32(info.registers + R600_BUS_CNTL, (bus_cntl & ~R600_BIOS_ROM_DIS));
	// disable VGA mode
	write32(info.registers + AVIVO_D1VGA_CONTROL, (d1vga_control
		& ~(AVIVO_DVGA_CONTROL_MODE_ENABLE
			| AVIVO_DVGA_CONTROL_TIMING_SELECT)));
	write32(info.registers + AVIVO_D2VGA_CONTROL, (d2vga_control
		& ~(AVIVO_DVGA_CONTROL_MODE_ENABLE
			| AVIVO_DVGA_CONTROL_TIMING_SELECT)));
	write32(info.registers + AVIVO_VGA_RENDER_CONTROL,
		(vga_render_control & ~AVIVO_VGA_VSTATUS_CNTL_MASK));
 
	write32(info.registers + R600_ROM_CNTL, (rom_cntl | R600_SCK_OVERWRITE));
 
	// try to grab the bios via PCI ROM bar
	// Enable ROM decoding for PCI BAR rom
	uint32 pciConfig = get_pci_config(info.pci, PCI_rom_base, 4);
	pciConfig |= PCI_rom_enable;
	set_pci_config(info.pci, PCI_rom_base, 4, pciConfig);
 
	uint32 flags = get_pci_config(info.pci, PCI_rom_base, 4);
	if (flags & PCI_rom_enable)
		TRACE("%s: PCI ROM decode enabled\n", __func__);
 
	uint32 romBase = info.pci->u.h0.rom_base;
	uint32 romSize = info.pci->u.h0.rom_size;
 
	status_t result = B_OK;
	if (romBase == 0 || romSize == 0) {
		ERROR("%s: No AtomBIOS location found at PCI ROM BAR\n", __func__);
		result = B_ERROR;
	} else {
		result = mapAtomBIOS(info, romBase, romSize);
	}
 
	if (result == B_OK) {
		ERROR("%s: AtomBIOS found using disabled method at 0x%" B_PRIX32
			" [size: 0x%" B_PRIX32 "]\n", __func__, romBase, romSize);
		info.shared_info->rom_phys = romBase;
		info.shared_info->rom_size = romSize;
	}
 
	// Disable ROM decoding
	pciConfig &= ~PCI_rom_enable;
	set_pci_config(info.pci, PCI_rom_base, 4, pciConfig);
 
	// restore regs
	write32(info.registers + R600_BUS_CNTL, bus_cntl);
	write32(info.registers + AVIVO_D1VGA_CONTROL, d1vga_control);
	write32(info.registers + AVIVO_D2VGA_CONTROL, d2vga_control);
	write32(info.registers + AVIVO_VGA_RENDER_CONTROL, vga_render_control);
	write32(info.registers + R600_ROM_CNTL, rom_cntl);
 
	return result;
}
 
 
static status_t
radeon_hd_getbios_r700(radeon_info &info)
{
	TRACE("card(%ld): %s: called\n", info.id, __func__);
	uint32 viph_control = read32(info.registers + RADEON_VIPH_CONTROL);
	uint32 bus_cntl = read32(info.registers + R600_BUS_CNTL);
	uint32 d1vga_control = read32(info.registers + AVIVO_D1VGA_CONTROL);
	uint32 d2vga_control = read32(info.registers + AVIVO_D2VGA_CONTROL);
	uint32 vga_render_control
		= read32(info.registers + AVIVO_VGA_RENDER_CONTROL);
	uint32 rom_cntl = read32(info.registers + R600_ROM_CNTL);
 
	// disable VIP
	write32(info.registers + RADEON_VIPH_CONTROL,
		(viph_control & ~RADEON_VIPH_EN));
	// enable the rom
	write32(info.registers + R600_BUS_CNTL, (bus_cntl & ~R600_BIOS_ROM_DIS));
	// disable VGA mode
	write32(info.registers + AVIVO_D1VGA_CONTROL, (d1vga_control
		& ~(AVIVO_DVGA_CONTROL_MODE_ENABLE
			| AVIVO_DVGA_CONTROL_TIMING_SELECT)));
	write32(info.registers + AVIVO_D2VGA_CONTROL, (d2vga_control
		& ~(AVIVO_DVGA_CONTROL_MODE_ENABLE
			| AVIVO_DVGA_CONTROL_TIMING_SELECT)));
	write32(info.registers + AVIVO_VGA_RENDER_CONTROL,
		(vga_render_control & ~AVIVO_VGA_VSTATUS_CNTL_MASK));
 
	write32(info.registers + R600_ROM_CNTL, (rom_cntl | R600_SCK_OVERWRITE));
 
	// try to grab the bios via PCI ROM bar
	// Enable ROM decoding for PCI BAR rom
	uint32 pciConfig = get_pci_config(info.pci, PCI_rom_base, 4);
	pciConfig |= PCI_rom_enable;
	set_pci_config(info.pci, PCI_rom_base, 4, pciConfig);
 
	uint32 flags = get_pci_config(info.pci, PCI_rom_base, 4);
	if (flags & PCI_rom_enable)
		TRACE("%s: PCI ROM decode enabled\n", __func__);
 
	uint32 romBase = info.pci->u.h0.rom_base;
	uint32 romSize = info.pci->u.h0.rom_size;
 
	status_t result = B_OK;
	if (romBase == 0 || romSize == 0) {
		ERROR("%s: No AtomBIOS location found at PCI ROM BAR\n", __func__);
		result = B_ERROR;
	} else {
		result = mapAtomBIOS(info, romBase, romSize);
	}
 
	if (result == B_OK) {
		ERROR("%s: AtomBIOS found using disabled method at 0x%" B_PRIX32
			" [size: 0x%" B_PRIX32 "]\n", __func__, romBase, romSize);
		info.shared_info->rom_phys = romBase;
		info.shared_info->rom_size = romSize;
	}
 
	// Disable ROM decoding
	pciConfig &= ~PCI_rom_enable;
	set_pci_config(info.pci, PCI_rom_base, 4, pciConfig);
 
	// restore regs
	write32(info.registers + RADEON_VIPH_CONTROL, viph_control);
	write32(info.registers + R600_BUS_CNTL, bus_cntl);
	write32(info.registers + AVIVO_D1VGA_CONTROL, d1vga_control);
	write32(info.registers + AVIVO_D2VGA_CONTROL, d2vga_control);
	write32(info.registers + AVIVO_VGA_RENDER_CONTROL, vga_render_control);
	write32(info.registers + R600_ROM_CNTL, rom_cntl);
 
	return result;
}
 
 
static status_t
radeon_hd_getbios_r600(radeon_info &info)
{
	TRACE("card(%ld): %s: called\n", info.id, __func__);
	uint32 viph_control = read32(info.registers + RADEON_VIPH_CONTROL);
	uint32 bus_cntl = read32(info.registers + R600_BUS_CNTL);
	uint32 d1vga_control = read32(info.registers + AVIVO_D1VGA_CONTROL);
	uint32 d2vga_control = read32(info.registers + AVIVO_D2VGA_CONTROL);
	uint32 vga_render_control
		= read32(info.registers + AVIVO_VGA_RENDER_CONTROL);
	uint32 rom_cntl = read32(info.registers + R600_ROM_CNTL);
	uint32 general_pwrmgt = read32(info.registers + R600_GENERAL_PWRMGT);
	uint32 low_vid_lower_gpio_cntl
		= read32(info.registers + R600_LOW_VID_LOWER_GPIO_CNTL);
	uint32 medium_vid_lower_gpio_cntl
		= read32(info.registers + R600_MEDIUM_VID_LOWER_GPIO_CNTL);
	uint32 high_vid_lower_gpio_cntl
		= read32(info.registers + R600_HIGH_VID_LOWER_GPIO_CNTL);
	uint32 ctxsw_vid_lower_gpio_cntl
		= read32(info.registers + R600_CTXSW_VID_LOWER_GPIO_CNTL);
	uint32 lower_gpio_enable
		= read32(info.registers + R600_LOWER_GPIO_ENABLE);
 
	// disable VIP
	write32(info.registers + RADEON_VIPH_CONTROL,
		(viph_control & ~RADEON_VIPH_EN));
	// enable the rom
	write32(info.registers + R600_BUS_CNTL, (bus_cntl & ~R600_BIOS_ROM_DIS));
	// disable VGA mode
	write32(info.registers + AVIVO_D1VGA_CONTROL, (d1vga_control
		& ~(AVIVO_DVGA_CONTROL_MODE_ENABLE
			| AVIVO_DVGA_CONTROL_TIMING_SELECT)));
	write32(info.registers + AVIVO_D2VGA_CONTROL, (d2vga_control
		& ~(AVIVO_DVGA_CONTROL_MODE_ENABLE
			| AVIVO_DVGA_CONTROL_TIMING_SELECT)));
	write32(info.registers + AVIVO_VGA_RENDER_CONTROL,
		(vga_render_control & ~AVIVO_VGA_VSTATUS_CNTL_MASK));
 
	write32(info.registers + R600_ROM_CNTL,
		((rom_cntl & ~R600_SCK_PRESCALE_CRYSTAL_CLK_MASK)
		| (1 << R600_SCK_PRESCALE_CRYSTAL_CLK_SHIFT) | R600_SCK_OVERWRITE));
 
	write32(info.registers + R600_GENERAL_PWRMGT,
		(general_pwrmgt & ~R600_OPEN_DRAIN_PADS));
	write32(info.registers + R600_LOW_VID_LOWER_GPIO_CNTL,
		(low_vid_lower_gpio_cntl & ~0x400));
	write32(info.registers + R600_MEDIUM_VID_LOWER_GPIO_CNTL,
		(medium_vid_lower_gpio_cntl & ~0x400));
	write32(info.registers + R600_HIGH_VID_LOWER_GPIO_CNTL,
		(high_vid_lower_gpio_cntl & ~0x400));
	write32(info.registers + R600_CTXSW_VID_LOWER_GPIO_CNTL,
		(ctxsw_vid_lower_gpio_cntl & ~0x400));
	write32(info.registers + R600_LOWER_GPIO_ENABLE,
		(lower_gpio_enable | 0x400));
 
	// try to grab the bios via PCI ROM bar
	// Enable ROM decoding for PCI BAR rom
	uint32 pciConfig = get_pci_config(info.pci, PCI_rom_base, 4);
	pciConfig |= PCI_rom_enable;
	set_pci_config(info.pci, PCI_rom_base, 4, pciConfig);
 
	uint32 flags = get_pci_config(info.pci, PCI_rom_base, 4);
	if (flags & PCI_rom_enable)
		TRACE("%s: PCI ROM decode enabled\n", __func__);
 
	uint32 romBase = info.pci->u.h0.rom_base;
	uint32 romSize = info.pci->u.h0.rom_size;
 
	status_t result = B_OK;
	if (romBase == 0 || romSize == 0) {
		ERROR("%s: No AtomBIOS location found at PCI ROM BAR\n", __func__);
		result = B_ERROR;
	} else {
		result = mapAtomBIOS(info, romBase, romSize);
	}
 
	if (result == B_OK) {
		ERROR("%s: AtomBIOS found using disabled method at 0x%" B_PRIX32
			" [size: 0x%" B_PRIX32 "]\n", __func__, romBase, romSize);
		info.shared_info->rom_phys = romBase;
		info.shared_info->rom_size = romSize;
	}
 
	// Disable ROM decoding
	pciConfig &= ~PCI_rom_enable;
	set_pci_config(info.pci, PCI_rom_base, 4, pciConfig);
 
	// restore regs
	write32(info.registers + RADEON_VIPH_CONTROL, viph_control);
	write32(info.registers + R600_BUS_CNTL, bus_cntl);
	write32(info.registers + AVIVO_D1VGA_CONTROL, d1vga_control);
	write32(info.registers + AVIVO_D2VGA_CONTROL, d2vga_control);
	write32(info.registers + AVIVO_VGA_RENDER_CONTROL, vga_render_control);
	write32(info.registers + R600_ROM_CNTL, rom_cntl);
	write32(info.registers + R600_GENERAL_PWRMGT, general_pwrmgt);
	write32(info.registers + R600_LOW_VID_LOWER_GPIO_CNTL,
		low_vid_lower_gpio_cntl);
	write32(info.registers + R600_MEDIUM_VID_LOWER_GPIO_CNTL,
		medium_vid_lower_gpio_cntl);
	write32(info.registers + R600_HIGH_VID_LOWER_GPIO_CNTL,
		high_vid_lower_gpio_cntl);
	write32(info.registers + R600_CTXSW_VID_LOWER_GPIO_CNTL,
		ctxsw_vid_lower_gpio_cntl);
	write32(info.registers + R600_LOWER_GPIO_ENABLE, lower_gpio_enable);
 
	return result;
}
 
 
static status_t
radeon_hd_getbios_avivo(radeon_info &info)
{
	TRACE("card(%ld): %s: called\n", info.id, __func__);
	uint32 sepromControl = read32(info.registers + RADEON_SEPROM_CNTL1);
	uint32 viphControl = read32(info.registers + RADEON_VIPH_CONTROL);
	uint32 busControl = read32(info.registers + RV370_BUS_CNTL);
	uint32 d1vgaControl = read32(info.registers + AVIVO_D1VGA_CONTROL);
	uint32 d2vgaControl = read32(info.registers + AVIVO_D2VGA_CONTROL);
	uint32 vgaRenderControl
		= read32(info.registers + AVIVO_VGA_RENDER_CONTROL);
	uint32 gpioPadA = read32(info.registers + RADEON_GPIOPAD_A);
	uint32 gpioPadEN = read32(info.registers + RADEON_GPIOPAD_EN);
	uint32 gpioPadMask = read32(info.registers + RADEON_GPIOPAD_MASK);
 
	write32(info.registers + RADEON_SEPROM_CNTL1,
		((sepromControl & ~RADEON_SCK_PRESCALE_MASK)
		| (0xc << RADEON_SCK_PRESCALE_SHIFT)));
	write32(info.registers + RADEON_GPIOPAD_A, 0);
	write32(info.registers + RADEON_GPIOPAD_EN, 0);
	write32(info.registers + RADEON_GPIOPAD_MASK, 0);
 
	// disable VIP
	write32(info.registers + RADEON_VIPH_CONTROL,
		(viphControl & ~RADEON_VIPH_EN));
 
	// enable the ROM
	write32(info.registers + RV370_BUS_CNTL,
		(busControl & ~RV370_BUS_BIOS_DIS_ROM));
 
	// disable VGA
	write32(info.registers + AVIVO_D1VGA_CONTROL,
		(d1vgaControl & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE
		| AVIVO_DVGA_CONTROL_TIMING_SELECT)));
	write32(info.registers + AVIVO_D2VGA_CONTROL,
		(d2vgaControl & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE
		| AVIVO_DVGA_CONTROL_TIMING_SELECT)));
	write32(info.registers + AVIVO_VGA_RENDER_CONTROL,
		(vgaRenderControl & ~AVIVO_VGA_VSTATUS_CNTL_MASK));
 
	uint32 romBase = info.pci->u.h0.rom_base;
	uint32 romSize = info.pci->u.h0.rom_size;
 
	status_t result = B_OK;
	if (romBase == 0 || romSize == 0) {
		ERROR("%s: No AtomBIOS location found at PCI ROM BAR\n", __func__);
		result = B_ERROR;
	} else {
		result = mapAtomBIOS(info, romBase, romSize);
	}
 
	if (result == B_OK) {
		ERROR("%s: AtomBIOS found using disabled method at 0x%" B_PRIX32
			" [size: 0x%" B_PRIX32 "]\n", __func__, romBase, romSize);
		info.shared_info->rom_phys = romBase;
		info.shared_info->rom_size = romSize;
	}
 
	// restore registers
	write32(info.registers + RADEON_SEPROM_CNTL1, sepromControl);
	write32(info.registers + RADEON_VIPH_CONTROL, viphControl);
	write32(info.registers + RV370_BUS_CNTL, busControl);
	write32(info.registers + AVIVO_D1VGA_CONTROL, d1vgaControl);
	write32(info.registers + AVIVO_D2VGA_CONTROL, d2vgaControl);
	write32(info.registers + AVIVO_VGA_RENDER_CONTROL, vgaRenderControl);
	write32(info.registers + RADEON_GPIOPAD_A, gpioPadA);
	write32(info.registers + RADEON_GPIOPAD_EN, gpioPadEN);
	write32(info.registers + RADEON_GPIOPAD_MASK, gpioPadMask);
 
	return result;
}
 
 
static uint32
radeon_hd_pci_bar_mmio(uint16 chipsetID)
{
	if (chipsetID < RADEON_BONAIRE)
		return 2;
	else
		return 5;
}
 
 
status_t
radeon_hd_init(radeon_info &info)
{
	TRACE("card(%ld): %s: called\n", info.id, __func__);
 
	ERROR("%s: card(%ld): "
		"Radeon %s 1002:%" B_PRIX32 "\n", __func__, info.id,
		radeon_chip_name[info.chipsetID], info.pciID);
 
	// *** Map shared info
	AreaKeeper sharedCreator;
	info.shared_area = sharedCreator.Create("radeon hd shared info",
		(void**)&info.shared_info, B_ANY_KERNEL_ADDRESS,
		ROUND_TO_PAGE_SIZE(sizeof(radeon_shared_info)), B_FULL_LOCK,
		B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_USER_CLONEABLE_AREA);
	if (info.shared_area < B_OK) {
		ERROR("%s: card (%ld): couldn't map shared area!\n",
			__func__, info.id);
		return info.shared_area;
	}
 
	memset((void*)info.shared_info, 0, sizeof(radeon_shared_info));
	sharedCreator.Detach();
 
	// *** Map Memory mapped IO
	AreaKeeper mmioMapper;
	const uint32 pciBarMmio = radeon_hd_pci_bar_mmio(info.chipsetID);
	info.registers_area = mmioMapper.Map("radeon hd mmio",
		info.pci->u.h0.base_registers[pciBarMmio],
		info.pci->u.h0.base_register_sizes[pciBarMmio],
		B_ANY_KERNEL_ADDRESS,
		B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_USER_CLONEABLE_AREA,
		(void**)&info.registers);
	if (mmioMapper.InitCheck() < B_OK) {
		ERROR("%s: card (%ld): couldn't map memory I/O!\n",
			__func__, info.id);
		return info.registers_area;
	}
	mmioMapper.Detach();
 
	// *** Populate frame buffer information
	if (info.chipsetID >= RADEON_CEDAR) {
		if ((info.chipsetFlags & CHIP_APU) != 0
			|| (info.chipsetFlags & CHIP_IGP) != 0) {
			// Evergreen+ fusion in bytes
			info.shared_info->graphics_memory_size
				= read32(info.registers + CONFIG_MEMSIZE) / 1024;
		} else {
			// Evergreen+ has memory stored in MB
			info.shared_info->graphics_memory_size
				= read32(info.registers + CONFIG_MEMSIZE) * 1024;
		}
	} else if (info.chipsetID >= RADEON_R600) {
		// R600-R700 has memory stored in bytes
		info.shared_info->graphics_memory_size
			= read32(info.registers + CONFIG_MEMSIZE) / 1024;
	} else {
		// R420 - R600 cards
		// older cards use RADEON_CONFIG_MEMSIZE vs CONFIG_MEMSIZE
		if ((info.chipsetFlags & CHIP_IGP) != 0) {
			// NB_TOM holds amount of ram stolen for GPU
			uint32 tom = read32(info.registers + RADEON_NB_TOM);
			info.shared_info->graphics_memory_size
				= (((tom >> 16) - (tom & 0xffff) + 1) << 16);
			write32(info.registers + RADEON_CONFIG_MEMSIZE,
				info.shared_info->graphics_memory_size);
		} else {
			info.shared_info->graphics_memory_size
				= read32(info.registers + RADEON_CONFIG_MEMSIZE);
			if (info.shared_info->graphics_memory_size == 0) {
				// known bug if video memory == 8MB
				info.shared_info->graphics_memory_size = 8192;
				write32(info.registers + RADEON_CONFIG_MEMSIZE,
					info.shared_info->graphics_memory_size * 1024);
			}
		}
	}
 
	uint32 barSize = info.pci->u.h0.base_register_sizes[PCI_BAR_FB] / 1024;
 
	// if graphics memory is larger then PCI bar, just map bar
	if (info.shared_info->graphics_memory_size == 0) {
		// we can recover as we have PCI FB bar, but this should be fixed
		ERROR("%s: Error: found 0MB video ram, using PCI bar size...\n",
			__func__);
		info.shared_info->frame_buffer_size = barSize;
	} else if (info.shared_info->graphics_memory_size > barSize) {
		TRACE("%s: shrinking frame buffer to PCI bar...\n",
			__func__);
		info.shared_info->frame_buffer_size = barSize;
	} else {
		info.shared_info->frame_buffer_size
			= info.shared_info->graphics_memory_size;
	}
 
	TRACE("%s: mapping a frame buffer of %" B_PRIu32 "MB out of %" B_PRIu32
		"MB video ram\n", __func__, info.shared_info->frame_buffer_size / 1024,
		info.shared_info->graphics_memory_size / 1024);
 
	// *** Framebuffer mapping
	AreaKeeper frambufferMapper;
	info.framebuffer_area = frambufferMapper.Map("radeon hd frame buffer",
		info.pci->u.h0.base_registers[PCI_BAR_FB],
		info.shared_info->frame_buffer_size * 1024,
		B_ANY_KERNEL_ADDRESS, B_READ_AREA | B_WRITE_AREA,
		(void**)&info.shared_info->frame_buffer);
	if (frambufferMapper.InitCheck() < B_OK) {
		ERROR("%s: card(%ld): couldn't map frame buffer!\n",
			__func__, info.id);
		return info.framebuffer_area;
	}
 
	// Turn on write combining for the frame buffer area
	vm_set_area_memory_type(info.framebuffer_area,
		info.pci->u.h0.base_registers[PCI_BAR_FB], B_MTR_WC);
 
	frambufferMapper.Detach();
 
	info.shared_info->frame_buffer_area = info.framebuffer_area;
	info.shared_info->frame_buffer_phys
		= info.pci->u.h0.base_registers[PCI_BAR_FB];
 
	// Pass common information to accelerant
	info.shared_info->deviceIndex = info.id;
	info.shared_info->pciID = info.pciID;
	info.shared_info->pciRev = info.pci->revision;
	info.shared_info->chipsetID = info.chipsetID;
	info.shared_info->chipsetFlags = info.chipsetFlags;
	info.shared_info->dceMajor = info.dceMajor;
	info.shared_info->dceMinor = info.dceMinor;
	info.shared_info->registers_area = info.registers_area;
	strlcpy(info.shared_info->deviceName,
		info.deviceName, MAX_NAME_LENGTH);
	strlcpy(info.shared_info->chipsetName,
		radeon_chip_name[info.chipsetID], MAX_NAME_LENGTH);
 
	// *** AtomBIOS mapping
	// First we try an active bios read
	status_t biosStatus = radeon_hd_getbios(info);
 
	if (biosStatus != B_OK) {
		// If the active read fails, we try a disabled read
		if (info.chipsetID >= RADEON_CAICOS)
			biosStatus = radeon_hd_getbios_ni(info);
		else if (info.chipsetID >= RADEON_RV770)
			biosStatus = radeon_hd_getbios_r700(info);
		else if (info.chipsetID >= RADEON_R600)
			biosStatus = radeon_hd_getbios_r600(info);
		else if (info.chipsetID >= RADEON_RS600)
			biosStatus = radeon_hd_getbios_avivo(info);
		// else legacy_read_disabled_bios
	}
 
	if (biosStatus != B_OK) {
		// *** very last resort, shadow bios VGA rom
		ERROR("%s: Can't find an AtomBIOS rom! Trying shadow rom...\n",
			__func__);
 
		// This works as long as the primary card is what this driver
		// is loaded for. Multiple cards may pose the risk of loading
		// the wrong AtomBIOS for the wrong card.
 
		uint32 romBase = 0xC0000;
		uint32 romSize = 128 * 1024;
			// what happens when AtomBIOS goes over 128Kb?
			// A Radeon HD 6990 has a 128Kb AtomBIOS
 
		if (mapAtomBIOS(info, romBase, romSize) == B_OK) {
			ERROR("%s: Found AtomBIOS at VGA shadow rom\n", __func__);
			// Whew!
			info.shared_info->rom_phys = romBase;
			info.shared_info->rom_size = romSize;
			biosStatus = B_OK;
		}
	}
 
	// Check if a valid AtomBIOS image was found.
	if (biosStatus != B_OK) {
		ERROR("%s: card (%ld): couldn't find AtomBIOS rom!\n",
			__func__, info.id);
		ERROR("%s: card (%ld): exiting. Please open a bug ticket"
			" at haiku-os.org with your /var/log/syslog\n",
			__func__, info.id);
		// Fallback to VESA (more likely crash app_server)
		return B_ERROR;
	}
 
	info.shared_info->has_rom = (biosStatus == B_OK) ? true : false;
	info.shared_info->rom_area = (biosStatus == B_OK) ? info.rom_area : -1;
 
	// *** Pull active monitor VESA EDID from boot loader
	edid1_info* edidInfo
		= (edid1_info*)get_boot_item(EDID_BOOT_INFO, NULL);
 
	if (edidInfo != NULL) {
		TRACE("card(%ld): %s found VESA EDID information.\n", info.id,
			__func__);
		info.shared_info->has_edid = true;
		memcpy(&info.shared_info->edid_info, edidInfo, sizeof(edid1_info));
	} else {
		TRACE("card(%ld): %s didn't find VESA EDID modes.\n", info.id,
			__func__);
		info.shared_info->has_edid = false;
	}
 
	TRACE("card(%ld): %s completed successfully!\n", info.id, __func__);
 
	TRACE("card(%ld): GPU thermal status: %" B_PRId32 "C\n", info.id,
		radeon_thermal_query(info) / 1000);
 
	return B_OK;
}
 
 
void
radeon_hd_uninit(radeon_info &info)
{
	TRACE("card(%ld): %s called\n", info.id, __func__);
 
	delete_area(info.shared_area);
	delete_area(info.registers_area);
	delete_area(info.framebuffer_area);
	delete_area(info.rom_area);
}
 

↑ V576 Incorrect format. Consider checking the third actual argument of the 'dprintf' function. The memsize type argument is expected.

↑ V576 Incorrect format. Consider checking the third actual argument of the 'dprintf' function. The memsize type argument is expected.

↑ V576 Incorrect format. Consider checking the third actual argument of the 'dprintf' function. The memsize type argument is expected.

↑ V576 Incorrect format. Consider checking the second actual argument of the 'dprintf' function. The memsize type argument is expected.

↑ V576 Incorrect format. Consider checking the second actual argument of the 'dprintf' function. The memsize type argument is expected.

↑ V576 Incorrect format. Consider checking the third actual argument of the 'dprintf' function. The memsize type argument is expected.

↑ V576 Incorrect format. Consider checking the third actual argument of the 'dprintf' function. The memsize type argument is expected.

↑ V576 Incorrect format. Consider checking the third actual argument of the 'dprintf' function. The memsize type argument is expected.

↑ V576 Incorrect format. Consider checking the second actual argument of the 'dprintf' function. The memsize type argument is expected.

↑ V576 Incorrect format. Consider checking the second actual argument of the 'dprintf' function. The memsize type argument is expected.

↑ V576 Incorrect format. Consider checking the second actual argument of the 'dprintf' function. The memsize type argument is expected.

↑ V576 Incorrect format. Consider checking the second actual argument of the 'dprintf' function. The memsize type argument is expected.

↑ V576 Incorrect format. Consider checking the second actual argument of the 'dprintf' function. The memsize type argument is expected.

↑ V576 Incorrect format. Consider checking the second actual argument of the 'dprintf' function. The memsize type argument is expected.

↑ V576 Incorrect format. Consider checking the second actual argument of the 'dprintf' function. The memsize type argument is expected.

↑ V547 Expression 'biosStatus == ((int) 0)' is always true.

↑ V547 Expression 'biosStatus == ((int) 0)' is always true.

↑ V576 Incorrect format. Consider checking the second actual argument of the 'dprintf' function. The memsize type argument is expected.

↑ V576 Incorrect format. Consider checking the second actual argument of the 'dprintf' function. The memsize type argument is expected.