#include "radeon_hd.h"
#include "sensors.h"
#include "atombios/atombios.h"
#include "driver.h"
#include "utility.h"
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <ACPI.h>
#include <boot_item.h>
#include <driver_settings.h>
#include <util/AreaKeeper.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)
static status_t
mapAtomBIOSACPI(radeon_info &info, uint32& romSize)
{
TRACE("%s: seeking AtomBIOS from ACPI\n", __func__);
uint8* rom;
acpi_module_info* acpiModule;
status_t status = get_module(B_ACPI_MODULE_NAME, (module_info**)&acpiModule);
if (status < B_OK)
return status;
UEFI_ACPI_VFCT* vfct;
GOP_VBIOS_CONTENT* vbios;
VFCT_IMAGE_HEADER* vhdr;
status = acpiModule->get_table("VFCT", 0, (void**)&vfct);
if (status != B_OK) {
put_module(B_ACPI_MODULE_NAME);
return status;
}
vbios = (GOP_VBIOS_CONTENT*)((char*)vfct + vfct->VBIOSImageOffset);
vhdr = &vbios->VbiosHeader;
TRACE("%s: ACPI VFCT contains a BIOS for: %" B_PRIx32 ":%" B_PRIx32 ":%"
B_PRId32 " %04x:%04x\n", __func__,
vhdr->PCIBus, vhdr->PCIDevice, vhdr->PCIFunction, vhdr->VendorID, vhdr->DeviceID);
if (info.pci->vendor_id != vhdr->VendorID || info.pci->device_id != vhdr->DeviceID
|| info.pci->bus != vhdr->PCIBus || info.pci->device != vhdr->PCIDevice
|| info.pci->function != vhdr->PCIFunction) {
TRACE("%s: not valid AtomBIOS rom for current device\n", __func__);
put_module(B_ACPI_MODULE_NAME);
return B_ERROR;
}
rom = vbios->VbiosContent;
romSize = vhdr->ImageLength;
uint16 romHeader = RADEON_BIOS16(rom, 0x48);
bool romValid = !memcmp(&rom[romHeader + 4], "ATOM", 4)
|| !memcmp(&rom[romHeader + 4], "MOTA", 4);
if (romValid == false) {
TRACE("%s: not valid AtomBIOS rom at ACPI\n", __func__);
put_module(B_ACPI_MODULE_NAME);
return B_ERROR;
}
uint32 areaSize = ROUNDUP(romSize, 1 << 16);
info.rom_area = create_area("radeon hd AtomBIOS",
(void**)&info.atom_buffer, B_ANY_KERNEL_ADDRESS,
areaSize, B_NO_LOCK,
B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_CLONEABLE_AREA);
if (info.rom_area < 0) {
ERROR("%s: unable to map kernel AtomBIOS space!\n",
__func__);
put_module(B_ACPI_MODULE_NAME);
return B_NO_MEMORY;
}
memset((void*)info.atom_buffer, 0, areaSize);
memcpy(info.atom_buffer, (void*)rom, romSize);
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) {
ERROR("%s: AtomBIOS verified and locked (%" B_PRIu32 ")\n", __func__, romSize);
} else
ERROR("%s: AtomBIOS memcpy failed!\n", __func__);
put_module(B_ACPI_MODULE_NAME);
return romValid ? B_OK : B_ERROR;
}
static size_t
radeon_get_rom_size(uint8* rom, size_t romSize)
{
uint8* image = rom;
uint8* end = rom + romSize;
uint32 length = 0;
bool lastImage;
if (image[0] != 0x55 || image[1] != 0xaa)
return 0;
do {
uint8* pds = image + *(uint16*)(image + 0x18);
if (memcmp(pds, "PCIR", 4) != 0)
break;
lastImage = (*(pds + 0x15) & 0x80) != 0;
length = *(uint16*)(pds + 0x10);
image += length * 512;
if (image >= end)
break;
if (!lastImage && (image[0] != 0x55 || image[1] != 0xaa))
break;
} while (length > 0 && !lastImage);
return min_c((size_t)(image - rom), romSize);
}
static status_t
mapAtomBIOS(radeon_info &info, phys_addr_t romBase, uint32 romSize,
bool findROMlength = false)
{
TRACE("%s: seeking AtomBIOS @ 0x%" B_PRIXPHYSADDR " [size: 0x%" B_PRIX32 "]\n",
__func__, romBase, romSize);
uint8* rom;
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_PRIXPHYSADDR
"\n", __func__, romBase);
return B_NO_MEMORY;
}
if (rom[0] != 0x55 || rom[1] != 0xAA) {
uint16 id = rom[0] + (rom[1] << 8);
TRACE("%s: BIOS signature incorrect @ 0x%" B_PRIXPHYSADDR " (%X)\n",
__func__, romBase, id);
delete_area(testArea);
return B_ERROR;
}
uint16 romHeader = RADEON_BIOS16(rom, 0x48);
bool romValid = !memcmp(&rom[romHeader + 4], "ATOM", 4)
|| !memcmp(&rom[romHeader + 4], "MOTA", 4);
if (romValid == false) {
uint16 id = rom[0] + (rom[1] << 8);
TRACE("%s: not AtomBIOS rom at 0x%" B_PRIXPHYSADDR "(%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_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);
if (findROMlength) {
romSize = radeon_get_rom_size(rom, romSize);
if (romSize == 0) {
TRACE("%s: rom size is zero\n", __func__);
delete_area(testArea);
return B_ERROR;
}
}
memcpy(info.atom_buffer, (void*)rom, romSize);
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) {
ERROR("%s: AtomBIOS verified and locked (%" B_PRIu32 ")\n", __func__, romSize);
} 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(%" B_PRId32 "): %s: called\n", info.id, __func__);
phys_addr_t romBase = 0;
uint32 romSize = 0;
uint32 romMethod = 0;
status_t mapResult = B_ERROR;
for (romMethod = 0; romMethod < 3; romMethod++) {
switch(romMethod) {
case 0:
mapResult = mapAtomBIOSACPI(info, romSize);
break;
case 1:
romBase = info.pci->u.h0.base_registers[PCI_BAR_FB];
if ((info.pci->u.h0.base_register_flags[PCI_BAR_FB] & PCI_address_type)
== PCI_address_type_64) {
romBase |= (uint64)info.pci->u.h0.base_registers[PCI_BAR_FB + 1] << 32;
}
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:
{
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, true);
}
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_PRIXPHYSADDR "\n", __func__, romMethod, romBase);
break;
} else {
ERROR("%s: AtomBIOS not found using active method %" B_PRIu32
" at 0x%" B_PRIXPHYSADDR "\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(%" B_PRId32 "): %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);
write32(info.registers + R600_BUS_CNTL, (bus_cntl & ~R600_BIOS_ROM_DIS));
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));
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, true);
}
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;
}
pciConfig &= ~PCI_rom_enable;
set_pci_config(info.pci, PCI_rom_base, 4, pciConfig);
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(%" B_PRId32 "): %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);
write32(info.registers + RADEON_VIPH_CONTROL,
(viph_control & ~RADEON_VIPH_EN));
write32(info.registers + R600_BUS_CNTL, (bus_cntl & ~R600_BIOS_ROM_DIS));
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));
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;
}
pciConfig &= ~PCI_rom_enable;
set_pci_config(info.pci, PCI_rom_base, 4, pciConfig);
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(%" B_PRId32 "): %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);
write32(info.registers + RADEON_VIPH_CONTROL,
(viph_control & ~RADEON_VIPH_EN));
write32(info.registers + R600_BUS_CNTL, (bus_cntl & ~R600_BIOS_ROM_DIS));
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));
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;
}
pciConfig &= ~PCI_rom_enable;
set_pci_config(info.pci, PCI_rom_base, 4, pciConfig);
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(%" B_PRId32 "): %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);
write32(info.registers + RADEON_VIPH_CONTROL,
(viphControl & ~RADEON_VIPH_EN));
write32(info.registers + RV370_BUS_CNTL,
(busControl & ~RV370_BUS_BIOS_DIS_ROM));
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;
}
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(%" B_PRId32 "): %s: called\n", info.id, __func__);
ERROR("%s: card(%" B_PRId32 "): "
"Radeon %s 1002:%" B_PRIX32 "\n", __func__, info.id,
radeon_chip_name[info.chipsetID], info.pciID);
uint32 pciConfig = get_pci_config(info.pci, PCI_command, 2);
pciConfig |= PCI_command_io | PCI_command_memory | PCI_command_master;
set_pci_config(info.pci, PCI_command, 2, pciConfig);
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_CLONEABLE_AREA);
if (info.shared_area < B_OK) {
ERROR("%s: card (%" B_PRId32 "): 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();
const uint32 pciBarMmio = radeon_hd_pci_bar_mmio(info.chipsetID);
phys_addr_t addr = info.pci->u.h0.base_registers[pciBarMmio];
uint64 mmioSize = info.pci->u.h0.base_register_sizes[pciBarMmio];
if (pciBarMmio < 5
&& (info.pci->u.h0.base_register_flags[pciBarMmio] & PCI_address_type) == PCI_address_type_64) {
addr |= (uint64)info.pci->u.h0.base_registers[pciBarMmio + 1] << 32;
mmioSize |= (uint64)info.pci->u.h0.base_register_sizes[pciBarMmio + 1] << 32;
}
AreaKeeper mmioMapper;
info.registers_area = mmioMapper.Map("radeon hd mmio", addr, mmioSize,
B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_CLONEABLE_AREA,
(void**)&info.registers);
if (mmioMapper.InitCheck() < B_OK) {
ERROR("%s: card (%" B_PRId32 "): couldn't map memory I/O!\n",
__func__, info.id);
return info.registers_area;
}
mmioMapper.Detach();
if (info.chipsetID >= RADEON_TAHITI) {
info.shared_info->graphics_memory_size
= read32(info.registers + CONFIG_MEMSIZE_TAHITI) * 1024;
} else if (info.chipsetID >= RADEON_CEDAR) {
switch (info.chipsetID) {
default:
info.shared_info->graphics_memory_size
= read32(info.registers + CONFIG_MEMSIZE) * 1024;
break;
case RADEON_PALM:
case RADEON_SUMO:
case RADEON_SUMO2:
info.shared_info->graphics_memory_size
= read32(info.registers + CONFIG_MEMSIZE) / 1024;
break;
}
} else if (info.chipsetID >= RADEON_R600) {
info.shared_info->graphics_memory_size
= read32(info.registers + CONFIG_MEMSIZE) / 1024;
} else {
if ((info.chipsetFlags & CHIP_IGP) != 0) {
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) {
info.shared_info->graphics_memory_size = 8192;
write32(info.registers + RADEON_CONFIG_MEMSIZE,
info.shared_info->graphics_memory_size * 1024);
}
}
}
phys_addr_t fbAddr = info.pci->u.h0.base_registers[PCI_BAR_FB];
uint64 fbBarSize = info.pci->u.h0.base_register_sizes[PCI_BAR_FB];
if ((info.pci->u.h0.base_register_flags[PCI_BAR_FB] & PCI_address_type)
== PCI_address_type_64) {
fbAddr |= (uint64)info.pci->u.h0.base_registers[PCI_BAR_FB + 1] << 32;
fbBarSize |= (uint64)info.pci->u.h0.base_register_sizes[PCI_BAR_FB + 1] << 32;
}
fbBarSize /= 1024;
if (info.shared_info->graphics_memory_size == 0) {
ERROR("%s: Error: found 0MB video ram, using PCI bar size...\n",
__func__);
info.shared_info->frame_buffer_size = fbBarSize;
} else if (info.shared_info->graphics_memory_size > fbBarSize) {
TRACE("%s: shrinking frame buffer to PCI bar...\n",
__func__);
info.shared_info->frame_buffer_size = fbBarSize;
} else {
info.shared_info->frame_buffer_size
= info.shared_info->graphics_memory_size;
}
if (info.shared_info->frame_buffer_size < 8192) {
ERROR("%s: Error: frame buffer is less than 8 MiB. I give up.\n",
__func__);
return B_ERROR;
}
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);
TRACE("framebuffer paddr: %#" B_PRIxPHYSADDR "\n", fbAddr);
AreaKeeper frambufferMapper;
info.framebuffer_area = frambufferMapper.Map("radeon hd frame buffer",
fbAddr, 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(%" B_PRId32 "): couldn't map frame buffer!\n",
__func__, info.id);
return info.framebuffer_area;
}
TRACE("frambuffer vaddr: %#" B_PRIxADDR "\n",
(addr_t)info.shared_info->frame_buffer);
TRACE("frambuffer size: %#" B_PRIxSIZE "\n",
(size_t)info.shared_info->frame_buffer_size * 1024);
vm_set_area_memory_type(info.framebuffer_area, fbAddr, B_WRITE_COMBINING_MEMORY);
frambufferMapper.Detach();
info.shared_info->frame_buffer_area = info.framebuffer_area;
info.shared_info->frame_buffer_phys = fbAddr;
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);
status_t biosStatus = radeon_hd_getbios(info);
if (biosStatus != B_OK) {
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);
}
if (biosStatus != B_OK) {
ERROR("%s: Can't find an AtomBIOS rom! Trying shadow rom...\n",
__func__);
uint32 romBase = 0xC0000;
uint32 romSize = 128 * 1024;
if (mapAtomBIOS(info, romBase, romSize) == B_OK) {
ERROR("%s: Found AtomBIOS at VGA shadow rom\n", __func__);
info.shared_info->rom_phys = romBase;
info.shared_info->rom_size = romSize;
biosStatus = B_OK;
}
}
if (biosStatus != B_OK) {
ERROR("%s: card (%" B_PRId32 "): couldn't find AtomBIOS rom!\n",
__func__, info.id);
ERROR("%s: card (%" B_PRId32 "): exiting. Please open a bug ticket"
" at haiku-os.org with your /var/log/syslog\n",
__func__, info.id);
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;
edid1_info* edidInfo
= (edid1_info*)get_boot_item(EDID_BOOT_INFO, NULL);
if (edidInfo != NULL) {
TRACE("card(%" B_PRId32 "): %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(%" B_PRId32 "): %s didn't find VESA EDID modes.\n",
info.id, __func__);
info.shared_info->has_edid = false;
}
TRACE("card(%" B_PRId32 "): %s completed successfully!\n",
info.id, __func__);
TRACE("card(%" B_PRId32 "): 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(%" B_PRId32 "): %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);
}