#include "dac_regs.h"
#include "tv_out_regs.h"
#include "fp_regs.h"
#include "mmio.h"
#include "radeon_driver.h"
#include <PCI.h>
#include <stdio.h>
#include <string.h>
#define get_pci(o, s) (*pci_bus->read_pci_config)(pcii->bus, pcii->device, pcii->function, (o), (s))
#define set_pci(o, s, v) (*pci_bus->write_pci_config)(pcii->bus, pcii->device, pcii->function, (o), (s), (v))
extern radeon_settings current_settings;
status_t Radeon_MapDevice( device_info *di, bool mmio_only )
{
int regs = 2;
int fb = 0;
char buffer[100];
shared_info *si = di->si;
uint32 tmp;
pci_info *pcii = &(di->pcii);
status_t result;
SHOW_FLOW( 3, "device: %02X%02X%02X",
di->pcii.bus, di->pcii.device, di->pcii.function );
si->ROM_area = si->regs_area = si->memory[mt_local].area = 0;
tmp = get_pci( PCI_command, 2 );
SHOW_FLOW( 3, "old PCI command state: 0x%08" B_PRIx32, tmp );
tmp |= PCI_command_io | PCI_command_memory | PCI_command_master;
set_pci( PCI_command, 2, tmp );
SHOW_INFO( 1,
"physical address of memory-mapped I/O: 0x%8" B_PRIx32 "-0x%8" B_PRIx32,
di->pcii.u.h0.base_registers[regs],
di->pcii.u.h0.base_registers[regs] + di->pcii.u.h0.base_register_sizes[regs] - 1 );
sprintf( buffer, "%04X_%04X_%02X%02X%02X regs",
di->pcii.vendor_id, di->pcii.device_id,
di->pcii.bus, di->pcii.device, di->pcii.function );
si->regs_area = map_physical_memory(
buffer,
di->pcii.u.h0.base_registers[regs],
di->pcii.u.h0.base_register_sizes[regs],
B_ANY_KERNEL_ADDRESS,
B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_CLONEABLE_AREA,
(void **)&(di->regs));
if( si->regs_area < 0 )
return si->regs_area;
if( mmio_only )
return B_OK;
sprintf( buffer, "%04X_%04X_%02X%02X%02X ROM",
di->pcii.vendor_id, di->pcii.device_id,
di->pcii.bus, di->pcii.device, di->pcii.function );
si->ROM_area = map_physical_memory(
buffer,
di->rom.phys_address,
di->rom.size,
B_ANY_KERNEL_ADDRESS,
0,
(void **)&(di->rom.rom_ptr));
if( si->ROM_area < 0 ) {
result = si->ROM_area;
goto err2;
}
if( di->pcii.u.h0.base_register_sizes[fb] > di->local_mem_size ) {
SHOW_INFO( 1,
"restrict frame buffer from 0x%8" B_PRIx32
" to 0x%8" B_PRIx32 " bytes",
di->pcii.u.h0.base_register_sizes[fb],
di->local_mem_size
);
di->pcii.u.h0.base_register_sizes[fb] = di->local_mem_size;
}
SHOW_INFO( 1,
"physical address of framebuffer: 0x%8" B_PRIx32 "-0x%8" B_PRIx32,
di->pcii.u.h0.base_registers[fb],
di->pcii.u.h0.base_registers[fb] + di->pcii.u.h0.base_register_sizes[fb] - 1 );
sprintf(buffer, "%04X_%04X_%02X%02X%02X framebuffer",
di->pcii.vendor_id, di->pcii.device_id,
di->pcii.bus, di->pcii.device, di->pcii.function);
si->memory[mt_local].area = map_physical_memory(
buffer,
di->pcii.u.h0.base_registers[fb],
di->pcii.u.h0.base_register_sizes[fb],
B_ANY_KERNEL_BLOCK_ADDRESS | B_WRITE_COMBINING_MEMORY,
B_READ_AREA | B_WRITE_AREA | B_CLONEABLE_AREA,
(void **)&(si->local_mem));
if( si->memory[mt_local].area < 0 ) {
SHOW_FLOW0( 3, "couldn't enable WC for frame buffer" );
si->memory[mt_local].area = map_physical_memory(
buffer,
di->pcii.u.h0.base_registers[fb],
di->pcii.u.h0.base_register_sizes[fb],
B_ANY_KERNEL_BLOCK_ADDRESS,
B_READ_AREA | B_WRITE_AREA | B_CLONEABLE_AREA,
(void **)&(si->local_mem));
}
SHOW_FLOW( 3, "mapped frame buffer @%p", si->local_mem );
if( si->memory[mt_local].area < 0 ) {
result = si->memory[mt_local].area;
goto err;
}
si->framebuffer_pci = (phys_addr_t)di->pcii.u.h0.base_registers_pci[fb];
return B_OK;
err:
delete_area( si->ROM_area );
err2:
delete_area( si->regs_area );
return result;
}
void Radeon_UnmapDevice(device_info *di)
{
shared_info *si = di->si;
pci_info *pcii = &(di->pcii);
uint32 tmp;
SHOW_FLOW0( 3, "" );
tmp = get_pci( PCI_command, 2 );
tmp &= ~PCI_command_io | PCI_command_memory | PCI_command_master;
set_pci( PCI_command, 2, tmp );
if( si->regs_area > 0 )
delete_area( si->regs_area );
if( si->ROM_area > 0 )
delete_area( si->ROM_area );
if( si->memory[mt_local].area > 0 )
delete_area( si->memory[mt_local].area );
si->regs_area = si->ROM_area = si->memory[mt_local].area = 0;
}
status_t Radeon_FirstOpen( device_info *di )
{
status_t result;
char buffer[100];
shared_info *si;
sprintf( buffer, "%04X_%04X_%02X%02X%02X shared",
di->pcii.vendor_id, di->pcii.device_id,
di->pcii.bus, di->pcii.device, di->pcii.function );
di->shared_area = create_area(
buffer,
(void **)&(di->si),
B_ANY_KERNEL_ADDRESS,
(sizeof(shared_info) + (B_PAGE_SIZE - 1)) & ~(B_PAGE_SIZE - 1),
B_FULL_LOCK,
B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_CLONEABLE_AREA);
if (di->shared_area < 0) {
result = di->shared_area;
goto err8;
}
memset( di->si, 0, sizeof( *di->si ));
si = di->si;
si->settings = di->settings = current_settings;
if (di->settings.force_acc_dma)
di->acc_dma = true;
if (di->settings.force_acc_mmio)
di->acc_dma = false;
#ifdef ENABLE_LOGGING
#ifdef LOG_INCLUDE_STARTUP
si->log = log_init( 1000000 );
#endif
#endif
si->vendor_id = di->pcii.vendor_id;
si->device_id = di->pcii.device_id;
si->revision = di->pcii.revision;
si->asic = di->asic;
si->is_mobility = di->is_mobility;
si->tv_chip = di->tv_chip;
si->new_pll = di->new_pll;
si->is_igp = di->is_igp;
si->has_no_i2c = di->has_no_i2c;
si->is_atombios = di->is_atombios;
si->is_mobility = di->is_mobility;
si->panel_pwr_delay = di->si->panel_pwr_delay;
si->acc_dma = di->acc_dma;
memcpy(&si->routing, &di->routing, sizeof(disp_entity));
si->theatre_channel = -1;
si->crtc[0].crtc_idx = 0;
si->crtc[0].flatpanel_port = 0;
si->crtc[1].crtc_idx = 1;
si->crtc[1].flatpanel_port = 1;
si->num_crtc = di->num_crtc;
if (di->is_mobility)
si->flatpanels[0] = di->fp_info;
si->pll = di->pll;
sprintf( buffer, "%04X_%04X_%02X%02X%02X virtual card 0",
di->pcii.vendor_id, di->pcii.device_id,
di->pcii.bus, di->pcii.device, di->pcii.function );
di->virtual_card_area = create_area(
buffer,
(void **)&(di->vc),
B_ANY_KERNEL_ADDRESS,
(sizeof(virtual_card) + (B_PAGE_SIZE - 1)) & ~(B_PAGE_SIZE - 1),
B_FULL_LOCK,
B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_CLONEABLE_AREA);
if (di->virtual_card_area < 0) {
result = di->virtual_card_area;
goto err7;
}
di->vc->assigned_crtc[0] = true;
di->vc->assigned_crtc[1] = si->num_crtc > 1;
di->vc->controlled_displays =
dd_tv_crt | dd_crt | dd_lvds | dd_dvi | dd_dvi_ext | dd_ctv | dd_stv;
di->vc->fb_mem_handle = 0;
di->vc->cursor.mem_handle = 0;
di->vc->id = di->virtual_card_area;
result = Radeon_MapDevice( di, false );
if (result < 0)
goto err6;
if( di->asic == rt_rv100 && di->is_mobility)
di->dac2_cntl = INREG( di->regs, RADEON_DAC_CNTL2 );
memcpy(&si->tmds_pll, &di->tmds_pll, sizeof(di->tmds_pll));
si->tmds_pll_cntl = INREG( di->regs, RADEON_TMDS_PLL_CNTL);
si->tmds_transmitter_cntl = INREG( di->regs, RADEON_TMDS_TRANSMITTER_CNTL);
SHOW_INFO0( 2, "Copy of Laptop Display Regs for Reference:");
SHOW_INFO( 2, "LVDS GEN = %8" B_PRIx32,
INREG( di->regs, RADEON_LVDS_GEN_CNTL ));
SHOW_INFO( 2, "LVDS PLL = %8" B_PRIx32,
INREG( di->regs, RADEON_LVDS_PLL_CNTL ));
SHOW_INFO( 2, "TMDS PLL = %8" B_PRIx32,
INREG( di->regs, RADEON_TMDS_PLL_CNTL ));
SHOW_INFO( 2, "TMDS TRANS = %8" B_PRIx32,
INREG( di->regs, RADEON_TMDS_TRANSMITTER_CNTL ));
SHOW_INFO( 2, "FP1 GEN = %8" B_PRIx32,
INREG( di->regs, RADEON_FP_GEN_CNTL ));
SHOW_INFO( 2, "FP2 GEN = %8" B_PRIx32 ,
INREG( di->regs, RADEON_FP2_GEN_CNTL ));
SHOW_INFO( 2, "TV DAC = %8" B_PRIx32 ,
INREG( di->regs, RADEON_TV_DAC_CNTL ));
result = Radeon_InitPCIGART( di );
if( result < 0 )
goto err5;
si->memory[mt_local].size = di->local_mem_size;
si->memory[mt_PCI].area = di->pci_gart.buffer.area;
si->memory[mt_PCI].size = di->pci_gart.buffer.size;
si->nonlocal_type = mt_PCI;
Radeon_InitMemController( di );
result = Radeon_SetupIRQ( di, buffer );
if( result < 0 )
goto err4;
di->memmgr[mt_local] = mem_init("radeon local memory", 0, di->local_mem_size, 1024,
di->local_mem_size / 1024);
if (di->memmgr[mt_local] == NULL) {
result = B_NO_MEMORY;
goto err3;
}
di->memmgr[mt_PCI] = mem_init("radeon PCI GART memory", 0, di->pci_gart.buffer.size, 4096,
di->pci_gart.buffer.size / 4096);
if (di->memmgr[mt_PCI] == NULL) {
result = B_NO_MEMORY;
goto err2;
}
di->memmgr[mt_AGP] = NULL;
Radeon_Set_AGP( di, !di->settings.force_pci );
result = Radeon_InitCP( di );
if( result != B_OK )
goto err;
if ( di->acc_dma )
{
result = Radeon_InitDMA( di );
if( result != B_OK )
goto err0;
}
else
{
SHOW_INFO0( 0, "DMA is diabled using PIO mode");
}
if (di->is_mobility && di->settings.dynamic_clocks)
Radeon_SetDynamicClock( di, 1);
return B_OK;
err0:
Radeon_UninitCP( di );
err:
mem_destroy( di->memmgr[mt_PCI] );
err2:
mem_destroy( di->memmgr[mt_local] );
err3:
Radeon_CleanupIRQ( di );
err4:
Radeon_CleanupPCIGART( di );
err5:
Radeon_UnmapDevice( di );
err6:
delete_area( di->virtual_card_area );
err7:
delete_area( di->shared_area );
err8:
return result;
}
void Radeon_LastClose( device_info *di )
{
if ( di->acc_dma )
Radeon_UninitCP( di );
if( di->asic == rt_rv100 && di->is_mobility)
OUTREG( di->regs, RADEON_DAC_CNTL2, di->dac2_cntl );
mem_destroy( di->memmgr[mt_local] );
if( di->memmgr[mt_PCI] )
mem_destroy( di->memmgr[mt_PCI] );
if( di->memmgr[mt_AGP] )
mem_destroy( di->memmgr[mt_AGP] );
Radeon_CleanupIRQ( di );
Radeon_CleanupPCIGART( di );
Radeon_UnmapDevice(di);
#ifdef ENABLE_LOGGING
#ifdef LOG_INCLUDE_STARTUP
log_exit( di->si->log );
#endif
#endif
delete_area( di->virtual_card_area );
delete_area( di->shared_area );
}