📄 radeon_dri.c
字号:
/** * \file server/radeon_dri.c * \brief File to perform the device-specific initialization tasks typically * done in the X server. * * Here they are converted to run in the client (or perhaps a standalone * process), and to work with the frame buffer device rather than the X * server infrastructure. */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <errno.h>#include <unistd.h>#include "driver.h"#include "drm.h"#include "memops.h"#include "radeon.h"#include "radeon_dri.h"#include "radeon_macros.h"#include "radeon_reg.h"#include "drm_sarea.h"static size_t radeon_drm_page_size;static int RadeonSetParam(const DRIDriverContext *ctx, int param, int value){ drm_radeon_setparam_t sp; memset(&sp, 0, sizeof(sp)); sp.param = param; sp.value = value; if (drmCommandWrite(ctx->drmFD, DRM_RADEON_SETPARAM, &sp, sizeof(sp))) { return -1; } return 0;}/** * \brief Wait for free FIFO entries. * * \param ctx display handle. * \param entries number of free entries to wait. * * It polls the free entries from the chip until it reaches the requested value * or a timeout (3000 tries) occurs. Aborts the program if the FIFO times out. */static void RADEONWaitForFifo( const DRIDriverContext *ctx, int entries ){ unsigned char *RADEONMMIO = ctx->MMIOAddress; int i; for (i = 0; i < 3000; i++) { int fifo_slots = INREG(RADEON_RBBM_STATUS) & RADEON_RBBM_FIFOCNT_MASK; if (fifo_slots >= entries) return; } /* There are recoveries possible, but I haven't seen them work * in practice: */ fprintf(stderr, "FIFO timed out: %d entries, stat=0x%08x\n", INREG(RADEON_RBBM_STATUS) & RADEON_RBBM_FIFOCNT_MASK, INREG(RADEON_RBBM_STATUS)); exit(1);}/** * \brief Read a PLL register. * * \param ctx display handle. * \param addr PLL register index. * * \return value of the PLL register. */static unsigned int RADEONINPLL( const DRIDriverContext *ctx, int addr){ unsigned char *RADEONMMIO = ctx->MMIOAddress; unsigned int data; OUTREG8(RADEON_CLOCK_CNTL_INDEX, addr & 0x3f); data = INREG(RADEON_CLOCK_CNTL_DATA); return data;}/** * \brief Reset graphics card to known state. * * \param ctx display handle. * * Resets the values of several Radeon registers. */static void RADEONEngineReset( const DRIDriverContext *ctx ){ unsigned char *RADEONMMIO = ctx->MMIOAddress; unsigned int clock_cntl_index; unsigned int mclk_cntl; unsigned int rbbm_soft_reset; unsigned int host_path_cntl; int i; OUTREGP(RADEON_RB2D_DSTCACHE_CTLSTAT, RADEON_RB2D_DC_FLUSH_ALL, ~RADEON_RB2D_DC_FLUSH_ALL); for (i = 0; i < 512; i++) { if (!(INREG(RADEON_RB2D_DSTCACHE_CTLSTAT) & RADEON_RB2D_DC_BUSY)) break; } clock_cntl_index = INREG(RADEON_CLOCK_CNTL_INDEX); mclk_cntl = INPLL(ctx, RADEON_MCLK_CNTL); OUTPLL(RADEON_MCLK_CNTL, (mclk_cntl | RADEON_FORCEON_MCLKA | RADEON_FORCEON_MCLKB | RADEON_FORCEON_YCLKA | RADEON_FORCEON_YCLKB | RADEON_FORCEON_MC | RADEON_FORCEON_AIC)); /* Soft resetting HDP thru RBBM_SOFT_RESET register can cause some * unexpected behaviour on some machines. Here we use * RADEON_HOST_PATH_CNTL to reset it. */ host_path_cntl = INREG(RADEON_HOST_PATH_CNTL); rbbm_soft_reset = INREG(RADEON_RBBM_SOFT_RESET); OUTREG(RADEON_RBBM_SOFT_RESET, (rbbm_soft_reset | RADEON_SOFT_RESET_CP | RADEON_SOFT_RESET_HI | RADEON_SOFT_RESET_SE | RADEON_SOFT_RESET_RE | RADEON_SOFT_RESET_PP | RADEON_SOFT_RESET_E2 | RADEON_SOFT_RESET_RB)); INREG(RADEON_RBBM_SOFT_RESET); OUTREG(RADEON_RBBM_SOFT_RESET, (rbbm_soft_reset & (unsigned int) ~(RADEON_SOFT_RESET_CP | RADEON_SOFT_RESET_HI | RADEON_SOFT_RESET_SE | RADEON_SOFT_RESET_RE | RADEON_SOFT_RESET_PP | RADEON_SOFT_RESET_E2 | RADEON_SOFT_RESET_RB))); INREG(RADEON_RBBM_SOFT_RESET); OUTREG(RADEON_HOST_PATH_CNTL, host_path_cntl | RADEON_HDP_SOFT_RESET); INREG(RADEON_HOST_PATH_CNTL); OUTREG(RADEON_HOST_PATH_CNTL, host_path_cntl); OUTREG(RADEON_RBBM_SOFT_RESET, rbbm_soft_reset); OUTREG(RADEON_CLOCK_CNTL_INDEX, clock_cntl_index); OUTPLL(RADEON_MCLK_CNTL, mclk_cntl);}/** * \brief Restore the drawing engine. * * \param ctx display handle * * Resets the graphics card and sets initial values for several registers of * the card's drawing engine. * * Turns on the radeon command processor engine (i.e., the ringbuffer). */static int RADEONEngineRestore( const DRIDriverContext *ctx ){ RADEONInfoPtr info = ctx->driverPrivate; unsigned char *RADEONMMIO = ctx->MMIOAddress; int pitch64, datatype, dp_gui_master_cntl, err; fprintf(stderr, "%s\n", __FUNCTION__); OUTREG(RADEON_RB3D_CNTL, 0); RADEONEngineReset( ctx ); switch (ctx->bpp) { case 16: datatype = 4; break; case 32: datatype = 6; break; default: return 0; } dp_gui_master_cntl = ((datatype << RADEON_GMC_DST_DATATYPE_SHIFT) | RADEON_GMC_CLR_CMP_CNTL_DIS); pitch64 = ((ctx->shared.virtualWidth * (ctx->bpp / 8) + 0x3f)) >> 6; RADEONWaitForFifo(ctx, 1); OUTREG(RADEON_DEFAULT_OFFSET, ((INREG(RADEON_DEFAULT_OFFSET) & 0xC0000000) | (pitch64 << 22))); RADEONWaitForFifo(ctx, 1); OUTREG(RADEON_SURFACE_CNTL, RADEON_SURF_TRANSLATION_DIS); RADEONWaitForFifo(ctx, 1); OUTREG(RADEON_DEFAULT_SC_BOTTOM_RIGHT, (RADEON_DEFAULT_SC_RIGHT_MAX | RADEON_DEFAULT_SC_BOTTOM_MAX)); RADEONWaitForFifo(ctx, 1); OUTREG(RADEON_DP_GUI_MASTER_CNTL, (dp_gui_master_cntl | RADEON_GMC_BRUSH_SOLID_COLOR | RADEON_GMC_SRC_DATATYPE_COLOR)); RADEONWaitForFifo(ctx, 7); OUTREG(RADEON_DST_LINE_START, 0); OUTREG(RADEON_DST_LINE_END, 0); OUTREG(RADEON_DP_BRUSH_FRGD_CLR, 0xffffffff); OUTREG(RADEON_DP_BRUSH_BKGD_CLR, 0); OUTREG(RADEON_DP_SRC_FRGD_CLR, 0xffffffff); OUTREG(RADEON_DP_SRC_BKGD_CLR, 0); OUTREG(RADEON_DP_WRITE_MASK, 0xffffffff); OUTREG(RADEON_AUX_SC_CNTL, 0);/* RADEONWaitForIdleMMIO(ctx); */ usleep(100); OUTREG(RADEON_GEN_INT_CNTL, info->gen_int_cntl); if (info->colorTiling) info->crtc_offset_cntl |= RADEON_CRTC_TILE_EN; OUTREG(RADEON_CRTC_OFFSET_CNTL, info->crtc_offset_cntl); /* Initialize and start the CP if required */ if ((err = drmCommandNone(ctx->drmFD, DRM_RADEON_CP_START)) != 0) { fprintf(stderr, "%s: CP start %d\n", __FUNCTION__, err); return 0; } return 1;}/** * \brief Shutdown the drawing engine. * * \param ctx display handle * * Turns off the command processor engine & restores the graphics card * to a state that fbdev understands. */static int RADEONEngineShutdown( const DRIDriverContext *ctx ){ drm_radeon_cp_stop_t stop; int ret, i; stop.flush = 1; stop.idle = 1; ret = drmCommandWrite(ctx->drmFD, DRM_RADEON_CP_STOP, &stop, sizeof(drm_radeon_cp_stop_t)); if (ret == 0) { return 0; } else if (errno != EBUSY) { return -errno; } stop.flush = 0; i = 0; do { ret = drmCommandWrite(ctx->drmFD, DRM_RADEON_CP_STOP, &stop, sizeof(drm_radeon_cp_stop_t)); } while (ret && errno == EBUSY && i++ < 10); if (ret == 0) { return 0; } else if (errno != EBUSY) { return -errno; } stop.idle = 0; if (drmCommandWrite(ctx->drmFD, DRM_RADEON_CP_STOP, &stop, sizeof(drm_radeon_cp_stop_t))) { return -errno; } else { return 0; }}/** * \brief Compute base 2 logarithm. * * \param val value. * * \return base 2 logarithm of \p val. */static int RADEONMinBits(int val){ int bits; if (!val) return 1; for (bits = 0; val; val >>= 1, ++bits); return bits;}/** * \brief Initialize the AGP state * * \param ctx display handle. * \param info driver private data. * * \return one on success, or zero on failure. * * Acquires and enables the AGP device. Reserves memory in the AGP space for * the ring buffer, vertex buffers and textures. Initialize the Radeon * registers to point to that memory and add client mappings. */static int RADEONDRIAgpInit( const DRIDriverContext *ctx, RADEONInfoPtr info){ unsigned char *RADEONMMIO = ctx->MMIOAddress; unsigned long mode; int ret; int s, l; if (drmAgpAcquire(ctx->drmFD) < 0) { fprintf(stderr, "[gart] AGP not available\n"); return 0; } /* Modify the mode if the default mode is not appropriate for this * particular combination of graphics card and AGP chipset. */ mode = drmAgpGetMode(ctx->drmFD); /* Default mode */ /* Disable fast write entirely - too many lockups. */ mode &= ~RADEON_AGP_MODE_MASK; switch (ctx->agpmode) { case 4: mode |= RADEON_AGP_4X_MODE; case 2: mode |= RADEON_AGP_2X_MODE; case 1: default: mode |= RADEON_AGP_1X_MODE; } if (drmAgpEnable(ctx->drmFD, mode) < 0) { fprintf(stderr, "[gart] AGP not enabled\n"); drmAgpRelease(ctx->drmFD); return 0; } else fprintf(stderr, "[gart] AGP enabled at %dx\n", ctx->agpmode); /* Workaround for some hardware bugs */ if (info->ChipFamily < CHIP_FAMILY_R200) OUTREG(RADEON_AGP_CNTL, INREG(RADEON_AGP_CNTL) | 0x000e0000); info->gartOffset = 0; if ((ret = drmAgpAlloc(ctx->drmFD, info->gartSize*1024*1024, 0, NULL, &info->gartMemHandle)) < 0) { fprintf(stderr, "[gart] Out of memory (%d)\n", ret); drmAgpRelease(ctx->drmFD); return 0; } fprintf(stderr, "[gart] %d kB allocated with handle 0x%08x\n", info->gartSize*1024, (unsigned)info->gartMemHandle); if (drmAgpBind(ctx->drmFD, info->gartMemHandle, info->gartOffset) < 0) { fprintf(stderr, "[gart] Could not bind\n"); drmAgpFree(ctx->drmFD, info->gartMemHandle); drmAgpRelease(ctx->drmFD); return 0; } /* Initialize the CP ring buffer data */ info->ringStart = info->gartOffset; info->ringMapSize = info->ringSize*1024*1024 + radeon_drm_page_size; info->ringReadOffset = info->ringStart + info->ringMapSize; info->ringReadMapSize = radeon_drm_page_size; /* Reserve space for vertex/indirect buffers */ info->bufStart = info->ringReadOffset + info->ringReadMapSize; info->bufMapSize = info->bufSize*1024*1024; /* Reserve the rest for AGP textures */ info->gartTexStart = info->bufStart + info->bufMapSize; s = (info->gartSize*1024*1024 - info->gartTexStart); l = RADEONMinBits((s-1) / RADEON_NR_TEX_REGIONS); if (l < RADEON_LOG_TEX_GRANULARITY) l = RADEON_LOG_TEX_GRANULARITY; info->gartTexMapSize = (s >> l) << l; info->log2GARTTexGran = l; if (drmAddMap(ctx->drmFD, info->ringStart, info->ringMapSize, DRM_AGP, DRM_READ_ONLY, &info->ringHandle) < 0) { fprintf(stderr, "[gart] Could not add ring mapping\n"); return 0; } fprintf(stderr, "[gart] ring handle = 0x%08x\n", info->ringHandle); if (drmAddMap(ctx->drmFD, info->ringReadOffset, info->ringReadMapSize, DRM_AGP, DRM_READ_ONLY, &info->ringReadPtrHandle) < 0) { fprintf(stderr, "[gart] Could not add ring read ptr mapping\n"); return 0; } fprintf(stderr, "[gart] ring read ptr handle = 0x%08lx\n", info->ringReadPtrHandle); if (drmAddMap(ctx->drmFD, info->bufStart, info->bufMapSize, DRM_AGP, 0, &info->bufHandle) < 0) { fprintf(stderr, "[gart] Could not add vertex/indirect buffers mapping\n"); return 0; } fprintf(stderr, "[gart] vertex/indirect buffers handle = 0x%08x\n", info->bufHandle); if (drmAddMap(ctx->drmFD, info->gartTexStart, info->gartTexMapSize, DRM_AGP, 0, &info->gartTexHandle) < 0) { fprintf(stderr, "[gart] Could not add AGP texture map mapping\n"); return 0; } fprintf(stderr, "[gart] AGP texture map handle = 0x%08lx\n", info->gartTexHandle); /* Initialize Radeon's AGP registers */ /* Ring buffer is at AGP offset 0 */ OUTREG(RADEON_AGP_BASE, info->ringHandle); return 1;}/* Initialize the PCI GART state. Request memory for use in PCI space, * and initialize the Radeon registers to point to that memory. */static int RADEONDRIPciInit(const DRIDriverContext *ctx, RADEONInfoPtr info){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -