drivers/video/fbdev/aty/radeon_accel.c

Source file repositories/reference/linux-study-clean/drivers/video/fbdev/aty/radeon_accel.c

File Facts

System
Linux kernel
Corpus path
drivers/video/fbdev/aty/radeon_accel.c
Extension
.c
Size
9140 bytes
Lines
330
Domain
Driver Families
Bucket
drivers/video
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

// SPDX-License-Identifier: GPL-2.0
#include "radeonfb.h"

/* the accelerated functions here are patterned after the 
 * "ACCEL_MMIO" ifdef branches in XFree86
 * --dte
 */

static void radeon_fixup_offset(struct radeonfb_info *rinfo)
{
	u32 local_base;

	/* *** Ugly workaround *** */
	/*
	 * On some platforms, the video memory is mapped at 0 in radeon chip space
	 * (like PPCs) by the firmware. X will always move it up so that it's seen
	 * by the chip to be at the same address as the PCI BAR.
	 * That means that when switching back from X, there is a mismatch between
	 * the offsets programmed into the engine. This means that potentially,
	 * accel operations done before radeonfb has a chance to re-init the engine
	 * will have incorrect offsets, and potentially trash system memory !
	 *
	 * The correct fix is for fbcon to never call any accel op before the engine
	 * has properly been re-initialized (by a call to set_var), but this is a
	 * complex fix. This workaround in the meantime, called before every accel
	 * operation, makes sure the offsets are in sync.
	 */

	radeon_fifo_wait (1);
	local_base = INREG(MC_FB_LOCATION) << 16;
	if (local_base == rinfo->fb_local_base)
		return;

	rinfo->fb_local_base = local_base;

	radeon_fifo_wait (3);
	OUTREG(DEFAULT_PITCH_OFFSET, (rinfo->pitch << 0x16) |
				     (rinfo->fb_local_base >> 10));
	OUTREG(DST_PITCH_OFFSET, (rinfo->pitch << 0x16) | (rinfo->fb_local_base >> 10));
	OUTREG(SRC_PITCH_OFFSET, (rinfo->pitch << 0x16) | (rinfo->fb_local_base >> 10));
}

static void radeonfb_prim_fillrect(struct radeonfb_info *rinfo, 
				   const struct fb_fillrect *region)
{
	radeon_fifo_wait(4);  
  
	OUTREG(DP_GUI_MASTER_CNTL,  
		rinfo->dp_gui_master_cntl  /* contains, like GMC_DST_32BPP */
                | GMC_BRUSH_SOLID_COLOR
                | ROP3_P);
	if (radeon_get_dstbpp(rinfo->depth) != DST_8BPP)
		OUTREG(DP_BRUSH_FRGD_CLR, rinfo->pseudo_palette[region->color]);
	else
		OUTREG(DP_BRUSH_FRGD_CLR, region->color);
	OUTREG(DP_WRITE_MSK, 0xffffffff);
	OUTREG(DP_CNTL, (DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM));

	radeon_fifo_wait(2);
	OUTREG(DSTCACHE_CTLSTAT, RB2D_DC_FLUSH_ALL);
	OUTREG(WAIT_UNTIL, (WAIT_2D_IDLECLEAN | WAIT_DMA_GUI_IDLE));

	radeon_fifo_wait(2);  
	OUTREG(DST_Y_X, (region->dy << 16) | region->dx);
	OUTREG(DST_WIDTH_HEIGHT, (region->width << 16) | region->height);
}

void radeonfb_fillrect(struct fb_info *info, const struct fb_fillrect *region)
{
	struct radeonfb_info *rinfo = info->par;
	struct fb_fillrect modded;
	int vxres, vyres;
  
	if (info->state != FBINFO_STATE_RUNNING)
		return;
	if (info->flags & FBINFO_HWACCEL_DISABLED) {
		cfb_fillrect(info, region);
		return;
	}

	radeon_fixup_offset(rinfo);

	vxres = info->var.xres_virtual;
	vyres = info->var.yres_virtual;

	memcpy(&modded, region, sizeof(struct fb_fillrect));

	if(!modded.width || !modded.height ||
	   modded.dx >= vxres || modded.dy >= vyres)
		return;

Annotation

Implementation Notes