162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci/* 462306a36Sopenharmony_ci * ATI Mach64 Hardware Acceleration 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/delay.h> 862306a36Sopenharmony_ci#include <asm/unaligned.h> 962306a36Sopenharmony_ci#include <linux/fb.h> 1062306a36Sopenharmony_ci#include <video/mach64.h> 1162306a36Sopenharmony_ci#include "atyfb.h" 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci /* 1462306a36Sopenharmony_ci * Generic Mach64 routines 1562306a36Sopenharmony_ci */ 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci/* this is for DMA GUI engine! work in progress */ 1862306a36Sopenharmony_citypedef struct { 1962306a36Sopenharmony_ci u32 frame_buf_offset; 2062306a36Sopenharmony_ci u32 system_mem_addr; 2162306a36Sopenharmony_ci u32 command; 2262306a36Sopenharmony_ci u32 reserved; 2362306a36Sopenharmony_ci} BM_DESCRIPTOR_ENTRY; 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#define LAST_DESCRIPTOR (1 << 31) 2662306a36Sopenharmony_ci#define SYSTEM_TO_FRAME_BUFFER 0 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic u32 rotation24bpp(u32 dx, u32 direction) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci u32 rotation; 3162306a36Sopenharmony_ci if (direction & DST_X_LEFT_TO_RIGHT) { 3262306a36Sopenharmony_ci rotation = (dx / 4) % 6; 3362306a36Sopenharmony_ci } else { 3462306a36Sopenharmony_ci rotation = ((dx + 2) / 4) % 6; 3562306a36Sopenharmony_ci } 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci return ((rotation << 8) | DST_24_ROTATION_ENABLE); 3862306a36Sopenharmony_ci} 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_civoid aty_reset_engine(struct atyfb_par *par) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci /* reset engine */ 4362306a36Sopenharmony_ci aty_st_le32(GEN_TEST_CNTL, 4462306a36Sopenharmony_ci aty_ld_le32(GEN_TEST_CNTL, par) & 4562306a36Sopenharmony_ci ~(GUI_ENGINE_ENABLE | HWCURSOR_ENABLE), par); 4662306a36Sopenharmony_ci /* enable engine */ 4762306a36Sopenharmony_ci aty_st_le32(GEN_TEST_CNTL, 4862306a36Sopenharmony_ci aty_ld_le32(GEN_TEST_CNTL, par) | GUI_ENGINE_ENABLE, par); 4962306a36Sopenharmony_ci /* ensure engine is not locked up by clearing any FIFO or */ 5062306a36Sopenharmony_ci /* HOST errors */ 5162306a36Sopenharmony_ci aty_st_le32(BUS_CNTL, 5262306a36Sopenharmony_ci aty_ld_le32(BUS_CNTL, par) | BUS_HOST_ERR_ACK | BUS_FIFO_ERR_ACK, par); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci par->fifo_space = 0; 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistatic void reset_GTC_3D_engine(const struct atyfb_par *par) 5862306a36Sopenharmony_ci{ 5962306a36Sopenharmony_ci aty_st_le32(SCALE_3D_CNTL, 0xc0, par); 6062306a36Sopenharmony_ci mdelay(GTC_3D_RESET_DELAY); 6162306a36Sopenharmony_ci aty_st_le32(SETUP_CNTL, 0x00, par); 6262306a36Sopenharmony_ci mdelay(GTC_3D_RESET_DELAY); 6362306a36Sopenharmony_ci aty_st_le32(SCALE_3D_CNTL, 0x00, par); 6462306a36Sopenharmony_ci mdelay(GTC_3D_RESET_DELAY); 6562306a36Sopenharmony_ci} 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_civoid aty_init_engine(struct atyfb_par *par, struct fb_info *info) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci u32 pitch_value; 7062306a36Sopenharmony_ci u32 vxres; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci /* determine modal information from global mode structure */ 7362306a36Sopenharmony_ci pitch_value = info->fix.line_length / (info->var.bits_per_pixel / 8); 7462306a36Sopenharmony_ci vxres = info->var.xres_virtual; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci if (info->var.bits_per_pixel == 24) { 7762306a36Sopenharmony_ci /* In 24 bpp, the engine is in 8 bpp - this requires that all */ 7862306a36Sopenharmony_ci /* horizontal coordinates and widths must be adjusted */ 7962306a36Sopenharmony_ci pitch_value *= 3; 8062306a36Sopenharmony_ci vxres *= 3; 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci /* On GTC (RagePro), we need to reset the 3D engine before */ 8462306a36Sopenharmony_ci if (M64_HAS(RESET_3D)) 8562306a36Sopenharmony_ci reset_GTC_3D_engine(par); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci /* Reset engine, enable, and clear any engine errors */ 8862306a36Sopenharmony_ci aty_reset_engine(par); 8962306a36Sopenharmony_ci /* Ensure that vga page pointers are set to zero - the upper */ 9062306a36Sopenharmony_ci /* page pointers are set to 1 to handle overflows in the */ 9162306a36Sopenharmony_ci /* lower page */ 9262306a36Sopenharmony_ci aty_st_le32(MEM_VGA_WP_SEL, 0x00010000, par); 9362306a36Sopenharmony_ci aty_st_le32(MEM_VGA_RP_SEL, 0x00010000, par); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci /* ---- Setup standard engine context ---- */ 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci /* All GUI registers here are FIFOed - therefore, wait for */ 9862306a36Sopenharmony_ci /* the appropriate number of empty FIFO entries */ 9962306a36Sopenharmony_ci wait_for_fifo(14, par); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci /* enable all registers to be loaded for context loads */ 10262306a36Sopenharmony_ci aty_st_le32(CONTEXT_MASK, 0xFFFFFFFF, par); 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci /* set destination pitch to modal pitch, set offset to zero */ 10562306a36Sopenharmony_ci aty_st_le32(DST_OFF_PITCH, (pitch_value / 8) << 22, par); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci /* zero these registers (set them to a known state) */ 10862306a36Sopenharmony_ci aty_st_le32(DST_Y_X, 0, par); 10962306a36Sopenharmony_ci aty_st_le32(DST_HEIGHT, 0, par); 11062306a36Sopenharmony_ci aty_st_le32(DST_BRES_ERR, 0, par); 11162306a36Sopenharmony_ci aty_st_le32(DST_BRES_INC, 0, par); 11262306a36Sopenharmony_ci aty_st_le32(DST_BRES_DEC, 0, par); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci /* set destination drawing attributes */ 11562306a36Sopenharmony_ci aty_st_le32(DST_CNTL, DST_LAST_PEL | DST_Y_TOP_TO_BOTTOM | 11662306a36Sopenharmony_ci DST_X_LEFT_TO_RIGHT, par); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci /* set source pitch to modal pitch, set offset to zero */ 11962306a36Sopenharmony_ci aty_st_le32(SRC_OFF_PITCH, (pitch_value / 8) << 22, par); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci /* set these registers to a known state */ 12262306a36Sopenharmony_ci aty_st_le32(SRC_Y_X, 0, par); 12362306a36Sopenharmony_ci aty_st_le32(SRC_HEIGHT1_WIDTH1, 1, par); 12462306a36Sopenharmony_ci aty_st_le32(SRC_Y_X_START, 0, par); 12562306a36Sopenharmony_ci aty_st_le32(SRC_HEIGHT2_WIDTH2, 1, par); 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci /* set source pixel retrieving attributes */ 12862306a36Sopenharmony_ci aty_st_le32(SRC_CNTL, SRC_LINE_X_LEFT_TO_RIGHT, par); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci /* set host attributes */ 13162306a36Sopenharmony_ci wait_for_fifo(13, par); 13262306a36Sopenharmony_ci aty_st_le32(HOST_CNTL, HOST_BYTE_ALIGN, par); 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci /* set pattern attributes */ 13562306a36Sopenharmony_ci aty_st_le32(PAT_REG0, 0, par); 13662306a36Sopenharmony_ci aty_st_le32(PAT_REG1, 0, par); 13762306a36Sopenharmony_ci aty_st_le32(PAT_CNTL, 0, par); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci /* set scissors to modal size */ 14062306a36Sopenharmony_ci aty_st_le32(SC_LEFT, 0, par); 14162306a36Sopenharmony_ci aty_st_le32(SC_TOP, 0, par); 14262306a36Sopenharmony_ci aty_st_le32(SC_BOTTOM, par->crtc.vyres - 1, par); 14362306a36Sopenharmony_ci aty_st_le32(SC_RIGHT, vxres - 1, par); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci /* set background color to minimum value (usually BLACK) */ 14662306a36Sopenharmony_ci aty_st_le32(DP_BKGD_CLR, 0, par); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci /* set foreground color to maximum value (usually WHITE) */ 14962306a36Sopenharmony_ci aty_st_le32(DP_FRGD_CLR, 0xFFFFFFFF, par); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci /* set write mask to effect all pixel bits */ 15262306a36Sopenharmony_ci aty_st_le32(DP_WRITE_MASK, 0xFFFFFFFF, par); 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci /* set foreground mix to overpaint and background mix to */ 15562306a36Sopenharmony_ci /* no-effect */ 15662306a36Sopenharmony_ci aty_st_le32(DP_MIX, FRGD_MIX_S | BKGD_MIX_D, par); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci /* set primary source pixel channel to foreground color */ 15962306a36Sopenharmony_ci /* register */ 16062306a36Sopenharmony_ci aty_st_le32(DP_SRC, FRGD_SRC_FRGD_CLR, par); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci /* set compare functionality to false (no-effect on */ 16362306a36Sopenharmony_ci /* destination) */ 16462306a36Sopenharmony_ci wait_for_fifo(3, par); 16562306a36Sopenharmony_ci aty_st_le32(CLR_CMP_CLR, 0, par); 16662306a36Sopenharmony_ci aty_st_le32(CLR_CMP_MASK, 0xFFFFFFFF, par); 16762306a36Sopenharmony_ci aty_st_le32(CLR_CMP_CNTL, 0, par); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci /* set pixel depth */ 17062306a36Sopenharmony_ci wait_for_fifo(2, par); 17162306a36Sopenharmony_ci aty_st_le32(DP_PIX_WIDTH, par->crtc.dp_pix_width, par); 17262306a36Sopenharmony_ci aty_st_le32(DP_CHAIN_MASK, par->crtc.dp_chain_mask, par); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci wait_for_fifo(5, par); 17562306a36Sopenharmony_ci aty_st_le32(SCALE_3D_CNTL, 0, par); 17662306a36Sopenharmony_ci aty_st_le32(Z_CNTL, 0, par); 17762306a36Sopenharmony_ci aty_st_le32(CRTC_INT_CNTL, aty_ld_le32(CRTC_INT_CNTL, par) & ~0x20, 17862306a36Sopenharmony_ci par); 17962306a36Sopenharmony_ci aty_st_le32(GUI_TRAJ_CNTL, 0x100023, par); 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci /* insure engine is idle before leaving */ 18262306a36Sopenharmony_ci wait_for_idle(par); 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci /* 18662306a36Sopenharmony_ci * Accelerated functions 18762306a36Sopenharmony_ci */ 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistatic inline void draw_rect(s16 x, s16 y, u16 width, u16 height, 19062306a36Sopenharmony_ci struct atyfb_par *par) 19162306a36Sopenharmony_ci{ 19262306a36Sopenharmony_ci /* perform rectangle fill */ 19362306a36Sopenharmony_ci wait_for_fifo(2, par); 19462306a36Sopenharmony_ci aty_st_le32(DST_Y_X, (x << 16) | y, par); 19562306a36Sopenharmony_ci aty_st_le32(DST_HEIGHT_WIDTH, (width << 16) | height, par); 19662306a36Sopenharmony_ci par->blitter_may_be_busy = 1; 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_civoid atyfb_copyarea(struct fb_info *info, const struct fb_copyarea *area) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci struct atyfb_par *par = (struct atyfb_par *) info->par; 20262306a36Sopenharmony_ci u32 dy = area->dy, sy = area->sy, direction = DST_LAST_PEL; 20362306a36Sopenharmony_ci u32 sx = area->sx, dx = area->dx, width = area->width, rotation = 0; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci if (par->asleep) 20662306a36Sopenharmony_ci return; 20762306a36Sopenharmony_ci if (!area->width || !area->height) 20862306a36Sopenharmony_ci return; 20962306a36Sopenharmony_ci if (!par->accel_flags) { 21062306a36Sopenharmony_ci cfb_copyarea(info, area); 21162306a36Sopenharmony_ci return; 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci if (info->var.bits_per_pixel == 24) { 21562306a36Sopenharmony_ci /* In 24 bpp, the engine is in 8 bpp - this requires that all */ 21662306a36Sopenharmony_ci /* horizontal coordinates and widths must be adjusted */ 21762306a36Sopenharmony_ci sx *= 3; 21862306a36Sopenharmony_ci dx *= 3; 21962306a36Sopenharmony_ci width *= 3; 22062306a36Sopenharmony_ci } 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci if (area->sy < area->dy) { 22362306a36Sopenharmony_ci dy += area->height - 1; 22462306a36Sopenharmony_ci sy += area->height - 1; 22562306a36Sopenharmony_ci } else 22662306a36Sopenharmony_ci direction |= DST_Y_TOP_TO_BOTTOM; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci if (sx < dx) { 22962306a36Sopenharmony_ci dx += width - 1; 23062306a36Sopenharmony_ci sx += width - 1; 23162306a36Sopenharmony_ci } else 23262306a36Sopenharmony_ci direction |= DST_X_LEFT_TO_RIGHT; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci if (info->var.bits_per_pixel == 24) { 23562306a36Sopenharmony_ci rotation = rotation24bpp(dx, direction); 23662306a36Sopenharmony_ci } 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci wait_for_fifo(5, par); 23962306a36Sopenharmony_ci aty_st_le32(DP_PIX_WIDTH, par->crtc.dp_pix_width, par); 24062306a36Sopenharmony_ci aty_st_le32(DP_SRC, FRGD_SRC_BLIT, par); 24162306a36Sopenharmony_ci aty_st_le32(SRC_Y_X, (sx << 16) | sy, par); 24262306a36Sopenharmony_ci aty_st_le32(SRC_HEIGHT1_WIDTH1, (width << 16) | area->height, par); 24362306a36Sopenharmony_ci aty_st_le32(DST_CNTL, direction | rotation, par); 24462306a36Sopenharmony_ci draw_rect(dx, dy, width, area->height, par); 24562306a36Sopenharmony_ci} 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_civoid atyfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci struct atyfb_par *par = (struct atyfb_par *) info->par; 25062306a36Sopenharmony_ci u32 color, dx = rect->dx, width = rect->width, rotation = 0; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci if (par->asleep) 25362306a36Sopenharmony_ci return; 25462306a36Sopenharmony_ci if (!rect->width || !rect->height) 25562306a36Sopenharmony_ci return; 25662306a36Sopenharmony_ci if (!par->accel_flags) { 25762306a36Sopenharmony_ci cfb_fillrect(info, rect); 25862306a36Sopenharmony_ci return; 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci if (info->fix.visual == FB_VISUAL_TRUECOLOR || 26262306a36Sopenharmony_ci info->fix.visual == FB_VISUAL_DIRECTCOLOR) 26362306a36Sopenharmony_ci color = ((u32 *)(info->pseudo_palette))[rect->color]; 26462306a36Sopenharmony_ci else 26562306a36Sopenharmony_ci color = rect->color; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci if (info->var.bits_per_pixel == 24) { 26862306a36Sopenharmony_ci /* In 24 bpp, the engine is in 8 bpp - this requires that all */ 26962306a36Sopenharmony_ci /* horizontal coordinates and widths must be adjusted */ 27062306a36Sopenharmony_ci dx *= 3; 27162306a36Sopenharmony_ci width *= 3; 27262306a36Sopenharmony_ci rotation = rotation24bpp(dx, DST_X_LEFT_TO_RIGHT); 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci wait_for_fifo(4, par); 27662306a36Sopenharmony_ci aty_st_le32(DP_PIX_WIDTH, par->crtc.dp_pix_width, par); 27762306a36Sopenharmony_ci aty_st_le32(DP_FRGD_CLR, color, par); 27862306a36Sopenharmony_ci aty_st_le32(DP_SRC, 27962306a36Sopenharmony_ci BKGD_SRC_BKGD_CLR | FRGD_SRC_FRGD_CLR | MONO_SRC_ONE, 28062306a36Sopenharmony_ci par); 28162306a36Sopenharmony_ci aty_st_le32(DST_CNTL, 28262306a36Sopenharmony_ci DST_LAST_PEL | DST_Y_TOP_TO_BOTTOM | 28362306a36Sopenharmony_ci DST_X_LEFT_TO_RIGHT | rotation, par); 28462306a36Sopenharmony_ci draw_rect(dx, rect->dy, width, rect->height, par); 28562306a36Sopenharmony_ci} 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_civoid atyfb_imageblit(struct fb_info *info, const struct fb_image *image) 28862306a36Sopenharmony_ci{ 28962306a36Sopenharmony_ci struct atyfb_par *par = (struct atyfb_par *) info->par; 29062306a36Sopenharmony_ci u32 src_bytes, dx = image->dx, dy = image->dy, width = image->width; 29162306a36Sopenharmony_ci u32 pix_width, rotation = 0, src, mix; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci if (par->asleep) 29462306a36Sopenharmony_ci return; 29562306a36Sopenharmony_ci if (!image->width || !image->height) 29662306a36Sopenharmony_ci return; 29762306a36Sopenharmony_ci if (!par->accel_flags || 29862306a36Sopenharmony_ci (image->depth != 1 && info->var.bits_per_pixel != image->depth)) { 29962306a36Sopenharmony_ci cfb_imageblit(info, image); 30062306a36Sopenharmony_ci return; 30162306a36Sopenharmony_ci } 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci pix_width = par->crtc.dp_pix_width; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci switch (image->depth) { 30662306a36Sopenharmony_ci case 1: 30762306a36Sopenharmony_ci pix_width &= ~(BYTE_ORDER_MASK | HOST_MASK); 30862306a36Sopenharmony_ci pix_width |= (BYTE_ORDER_MSB_TO_LSB | HOST_1BPP); 30962306a36Sopenharmony_ci break; 31062306a36Sopenharmony_ci case 4: 31162306a36Sopenharmony_ci pix_width &= ~(BYTE_ORDER_MASK | HOST_MASK); 31262306a36Sopenharmony_ci pix_width |= (BYTE_ORDER_MSB_TO_LSB | HOST_4BPP); 31362306a36Sopenharmony_ci break; 31462306a36Sopenharmony_ci case 8: 31562306a36Sopenharmony_ci pix_width &= ~HOST_MASK; 31662306a36Sopenharmony_ci pix_width |= HOST_8BPP; 31762306a36Sopenharmony_ci break; 31862306a36Sopenharmony_ci case 15: 31962306a36Sopenharmony_ci pix_width &= ~HOST_MASK; 32062306a36Sopenharmony_ci pix_width |= HOST_15BPP; 32162306a36Sopenharmony_ci break; 32262306a36Sopenharmony_ci case 16: 32362306a36Sopenharmony_ci pix_width &= ~HOST_MASK; 32462306a36Sopenharmony_ci pix_width |= HOST_16BPP; 32562306a36Sopenharmony_ci break; 32662306a36Sopenharmony_ci case 24: 32762306a36Sopenharmony_ci pix_width &= ~HOST_MASK; 32862306a36Sopenharmony_ci pix_width |= HOST_24BPP; 32962306a36Sopenharmony_ci break; 33062306a36Sopenharmony_ci case 32: 33162306a36Sopenharmony_ci pix_width &= ~HOST_MASK; 33262306a36Sopenharmony_ci pix_width |= HOST_32BPP; 33362306a36Sopenharmony_ci break; 33462306a36Sopenharmony_ci } 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci if (info->var.bits_per_pixel == 24) { 33762306a36Sopenharmony_ci /* In 24 bpp, the engine is in 8 bpp - this requires that all */ 33862306a36Sopenharmony_ci /* horizontal coordinates and widths must be adjusted */ 33962306a36Sopenharmony_ci dx *= 3; 34062306a36Sopenharmony_ci width *= 3; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci rotation = rotation24bpp(dx, DST_X_LEFT_TO_RIGHT); 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci pix_width &= ~DST_MASK; 34562306a36Sopenharmony_ci pix_width |= DST_8BPP; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci /* 34862306a36Sopenharmony_ci * since Rage 3D IIc we have DP_HOST_TRIPLE_EN bit 34962306a36Sopenharmony_ci * this hwaccelerated triple has an issue with not aligned data 35062306a36Sopenharmony_ci */ 35162306a36Sopenharmony_ci if (image->depth == 1 && M64_HAS(HW_TRIPLE) && image->width % 8 == 0) 35262306a36Sopenharmony_ci pix_width |= DP_HOST_TRIPLE_EN; 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci if (image->depth == 1) { 35662306a36Sopenharmony_ci u32 fg, bg; 35762306a36Sopenharmony_ci if (info->fix.visual == FB_VISUAL_TRUECOLOR || 35862306a36Sopenharmony_ci info->fix.visual == FB_VISUAL_DIRECTCOLOR) { 35962306a36Sopenharmony_ci fg = ((u32*)(info->pseudo_palette))[image->fg_color]; 36062306a36Sopenharmony_ci bg = ((u32*)(info->pseudo_palette))[image->bg_color]; 36162306a36Sopenharmony_ci } else { 36262306a36Sopenharmony_ci fg = image->fg_color; 36362306a36Sopenharmony_ci bg = image->bg_color; 36462306a36Sopenharmony_ci } 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci wait_for_fifo(2, par); 36762306a36Sopenharmony_ci aty_st_le32(DP_BKGD_CLR, bg, par); 36862306a36Sopenharmony_ci aty_st_le32(DP_FRGD_CLR, fg, par); 36962306a36Sopenharmony_ci src = MONO_SRC_HOST | FRGD_SRC_FRGD_CLR | BKGD_SRC_BKGD_CLR; 37062306a36Sopenharmony_ci mix = FRGD_MIX_S | BKGD_MIX_S; 37162306a36Sopenharmony_ci } else { 37262306a36Sopenharmony_ci src = MONO_SRC_ONE | FRGD_SRC_HOST; 37362306a36Sopenharmony_ci mix = FRGD_MIX_D_XOR_S | BKGD_MIX_D; 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci wait_for_fifo(5, par); 37762306a36Sopenharmony_ci aty_st_le32(DP_PIX_WIDTH, pix_width, par); 37862306a36Sopenharmony_ci aty_st_le32(DP_MIX, mix, par); 37962306a36Sopenharmony_ci aty_st_le32(DP_SRC, src, par); 38062306a36Sopenharmony_ci aty_st_le32(HOST_CNTL, HOST_BYTE_ALIGN, par); 38162306a36Sopenharmony_ci aty_st_le32(DST_CNTL, DST_Y_TOP_TO_BOTTOM | DST_X_LEFT_TO_RIGHT | rotation, par); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci draw_rect(dx, dy, width, image->height, par); 38462306a36Sopenharmony_ci src_bytes = (((image->width * image->depth) + 7) / 8) * image->height; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci /* manual triple each pixel */ 38762306a36Sopenharmony_ci if (image->depth == 1 && info->var.bits_per_pixel == 24 && !(pix_width & DP_HOST_TRIPLE_EN)) { 38862306a36Sopenharmony_ci int inbit, outbit, mult24, byte_id_in_dword, width; 38962306a36Sopenharmony_ci u8 *pbitmapin = (u8*)image->data, *pbitmapout; 39062306a36Sopenharmony_ci u32 hostdword; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci for (width = image->width, inbit = 7, mult24 = 0; src_bytes; ) { 39362306a36Sopenharmony_ci for (hostdword = 0, pbitmapout = (u8*)&hostdword, byte_id_in_dword = 0; 39462306a36Sopenharmony_ci byte_id_in_dword < 4 && src_bytes; 39562306a36Sopenharmony_ci byte_id_in_dword++, pbitmapout++) { 39662306a36Sopenharmony_ci for (outbit = 7; outbit >= 0; outbit--) { 39762306a36Sopenharmony_ci *pbitmapout |= (((*pbitmapin >> inbit) & 1) << outbit); 39862306a36Sopenharmony_ci mult24++; 39962306a36Sopenharmony_ci /* next bit */ 40062306a36Sopenharmony_ci if (mult24 == 3) { 40162306a36Sopenharmony_ci mult24 = 0; 40262306a36Sopenharmony_ci inbit--; 40362306a36Sopenharmony_ci width--; 40462306a36Sopenharmony_ci } 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci /* next byte */ 40762306a36Sopenharmony_ci if (inbit < 0 || width == 0) { 40862306a36Sopenharmony_ci src_bytes--; 40962306a36Sopenharmony_ci pbitmapin++; 41062306a36Sopenharmony_ci inbit = 7; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci if (width == 0) { 41362306a36Sopenharmony_ci width = image->width; 41462306a36Sopenharmony_ci outbit = 0; 41562306a36Sopenharmony_ci } 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci } 41862306a36Sopenharmony_ci } 41962306a36Sopenharmony_ci wait_for_fifo(1, par); 42062306a36Sopenharmony_ci aty_st_le32(HOST_DATA0, le32_to_cpu(hostdword), par); 42162306a36Sopenharmony_ci } 42262306a36Sopenharmony_ci } else { 42362306a36Sopenharmony_ci u32 *pbitmap, dwords = (src_bytes + 3) / 4; 42462306a36Sopenharmony_ci for (pbitmap = (u32*)(image->data); dwords; dwords--, pbitmap++) { 42562306a36Sopenharmony_ci wait_for_fifo(1, par); 42662306a36Sopenharmony_ci aty_st_le32(HOST_DATA0, get_unaligned_le32(pbitmap), par); 42762306a36Sopenharmony_ci } 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci} 430