From e5cedeba3d398a1e99120d97a2a618d781816b31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Fr=C3=B6schle?= Date: Fri, 27 Dec 2013 13:15:13 +0000 Subject: [PATCH] added more radeon driver files --- Makefile | 2 + include/pci.h | 1 + include/radeonfb.h | 129 +++--- radeon/radeon_accel.c | 1006 ++++++++++++++++++++++++++++++++++++++++ radeon/radeon_base.c | 138 +++--- radeon/radeon_cursor.c | 312 +++++++++++++ 6 files changed, 1444 insertions(+), 144 deletions(-) create mode 100644 radeon/radeon_accel.c create mode 100644 radeon/radeon_cursor.c diff --git a/Makefile b/Makefile index 5626fc1..8192ec7 100644 --- a/Makefile +++ b/Makefile @@ -107,6 +107,8 @@ CSRCS= \ video.c \ \ radeon_base.c \ + radeon_accel.c \ + radeon_cursor.c \ \ basflash.c \ basflash_start.c diff --git a/include/pci.h b/include/pci.h index 4c669bd..6ae8f80 100644 --- a/include/pci.h +++ b/include/pci.h @@ -22,6 +22,7 @@ */ #include +#include "util.h" /* for swpX() */ #define PCI_MEMORY_OFFSET (0x80000000) #define PCI_MEMORY_SIZE (0x40000000) /* 1 GByte PCI memory window */ diff --git a/include/radeonfb.h b/include/radeonfb.h index 37e1499..d7d98cd 100644 --- a/include/radeonfb.h +++ b/include/radeonfb.h @@ -498,14 +498,9 @@ extern uint32_t _swap_int32_t(uint32_t val); #define OUTREG(addr,val) (*((uint32_t *)(rinfo->mmio_base+addr)) = _swap_int32_t(val)) extern int32_t *tab_funcs_pci; - -#define BIOS_IN8(v) (Fast_read_mem_byte(rinfo->handle,rinfo->bios_seg_phys+v)) -#define BIOS_IN16(v) ((uint16_t)Fast_read_mem_byte(rinfo->handle,rinfo->bios_seg_phys+v) | \ - ((uint16_t)Fast_read_mem_byte(rinfo->handle,rinfo->bios_seg_phys+v+1) << 8)) -#define BIOS_IN32(v) ((uint32_t)Fast_read_mem_byte(rinfo->handle,rinfo->bios_seg_phys+v) | \ - ((uint32_t)Fast_read_mem_byte(rinfo->handle,rinfo->bios_seg_phys+v+1) << 8) | \ - ((uint32_t)Fast_read_mem_byte(rinfo->handle,rinfo->bios_seg_phys+v+2) << 16) | \ - ((uint32_t)Fast_read_mem_byte(rinfo->handle,rinfo->bios_seg_phys+v+3) << 24)) +#define BIOS_IN8(v) (* ((uint8_t *) rinfo->bios_seg_phys + v)) +#define BIOS_IN16(v) (swpw(*(uint16_t *) ((uint8_t *) rinfo->bios_seg_phys + v))) +#define BIOS_IN32(v) (swpl(*(uint32_t *) ((uint8_t *) rinfo->bios_seg_phys + v))) #define ADDRREG(addr) ((volatile uint32_t *)(rinfo->mmio_base + (addr))) #define OUTREGP(addr,val,mask) _OUTREGP(rinfo, addr, val, mask) @@ -602,79 +597,73 @@ do { \ #define radeonfb_engine_init(rinfo) RADEONEngineInit(rinfo) #define radeon_engine_idle() RADEONWaitForIdleMMIO(rinfo) -static inline int32_t radeonfb_sync(struct fb_info *info) +static inline int radeonfb_sync(struct fb_info *info) { struct radeonfb_info *rinfo = info->par; radeon_engine_idle(); return 0; } -extern void RADEONRestoreAccelStateMMIO(struct fb_info *info); -extern void RADEONSetupForSolidFillMMIO(struct fb_info *info, int32_t color, int32_t rop, int32_t planemask); -extern void RADEONSubsequentSolidFillRectMMIO(struct fb_info *info, int32_t x, int32_t y, int32_t w, int32_t h); -extern void RADEONSetupForSolidLineMMIO(struct fb_info *info, int32_t color, int32_t rop, int32_t planemask); -extern void RADEONSubsequentSolidHorVertLineMMIO(struct fb_info *info, int32_t x, int32_t y, int32_t len, int32_t dir); - -extern void RADEONSubsequentSolidTwoPointLineMMIO(struct fb_info *info, int32_t xa, int32_t ya, int32_t xb, - int32_t yb, int32_t flags); -extern void RADEONSetupForDashedLineMMIO(struct fb_info *info, int32_t fg, int32_t bg, - int32_t rop, int32_t planemask, int32_t length, uint8_t *pattern); -extern void RADEONSubsequentDashedTwoPointLineMMIO(struct fb_info *info, - int32_t xa, int32_t ya, int32_t xb, int32_t yb, int32_t flags, int32_t phase); -extern void RADEONSetupForScreenToScreenCopyMMIO(struct fb_info *info, - int32_t xdir, int32_t ydir, int32_t rop, int32_t planemask, int32_t trans_color); -extern void RADEONSubsequentScreenToScreenCopyMMIO(struct fb_info *info, - int32_t xa, int32_t ya, int32_t xb, int32_t yb, int32_t w, int32_t h); -extern void RADEONScreenToScreenCopyMMIO(struct fb_info *info, - int32_t xa, int32_t ya, int32_t xb, int32_t yb, int32_t w, int32_t h, int32_t rop); -extern void RADEONSetupForMono8x8PatternFillMMIO(struct fb_info *info, - int32_t patternx, int32_t patterny, int32_t fg, int32_t bg, int32_t rop, int32_t planemask); -extern void RADEONSubsequentMono8x8PatternFillRectMMIO(struct fb_info *info, - int32_t patternx, int32_t patterny, int32_t x, int32_t y, int32_t w, int32_t h); -extern void RADEONSetupForScanlineCPUToScreenColorExpandFillMMIO(struct fb_info *info, - int32_t fg, int32_t bg, int32_t rop, int32_t planemask); -extern void RADEONSubsequentScanlineCPUToScreenColorExpandFillMMIO(struct fb_info *info, - int32_t x, int32_t y, int32_t w, int32_t h, int32_t skipleft); -extern void RADEONSubsequentScanlineMMIO(struct fb_info *info, uint32_t *buf); -extern void RADEONSetupForScanlineImageWriteMMIO(struct fb_info *info, - int32_t rop, int32_t planemask, int32_t trans_color, int32_t bpp); -extern void RADEONSubsequentScanlineImageWriteRectMMIO(struct fb_info *info, - int32_t x, int32_t y, int32_t w, int32_t h, int32_t skipleft); -extern void RADEONSetClippingRectangleMMIO(struct fb_info *info, - int32_t xa, int32_t ya, int32_t xb, int32_t yb); -extern void RADEONDisableClippingMMIO(struct fb_info *info); - -#ifndef MCF5445X -extern int32_t RADEONSetupForCPUToScreenAlphaTextureMMIO(struct fb_info *info, - int32_t op, uint16_t red, uint16_t green, uint16_t blue, uint16_t alpha, uint32_t maskFormat, uint32_t dstFormat, uint8_t *alphaPtr, int32_t alphaPitch, int32_t width, int32_t height, int32_t flags); -extern int32_t RADEONSetupForCPUToScreenTextureMMIO(struct fb_info *info, - int32_t op, uint32_t srcFormat, uint32_t dstFormat, uint8_t *texPtr, int32_t texPitch, int32_t width, int32_t height, int32_t flags); -extern void RADEONSubsequentCPUToScreenTextureMMIO(struct fb_info *info, - int32_t dstx, int32_t dsty, int32_t srcx, int32_t srcy, int32_t width, int32_t height); -#else -static __inline__ int32_t RADEONSetupForCPUToScreenAlphaTextureMMIO(struct fb_info *info, - int32_t op, uint16_t red, uint16_t green, uint16_t blue, uint16_t alpha, uint32_t maskFormat, uint32_t dstFormat, uint8_t *alphaPtr, int32_t alphaPitch, int32_t width, int32_t height, int32_t flags) -{ return FALSE; } -static __inline__ int32_t RADEONSetupForCPUToScreenTextureMMIO(struct fb_info *info, - int32_t op, uint32_t srcFormat, uint32_t dstFormat, uint8_t *texPtr, int32_t texPitch, int32_t width, int32_t height, int32_t flags) -{ return FALSE; } -static __inline__ void RADEONSubsequentCPUToScreenTextureMMIO(struct fb_info *info, - int32_t dstx, int32_t dsty, int32_t srcx, int32_t srcy, int32_t width, int32_t height) { } -#endif /* MCF5445X */ +extern void radeon_restore_accel_state_mmio(struct fb_info *info); +extern void radeon_setup_for_solid_fill(struct fb_info *info, int color, int rop, unsigned int planemask); +extern void radeon_subsequent_solid_fill_rect_mmio(struct fb_info *info, int x, int y, int w, int h); +extern void radeon_setup_for_solid_line_mmio(struct fb_info *info, int color, int rop, unsigned int planemask); +extern void radeon_subsequent_solid_hor_vert_line_mmio(struct fb_info *info, int x, int y, int len, int dir); +extern void radeon_subsequent_solid_two_point_line_mmio(struct fb_info *info, int xa, int ya, int xb, + int yb, int flags); +extern void radeon_setup_for_dashed_line_mmio(struct fb_info *info, int fg, int bg, + int rop, unsigned int planemask, int length, unsigned char *pattern); +extern void radeon_subsequent_dashed_two_point_line_mmio(struct fb_info *info, + int xa, int ya, int xb, int yb, int flags, int phase); +extern void radeon_setup_for_screen_to_screen_copy_mmio(struct fb_info *info, + int xdir, int ydir, int rop, unsigned int planemask, int trans_color); +extern void radeon_subsequent_screen_to_screen_copy_mmio(struct fb_info *info, + int xa, int ya, int xb, int yb, int w, int h); +extern void radeon_screen_to_screen_copy_mmio(struct fb_info *info, + int xa, int ya, int xb, int yb, int w, int h, int rop); +extern void radeon_setup_for_mono_8x8_pattern_fill_mmio(struct fb_info *info, + int patternx, int patterny, int fg, int bg, int rop, unsigned int planemask); +extern void radeon_subsequent_mono_8x8_pattern_fill_rect_mmio(struct fb_info *info, + int patternx, int patterny, int x, int y, int w, int h); +extern void radeon_setup_for_scanline_cpu_to_screen_color_expand_fill_mmio(struct fb_info *info, + int fg, int bg, int rop, unsigned int planemask); +extern void radeon_subsequent_scanline_cpu_to_screen_color_expand_fill_mmio(struct fb_info *info, + int x, int y, int w, int h, int skipleft); +extern void radeon_subsequent_scanline_mmio(struct fb_info *info, int *buf); +extern void radeon_setup_for_scanline_image_write_mmio(struct fb_info *info, + int rop, unsigned int planemask, int trans_color, int bpp); +extern void radeon_subsequent_scanline_image_write_rect_mmio(struct fb_info *info, + int x, int y, int w, int h, int skipleft); +extern void radeon_set_clipping_rectangle_mmio(struct fb_info *info, + int xa, int ya, int xb, int yb); +extern void radeon_disable_clipping_mmio(struct fb_info *info); +extern int32_t radeon_setup_for_cpu_to_screen_alpha_texture_mmio(struct fb_info *info, + int op, int red, int green, int blue, + int alpha, int maskFormat, int dstFormat, + uint8_t *alphaPtr, int alphaPitch, + int width, int height, int32_t flags); +extern int32_t radeon_setup_for_cpu_to_screen_texture_mmio(struct fb_info *info, int32_t op, + uint32_t srcFormat, uint32_t dstFormat, + uint8_t *texPtr, int32_t texPitch, + int32_t width, int32_t height, int32_t flags); +extern void radeon_subsequent_cpu_to_screen_texture_mmio(struct fb_info *info, + int32_t dstx, int32_t dsty, + int32_t srcx, int32_t srcy, + int32_t width, int32_t height); /* Cursor functions */ -extern void RADEONSetCursorColors(struct fb_info *info, int32_t bg, int32_t fg); -extern void RADEONSetCursorPosition(struct fb_info *info, int32_t x, int32_t y); -extern void RADEONLoadCursorImage(struct fb_info *info, uint16_t *mask, uint16_t *data, int32_t zoom); -extern void RADEONHideCursor(struct fb_info *info); -extern void RADEONShowCursor(struct fb_info *info); -extern int32_t RADEONCursorInit(struct fb_info *info); +extern void radeon_set_cursor_colors(struct fb_info *info, int32_t bg, int32_t fg); +extern void radeon_set_cursor_position(struct fb_info *info, int32_t x, int32_t y); +extern void radeon_load_cursor_image(struct fb_info *info, uint16_t *mask, uint16_t *data, int32_t zoom); +extern void radeon_hide_cursor(struct fb_info *info); +extern void radeon_show_corsor(struct fb_info *info); +extern int32_t radeon_cursor_init(struct fb_info *info); /* Other functions */ extern int32_t radeon_screen_blank(struct radeonfb_info *rinfo, int32_t blank, int32_t mode_switch); -extern void radeon_write_mode (struct radeonfb_info *rinfo, struct radeon_regs *mode, int32_t reg_only); -int32_t radeonfb_setcolreg(uint32_t regno, uint32_t red, uint32_t green, - uint32_t blue, uint32_t transp, struct fb_info *info); +extern void radeon_write_mode(struct radeonfb_info *rinfo, struct radeon_regs *mode, int32_t reg_only); +int radeonfb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, struct fb_info *info); extern int32_t radeonfb_pci_register(int32_t handle, const struct pci_device_id *ent); extern void radeonfb_pci_unregister(void); diff --git a/radeon/radeon_accel.c b/radeon/radeon_accel.c new file mode 100644 index 0000000..3f0c07b --- /dev/null +++ b/radeon/radeon_accel.c @@ -0,0 +1,1006 @@ +/* + * Copyright 2000 ATI Technologies Inc., Markham, Ontario, and + * VA Linux Systems Inc., Fremont, California. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR + * THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/* + * Authors: + * Kevin E. Martin + * Rickard E. Faith + * Alan Hourihane + * + * Credits: + * + * Thanks to Ani Joshi for providing source + * code to his Radeon driver. Portions of this file are based on the + * initialization code for that driver. + * + * References: + * + * !!!! FIXME !!!! + * RAGE 128 VR/ RAGE 128 GL Register Reference Manual (Technical + * Reference Manual P/N RRG-G04100-C Rev. 0.04), ATI Technologies: April + * 1999. + * + * RAGE 128 Software Development Manual (Technical Reference Manual P/N + * SDK-G04000 Rev. 0.01), ATI Technologies: June 1999. + * + * Notes on unimplemented XAA optimizations: + * + * SetClipping: This has been removed as XAA expects 16bit registers + * for full clipping. + * TwoPointLine: The Radeon supports this. Not Bresenham. + * DashedLine with non-power-of-two pattern length: Apparently, there is + * no way to set the length of the pattern -- it is always + * assumed to be 8 or 32 (or 1024?). + * ScreenToScreenColorExpandFill: See p. 4-17 of the Technical Reference + * Manual where it states that monochrome expansion of frame + * buffer data is not supported. + * Color8x8PatternFill: Apparently, an 8x8 color brush cannot take an 8x8 + * pattern from frame buffer memory. + * + */ + +#include "fb.h" +#include "radeonfb.h" + +static struct { + int rop; + int pattern; +} RADEON_ROP[] = { + { ROP3_ZERO, ROP3_ZERO }, /* GXclear */ + { ROP3_DSa, ROP3_DPa }, /* Gxand */ + { ROP3_SDna, ROP3_PDna }, /* GXandReverse */ + { ROP3_S, ROP3_P }, /* GXcopy */ + { ROP3_DSna, ROP3_DPna }, /* GXandInverted */ + { ROP3_D, ROP3_D }, /* GXnoop */ + { ROP3_DSx, ROP3_DPx }, /* GXxor */ + { ROP3_DSo, ROP3_DPo }, /* GXor */ + { ROP3_DSon, ROP3_DPon }, /* GXnor */ + { ROP3_DSxn, ROP3_PDxn }, /* GXequiv */ + { ROP3_Dn, ROP3_Dn }, /* GXinvert */ + { ROP3_SDno, ROP3_PDno }, /* GXorReverse */ + { ROP3_Sn, ROP3_Pn }, /* GXcopyInverted */ + { ROP3_DSno, ROP3_DPno }, /* GXorInverted */ + { ROP3_DSan, ROP3_DPan }, /* GXnand */ + { ROP3_ONE, ROP3_ONE } /* GXset */ +}; + +#define ACCEL_MMIO +#define ACCEL_PREAMBLE() +#define BEGIN_ACCEL(n) RADEONWaitForFifo(rinfo, (n)) +#define OUT_ACCEL_REG(reg, val) OUTREG(reg, val) +#define FINISH_ACCEL() + +/* MMIO: + * + * Wait for the graphics engine to be completely idle: the FIFO has + * drained, the Pixel Cache is flushed, and the engine is idle. This is + * a standard "sync" function that will make the hardware "quiescent". + */ +void RADEONWaitForIdleMMIO(struct radeonfb_info *rinfo) +{ + int i = 0; + /* Wait for the engine to go idle */ + RADEONWaitForFifoFunction(rinfo, 64); + while(1) + { + for(i = 0; i < RADEON_TIMEOUT; i++) + { + if (!(INREG(RBBM_STATUS) & RBBM_ACTIVE)) + { + RADEONEngineFlush(rinfo); + return; + } + } + RADEONEngineReset(rinfo); + RADEONEngineRestore(rinfo); + } +} + +#if 0 + +/* This callback is required for multiheader cards using XAA */ +void RADEONRestoreAccelStateMMIO(struct fb_info *info) +{ + struct radeonfb_info *rinfo = info->par; +// unsigned long pitch64 = ((info->var.xres * (rinfo->bpp / 8) + 0x3f)) >> 6; + OUTREG(DEFAULT_OFFSET, (((INREG(DISPLAY_BASE_ADDR) + rinfo->fb_local_base) >> 10) | (rinfo->pitch << 22))); + /* FIXME: May need to restore other things, like BKGD_CLK FG_CLK... */ + RADEONWaitForIdleMMIO(rinfo); +} + +#endif + +/* Setup for XAA SolidFill */ +void radeon_setup_for_solid_fill(struct fb_info *info, int color, int rop, unsigned int planemask) +{ + struct radeonfb_info *rinfo = info->par; + ACCEL_PREAMBLE(); + /* Save for later clipping */ + rinfo->dp_gui_master_cntl_clip = (rinfo->dp_gui_master_cntl + | GMC_BRUSH_SOLID_COLOR | GMC_SRC_DATATYPE_COLOR | RADEON_ROP[rop].pattern); + BEGIN_ACCEL(4); + OUT_ACCEL_REG(DP_GUI_MASTER_CNTL, rinfo->dp_gui_master_cntl_clip); + OUT_ACCEL_REG(DP_BRUSH_FRGD_CLR, color); + OUT_ACCEL_REG(DP_WRITE_MSK, planemask); + OUT_ACCEL_REG(DP_CNTL, (DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM)); + FINISH_ACCEL(); +} + +/* Subsequent XAA SolidFillRect */ +void radeon_subsequent_solid_fill_rect_mmio(struct fb_info *info, int x, int y, int w, int h) +{ + struct radeonfb_info *rinfo = info->par; + ACCEL_PREAMBLE(); +#ifdef RADEON_TILING + BEGIN_ACCEL(3); + OUT_ACCEL_REG(DST_PITCH_OFFSET, rinfo->dst_pitch_offset + | ((rinfo->tilingEnabled && (y <= info->var.yres_virtual)) ? DST_TILE_MACRO : 0)); +#else + BEGIN_ACCEL(2); +#endif + OUT_ACCEL_REG(DST_Y_X, (y << 16) | x); + OUT_ACCEL_REG(DST_WIDTH_HEIGHT, (w << 16) | h); + FINISH_ACCEL(); +} + +/* Setup for XAA solid lines */ +void radeon_setup_for_solid_line_mmio(struct fb_info *info, int color, int rop, unsigned int planemask) +{ + struct radeonfb_info *rinfo = info->par; + ACCEL_PREAMBLE(); + /* Save for later clipping */ + rinfo->dp_gui_master_cntl_clip = (rinfo->dp_gui_master_cntl + | GMC_BRUSH_SOLID_COLOR | GMC_SRC_DATATYPE_COLOR | RADEON_ROP[rop].pattern); + if (rinfo->family >= CHIP_FAMILY_RV200) + { + BEGIN_ACCEL(1); + OUT_ACCEL_REG(DST_LINE_PATCOUNT, 0x55 << BRES_CNTL_SHIFT); + } + BEGIN_ACCEL(3); + OUT_ACCEL_REG(DP_GUI_MASTER_CNTL, rinfo->dp_gui_master_cntl_clip); + OUT_ACCEL_REG(DP_BRUSH_FRGD_CLR, color); + OUT_ACCEL_REG(DP_WRITE_MSK, planemask); + FINISH_ACCEL(); +} + +/* Subsequent XAA solid horizontal and vertical lines */ +void radeon_subsequent_solid_hor_vert_line_mmio(struct fb_info *info, int x, int y, int len, int dir) +{ + struct radeonfb_info *rinfo = info->par; + int w = 1; + int h = 1; + ACCEL_PREAMBLE(); + if (dir == DEGREES_0) + w = len; + else + h = len; +#ifdef RADEON_TILING + BEGIN_ACCEL(4); + OUT_ACCEL_REG(DP_CNTL, (DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM)); + OUT_ACCEL_REG(DST_PITCH_OFFSET, rinfo->dst_pitch_offset + | ((rinfo->tilingEnabled && (y <= info->var.xres_virtual)) ? DST_TILE_MACRO : 0)); +#else + BEGIN_ACCEL(3); + OUT_ACCEL_REG(DP_CNTL, (DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM)); +#endif + OUT_ACCEL_REG(DST_Y_X, (y << 16) | x); + OUT_ACCEL_REG(DST_WIDTH_HEIGHT, (w << 16) | h); + FINISH_ACCEL(); +} + +/* Subsequent XAA solid TwoPointLine line */ +void radeon_subsequent_solid_two_point_line_mmio(struct fb_info *info, + int xa, int ya, int xb, int yb, int flags) +{ + struct radeonfb_info *rinfo = info->par; + + ACCEL_PREAMBLE(); + + /* TODO: Check bounds -- RADEON only has 14 bits */ + if (!(flags & OMIT_LAST)) + RADEONSubsequentSolidHorVertLineMMIO(info, xb, yb, 1, DEGREES_0); +#ifdef RADEON_TILING + BEGIN_ACCEL(3); + OUT_ACCEL_REG(DST_PITCH_OFFSET, rinfo->dst_pitch_offset + | ((rinfo->tilingEnabled && (ya <= info->var.yres_virtual)) ? DST_TILE_MACRO : 0)); +#else + BEGIN_ACCEL(2); +#endif + OUT_ACCEL_REG(DST_LINE_START, (ya << 16) | xa); + OUT_ACCEL_REG(DST_LINE_END, (yb << 16) | xb); + FINISH_ACCEL(); +} + +/* Setup for XAA dashed lines + * NOTE: Since we can only accelerate lines with power-of-2 patterns of * length <= 32 + */ +void radeon_setup_for_dashed_line_mmio(struct fb_info *info, int fg, int bg, + int rop, unsigned int planemask, int length, unsigned char *pattern) +{ + struct radeonfb_info *rinfo = info->par; + unsigned long pat = *(unsigned long *) pattern; + + ACCEL_PREAMBLE(); + /* Save for determining whether or not to draw last pixel */ + rinfo->dashLen = length; + rinfo->dashPattern = pat; + if (rinfo->big_endian) + { + switch (length) + { + case 2: pat |= (pat >> 2); /* fall through */ + case 4: pat |= (pat >> 4); /* fall through */ + case 8: pat |= (pat >> 8); /* fall through */ + case 16: pat |= (pat >> 16); + } + } + else + { + switch (length) + { + case 2: pat |= (pat << 2); /* fall through */ + case 4: pat |= (pat << 4); /* fall through */ + case 8: pat |= (pat << 8); /* fall through */ + case 16: pat |= (pat << 16); + } + } + /* Save for later clipping */ + rinfo->dp_gui_master_cntl_clip = (rinfo->dp_gui_master_cntl + | (bg == -1 ? GMC_BRUSH_32X1_MONO_FG_LA : GMC_BRUSH_32X1_MONO_FG_BG) + | RADEON_ROP[rop].pattern | GMC_BYTE_LSB_TO_MSB); + rinfo->dash_fg = fg; + rinfo->dash_bg = bg; + BEGIN_ACCEL((bg == -1) ? 4 : 5); + OUT_ACCEL_REG(DP_GUI_MASTER_CNTL, rinfo->dp_gui_master_cntl_clip); + OUT_ACCEL_REG(DP_WRITE_MSK, planemask); + OUT_ACCEL_REG(DP_BRUSH_FRGD_CLR, fg); + if (bg != -1) + OUT_ACCEL_REG(DP_BRUSH_BKGD_CLR, bg); + OUT_ACCEL_REG(BRUSH_DATA0, pat); + FINISH_ACCEL(); +} + +/* Helper function to draw last point for dashed lines */ +static void RADEONDashedLastPelMMIO(struct fb_info *info, + int x, int y, int fg) +{ + struct radeonfb_info *rinfo = info->par; + unsigned long dp_gui_master_cntl = rinfo->dp_gui_master_cntl_clip; + ACCEL_PREAMBLE(); + dp_gui_master_cntl &= ~GMC_BRUSH_DATATYPE_MASK; + dp_gui_master_cntl |= GMC_BRUSH_SOLID_COLOR; + dp_gui_master_cntl &= ~GMC_SRC_DATATYPE_MASK; + dp_gui_master_cntl |= GMC_SRC_DATATYPE_COLOR; +#ifdef RADEON_TILING + BEGIN_ACCEL(8); + OUT_ACCEL_REG(DP_GUI_MASTER_CNTL, dp_gui_master_cntl); + OUT_ACCEL_REG(DP_CNTL, (DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM)); + OUT_ACCEL_REG(DST_PITCH_OFFSET, rinfo->dst_pitch_offset + | ((rinfo->tilingEnabled && (y <= info->var.yres_virtual)) ? DST_TILE_MACRO : 0)); +#else + BEGIN_ACCEL(7); + OUT_ACCEL_REG(DP_GUI_MASTER_CNTL, dp_gui_master_cntl); + OUT_ACCEL_REG(DP_CNTL, (DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM)); +#endif + OUT_ACCEL_REG(DP_BRUSH_FRGD_CLR, fg); + OUT_ACCEL_REG(DST_Y_X, (y << 16) | x); + OUT_ACCEL_REG(DST_WIDTH_HEIGHT, (1 << 16) | 1); + /* Restore old values */ + OUT_ACCEL_REG(DP_GUI_MASTER_CNTL, rinfo->dp_gui_master_cntl_clip); + OUT_ACCEL_REG(DP_BRUSH_FRGD_CLR, rinfo->dash_fg); + FINISH_ACCEL(); +} + +/* Subsequent XAA dashed line */ +void radeon_subsequent_dashed_two_point_line_mmio(struct fb_info *info, int xa, int ya, int xb, int yb, int flags, int phase) +{ + struct radeonfb_info *rinfo = info->par; + + ACCEL_PREAMBLE(); + + /* TODO: Check bounds -- RADEON only has 14 bits */ + if (!(flags & OMIT_LAST)) + { + int deltax = xa - xb; + int deltay = ya - yb; + int shift; + if (deltax < 0) + deltax = -deltax; + if (deltay < 0) + deltay = -deltay; + if (deltax > deltay) + shift = deltax; + else + shift = deltay; + shift += phase; + shift %= rinfo->dashLen; + if ((rinfo->dashPattern >> shift) & 1) + RADEONDashedLastPelMMIO(info, xb, yb, rinfo->dash_fg); + else if (rinfo->dash_bg != -1) + RADEONDashedLastPelMMIO(info, xb, yb, rinfo->dash_bg); + } +#ifdef RADEON_TILING + BEGIN_ACCEL(4); + OUT_ACCEL_REG(DST_PITCH_OFFSET, rinfo->dst_pitch_offset + | ((rinfo->tilingEnabled && (ya <= info->var.yres_virtual)) ? DST_TILE_MACRO : 0)); +#else + BEGIN_ACCEL(3); +#endif + OUT_ACCEL_REG(DST_LINE_START, (ya << 16) | xa); + OUT_ACCEL_REG(DST_LINE_PATCOUNT, phase); + OUT_ACCEL_REG(DST_LINE_END, (yb << 16) | xb); + FINISH_ACCEL(); +} + +/* Set up for transparency + * + * Mmmm, Seems as though the transparency compare is opposite to r128. + * It should only draw when source != trans_color, this is the opposite + * of that. + */ +static void radeon_set_transparency_mmio(struct radeonfb_info *rinfo, int trans_color) +{ + if (trans_color != -1) + { + ACCEL_PREAMBLE(); + BEGIN_ACCEL(3); + OUT_ACCEL_REG(CLR_CMP_CLR_SRC, trans_color); + OUT_ACCEL_REG(CLR_CMP_MSK, 0xffffffff); + OUT_ACCEL_REG(CLR_CMP_CNTL, (SRC_CMP_EQ_COLOR | CLR_CMP_SRC_SOURCE)); + FINISH_ACCEL(); + } +} + +/* Setup for XAA screen-to-screen copy */ +void radeon_setup_for_screen_to_screen_copy_mmio(struct fb_info *info, + int xdir, int ydir, int rop, unsigned int planemask, int trans_color) +{ + struct radeonfb_info *rinfo = info->par; + + ACCEL_PREAMBLE(); + rinfo->xdir = xdir; + rinfo->ydir = ydir; + /* Save for later clipping */ +#ifdef RADEON_TILING + rinfo->dp_gui_master_cntl_clip = (rinfo->dp_gui_master_cntl + | GMC_BRUSH_NONE | GMC_SRC_DATATYPE_COLOR | RADEON_ROP[rop].rop + | DP_SRC_SOURCE_MEMORY | GMC_SRC_PITCH_OFFSET_CNTL); +#else + rinfo->dp_gui_master_cntl_clip = (rinfo->dp_gui_master_cntl + | GMC_BRUSH_NONE | GMC_SRC_DATATYPE_COLOR | RADEON_ROP[rop].rop | DP_SRC_SOURCE_MEMORY); +#endif + BEGIN_ACCEL(3); + OUT_ACCEL_REG(DP_GUI_MASTER_CNTL, rinfo->dp_gui_master_cntl_clip); + OUT_ACCEL_REG(DP_WRITE_MSK, planemask); + OUT_ACCEL_REG(DP_CNTL, ((xdir >= 0 ? DST_X_LEFT_TO_RIGHT : 0) | (ydir >= 0 ? DST_Y_TOP_TO_BOTTOM : 0))); + FINISH_ACCEL(); + rinfo->trans_color = trans_color; + if (trans_color != -1) + radeon_set_transparency_mmio(rinfo, trans_color); +} + +/* Subsequent XAA screen-to-screen copy */ +void radeon_subsequent_screen_to_screen_copy(struct fb_info *info, int xa, int ya, int xb, int yb, int w, int h) +{ + struct radeonfb_info *rinfo = info->par; + + ACCEL_PREAMBLE(); + if (rinfo->xdir < 0) + xa += w - 1, xb += w - 1; + + if (rinfo->ydir < 0) + ya += h - 1, yb += h - 1; + +#ifdef RADEON_TILING + BEGIN_ACCEL(5); + OUT_ACCEL_REG(SRC_PITCH_OFFSET, rinfo->dst_pitch_offset + | ((rinfo->tilingEnabled && (ya <= info->var.yres_virtual)) ? DST_TILE_MACRO : 0)); + OUT_ACCEL_REG(DST_PITCH_OFFSET, rinfo->dst_pitch_offset + | ((rinfo->tilingEnabled && (yb <= info->var.yres_virtual)) ? DST_TILE_MACRO : 0)); +#else + BEGIN_ACCEL(3); +#endif + OUT_ACCEL_REG(SRC_Y_X, (ya << 16) | xa); + OUT_ACCEL_REG(DST_Y_X, (yb << 16) | xb); + OUT_ACCEL_REG(DST_HEIGHT_WIDTH, (h << 16) | w); + FINISH_ACCEL(); +} + +/* XAA screen-to-screen copy */ +void radeon_screen_to_screen_copy_mmio(struct fb_info *info, int xa, int ya, int xb, int yb, int w, int h, int rop) +{ + struct radeonfb_info *rinfo = info->par; + + int xdir = xa - xb; + int ydir = ya - yb; + ACCEL_PREAMBLE(); + if (xdir < 0) + xa += w - 1, xb += w - 1; + if (ydir < 0) + ya += h - 1, yb += h - 1; +#ifdef RADEON_TILING + /* Save for later clipping */ + rinfo->dp_gui_master_cntl_clip = (rinfo->dp_gui_master_cntl + | GMC_BRUSH_NONE | GMC_SRC_DATATYPE_COLOR | RADEON_ROP[rop].rop + | DP_SRC_SOURCE_MEMORY | GMC_SRC_PITCH_OFFSET_CNTL); + BEGIN_ACCEL(8); + + OUT_ACCEL_REG(SRC_PITCH_OFFSET, rinfo->dst_pitch_offset + | ((rinfo->tilingEnabled && (ya <= info->var.yres_virtual)) ? DST_TILE_MACRO : 0)); + OUT_ACCEL_REG(DST_PITCH_OFFSET, rinfo->dst_pitch_offset + | ((rinfo->tilingEnabled && (yb <= info->var.yres_virtual)) ? DST_TILE_MACRO : 0)); +#else + /* Save for later clipping */ + rinfo->dp_gui_master_cntl_clip = (rinfo->dp_gui_master_cntl + | GMC_BRUSH_NONE | GMC_SRC_DATATYPE_COLOR | RADEON_ROP[rop].rop | DP_SRC_SOURCE_MEMORY); + BEGIN_ACCEL(6); +#endif + OUT_ACCEL_REG(DP_GUI_MASTER_CNTL, rinfo->dp_gui_master_cntl_clip); + OUT_ACCEL_REG(DP_WRITE_MSK, -1); + OUT_ACCEL_REG(DP_CNTL, ((xdir >= 0 ? DST_X_LEFT_TO_RIGHT : 0) | (ydir >= 0 ? DST_Y_TOP_TO_BOTTOM : 0))); + OUT_ACCEL_REG(SRC_Y_X, (ya << 16) | xa); + OUT_ACCEL_REG(DST_Y_X, (yb << 16) | xb); + OUT_ACCEL_REG(DST_HEIGHT_WIDTH, (h << 16) | w); + FINISH_ACCEL(); +} + +/* Setup for XAA mono 8x8 pattern color expansion. Patterns with + * transparency use `bg == -1'. This routine is only used if the XAA + * pixmap cache is turned on. + */ +void radeon_setup_for_mono_8x8_pattern_fill_mmio(struct fb_info *info, int patternx, int patterny, + int fg, int bg, int rop, unsigned int planemask) +{ + struct radeonfb_info *rinfo = info->par; + unsigned char pattern[8]; + + ACCEL_PREAMBLE(); + if (rinfo->big_endian) + { + /* Take care of endianness */ + pattern[0] = (patternx & 0x000000ff); + pattern[1] = (patternx & 0x0000ff00) >> 8; + pattern[2] = (patternx & 0x00ff0000) >> 16; + pattern[3] = (patternx & 0xff000000) >> 24; + pattern[4] = (patterny & 0x000000ff); + pattern[5] = (patterny & 0x0000ff00) >> 8; + pattern[6] = (patterny & 0x00ff0000) >> 16; + pattern[7] = (patterny & 0xff000000) >> 24; + /* Save for later clipping */ + rinfo->dp_gui_master_cntl_clip = (rinfo->dp_gui_master_cntl + | (bg == -1 ? GMC_BRUSH_8X8_MONO_FG_LA : GMC_BRUSH_8X8_MONO_FG_BG) + | RADEON_ROP[rop].pattern | GMC_BYTE_MSB_TO_LSB); + } + else + /* Save for later clipping */ + rinfo->dp_gui_master_cntl_clip = (rinfo->dp_gui_master_cntl + | (bg == -1 ? GMC_BRUSH_8X8_MONO_FG_LA : GMC_BRUSH_8X8_MONO_FG_BG) + | RADEON_ROP[rop].pattern); + BEGIN_ACCEL((bg == -1) ? 5 : 6); + OUT_ACCEL_REG(DP_GUI_MASTER_CNTL, rinfo->dp_gui_master_cntl_clip); + OUT_ACCEL_REG(DP_WRITE_MSK, planemask); + OUT_ACCEL_REG(DP_BRUSH_FRGD_CLR, fg); + if (bg != -1) + OUT_ACCEL_REG(DP_BRUSH_BKGD_CLR, bg); + if (rinfo->big_endian) + { + OUT_ACCEL_REG(BRUSH_DATA0, *(unsigned long *) &pattern[0]); + OUT_ACCEL_REG(BRUSH_DATA1, *(unsigned long *) &pattern[4]); + } + else + { + OUT_ACCEL_REG(BRUSH_DATA0, patternx); + OUT_ACCEL_REG(BRUSH_DATA1, patterny); + } + FINISH_ACCEL(); +} + +/* Subsequent XAA 8x8 pattern color expansion. Because they are used in + * the setup function, `patternx' and `patterny' are not used here. + */ +void radeon_subsequent_mono_8x8_pattern_fill_rect_mmio(struct fb_info *info, int patternx, int patterny, + int x, int y, int w, int h) +{ + struct radeonfb_info *rinfo = info->par; + + ACCEL_PREAMBLE(); +#ifdef RADEON_TILING + BEGIN_ACCEL(4); + OUT_ACCEL_REG(DST_PITCH_OFFSET, rinfo->dst_pitch_offset + | ((rinfo->tilingEnabled && (y <= info->var.yres_virtual)) ? DST_TILE_MACRO : 0)); +#else + BEGIN_ACCEL(3); +#endif + OUT_ACCEL_REG(BRUSH_Y_X, (patterny << 8) | patternx); + OUT_ACCEL_REG(DST_Y_X, (y << 16) | x); + OUT_ACCEL_REG(DST_HEIGHT_WIDTH, (h << 16) | w); + FINISH_ACCEL(); +} + +/* Setup for XAA indirect CPU-to-screen color expansion (indirect). + * Because of how the scratch buffer is initialized, this is really a + * mainstore-to-screen color expansion. Transparency is supported when + * `bg == -1'. + */ +void radeon_setup_for_scanline_cpu_to_screen_color_expand_fill_mmio(struct fb_info *info, + int fg, int bg, int rop, unsigned int planemask) +{ + struct radeonfb_info *rinfo = info->par; + + ACCEL_PREAMBLE(); + /* Save for later clipping */ + if (rinfo->big_endian) + rinfo->dp_gui_master_cntl_clip = (rinfo->dp_gui_master_cntl + | GMC_DST_CLIPPING | GMC_BRUSH_NONE + | (bg == -1 ? GMC_SRC_DATATYPE_MONO_FG_LA : GMC_SRC_DATATYPE_MONO_FG_BG) + | RADEON_ROP[rop].rop | GMC_BYTE_MSB_TO_LSB | DP_SRC_SOURCE_HOST_DATA); + else + rinfo->dp_gui_master_cntl_clip = (rinfo->dp_gui_master_cntl + | GMC_DST_CLIPPING | GMC_BRUSH_NONE + | (bg == -1 ? GMC_SRC_DATATYPE_MONO_FG_LA : GMC_SRC_DATATYPE_MONO_FG_BG) + | RADEON_ROP[rop].rop | GMC_BYTE_LSB_TO_MSB | DP_SRC_SOURCE_HOST_DATA); + if (rinfo->big_endian) + { + BEGIN_ACCEL(5); + OUT_ACCEL_REG(RBBM_GUICNTL, HOST_DATA_SWAP_NONE); + } + else + BEGIN_ACCEL(4); + OUT_ACCEL_REG(DP_GUI_MASTER_CNTL, rinfo->dp_gui_master_cntl_clip); + OUT_ACCEL_REG(DP_WRITE_MSK, planemask); + OUT_ACCEL_REG(DP_SRC_FRGD_CLR, fg); + OUT_ACCEL_REG(DP_SRC_BKGD_CLR, bg); + FINISH_ACCEL(); +} + +/* Subsequent XAA indirect CPU-to-screen color expansion. This is only + * called once for each rectangle. + */ +void radeon_subsequent_scanline_cpu_to_screen_color_expand_fill_mmio(struct fb_info *info, + int x, int y, int w, int h, int skipleft) +{ + struct radeonfb_info *rinfo = info->par; + ACCEL_PREAMBLE(); + rinfo->scanline_h = h; + rinfo->scanline_words = (w + 31) >> 5; +#ifdef RADEON_TILING + BEGIN_ACCEL(5); + OUT_ACCEL_REG(DST_PITCH_OFFSET, rinfo->dst_pitch_offset + | ((rinfo->tilingEnabled && (y <= info->var.yres_virtual)) ? DST_TILE_MACRO : 0)); +#else + BEGIN_ACCEL(4); +#endif + OUT_ACCEL_REG(SC_TOP_LEFT, (y << 16) | ((x+skipleft) & 0xffff)); + OUT_ACCEL_REG(SC_BOTTOM_RIGHT, ((y+h) << 16) | ((x+w) & 0xffff)); + OUT_ACCEL_REG(DST_Y_X, (y << 16) | (x & 0xffff)); + /* Have to pad the width here and use clipping engine */ + OUT_ACCEL_REG(DST_HEIGHT_WIDTH, (h << 16) | ((w + 31) & ~31)); + FINISH_ACCEL(); +} + +/* Subsequent XAA indirect CPU-to-screen color expansion and indirect + * image write. This is called once for each scanline. + */ +void radeon_subsequent_scanline_mmio(struct fb_info *info, unsigned long *src) +{ + struct radeonfb_info *rinfo = info->par; + int left = rinfo->scanline_words; + volatile unsigned long *d; + ACCEL_PREAMBLE(); + --rinfo->scanline_h; + while(left) + { + if (left <= 8) + { + /* Last scanline - finish write to DATA_LAST */ + if (rinfo->scanline_h == 0) + { + BEGIN_ACCEL(left); + /* Unrolling doesn't improve performance */ + for(d = ADDRREG(HOST_DATA_LAST) - (left - 1); left; --left) + *d++ = *src++; + return; + } + else + { + BEGIN_ACCEL(left); + /* Unrolling doesn't improve performance */ + for(d = ADDRREG(HOST_DATA7) - (left - 1); left; --left) + *d++ = *src++; + } + } + else + { + BEGIN_ACCEL(8); + /* Unrolling doesn't improve performance */ + d = ADDRREG(HOST_DATA0); + *d++ = *src++; + *d++ = *src++; + *d++ = *src++; + *d++ = *src++; + *d++ = *src++; + *d++ = *src++; + *d++ = *src++; + *d++ = *src++; + left -= 8; + } + } + FINISH_ACCEL(); +} + +/* Setup for XAA indirect image write */ +void radeon_setup_for_scanline_image_write_mmio(struct fb_info *info, int rop, unsigned int planemask, + int trans_color, int bpp) +{ + struct radeonfb_info *rinfo = info->par; + + ACCEL_PREAMBLE(); + rinfo->scanline_bpp = bpp; + /* Save for later clipping */ + rinfo->dp_gui_master_cntl_clip = (rinfo->dp_gui_master_cntl + | GMC_DST_CLIPPING | GMC_BRUSH_NONE | GMC_SRC_DATATYPE_COLOR | RADEON_ROP[rop].rop + | GMC_BYTE_MSB_TO_LSB | DP_SRC_SOURCE_HOST_DATA); + if (rinfo->big_endian) + { + BEGIN_ACCEL(3); + if (bpp == 16) + OUT_ACCEL_REG(RBBM_GUICNTL, HOST_DATA_SWAP_16BIT); + else if (bpp == 32) + OUT_ACCEL_REG(RBBM_GUICNTL, HOST_DATA_SWAP_32BIT); + else + OUT_ACCEL_REG(RBBM_GUICNTL, HOST_DATA_SWAP_NONE); + } + else + BEGIN_ACCEL(2); + OUT_ACCEL_REG(DP_GUI_MASTER_CNTL, rinfo->dp_gui_master_cntl_clip); + OUT_ACCEL_REG(DP_WRITE_MSK, planemask); + FINISH_ACCEL(); + rinfo->trans_color = trans_color; + if (trans_color != -1) + radeon_set_transparency_mmio(rinfo, trans_color); +} + +/* Subsequent XAA indirect image write. This is only called once for each rectangle. */ +void radeon_subsequent_scanline_image_write_rect_mmio(struct fb_info *info, int x, int y, int w, int h, int skipleft) +{ + struct radeonfb_info *rinfo = info->par; + int shift = 0; /* 32bpp */ + ACCEL_PREAMBLE(); + if (rinfo->bpp == 8) + shift = 3; + else if (rinfo->bpp == 16) + shift = 1; + rinfo->scanline_h = h; + rinfo->scanline_words = (w * rinfo->scanline_bpp + 31) >> 5; +#ifdef RADEON_TILING + BEGIN_ACCEL(5); + OUT_ACCEL_REG(DST_PITCH_OFFSET, rinfo->dst_pitch_offset + | ((rinfo->tilingEnabled && (y <= info->var.yres_virtual)) ? DST_TILE_MACRO : 0)); +#else + BEGIN_ACCEL(4); +#endif + OUT_ACCEL_REG(SC_TOP_LEFT, (y << 16) | ((x+skipleft) & 0xffff)); + OUT_ACCEL_REG(SC_BOTTOM_RIGHT, ((y+h) << 16) | ((x+w) & 0xffff)); + OUT_ACCEL_REG(DST_Y_X, (y << 16) | (x & 0xffff)); + /* Have to pad the width here and use clipping engine */ + OUT_ACCEL_REG(DST_HEIGHT_WIDTH, (h << 16) | ((w + shift) & ~shift)); + FINISH_ACCEL(); +} + +/* Set up the clipping rectangle */ +void radeon_set_clipping_rectangle_mmio(struct fb_info *info, int xa, int ya, int xb, int yb) +{ + struct radeonfb_info *rinfo = info->par; + + unsigned long tmp1 = 0; + unsigned long tmp2 = 0; + ACCEL_PREAMBLE(); + if (xa < 0) + { + tmp1 = (-xa) & 0x3fff; + tmp1 |= SC_SIGN_MASK_LO; + } + else + tmp1 = xa; + if (ya < 0) + { + tmp1 |= (((-ya) & 0x3fff) << 16); + tmp1 |= SC_SIGN_MASK_HI; + } + else + tmp1 |= (ya << 16); + xb++; yb++; + if (xb < 0) + { + tmp2 = (-xb) & 0x3fff; + tmp2 |= SC_SIGN_MASK_LO; + } + else + tmp2 = xb; + if (yb < 0) + { + tmp2 |= (((-yb) & 0x3fff) << 16); + tmp2 |= SC_SIGN_MASK_HI; + } + else + tmp2 |= (yb << 16); + BEGIN_ACCEL(3); + OUT_ACCEL_REG(DP_GUI_MASTER_CNTL, (rinfo->dp_gui_master_cntl_clip | GMC_DST_CLIPPING)); + OUT_ACCEL_REG(SC_TOP_LEFT, tmp1); + OUT_ACCEL_REG(SC_BOTTOM_RIGHT, tmp2); + FINISH_ACCEL(); + if (rinfo->trans_color != -1) + radeon_set_transparency_mmio(rinfo, rinfo->trans_color); +} + +/* Disable the clipping rectangle */ +void radeon_disable_clipping_mmio(struct fb_info *info) +{ + struct radeonfb_info *rinfo = info->par; + + ACCEL_PREAMBLE(); + BEGIN_ACCEL(3); + OUT_ACCEL_REG(DP_GUI_MASTER_CNTL, rinfo->dp_gui_master_cntl_clip); + OUT_ACCEL_REG(SC_TOP_LEFT, 0); + OUT_ACCEL_REG(SC_BOTTOM_RIGHT, (DEFAULT_SC_RIGHT_MAX | DEFAULT_SC_BOTTOM_MAX)); + FINISH_ACCEL(); + if (rinfo->trans_color != -1) + radeon_set_transparency_mmio(rinfo, rinfo->trans_color); +} + +#if 0 + +/* Change surfaces + The idea here is to only set up front buffer as tiled, and back/depth buffer when needed. + Everything else is left as untiled. This means we need to use eplicit src/dst pitch control + when blitting, based on the src/target address, and can no longer use a default offset. + But OTOH we don't need to dynamically change surfaces (for xv for instance), and some + ugly offset / fb reservation (cursor) is gone. And as a bonus, everything actually works... + All surface addresses are relative to MC_FB_LOCATION + */ +void RADEONChangeSurfaces(struct fb_info *info) +{ + struct radeonfb_info *rinfo = info->par; + int cpp = rinfo->bpp >> 3; + /* depth/front/back pitch must be identical (and the same as displayWidth) */ + int width_bytes = info->var.xres_virtual * cpp; + int bufferSize = (((((info->var.yres_virtual + 15) & ~15) * width_bytes) + RADEON_BUFFER_ALIGN) & ~RADEON_BUFFER_ALIGN); + unsigned int depth_pattern, color_pattern, swap_pattern, surf_info; + if (rinfo->big_endian) + { + switch(rinfo->bpp) + { + case 16: + swap_pattern = SURF_AP0_SWP_16BPP | SURF_AP1_SWP_16BPP; + break; + case 32: + swap_pattern = SURF_AP0_SWP_32BPP | SURF_AP1_SWP_32BPP; + break; + default: + swap_pattern = 0; + } + } + else + swap_pattern = 0; + if (rinfo->family < CHIP_FAMILY_R200) + { + color_pattern = SURF_TILE_COLOR_MACRO; + if (cpp == 2) + depth_pattern = SURF_TILE_DEPTH_16BPP; + else + depth_pattern = SURF_TILE_DEPTH_32BPP; + } + else if (rinfo->family >= CHIP_FAMILY_R300) + { + color_pattern = R300_SURF_TILE_COLOR_MACRO; + if (cpp == 2) + depth_pattern = R300_SURF_TILE_COLOR_MACRO; + else + depth_pattern = R300_SURF_TILE_COLOR_MACRO | R300_SURF_TILE_DEPTH_32BPP; + } + else + { + color_pattern = R200_SURF_TILE_COLOR_MACRO; + if (cpp == 2) + depth_pattern = R200_SURF_TILE_DEPTH_16BPP; + else + depth_pattern = R200_SURF_TILE_DEPTH_32BPP; + } + /* we don't need anything like WaitForFifo, no? */ +#ifdef RADEON_TILING + if (rinfo->tilingEnabled) + { + if (rinfo->family >= CHIP_FAMILY_R300) + surf_info = swap_pattern | (width_bytes / 8) | color_pattern; + else + surf_info = swap_pattern | (width_bytes / 16) | color_pattern; + } + else +#endif + surf_info = 0; + OUTREG(SURFACE0_INFO, surf_info); + OUTREG(SURFACE0_LOWER_BOUND, 0); + OUTREG(SURFACE0_UPPER_BOUND, bufferSize - 1); +} + +#endif + +/* The FIFO has 64 slots. This routines waits until at least `entries' + * of these slots are empty. + */ +void radeon_wait_for_fifo_function(struct radeonfb_info *rinfo, int entries) +{ + int i; + while(1) + { + for(i = 0; i < RADEON_TIMEOUT; i++) + { + rinfo->fifo_slots = INREG(RBBM_STATUS) & RBBM_FIFOCNT_MASK; + if (rinfo->fifo_slots >= entries) + return; + } + RADEONEngineReset(rinfo); + RADEONEngineRestore(rinfo); + } +} + +/* Flush all dirty data in the Pixel Cache to memory */ +void radeon_engine_flush(struct radeonfb_info *rinfo) +{ + int i; + OUTREGP(RB2D_DSTCACHE_CTLSTAT, RB2D_DC_FLUSH_ALL, ~RB2D_DC_FLUSH_ALL); + for(i = 0; i < RADEON_TIMEOUT; i++) + { + if (!(INREG(RB2D_DSTCACHE_CTLSTAT) & RB2D_DC_BUSY)) + break; + } +} + +/* Reset graphics card to known state */ +void radeon_engine_reset(struct radeonfb_info *rinfo) +{ + unsigned long clock_cntl_index; + unsigned long mclk_cntl; + unsigned long rbbm_soft_reset; + unsigned long host_path_cntl; + RADEONEngineFlush(rinfo); + clock_cntl_index = INREG(CLOCK_CNTL_INDEX); + /* Some ASICs have bugs with dynamic-on feature, which are + * ASIC-version dependent, so we force all blocks on for now + */ + if (rinfo->has_CRTC2) + { + unsigned long tmp; + tmp = INPLL(SCLK_CNTL); + OUTPLL(SCLK_CNTL, ((tmp & ~DYN_STOP_LAT_MASK) | CP_MAX_DYN_STOP_LAT | SCLK_FORCEON_MASK)); + if (rinfo->family == CHIP_FAMILY_RV200) + { + tmp = INPLL(SCLK_MORE_CNTL); + OUTPLL(SCLK_MORE_CNTL, tmp | SCLK_MORE_FORCEON); + } + } + mclk_cntl = INPLL(MCLK_CNTL); + OUTPLL(MCLK_CNTL, (mclk_cntl | FORCEON_MCLKA | FORCEON_MCLKB + | FORCEON_YCLKA | FORCEON_YCLKB | FORCEON_MC | FORCEON_AIC)); + /* Soft resetting HDP thru RBBM_SOFT_RESET register can cause some + * unexpected behaviour on some machines. Here we use + * HOST_PATH_CNTL to reset it. + */ + host_path_cntl = INREG(HOST_PATH_CNTL); + rbbm_soft_reset = INREG(RBBM_SOFT_RESET); + if ((rinfo->family == CHIP_FAMILY_R300) + || (rinfo->family == CHIP_FAMILY_R350) + || (rinfo->family == CHIP_FAMILY_RV350)) + { + unsigned long tmp; + OUTREG(RBBM_SOFT_RESET, (rbbm_soft_reset + | SOFT_RESET_CP | SOFT_RESET_HI | SOFT_RESET_E2)); + INREG(RBBM_SOFT_RESET); + OUTREG(RBBM_SOFT_RESET, 0); + tmp = INREG(RB2D_DSTCACHE_MODE); + OUTREG(RB2D_DSTCACHE_MODE, tmp | (1 << 17)); /* FIXME */ + } + else + { + OUTREG(RBBM_SOFT_RESET, (rbbm_soft_reset | SOFT_RESET_CP + | SOFT_RESET_HI | SOFT_RESET_SE | SOFT_RESET_RE + | SOFT_RESET_PP | SOFT_RESET_E2 | SOFT_RESET_RB)); + INREG(RBBM_SOFT_RESET); + OUTREG(RBBM_SOFT_RESET, (rbbm_soft_reset + & (unsigned long) ~(SOFT_RESET_CP | SOFT_RESET_HI | SOFT_RESET_SE + | SOFT_RESET_RE | SOFT_RESET_PP | SOFT_RESET_E2 | SOFT_RESET_RB))); + INREG(RBBM_SOFT_RESET); + } + OUTREG(HOST_PATH_CNTL, host_path_cntl | HDP_SOFT_RESET); + INREG(HOST_PATH_CNTL); + OUTREG(HOST_PATH_CNTL, host_path_cntl); + if ((rinfo->family != CHIP_FAMILY_R300) + && (rinfo->family != CHIP_FAMILY_R350) + && (rinfo->family != CHIP_FAMILY_RV350)) + OUTREG(RBBM_SOFT_RESET, rbbm_soft_reset); + OUTREG(CLOCK_CNTL_INDEX, clock_cntl_index); + OUTPLL(MCLK_CNTL, mclk_cntl); +} + +/* Restore the acceleration hardware to its previous state */ +void radeon_engine_restore(struct radeonfb_info *rinfo) +{ + BEGIN_ACCEL(1); + /* NOTE: The following RB2D_DSTCACHE_MODE setting will cause the + * R300 to hang. ATI does not see a reason to change it from the + * default BIOS settings (even on non-R300 cards). This setting + * might be removed in future versions of the Radeon driver. + */ + /* Turn of all automatic flushing - we'll do it all */ + if ((rinfo->family != CHIP_FAMILY_R300) + && (rinfo->family != CHIP_FAMILY_R350) + && (rinfo->family != CHIP_FAMILY_RV350)) + OUTREG(RB2D_DSTCACHE_MODE, 0); + rinfo->fb_local_base = INREG(MC_FB_LOCATION) << 16; + BEGIN_ACCEL(3); + OUTREG(DEFAULT_PITCH_OFFSET, rinfo->dst_pitch_offset); + OUTREG(DST_PITCH_OFFSET, rinfo->dst_pitch_offset); + OUTREG(SRC_PITCH_OFFSET, rinfo->dst_pitch_offset); + BEGIN_ACCEL(1); + if (rinfo->big_endian) + OUTREGP(DP_DATATYPE, HOST_BIG_ENDIAN_EN, ~HOST_BIG_ENDIAN_EN); + else + OUTREGP(DP_DATATYPE, 0, ~HOST_BIG_ENDIAN_EN); + /* Restore SURFACE_CNTL - only the first head contains valid data */ + OUTREG(SURFACE_CNTL, rinfo->state.surface_cntl); + BEGIN_ACCEL(2); + OUTREG(DEFAULT_SC_TOP_LEFT, 0); + OUTREG(DEFAULT_SC_BOTTOM_RIGHT, (DEFAULT_SC_RIGHT_MAX | DEFAULT_SC_BOTTOM_MAX)); + BEGIN_ACCEL(1); + OUTREG(DP_GUI_MASTER_CNTL, (rinfo->dp_gui_master_cntl | GMC_BRUSH_SOLID_COLOR | GMC_SRC_DATATYPE_COLOR)); + BEGIN_ACCEL(7); + OUTREG(DST_LINE_START, 0); + OUTREG(DST_LINE_END, 0); + OUTREG(DP_BRUSH_FRGD_CLR, 0xffffffff); + OUTREG(DP_BRUSH_BKGD_CLR, 0x00000000); + OUTREG(DP_SRC_FRGD_CLR, 0xffffffff); + OUTREG(DP_SRC_BKGD_CLR, 0x00000000); + OUTREG(DP_WRITE_MSK, 0xffffffff); + RADEONWaitForIdleMMIO(rinfo); +} + +/* Initialize the acceleration hardware */ +void radeon_engine_init(struct radeonfb_info *rinfo) +{ + unsigned long temp; + OUTREG(RB3D_CNTL, 0); + RADEONEngineReset(rinfo); + temp = radeon_get_dstbpp(rinfo->depth); +#ifdef RADEON_TILING + rinfo->dp_gui_master_cntl = ((temp << GMC_DST_DATATYPE_SHIFT) | GMC_CLR_CMP_CNTL_DIS | GMC_DST_PITCH_OFFSET_CNTL); +#else + rinfo->dp_gui_master_cntl = ((temp << GMC_DST_DATATYPE_SHIFT) | GMC_CLR_CMP_CNTL_DIS); +#endif + RADEONEngineRestore(rinfo); +} + diff --git a/radeon/radeon_base.c b/radeon/radeon_base.c index 0003bf1..61b0e06 100644 --- a/radeon/radeon_base.c +++ b/radeon/radeon_base.c @@ -57,6 +57,7 @@ #include "radeonfb.h" #include "edid.h" #include "ati_ids.h" +#include "exceptions.h" /* for set_ipl() */ #ifdef DRIVER_IN_ROM extern void run_bios(struct radeonfb_info *rinfo); @@ -894,7 +895,7 @@ int radeonfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) return 0; } -int radeonfb_ioctl(uint32_t cmd, uint32_t arg, struct fb_info *info) +int radeonfb_ioctl(unsigned int cmd, unsigned long arg, struct fb_info *info) { struct radeonfb_info *rinfo = info->par; uint32_t tmp; @@ -1067,8 +1068,9 @@ int radeonfb_blank(int blank, struct fb_info *info) } static int radeon_setcolreg(unsigned regno, unsigned red, unsigned green, - unsigned blue, unsigned transp, struct radeonfb_info *rinfo) + unsigned blue, unsigned transp, struct fb_info *info) { + struct radeonfb_info *rinfo = info->par; uint32_t pindex; if (regno > 255) return 1; @@ -1110,8 +1112,8 @@ static int radeon_setcolreg(unsigned regno, unsigned red, unsigned green, return 0; } -int32_t radeonfb_setcolreg(uint32_t regno, uint32_t red, uint32_t green, - uint32_t blue, uint32_t transp, struct fb_info *info) +int radeonfb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, struct fb_info *info) { struct radeonfb_info *rinfo = info->par; uint32_t dac_cntl2, vclk_cntl = 0; @@ -1131,7 +1133,7 @@ int32_t radeonfb_setcolreg(uint32_t regno, uint32_t red, uint32_t green, OUTREG(DAC_CNTL2, dac_cntl2); } } - rc = radeon_setcolreg(regno, red, green, blue, transp, rinfo); + rc = radeon_setcolreg(regno, red, green, blue, transp, info); if (!rinfo->asleep && rinfo->is_mobility) OUTPLL(VCLK_ECP_CNTL, vclk_cntl); return rc; @@ -1260,15 +1262,15 @@ static void radeon_timer_func(void) { struct fb_info *info = info_fvdi; struct radeonfb_info *rinfo = info->par; - static int32_t start_timer; struct fb_var_screeninfo var; uint32_t x, y; int chg, disp; +#ifdef FIXME_LATER + static int32_t start_timer; /* delayed LVDS panel power up/down */ if (rinfo->lvds_timer) { -#ifdef FIXME_LATER if (!start_timer) start_timer = *_hz_200; @@ -1278,10 +1280,10 @@ static void radeon_timer_func(void) radeon_engine_idle(); OUTREG(LVDS_GEN_CNTL, rinfo->pending_lvds_gen_cntl); } -#endif } else start_timer = 0; +#endif if (rinfo->RenderCallback != NULL) rinfo->RenderCallback(rinfo); @@ -1311,25 +1313,14 @@ static void radeon_timer_func(void) if ((info->var.xres_virtual != info->var.xres) || (info->var.yres_virtual != info->var.yres)) { -#ifdef __mcoldfire__ - asm volatile ( - " clr.l -(SP)\n\t" - " move.l D0,-(SP)\n\t" - " move.w SR,D0\n\t" - " move.l D0,4(SP)\n\t" - " or.l #0x700,D0\n\t" /* disable interrupts */ - " move.w D0,SR\n\t" - " move.l (SP)+,D0\n\t" ); -#else - asm volatile ( - " move.w SR,-(SP)\n\t" - " or.w #0x700,SR\n\t" ); /* disable interrupts */ -#endif + int ipl; + ipl = set_ipl(0); + chg = 0; x = info->var.xoffset; y = info->var.yoffset; - if (((x + info->var.xres) < info->var.xres_virtual) - && (rinfo->cursor_x >= (info->var.xres - 8))) + + if (((x + info->var.xres) < info->var.xres_virtual) && (rinfo->cursor_x >= (info->var.xres - 8))) { x += 8; chg = 1; @@ -1339,8 +1330,7 @@ static void radeon_timer_func(void) x -= 8; chg = 1; } - if (((y + info->var.yres) < info->var.yres_virtual) - && (rinfo->cursor_y >= (info->var.yres - 8))) + if (((y + info->var.yres) < info->var.yres_virtual) && (rinfo->cursor_y >= (info->var.yres - 8))) { y += 8; chg = 1; @@ -1350,6 +1340,7 @@ static void radeon_timer_func(void) y -= 8; chg = 1; } + if (chg) { memcpy(&var, &info->var, sizeof(struct fb_var_screeninfo)); @@ -1357,22 +1348,12 @@ static void radeon_timer_func(void) var.yoffset = y; disp = rinfo->cursor_show; if (disp) - RADEONHideCursor(info); + info->fbops->HideCursor(info); fb_pan_display(info,&var); if (disp) - RADEONShowCursor(info); + info->fbops->ShowCursor(info); } -#ifdef __mcoldfire__ - asm volatile ( - " move.l D0,-(SP)\n\t" - " move.l 4(SP),D0\n\t" - " move.w D0,SR\n\t" - " move.l (SP)+,D0\n\t" - " addq.l #4,SP\n\t" ); -#else - asm volatile ( - " move.w (SP)+,SR\n\r" ); -#endif + set_ipl(ipl); } } @@ -1553,14 +1534,20 @@ int radeonfb_set_par(struct fb_info *info) struct radeonfb_info *rinfo = info->par; struct fb_var_screeninfo *mode = &info->var; struct radeon_regs *newmode; - int hTotal, vTotal, hSyncStart, hSyncEnd, hSyncPol, vSyncStart, vSyncEnd, vSyncPol, cSync; + int hTotal, vTotal, hSyncStart, hSyncEnd, vSyncStart, vSyncEnd; + // FIXME: int hSyncPol; this is not used anywhere + // FIXME: int vSyncPol; this is not used anywhere + // FIXME: int cSync; this is not used anywhere static uint8_t hsync_adj_tab[] = {0, 0x12, 9, 9, 6, 5}; static uint8_t hsync_fudge_fp[] = {2, 2, 0, 0, 5, 5}; uint32_t sync, h_sync_pol, v_sync_pol, dotClock, pixClock; int i, freq; int format = 0; int nopllcalc = 0; - int hsync_start, hsync_fudge, bytpp, hsync_wid, vsync_wid; + int hsync_start; + int hsync_fudge; + // int bytpp; FIXME: this doesn't seem to be used anywhere + int hsync_wid, vsync_wid; int primary_mon = PRIMARY_MONITOR(rinfo); int depth = var_to_depth(mode); int use_rmx = 0; @@ -1632,17 +1619,20 @@ int radeonfb_set_par(struct fb_info *info) vsync_wid = 1; else if (vsync_wid > 0x1f) /* max */ vsync_wid = 0x1f; - hSyncPol = mode->sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1; - vSyncPol = mode->sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1; - cSync = mode->sync & FB_SYNC_COMP_HIGH_ACT ? (1 << 4) : 0; + // FIXME: this doesn't seem to be used anywhere hSyncPol = mode->sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1; + // FIXME: this doesn't seem to be used anywhere vSyncPol = mode->sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1; + // FIXME: this doesn't seem to be used anywhere cSync = mode->sync & FB_SYNC_COMP_HIGH_ACT ? (1 << 4) : 0; format = radeon_get_dstbpp(depth); - bytpp = mode->bits_per_pixel >> 3; + // FIXME: this doesn't seem to be used anywhere bytpp = mode->bits_per_pixel >> 3; + if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) hsync_fudge = hsync_fudge_fp[format-1]; else hsync_fudge = hsync_adj_tab[format-1]; + if (mode->vmode & FB_VMODE_DOUBLE) hsync_fudge = 0; /* todo: need adjust */ + hsync_start = hSyncStart - 8 + hsync_fudge; newmode->crtc_gen_cntl = CRTC_EXT_DISP_EN | CRTC_EN | (format << 8); if (mode->vmode & FB_VMODE_DOUBLE) @@ -1815,47 +1805,47 @@ static void radeonfb_check_modes(struct fb_info *info, struct mode_option *resol static struct fb_ops radeonfb_ops = { .fb_check_var = radeonfb_check_var, - .fb_setcolreg = radeonfb_setcolreg, .fb_set_par = radeonfb_set_par, + .fb_setcolreg = radeonfb_setcolreg, .fb_pan_display = radeonfb_pan_display, .fb_blank = radeonfb_blank, .fb_sync = radeonfb_sync, .fb_ioctl = radeonfb_ioctl, .fb_check_modes = radeonfb_check_modes, - .SetupForSolidFill = RADEONSetupForSolidFillMMIO, - .SubsequentSolidFillRect = RADEONSubsequentSolidFillRectMMIO, - .SetupForSolidLine = RADEONSetupForSolidLineMMIO, - .SubsequentSolidHorVertLine = RADEONSubsequentSolidHorVertLineMMIO, - .SubsequentSolidTwoPointLine = RADEONSubsequentSolidTwoPointLineMMIO, - .SetupForDashedLine = RADEONSetupForDashedLineMMIO, - .SubsequentDashedTwoPointLine = RADEONSubsequentDashedTwoPointLineMMIO, - .SetupForScreenToScreenCopy = RADEONSetupForScreenToScreenCopyMMIO, - .SubsequentScreenToScreenCopy = RADEONSubsequentScreenToScreenCopyMMIO, - .ScreenToScreenCopy = RADEONScreenToScreenCopyMMIO, - .SetupForMono8x8PatternFill = RADEONSetupForMono8x8PatternFillMMIO, - .SubsequentMono8x8PatternFillRect = RADEONSubsequentMono8x8PatternFillRectMMIO, - .SetupForScanlineCPUToScreenColorExpandFill = RADEONSetupForScanlineCPUToScreenColorExpandFillMMIO, - .SubsequentScanlineCPUToScreenColorExpandFill = RADEONSubsequentScanlineCPUToScreenColorExpandFillMMIO, - .SubsequentScanline = RADEONSubsequentScanlineMMIO, - .SetupForScanlineImageWrite = RADEONSetupForScanlineImageWriteMMIO, - .SubsequentScanlineImageWriteRect = RADEONSubsequentScanlineImageWriteRectMMIO, - .SetClippingRectangle = RADEONSetClippingRectangleMMIO, - .DisableClipping = RADEONDisableClippingMMIO, + .SetupForSolidFill = radeon_setup_for_solid_fill, + .SubsequentSolidFillRect = radeon_subsequent_solid_fill_rect_mmio, + .SetupForSolidLine = radeon_setup_for_solid_line_mmio, + .SubsequentSolidHorVertLine = radeon_subsequent_solid_hor_vert_line_mmio, + .SubsequentSolidTwoPointLine = radeon_subsequent_solid_two_point_line_mmio, + .SetupForDashedLine = radeon_setup_for_dashed_line_mmio, + .SubsequentDashedTwoPointLine = radeon_subsequent_dashed_two_point_line_mmio, + .SetupForScreenToScreenCopy = radeon_setup_for_screen_to_screen_copy_mmio, + .SubsequentScreenToScreenCopy = radeon_subsequent_screen_to_screen_copy_mmio, + .ScreenToScreenCopy = radeon_screen_to_screen_copy_mmio, + .SetupForMono8x8PatternFill = radeon_setup_for_mono_8x8_pattern_fill_mmio, + .SubsequentMono8x8PatternFillRect = radeon_subsequent_mono_8x8_pattern_fill_rect_mmio, + .SetupForScanlineCPUToScreenColorExpandFill = radeon_setup_for_scanline_cpu_to_screen_color_expand_fill_mmio, + .SubsequentScanlineCPUToScreenColorExpandFill = radeon_subsequent_scanline_cpu_to_screen_color_expand_fill_mmio, + .SubsequentScanline = radeon_subsequent_scanline_mmio, + .SetupForScanlineImageWrite = radeon_setup_for_scanline_image_write_mmio, + .SubsequentScanlineImageWriteRect = radeon_subsequent_scanline_image_write_rect_mmio, + .SetClippingRectangle = radeon_set_clipping_rectangle_mmio, + .DisableClipping = radeon_disable_clipping_mmio, #ifdef RADEON_RENDER - .SetupForCPUToScreenAlphaTexture = RADEONSetupForCPUToScreenAlphaTextureMMIO, - .SetupForCPUToScreenTexture = RADEONSetupForCPUToScreenTextureMMIO, - .SubsequentCPUToScreenTexture = RADEONSubsequentCPUToScreenTextureMMIO, + .SetupForCPUToScreenAlphaTexture = radeon_setup_for_cpu_to_screen_alpha_texture_mmio, + .SetupForCPUToScreenTexture = radeon_setup_for_cpu_to_screen_texture_mmio, + .SubsequentCPUToScreenTexture = radeon_subsequent_cpu_to_screen_texture_mmio, #else .SetupForCPUToScreenAlphaTexture = NULL, .SetupForCPUToScreenTexture = NULL, .SubsequentCPUToScreenTexture = NULL, #endif /* RADEON_RENDER */ - .SetCursorColors = RADEONSetCursorColors, - .SetCursorPosition = RADEONSetCursorPosition, - .LoadCursorImage = RADEONLoadCursorImage, - .HideCursor = RADEONHideCursor, - .ShowCursor = RADEONShowCursor, - .CursorInit = RADEONCursorInit, + .SetCursorColors = radeon_set_cursor_colors, + .SetCursorPosition = radeon_set_cursor_position, + .LoadCursorImage = radeon_load_cursor_image, + .HideCursor = radeon_hide_cursor, + .ShowCursor = radeon_show_cursor, + .CursorInit = radeon_cursor_init, .WaitVbl = radeon_wait_vbl, }; diff --git a/radeon/radeon_cursor.c b/radeon/radeon_cursor.c new file mode 100644 index 0000000..61d8cba --- /dev/null +++ b/radeon/radeon_cursor.c @@ -0,0 +1,312 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_cursor.c,v 1.26 2003/11/10 18:41:22 tsi Exp $ */ +/* + * Copyright 2000 ATI Technologies Inc., Markham, Ontario, and + * VA Linux Systems Inc., Fremont, California. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR + * THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/* + * Authors: + * Kevin E. Martin + * Rickard E. Faith + * + * References: + * + * !!!! FIXME !!!! + * RAGE 128 VR/ RAGE 128 GL Register Reference Manual (Technical + * Reference Manual P/N RRG-G04100-C Rev. 0.04), ATI Technologies: April + * 1999. + * + * RAGE 128 Software Development Manual (Technical Reference Manual P/N + * SDK-G04000 Rev. 0.01), ATI Technologies: June 1999. + * + */ + +#include "radeonfb.h" + +#define CURSOR_WIDTH 64 +#define CURSOR_HEIGHT 64 + +/* + * The cursor bits are always 32bpp. On MSBFirst buses, + * configure byte swapping to swap 32 bit units when writing + * the cursor image. Byte swapping must always be returned + * to its previous value before returning. + */ +#define CURSOR_SWAPPING_DECL_MMIO +#define CURSOR_SWAPPING_DECL unsigned long __surface_cntl=0; +#define CURSOR_SWAPPING_START() \ + if(rinfo->big_endian) \ + OUTREG(SURFACE_CNTL, \ + ((__surface_cntl = INREG(SURFACE_CNTL)) | \ + NONSURF_AP0_SWP_32BPP) & \ + ~NONSURF_AP0_SWP_16BPP); +#define CURSOR_SWAPPING_END() \ + if(rinfo->big_endian) \ + (OUTREG(SURFACE_CNTL, __surface_cntl)); + +/* Set cursor foreground and background colors */ +void radeon_set_cursor_colors(struct fb_info *info, int bg, int fg) +{ + struct radeonfb_info *rinfo = info->par; + unsigned long *pixels = (unsigned long *)(pointer)((unsigned long)rinfo->fb_base+rinfo->cursor_start); + int pixel, i; + CURSOR_SWAPPING_DECL_MMIO + CURSOR_SWAPPING_DECL +// DPRINTVALHEX("radeonfb: RADEONSetCursorColors: cursor_start ",rinfo->cursor_start); +// DPRINT("\r\n"); + fg |= 0xff000000; + bg |= 0xff000000; + /* Don't recolour the image if we don't have to. */ + if(fg == rinfo->cursor_fg && bg == rinfo->cursor_bg) + return; + CURSOR_SWAPPING_START(); + /* Note: We assume that the pixels are either fully opaque or fully + * transparent, so we won't premultiply them, and we can just + * check for non-zero pixel values; those are either fg or bg + */ + for(i = 0; i < CURSOR_WIDTH * CURSOR_HEIGHT; i++, pixels++) + if((pixel = *pixels)) + *pixels = (pixel == rinfo->cursor_fg) ? fg : bg; + CURSOR_SWAPPING_END(); + rinfo->cursor_fg = fg; + rinfo->cursor_bg = bg; +} + +/* Set cursor position to (x,y) with offset into cursor bitmap at + * (xorigin,yorigin) + */ +void radeon_set_cursor_position(struct fb_info *info, int x, int y) +{ + struct radeonfb_info *rinfo = info->par; + struct fb_var_screeninfo *mode = &info->var; + int xorigin = 0; + int yorigin = 0; + if(mode->vmode & FB_VMODE_DOUBLE) + y <<= 1; + if(x < 0) + xorigin = 1 - x; + if(y < 0) + yorigin = 1 - y; +// DPRINTVALHEX("radeonfb: RADEONSetCursorPosition: cursor_start ",rinfo->cursor_start); +// DPRINTVAL(" x ",x); +// DPRINTVAL(" y ",y); +// DPRINT("\r\n"); + OUTREG(CUR_HORZ_VERT_OFF, (CUR_LOCK | (xorigin << 16) | yorigin)); + OUTREG(CUR_HORZ_VERT_POSN, (CUR_LOCK | ((xorigin ? 0 : x) << 16) | (yorigin ? 0 : y))); + OUTREG(CUR_OFFSET, rinfo->cursor_start + yorigin * 256); + rinfo->cursor_x = (unsigned long)x; + if(mode->vmode & FB_VMODE_DOUBLE) + rinfo->cursor_y = (unsigned long)y >> 1; + else + rinfo->cursor_y = (unsigned long)y; +} + +/* Copy cursor image from `image' to video memory. RADEONSetCursorPosition + * will be called after this, so we can ignore xorigin and yorigin. + */ +void radeon_load_cursor_image(struct fb_info *info, unsigned short *mask, unsigned short *data, int zoom) +{ + struct radeonfb_info *rinfo = info->par; + unsigned long *d = (unsigned long *)(pointer)((unsigned long)rinfo->fb_base+rinfo->cursor_start); + unsigned long save = 0; + unsigned short chunk, mchunk; + unsigned long i, j, k; + CURSOR_SWAPPING_DECL +// DPRINTVALHEX("radeonfb: RADEONLoadCursorImage: cursor_start ",rinfo->cursor_start); +// DPRINT("\r\n"); + save = INREG(CRTC_GEN_CNTL) & ~(unsigned long) (3 << 20); + save |= (unsigned long) (2 << 20); + OUTREG(CRTC_GEN_CNTL, save & (unsigned long)~CRTC_CUR_EN); + /* + * Convert the bitmap to ARGB32. + */ + CURSOR_SWAPPING_START(); +#define ARGB_PER_CHUNK (8 * sizeof (chunk)) + switch(zoom) + { + case 1: + default: + for(i = 0; i < CURSOR_HEIGHT; i++) + { + if(i < 16) + { + mchunk = *mask++; + chunk = *data++; + } + else + mchunk = chunk = 0; + for(j = 0; j < CURSOR_WIDTH / ARGB_PER_CHUNK; j++) + { + for(k = 0; k < ARGB_PER_CHUNK; k++, chunk <<= 1, mchunk <<= 1) + { + if(mchunk & 0x8000) + { + if(chunk & 0x8000) + *d++ = 0xff000000; /* Black, fully opaque. */ + else + *d++ = 0xffffffff; /* White, fully opaque. */ + } + else + *d++ = 0x00000000; /* White/Black, fully transparent. */ + } + } + } + break; + case 2: + for(i = 0; i < CURSOR_HEIGHT; i++) + { + if(i < 16*2) + { + mchunk = *mask; + chunk = *data; + if((i & 1) == 1) + { + mask++; + data++; + } + } + else + mchunk = chunk = 0; + for(j = 0; j < CURSOR_WIDTH / ARGB_PER_CHUNK; j+=2) + { + for(k = 0; k < ARGB_PER_CHUNK; k++, chunk <<= 1, mchunk <<= 1) + { + if(mchunk & 0x8000) + { + if(chunk & 0x8000) + { + *d++ = 0xff000000; /* Black, fully opaque. */ + *d++ = 0xff000000; + } + else + { + *d++ = 0xffffffff; /* White, fully opaque. */ + *d++ = 0xffffffff; + } + } + else + { + *d++ = 0x00000000; /* White/Black, fully transparent. */ + *d++ = 0x00000000; + } + } + } + } + break; + case 4: + for(i = 0; i < CURSOR_HEIGHT; i++) + { + if(i < 16*4) + { + mchunk = *mask; + chunk = *data; + if((i & 3) == 3) + { + mask++; + data++; + } + } + else + mchunk = chunk = 0; + for(j = 0; j < CURSOR_WIDTH / ARGB_PER_CHUNK; j+=4) + { + for(k = 0; k < ARGB_PER_CHUNK; k++, chunk <<= 1, mchunk <<= 1) + { + if(mchunk & 0x8000) + { + if(chunk & 0x8000) + { + *d++ = 0xff000000; /* Black, fully opaque. */ + *d++ = 0xff000000; + *d++ = 0xff000000; + *d++ = 0xff000000; + } + else + { + *d++ = 0xffffffff; /* White, fully opaque. */ + *d++ = 0xffffffff; + *d++ = 0xffffffff; + *d++ = 0xffffffff; + } + } + else + { + *d++ = 0x00000000; /* White/Black, fully transparent. */ + *d++ = 0x00000000; + *d++ = 0x00000000; + *d++ = 0x00000000; + } + } + } + } + break; + } + CURSOR_SWAPPING_END(); + rinfo->cursor_bg = 0xffffffff; /* White, fully opaque. */ + rinfo->cursor_fg = 0xff000000; /* Black, fully opaque. */ + OUTREG(CRTC_GEN_CNTL, save); +} + +/* Hide hardware cursor. */ +void radeon_hide_cursor(struct fb_info *info) +{ + struct radeonfb_info *rinfo = info->par; +// DPRINT("radeonfb: RADEONHideCursor\r\n"); + OUTREGP(CRTC_GEN_CNTL, 0, ~CRTC_CUR_EN); + rinfo->cursor_show = 0; +} + +/* Show hardware cursor. */ +void radeon_show_cursor(struct fb_info *info) +{ + struct radeonfb_info *rinfo = info->par; +// DPRINT("radeonfb: RADEONShowCursor\r\n"); + OUTREGP(CRTC_GEN_CNTL, CRTC_CUR_EN, ~CRTC_CUR_EN); + rinfo->cursor_show = 1; +} + +/* Initialize hardware cursor support. */ +long radeon_cursor_init(struct fb_info *info) +{ + struct radeonfb_info *rinfo = info->par; + int size_bytes = CURSOR_WIDTH * 4 * CURSOR_HEIGHT; + unsigned long fbarea = offscreen_alloc(rinfo->info, size_bytes+256); +// DPRINTVALHEX("radeonfb: RADEONCursorInit: fbarea ",fbarea); + if(!fbarea) + rinfo->cursor_start = 0; + else + { + unsigned short data[16], mask[16]; + memset(data, 0, sizeof(data)); + memset(mask, 0, sizeof(data)); + rinfo->cursor_start = RADEON_ALIGN(fbarea - (unsigned long)rinfo->fb_base, 256); + rinfo->cursor_end = rinfo->cursor_start + size_bytes; + RADEONLoadCursorImage(info, mask, data, 1); + } +// DPRINTVALHEX(" cursor_start ",rinfo->cursor_start); +// DPRINT("\r\n"); + return(rinfo->cursor_start ? fbarea : 0); +}