From 95e1d7e8288c9eb390705b0fa6e735ff091a0e65 Mon Sep 17 00:00:00 2001 From: Alexander von Gluck IV Date: Fri, 22 Jul 2011 04:59:07 +0000 Subject: [PATCH] * Large refactoring of display detection and storage * Create new display.c/h for display management * Rename global gCRT to gDisplay * Add CRT connection type into gDisplay * Add CRT connection index into gDisplay * Refactor registers for each display into gDisplay via regs * We now shouldn't freak out too badly on multi-monitors git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@42462 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/add-ons/accelerants/radeon_hd/Jamfile | 1 + .../accelerants/radeon_hd/accelerant.cpp | 197 ++----------- .../accelerants/radeon_hd/accelerant.h | 33 +-- src/add-ons/accelerants/radeon_hd/display.cpp | 261 ++++++++++++++++++ src/add-ons/accelerants/radeon_hd/display.h | 17 ++ src/add-ons/accelerants/radeon_hd/mode.cpp | 181 +++++------- src/add-ons/accelerants/radeon_hd/mode.h | 2 +- src/add-ons/accelerants/radeon_hd/pll.cpp | 8 +- 8 files changed, 391 insertions(+), 309 deletions(-) create mode 100644 src/add-ons/accelerants/radeon_hd/display.cpp create mode 100644 src/add-ons/accelerants/radeon_hd/display.h diff --git a/src/add-ons/accelerants/radeon_hd/Jamfile b/src/add-ons/accelerants/radeon_hd/Jamfile index 55d9702f7e..8a23985d26 100644 --- a/src/add-ons/accelerants/radeon_hd/Jamfile +++ b/src/add-ons/accelerants/radeon_hd/Jamfile @@ -15,6 +15,7 @@ Addon radeon_hd.accelerant : pll.cpp mc.cpp dac.cpp + display.cpp tmds.cpp mode.cpp bios.cpp diff --git a/src/add-ons/accelerants/radeon_hd/accelerant.cpp b/src/add-ons/accelerants/radeon_hd/accelerant.cpp index 2b8cea78eb..9f8319f728 100644 --- a/src/add-ons/accelerants/radeon_hd/accelerant.cpp +++ b/src/add-ons/accelerants/radeon_hd/accelerant.cpp @@ -11,6 +11,7 @@ #include "accelerant_protos.h" #include "accelerant.h" +#include "display.h" #include "utility.h" #include "pll.h" #include "mc.h" @@ -34,8 +35,7 @@ extern "C" void _sPrintf(const char *format, ...); struct accelerant_info *gInfo; -struct register_info *gRegister; -crt_info *gCRT[MAX_CRT]; +crt_info *gDisplay[MAX_DISPLAY]; class AreaCloner { @@ -97,22 +97,23 @@ init_common(int device, bool isClone) // initialize global accelerant info structure gInfo = (accelerant_info *)malloc(sizeof(accelerant_info)); - gRegister = (register_info *)malloc(sizeof(register_info)); - if (gInfo == NULL || gRegister == NULL) + if (gInfo == NULL) return B_NO_MEMORY; - for (uint32 id = 0; id < MAX_CRT; id++) { - gCRT[id] = (crt_info *)malloc(sizeof(crt_info)); - if (gCRT[id] == NULL) - return B_NO_MEMORY; - } - memset(gInfo, 0, sizeof(accelerant_info)); - memset(gRegister, 0, sizeof(register_info)); - for (uint32 id = 0; id < MAX_CRT; id++) - memset(gCRT[id], 0, sizeof(crt_info)); + for (uint32 id = 0; id < MAX_DISPLAY; id++) { + gDisplay[id] = (crt_info *)malloc(sizeof(crt_info)); + if (gDisplay[id] == NULL) + return B_NO_MEMORY; + memset(gDisplay[id], 0, sizeof(crt_info)); + + gDisplay[id]->regs = (register_info *)malloc(sizeof(register_info)); + if (gDisplay[id]->regs == NULL) + return B_NO_MEMORY; + memset(gDisplay[id]->regs, 0, sizeof(register_info)); + } gInfo->is_clone = isClone; gInfo->device = device; @@ -177,169 +178,13 @@ uninit_common(void) close(gInfo->device); free(gInfo); - free(gRegister); - for (uint32 id = 0; id < MAX_CRT; id++) - free(gCRT[id]); -} - - -/*! Populate gRegister with device dependant register locations */ -status_t -init_registers(uint8 crtid) -{ - radeon_shared_info &info = *gInfo->shared_info; - - if (info.device_chipset >= RADEON_R800) { - uint32 offset = 0; - - // AMD Eyefinity on Evergreen GPUs - if (crtid == 1) { - offset = EVERGREEN_CRTC1_REGISTER_OFFSET; - gRegister->vgaControl = D2VGA_CONTROL; - } else if (crtid == 2) { - offset = EVERGREEN_CRTC2_REGISTER_OFFSET; - gRegister->vgaControl = EVERGREEN_D3VGA_CONTROL; - } else if (crtid == 3) { - offset = EVERGREEN_CRTC3_REGISTER_OFFSET; - gRegister->vgaControl = EVERGREEN_D4VGA_CONTROL; - } else if (crtid == 4) { - offset = EVERGREEN_CRTC4_REGISTER_OFFSET; - gRegister->vgaControl = EVERGREEN_D5VGA_CONTROL; - } else if (crtid == 5) { - offset = EVERGREEN_CRTC5_REGISTER_OFFSET; - gRegister->vgaControl = EVERGREEN_D6VGA_CONTROL; - } else { - offset = EVERGREEN_CRTC0_REGISTER_OFFSET; - gRegister->vgaControl = D1VGA_CONTROL; - } - - // Evergreen+ is crtoffset + register - gRegister->grphEnable = offset + EVERGREEN_GRPH_ENABLE; - gRegister->grphControl = offset + EVERGREEN_GRPH_CONTROL; - gRegister->grphSwapControl = offset + EVERGREEN_GRPH_SWAP_CONTROL; - gRegister->grphPrimarySurfaceAddr - = offset + EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS; - gRegister->grphSecondarySurfaceAddr - = offset + EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS; - - gRegister->grphPrimarySurfaceAddrHigh - = offset + EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH; - gRegister->grphSecondarySurfaceAddrHigh - = offset + EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH; - - gRegister->grphPitch = offset + EVERGREEN_GRPH_PITCH; - gRegister->grphSurfaceOffsetX - = offset + EVERGREEN_GRPH_SURFACE_OFFSET_X; - gRegister->grphSurfaceOffsetY - = offset + EVERGREEN_GRPH_SURFACE_OFFSET_Y; - gRegister->grphXStart = offset + EVERGREEN_GRPH_X_START; - gRegister->grphYStart = offset + EVERGREEN_GRPH_Y_START; - gRegister->grphXEnd = offset + EVERGREEN_GRPH_X_END; - gRegister->grphYEnd = offset + EVERGREEN_GRPH_Y_END; - gRegister->crtControl = offset + EVERGREEN_CRTC_CONTROL; - gRegister->modeDesktopHeight = offset + EVERGREEN_DESKTOP_HEIGHT; - gRegister->modeDataFormat = offset + EVERGREEN_DATA_FORMAT; - gRegister->viewportStart = offset + EVERGREEN_VIEWPORT_START; - gRegister->viewportSize = offset + EVERGREEN_VIEWPORT_SIZE; - - } else if (info.device_chipset >= RADEON_R600 - && info.device_chipset < RADEON_R800) { - - // r600 - r700 are D1 or D2 based on primary / secondary crt - gRegister->vgaControl - = crtid == 1 ? D2VGA_CONTROL : D1VGA_CONTROL; - gRegister->grphEnable - = crtid == 1 ? D2GRPH_ENABLE : D1GRPH_ENABLE; - gRegister->grphControl - = crtid == 1 ? D2GRPH_CONTROL : D1GRPH_CONTROL; - gRegister->grphSwapControl - = crtid == 1 ? D2GRPH_SWAP_CNTL : D1GRPH_SWAP_CNTL; - gRegister->grphPrimarySurfaceAddr - = crtid == 1 ? D2GRPH_PRIMARY_SURFACE_ADDRESS - : D1GRPH_PRIMARY_SURFACE_ADDRESS; - gRegister->grphSecondarySurfaceAddr - = crtid == 1 ? D2GRPH_SECONDARY_SURFACE_ADDRESS - : D1GRPH_SECONDARY_SURFACE_ADDRESS; - - // Surface Address high only used on r770+ - gRegister->grphPrimarySurfaceAddrHigh - = crtid == 1 ? R700_D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH - : R700_D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH; - gRegister->grphSecondarySurfaceAddrHigh - = crtid == 1 ? R700_D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH - : R700_D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH; - - gRegister->grphPitch - = crtid == 1 ? D2GRPH_PITCH : D1GRPH_PITCH; - gRegister->grphSurfaceOffsetX - = crtid == 1 ? D2GRPH_SURFACE_OFFSET_X : D1GRPH_SURFACE_OFFSET_X; - gRegister->grphSurfaceOffsetY - = crtid == 1 ? D2GRPH_SURFACE_OFFSET_Y : D1GRPH_SURFACE_OFFSET_Y; - gRegister->grphXStart - = crtid == 1 ? D2GRPH_X_START : D1GRPH_X_START; - gRegister->grphYStart - = crtid == 1 ? D2GRPH_Y_START : D1GRPH_Y_START; - gRegister->grphXEnd - = crtid == 1 ? D2GRPH_X_END : D1GRPH_X_END; - gRegister->grphYEnd - = crtid == 1 ? D2GRPH_Y_END : D1GRPH_Y_END; - gRegister->crtControl - = crtid == 1 ? D2CRTC_CONTROL : D1CRTC_CONTROL; - gRegister->modeDesktopHeight - = crtid == 1 ? D2MODE_DESKTOP_HEIGHT : D1MODE_DESKTOP_HEIGHT; - gRegister->modeDataFormat - = crtid == 1 ? D2MODE_DATA_FORMAT : D1MODE_DATA_FORMAT; - gRegister->viewportStart - = crtid == 1 ? D2MODE_VIEWPORT_START : D1MODE_VIEWPORT_START; - gRegister->viewportSize - = crtid == 1 ? D2MODE_VIEWPORT_SIZE : D1MODE_VIEWPORT_SIZE; - } else { - // this really shouldn't happen unless a driver PCIID chipset is wrong - TRACE("%s, unknown Radeon chipset: r%X\n", __func__, - info.device_chipset); - return B_ERROR; + for (uint32 id = 0; id < MAX_DISPLAY; id++) { + if (gDisplay[id]->regs != NULL) + free(gDisplay[id]->regs); + if (gDisplay[id] != NULL) + free(gDisplay[id]); } - - // Populate common registers - // TODO : Wait.. this doesn't work with Eyefinity > crt 1. - gRegister->crtid = crtid; - - gRegister->modeCenter - = crtid == 1 ? D2MODE_CENTER : D1MODE_CENTER; - gRegister->grphUpdate - = crtid == 1 ? D2GRPH_UPDATE : D1GRPH_UPDATE; - gRegister->crtHPolarity - = crtid == 1 ? D2CRTC_H_SYNC_A_CNTL : D1CRTC_H_SYNC_A_CNTL; - gRegister->crtVPolarity - = crtid == 1 ? D2CRTC_V_SYNC_A_CNTL : D1CRTC_V_SYNC_A_CNTL; - gRegister->crtHTotal - = crtid == 1 ? D2CRTC_H_TOTAL : D1CRTC_H_TOTAL; - gRegister->crtVTotal - = crtid == 1 ? D2CRTC_V_TOTAL : D1CRTC_V_TOTAL; - gRegister->crtHSync - = crtid == 1 ? D2CRTC_H_SYNC_A : D1CRTC_H_SYNC_A; - gRegister->crtVSync - = crtid == 1 ? D2CRTC_V_SYNC_A : D1CRTC_V_SYNC_A; - gRegister->crtHBlank - = crtid == 1 ? D2CRTC_H_BLANK_START_END : D1CRTC_H_BLANK_START_END; - gRegister->crtVBlank - = crtid == 1 ? D2CRTC_V_BLANK_START_END : D1CRTC_V_BLANK_START_END; - gRegister->crtInterlace - = crtid == 1 ? D2CRTC_INTERLACE_CONTROL : D1CRTC_INTERLACE_CONTROL; - gRegister->crtCountControl - = crtid == 1 ? D2CRTC_COUNT_CONTROL : D1CRTC_COUNT_CONTROL; - gRegister->sclUpdate - = crtid == 1 ? D2SCL_UPDATE : D1SCL_UPDATE; - gRegister->sclEnable - = crtid == 1 ? D2SCL_ENABLE : D1SCL_ENABLE; - gRegister->sclTapControl - = crtid == 1 ? D2SCL_TAP_CONTROL : D1SCL_TAP_CONTROL; - - TRACE("%s, registers for ATI chipset r%X crt #%d loaded\n", __func__, - info.device_chipset, crtid); - - return B_OK; } @@ -361,9 +206,7 @@ radeon_init_accelerant(int device) init_lock(&info.accelerant_lock, "radeon hd accelerant"); init_lock(&info.engine_lock, "radeon hd engine"); - status = init_registers(0); - // Initilize registers for crt0 to begin - + status = detect_displays(); if (status != B_OK) return status; diff --git a/src/add-ons/accelerants/radeon_hd/accelerant.h b/src/add-ons/accelerants/radeon_hd/accelerant.h index be03fd1f1b..c45dd2089d 100644 --- a/src/add-ons/accelerants/radeon_hd/accelerant.h +++ b/src/add-ons/accelerants/radeon_hd/accelerant.h @@ -20,8 +20,8 @@ #include -#define MAX_CRT 6 - // eyefinity limit +#define MAX_DISPLAY 2 + // Maximum displays (more then two requires AtomBIOS) struct accelerant_info { @@ -46,7 +46,6 @@ struct accelerant_info { struct register_info { - uint16 crtid; uint16 vgaControl; uint16 grphEnable; uint16 grphUpdate; @@ -86,19 +85,21 @@ struct register_info { typedef struct { - uint16 location; - uint16 locationIndex; - uint32 vfreq_max; - uint32 vfreq_min; - uint32 hfreq_max; - uint32 hfreq_min; + bool active; + uint32 connection_type; + uint8 connection_id; + register_info *regs; + uint32 vfreq_max; + uint32 vfreq_min; + uint32 hfreq_max; + uint32 hfreq_min; } crt_info; -#define HEAD_MODE_A_ANALOG 0x01 -#define HEAD_MODE_B_DIGITAL 0x02 -#define HEAD_MODE_CLONE 0x03 -#define HEAD_MODE_LVDS_PANEL 0x08 +// crt_info connection_type +#define CONNECTION_DAC 0x0001 +#define CONNECTION_TMDS 0x0002 +#define CONNECTION_LVDS 0x0003 // register MMIO modes #define OUT 0x1 // direct MMIO calls @@ -109,11 +110,7 @@ typedef struct { extern accelerant_info *gInfo; -extern register_info *gRegister; -extern crt_info *gCRT[MAX_CRT]; - - -status_t init_registers(uint8 crtid); +extern crt_info *gDisplay[MAX_DISPLAY]; // register access diff --git a/src/add-ons/accelerants/radeon_hd/display.cpp b/src/add-ons/accelerants/radeon_hd/display.cpp new file mode 100644 index 0000000000..3060b99754 --- /dev/null +++ b/src/add-ons/accelerants/radeon_hd/display.cpp @@ -0,0 +1,261 @@ +/* + * Copyright 2006-2011, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Alexander von Gluck, kallisti5@unixzen.com + */ + + +#include "accelerant_protos.h" +#include "accelerant.h" +#include "display.h" + +#include +#include + + +#define TRACE_DISPLAY +#ifdef TRACE_DISPLAY +extern "C" void _sPrintf(const char *format, ...); +# define TRACE(x...) _sPrintf("radeon_hd: " x) +#else +# define TRACE(x...) ; +#endif + + +/*! Populate regs with device dependant register locations */ +status_t +init_registers(register_info* regs, uint8 crtid) +{ + memset(regs, 0, sizeof(register_info)); + + radeon_shared_info &info = *gInfo->shared_info; + + if (info.device_chipset >= RADEON_R800) { + uint32 offset = 0; + + // AMD Eyefinity on Evergreen GPUs + if (crtid == 1) { + offset = EVERGREEN_CRTC1_REGISTER_OFFSET; + regs->vgaControl = D2VGA_CONTROL; + } else if (crtid == 2) { + offset = EVERGREEN_CRTC2_REGISTER_OFFSET; + regs->vgaControl = EVERGREEN_D3VGA_CONTROL; + } else if (crtid == 3) { + offset = EVERGREEN_CRTC3_REGISTER_OFFSET; + regs->vgaControl = EVERGREEN_D4VGA_CONTROL; + } else if (crtid == 4) { + offset = EVERGREEN_CRTC4_REGISTER_OFFSET; + regs->vgaControl = EVERGREEN_D5VGA_CONTROL; + } else if (crtid == 5) { + offset = EVERGREEN_CRTC5_REGISTER_OFFSET; + regs->vgaControl = EVERGREEN_D6VGA_CONTROL; + } else { + offset = EVERGREEN_CRTC0_REGISTER_OFFSET; + regs->vgaControl = D1VGA_CONTROL; + } + + // Evergreen+ is crtoffset + register + regs->grphEnable = offset + EVERGREEN_GRPH_ENABLE; + regs->grphControl = offset + EVERGREEN_GRPH_CONTROL; + regs->grphSwapControl = offset + EVERGREEN_GRPH_SWAP_CONTROL; + regs->grphPrimarySurfaceAddr + = offset + EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS; + regs->grphSecondarySurfaceAddr + = offset + EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS; + + regs->grphPrimarySurfaceAddrHigh + = offset + EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH; + regs->grphSecondarySurfaceAddrHigh + = offset + EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH; + + regs->grphPitch = offset + EVERGREEN_GRPH_PITCH; + regs->grphSurfaceOffsetX + = offset + EVERGREEN_GRPH_SURFACE_OFFSET_X; + regs->grphSurfaceOffsetY + = offset + EVERGREEN_GRPH_SURFACE_OFFSET_Y; + regs->grphXStart = offset + EVERGREEN_GRPH_X_START; + regs->grphYStart = offset + EVERGREEN_GRPH_Y_START; + regs->grphXEnd = offset + EVERGREEN_GRPH_X_END; + regs->grphYEnd = offset + EVERGREEN_GRPH_Y_END; + regs->crtControl = offset + EVERGREEN_CRTC_CONTROL; + regs->modeDesktopHeight = offset + EVERGREEN_DESKTOP_HEIGHT; + regs->modeDataFormat = offset + EVERGREEN_DATA_FORMAT; + regs->viewportStart = offset + EVERGREEN_VIEWPORT_START; + regs->viewportSize = offset + EVERGREEN_VIEWPORT_SIZE; + + } else if (info.device_chipset >= RADEON_R600 + && info.device_chipset < RADEON_R800) { + + // r600 - r700 are D1 or D2 based on primary / secondary crt + regs->vgaControl + = crtid == 1 ? D2VGA_CONTROL : D1VGA_CONTROL; + regs->grphEnable + = crtid == 1 ? D2GRPH_ENABLE : D1GRPH_ENABLE; + regs->grphControl + = crtid == 1 ? D2GRPH_CONTROL : D1GRPH_CONTROL; + regs->grphSwapControl + = crtid == 1 ? D2GRPH_SWAP_CNTL : D1GRPH_SWAP_CNTL; + regs->grphPrimarySurfaceAddr + = crtid == 1 ? D2GRPH_PRIMARY_SURFACE_ADDRESS + : D1GRPH_PRIMARY_SURFACE_ADDRESS; + regs->grphSecondarySurfaceAddr + = crtid == 1 ? D2GRPH_SECONDARY_SURFACE_ADDRESS + : D1GRPH_SECONDARY_SURFACE_ADDRESS; + + // Surface Address high only used on r770+ + regs->grphPrimarySurfaceAddrHigh + = crtid == 1 ? R700_D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + : R700_D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH; + regs->grphSecondarySurfaceAddrHigh + = crtid == 1 ? R700_D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + : R700_D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH; + + regs->grphPitch + = crtid == 1 ? D2GRPH_PITCH : D1GRPH_PITCH; + regs->grphSurfaceOffsetX + = crtid == 1 ? D2GRPH_SURFACE_OFFSET_X : D1GRPH_SURFACE_OFFSET_X; + regs->grphSurfaceOffsetY + = crtid == 1 ? D2GRPH_SURFACE_OFFSET_Y : D1GRPH_SURFACE_OFFSET_Y; + regs->grphXStart + = crtid == 1 ? D2GRPH_X_START : D1GRPH_X_START; + regs->grphYStart + = crtid == 1 ? D2GRPH_Y_START : D1GRPH_Y_START; + regs->grphXEnd + = crtid == 1 ? D2GRPH_X_END : D1GRPH_X_END; + regs->grphYEnd + = crtid == 1 ? D2GRPH_Y_END : D1GRPH_Y_END; + regs->crtControl + = crtid == 1 ? D2CRTC_CONTROL : D1CRTC_CONTROL; + regs->modeDesktopHeight + = crtid == 1 ? D2MODE_DESKTOP_HEIGHT : D1MODE_DESKTOP_HEIGHT; + regs->modeDataFormat + = crtid == 1 ? D2MODE_DATA_FORMAT : D1MODE_DATA_FORMAT; + regs->viewportStart + = crtid == 1 ? D2MODE_VIEWPORT_START : D1MODE_VIEWPORT_START; + regs->viewportSize + = crtid == 1 ? D2MODE_VIEWPORT_SIZE : D1MODE_VIEWPORT_SIZE; + } else { + // this really shouldn't happen unless a driver PCIID chipset is wrong + TRACE("%s, unknown Radeon chipset: r%X\n", __func__, + info.device_chipset); + return B_ERROR; + } + + // Populate common registers + // TODO : Wait.. this doesn't work with Eyefinity > crt 1. + + regs->modeCenter + = crtid == 1 ? D2MODE_CENTER : D1MODE_CENTER; + regs->grphUpdate + = crtid == 1 ? D2GRPH_UPDATE : D1GRPH_UPDATE; + regs->crtHPolarity + = crtid == 1 ? D2CRTC_H_SYNC_A_CNTL : D1CRTC_H_SYNC_A_CNTL; + regs->crtVPolarity + = crtid == 1 ? D2CRTC_V_SYNC_A_CNTL : D1CRTC_V_SYNC_A_CNTL; + regs->crtHTotal + = crtid == 1 ? D2CRTC_H_TOTAL : D1CRTC_H_TOTAL; + regs->crtVTotal + = crtid == 1 ? D2CRTC_V_TOTAL : D1CRTC_V_TOTAL; + regs->crtHSync + = crtid == 1 ? D2CRTC_H_SYNC_A : D1CRTC_H_SYNC_A; + regs->crtVSync + = crtid == 1 ? D2CRTC_V_SYNC_A : D1CRTC_V_SYNC_A; + regs->crtHBlank + = crtid == 1 ? D2CRTC_H_BLANK_START_END : D1CRTC_H_BLANK_START_END; + regs->crtVBlank + = crtid == 1 ? D2CRTC_V_BLANK_START_END : D1CRTC_V_BLANK_START_END; + regs->crtInterlace + = crtid == 1 ? D2CRTC_INTERLACE_CONTROL : D1CRTC_INTERLACE_CONTROL; + regs->crtCountControl + = crtid == 1 ? D2CRTC_COUNT_CONTROL : D1CRTC_COUNT_CONTROL; + regs->sclUpdate + = crtid == 1 ? D2SCL_UPDATE : D1SCL_UPDATE; + regs->sclEnable + = crtid == 1 ? D2SCL_ENABLE : D1SCL_ENABLE; + regs->sclTapControl + = crtid == 1 ? D2SCL_TAP_CONTROL : D1SCL_TAP_CONTROL; + + TRACE("%s, registers for ATI chipset r%X crt #%d loaded\n", __func__, + info.device_chipset, crtid); + + return B_OK; +} + + +status_t +detect_crt_ranges(uint32 crtid) +{ + edid1_info *edid = &gInfo->shared_info->edid_info; + + // TODO : VESA edid is just for primary monitor + + // EDID spec states 4 descriptor blocks + for (uint32 index = 0; index < EDID1_NUM_DETAILED_MONITOR_DESC; index++) { + + edid1_detailed_monitor *monitor + = &edid->detailed_monitor[index]; + + if (monitor->monitor_desc_type + == EDID1_MONITOR_RANGES) { + edid1_monitor_range range = monitor->data.monitor_range; + gDisplay[crtid]->vfreq_min = range.min_v; /* in Hz */ + gDisplay[crtid]->vfreq_max = range.max_v; + gDisplay[crtid]->hfreq_min = range.min_h; /* in kHz */ + gDisplay[crtid]->hfreq_max = range.max_h; + TRACE("CRT %d : v_min %d : v_max %d : h_min %d : h_max %d\n", + crtid, gDisplay[crtid]->vfreq_min, gDisplay[crtid]->vfreq_max, + gDisplay[crtid]->hfreq_min, gDisplay[crtid]->hfreq_max); + return B_OK; + } + + } + + return B_ERROR; +} + + +status_t +detect_displays() +{ + // reset known displays + for (uint32 id = 0; id < MAX_DISPLAY; id++) + gDisplay[id]->active = false; + + uint32 index = 0; + + // Probe for DAC monitors connected + for (uint32 id = 0; id < 2; id++) { + if (DACSense(id)) { + gDisplay[index]->active = true; + gDisplay[index]->connection_type = CONNECTION_DAC; + gDisplay[index]->connection_id = id; + init_registers(gDisplay[index]->regs, index); + detect_crt_ranges(index); + if (index < MAX_DISPLAY) + index++; + else + return B_OK; + } + } + + // Probe for TMDS monitors connected + for (uint32 id = 0; id < 1; id++) { + if (TMDSSense(id)) { + gDisplay[index]->active = true; + gDisplay[index]->connection_type = CONNECTION_TMDS; + gDisplay[index]->connection_id = id; + init_registers(gDisplay[index]->regs, index); + detect_crt_ranges(index); + if (index < MAX_DISPLAY) + index++; + else + return B_OK; + } + } + + return B_OK; +} + + diff --git a/src/add-ons/accelerants/radeon_hd/display.h b/src/add-ons/accelerants/radeon_hd/display.h new file mode 100644 index 0000000000..7a916732dd --- /dev/null +++ b/src/add-ons/accelerants/radeon_hd/display.h @@ -0,0 +1,17 @@ +/* + * Copyright 2006-2011, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Alexander von Gluck, kallisti5@unixzen.com + */ +#ifndef RADEON_HD_DISPLAY_H +#define RADEON_HD_DISPLAY_H + + +status_t init_registers(register_info* reg, uint8 crtid); +status_t detect_crt_ranges(uint32 crtid); +status_t detect_displays(); + + +#endif /* RADEON_HD_DISPLAY_H */ diff --git a/src/add-ons/accelerants/radeon_hd/mode.cpp b/src/add-ons/accelerants/radeon_hd/mode.cpp index 0adfdd9934..da6ad0d6a8 100644 --- a/src/add-ons/accelerants/radeon_hd/mode.cpp +++ b/src/add-ons/accelerants/radeon_hd/mode.cpp @@ -38,8 +38,6 @@ create_mode_list(void) const color_space kRadeonHDSpaces[] = {B_RGB32_LITTLE, B_RGB24_LITTLE, B_RGB16_LITTLE, B_RGB15_LITTLE, B_CMAP8}; - detect_crt_ranges(); - gInfo->mode_list_area = create_display_modes("radeon HD modes", gInfo->shared_info->has_edid ? &gInfo->shared_info->edid_info : NULL, NULL, 0, kRadeonHDSpaces, @@ -141,14 +139,17 @@ CardBlankSet(uint8 crtid, bool blank) static void -CardFBSet(display_mode *mode) +CardFBSet(uint8 crtid, display_mode *mode) { + register_info* regs = gDisplay[crtid]->regs; + uint32 colorMode; uint32 bytesPerRow; uint32 bitsPerPixel; get_color_space_format(*mode, colorMode, bytesPerRow, bitsPerPixel); + #if 0 // TMDSAllIdle // DVI / HDMI // LVTMAAllIdle // DVI @@ -160,68 +161,68 @@ CardFBSet(display_mode *mode) MCFBSetup(Read32(OUT, R6XX_CONFIG_FB_BASE), mcFbSize); #endif - Write32(CRT, gRegister->grphUpdate, (1<<16)); + Write32(CRT, regs->grphUpdate, (1<<16)); // Lock for update (isn't this normally the other way around on VGA? // framebuffersize = w * h * bpp = fb bits / 8 = bytes needed uint64_t fbAddress = gInfo->shared_info->frame_buffer_phys; // Tell GPU which frame buffer address to draw from - Write32(CRT, gRegister->grphPrimarySurfaceAddr, + Write32(CRT, regs->grphPrimarySurfaceAddr, fbAddress & 0xffffffff); - Write32(CRT, gRegister->grphSecondarySurfaceAddr, + Write32(CRT, regs->grphSecondarySurfaceAddr, fbAddress & 0xffffffff); if (gInfo->shared_info->device_chipset >= (RADEON_R700 | 0x70)) { - Write32(CRT, gRegister->grphPrimarySurfaceAddrHigh, + Write32(CRT, regs->grphPrimarySurfaceAddrHigh, (fbAddress >> 32) & 0xf); - Write32(CRT, gRegister->grphSecondarySurfaceAddrHigh, + Write32(CRT, regs->grphSecondarySurfaceAddrHigh, (fbAddress >> 32) & 0xf); } - Write32(CRT, gRegister->grphControl, 0); + Write32(CRT, regs->grphControl, 0); // Reset stored depth, format, etc // set color mode on video card switch (mode->space) { case B_CMAP8: - Write32Mask(CRT, gRegister->grphControl, + Write32Mask(CRT, regs->grphControl, 0, 0x00000703); break; case B_RGB15_LITTLE: - Write32Mask(CRT, gRegister->grphControl, + Write32Mask(CRT, regs->grphControl, 0x000001, 0x00000703); break; case B_RGB16_LITTLE: - Write32Mask(CRT, gRegister->grphControl, + Write32Mask(CRT, regs->grphControl, 0x000101, 0x00000703); break; case B_RGB24_LITTLE: case B_RGB32_LITTLE: default: - Write32Mask(CRT, gRegister->grphControl, + Write32Mask(CRT, regs->grphControl, 0x000002, 0x00000703); break; } - Write32(CRT, gRegister->grphSwapControl, 0); + Write32(CRT, regs->grphSwapControl, 0); // only for chipsets > r600 // R5xx - RS690 case is GRPH_CONTROL bit 16 - Write32Mask(CRT, gRegister->grphEnable, 1, 0x00000001); + Write32Mask(CRT, regs->grphEnable, 1, 0x00000001); // Enable graphics - Write32(CRT, gRegister->grphSurfaceOffsetX, 0); - Write32(CRT, gRegister->grphSurfaceOffsetY, 0); - Write32(CRT, gRegister->grphXStart, 0); - Write32(CRT, gRegister->grphYStart, 0); - Write32(CRT, gRegister->grphXEnd, mode->virtual_width); - Write32(CRT, gRegister->grphYEnd, mode->virtual_height); - Write32(CRT, gRegister->grphPitch, bytesPerRow / 4); + Write32(CRT, regs->grphSurfaceOffsetX, 0); + Write32(CRT, regs->grphSurfaceOffsetY, 0); + Write32(CRT, regs->grphXStart, 0); + Write32(CRT, regs->grphYStart, 0); + Write32(CRT, regs->grphXEnd, mode->virtual_width); + Write32(CRT, regs->grphYEnd, mode->virtual_height); + Write32(CRT, regs->grphPitch, bytesPerRow / 4); - Write32(CRT, gRegister->modeDesktopHeight, mode->virtual_height); + Write32(CRT, regs->modeDesktopHeight, mode->virtual_height); - Write32(CRT, gRegister->grphUpdate, 0); + Write32(CRT, regs->grphUpdate, 0); // Unlock changed registers // update shared info @@ -232,18 +233,19 @@ CardFBSet(display_mode *mode) static void -CardModeSet(display_mode *mode) +CardModeSet(uint8 crtid, display_mode *mode) { display_timing& displayTiming = mode->timing; + register_info* regs = gDisplay[crtid]->regs; TRACE("%s called to do %dx%d\n", __func__, displayTiming.h_display, displayTiming.v_display); // enable read requests - Write32Mask(CRT, gRegister->grphControl, 0, 0x01000000); + Write32Mask(CRT, regs->grphControl, 0, 0x01000000); // *** Horizontal - Write32(CRT, gRegister->crtHTotal, + Write32(CRT, regs->crtHTotal, displayTiming.h_total - 1); // Blanking @@ -251,55 +253,57 @@ CardModeSet(display_mode *mode) + displayTiming.h_display - displayTiming.h_sync_start; uint16 blankEnd = displayTiming.h_total - displayTiming.h_sync_start; - Write32(CRT, gRegister->crtHBlank, + Write32(CRT, regs->crtHBlank, blankStart | (blankEnd << 16)); - Write32(CRT, gRegister->crtHSync, + Write32(CRT, regs->crtHSync, (displayTiming.h_sync_end - displayTiming.h_sync_start) << 16); // set flag for neg. H sync. M76 Register Reference Guide 2-256 - Write32Mask(CRT, gRegister->crtHPolarity, + Write32Mask(CRT, regs->crtHPolarity, displayTiming.flags & B_POSITIVE_HSYNC ? 0 : 1, 0x1); // *** Vertical - Write32(CRT, gRegister->crtVTotal, + Write32(CRT, regs->crtVTotal, displayTiming.v_total - 1); blankStart = displayTiming.v_total + displayTiming.v_display - displayTiming.v_sync_start; blankEnd = displayTiming.v_total - displayTiming.v_sync_start; - Write32(CRT, gRegister->crtVBlank, + Write32(CRT, regs->crtVBlank, blankStart | (blankEnd << 16)); // Set Interlace if specified within mode line if (displayTiming.flags & B_TIMING_INTERLACED) { - Write32(CRT, gRegister->crtInterlace, 0x1); - Write32(CRT, gRegister->modeDataFormat, 0x1); + Write32(CRT, regs->crtInterlace, 0x1); + Write32(CRT, regs->modeDataFormat, 0x1); } else { - Write32(CRT, gRegister->crtInterlace, 0x0); - Write32(CRT, gRegister->modeDataFormat, 0x0); + Write32(CRT, regs->crtInterlace, 0x0); + Write32(CRT, regs->modeDataFormat, 0x0); } - Write32(CRT, gRegister->crtVSync, + Write32(CRT, regs->crtVSync, (displayTiming.v_sync_end - displayTiming.v_sync_start) << 16); // set flag for neg. V sync. M76 Register Reference Guide 2-258 - Write32Mask(CRT, gRegister->crtVPolarity, + Write32Mask(CRT, regs->crtVPolarity, displayTiming.flags & B_POSITIVE_VSYNC ? 0 : 1, 0x1); /* set D1CRTC_HORZ_COUNT_BY2_EN to 0; should only be set to 1 on 30bpp DVI modes */ - Write32Mask(CRT, gRegister->crtCountControl, 0x0, 0x1); + Write32Mask(CRT, regs->crtCountControl, 0x0, 0x1); } static void -CardModeScale(display_mode *mode) +CardModeScale(uint8 crtid, display_mode *mode) { + register_info* regs = gDisplay[crtid]->regs; + // No scaling - Write32(CRT, gRegister->sclUpdate, (1<<16));// Lock + Write32(CRT, regs->sclUpdate, (1<<16));// Lock #if 0 Write32(CRT, D1MODE_EXT_OVERSCAN_LEFT_RIGHT, @@ -308,52 +312,40 @@ CardModeScale(display_mode *mode) (OVERSCAN << 16) | OVERSCAN); // TOP | BOTTOM #endif - Write32(CRT, gRegister->viewportStart, 0); - Write32(CRT, gRegister->viewportSize, + Write32(CRT, regs->viewportStart, 0); + Write32(CRT, regs->viewportSize, mode->timing.v_display | (mode->timing.h_display << 16)); - Write32(CRT, gRegister->sclEnable, 0); - Write32(CRT, gRegister->sclTapControl, 0); - Write32(CRT, gRegister->modeCenter, 2); + Write32(CRT, regs->sclEnable, 0); + Write32(CRT, regs->sclTapControl, 0); + Write32(CRT, regs->modeCenter, 2); // D1MODE_DATA_FORMAT? - Write32(CRT, gRegister->sclUpdate, 0); // Unlock + Write32(CRT, regs->sclUpdate, 0); // Unlock } status_t radeon_set_display_mode(display_mode *mode) { - uint8 crtNumber = 0; - uint8 dacNumber = 0; + uint8 display_id = 0; - init_registers(crtNumber); + CardFBSet(display_id, mode); + CardModeSet(display_id, mode); + CardModeScale(display_id, mode); - // TODO Populate gCRT with interface connection - if (DACSense(0)) - dacNumber = 0; - else if (DACSense(1)) - dacNumber = 1; + // If this is DAC, set our PLL + if ((gDisplay[display_id]->connection_type & CONNECTION_DAC) != 0) { + PLLSet(gDisplay[display_id]->connection_id, mode->timing.pixel_clock); + DACSet(gDisplay[display_id]->connection_id, display_id); - TMDSSense(0); // DVI / HDMI + // TODO : Shutdown unused PLL/DAC - CardFBSet(mode); - CardModeSet(mode); - CardModeScale(mode); - - PLLSet(dacNumber, mode->timing.pixel_clock); - // Set pixel clock - - Write32(CRT, D1GRPH_LUT_SEL, 0); - - DACSet(dacNumber, crtNumber); - - // TODO : Shutdown unused PLL/DAC - - // Power up the output - PLLPower(dacNumber, RHD_POWER_ON); - DACPower(dacNumber, RHD_POWER_ON); + // Power up the output + PLLPower(gDisplay[display_id]->connection_id, RHD_POWER_ON); + DACPower(gDisplay[display_id]->connection_id, RHD_POWER_ON); + } // Ensure screen isn't blanked - CardBlankSet(crtNumber, false); + CardBlankSet(display_id, false); int32 crtstatus = Read32(CRT, D1CRTC_STATUS); TRACE("CRT0 Status: 0x%X\n", crtstatus); @@ -430,16 +422,17 @@ is_mode_supported(display_mode *mode) if (is_mode_sane(mode) != B_OK) return false; + // TODO : is_mode_supported on *which* display? uint32 crtid = 0; // if we have edid info, check frequency adginst crt reported valid ranges if (gInfo->shared_info->has_edid) { uint32 hfreq = mode->timing.pixel_clock / mode->timing.h_total; - if (hfreq > gCRT[crtid]->hfreq_max + 1 - || hfreq < gCRT[crtid]->hfreq_min - 1) { + if (hfreq > gDisplay[crtid]->hfreq_max + 1 + || hfreq < gDisplay[crtid]->hfreq_min - 1) { TRACE("!!! hfreq : %d , hfreq_min : %d, hfreq_max : %d\n", - hfreq, gCRT[crtid]->hfreq_min, gCRT[crtid]->hfreq_max); + hfreq, gDisplay[crtid]->hfreq_min, gDisplay[crtid]->hfreq_max); TRACE("!!! %dx%d falls outside of CRT %d's valid " "horizontal range.\n", mode->timing.h_display, mode->timing.v_display, crtid); @@ -449,10 +442,10 @@ is_mode_supported(display_mode *mode) uint32 vfreq = mode->timing.pixel_clock / ((mode->timing.v_total * mode->timing.h_total) / 1000); - if (vfreq > gCRT[crtid]->vfreq_max + 1 - || vfreq < gCRT[crtid]->vfreq_min - 1) { + if (vfreq > gDisplay[crtid]->vfreq_max + 1 + || vfreq < gDisplay[crtid]->vfreq_min - 1) { TRACE("!!! vfreq : %d , vfreq_min : %d, vfreq_max : %d\n", - vfreq, gCRT[crtid]->vfreq_min, gCRT[crtid]->vfreq_max); + vfreq, gDisplay[crtid]->vfreq_min, gDisplay[crtid]->vfreq_max); TRACE("!!! %dx%d falls outside of CRT %d's valid vertical range\n", mode->timing.h_display, mode->timing.v_display, crtid); return false; @@ -518,33 +511,3 @@ is_mode_sane(display_mode *mode) } -// TODO : Move to a new "monitors.c" file -status_t -detect_crt_ranges() -{ - edid1_info *edid = &gInfo->shared_info->edid_info; - - int crtid = 0; - // edid indexes are not in order - - for (uint32 index = 0; index < MAX_CRT; index++) { - - edid1_detailed_monitor *monitor - = &edid->detailed_monitor[index]; - - if (monitor->monitor_desc_type - == EDID1_MONITOR_RANGES) { - edid1_monitor_range range = monitor->data.monitor_range; - gCRT[crtid]->vfreq_min = range.min_v; /* in Hz */ - gCRT[crtid]->vfreq_max = range.max_v; - gCRT[crtid]->hfreq_min = range.min_h; /* in kHz */ - gCRT[crtid]->hfreq_max = range.max_h; - TRACE("CRT %d : v_min %d : v_max %d : h_min %d : h_max %d\n", - crtid, gCRT[crtid]->vfreq_min, gCRT[crtid]->vfreq_max, - gCRT[crtid]->hfreq_min, gCRT[crtid]->hfreq_max); - crtid++; - } - - } - return B_OK; -} diff --git a/src/add-ons/accelerants/radeon_hd/mode.h b/src/add-ons/accelerants/radeon_hd/mode.h index 1ab7165cc4..0b51cd93e2 100644 --- a/src/add-ons/accelerants/radeon_hd/mode.h +++ b/src/add-ons/accelerants/radeon_hd/mode.h @@ -25,7 +25,7 @@ #define OVERSCAN 0 // TODO : Overscan and scaling support -status_t detect_crt_ranges(); + status_t create_mode_list(void); bool is_mode_supported(display_mode* mode); status_t is_mode_sane(display_mode *mode); diff --git a/src/add-ons/accelerants/radeon_hd/pll.cpp b/src/add-ons/accelerants/radeon_hd/pll.cpp index df55939d47..9e08b40e47 100644 --- a/src/add-ons/accelerants/radeon_hd/pll.cpp +++ b/src/add-ons/accelerants/radeon_hd/pll.cpp @@ -345,8 +345,8 @@ PLLSetLowLegacy(uint8 pllIndex, uint32 pixelClock, uint16 reference, Write32(PLL, pllExtPostDivSrc, 0x01); // Set source as PLL - // TODO : better way to grab crt to work on? - PLLCRTCGrab(pllIndex, gRegister->crtid); + // TODO : for now we assume crt 0, needs refactoring + PLLCRTCGrab(pllIndex, 0); } @@ -461,8 +461,8 @@ PLLSetLowR620(uint8 pllIndex, uint32 pixelClock, uint16 reference, Write32Mask(PLL, pllCntl, 0, 0x80000000); // needed and undocumented - // TODO : better way to grab crt to work on? - PLLCRTCGrab(pllIndex, gRegister->crtid); + // TODO : for now we assume crt 0, needs refactoring + PLLCRTCGrab(pllIndex, 0); if (hasDccg) DCCGCLKSet(pllIndex, RV620_DCCGCLK_GRAB);