18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci 38c2ecf20Sopenharmony_ci/* 48c2ecf20Sopenharmony_ci * ATI Mach64 Hardware Acceleration 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/delay.h> 88c2ecf20Sopenharmony_ci#include <asm/unaligned.h> 98c2ecf20Sopenharmony_ci#include <linux/fb.h> 108c2ecf20Sopenharmony_ci#include <video/mach64.h> 118c2ecf20Sopenharmony_ci#include "atyfb.h" 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci /* 148c2ecf20Sopenharmony_ci * Generic Mach64 routines 158c2ecf20Sopenharmony_ci */ 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci/* this is for DMA GUI engine! work in progress */ 188c2ecf20Sopenharmony_citypedef struct { 198c2ecf20Sopenharmony_ci u32 frame_buf_offset; 208c2ecf20Sopenharmony_ci u32 system_mem_addr; 218c2ecf20Sopenharmony_ci u32 command; 228c2ecf20Sopenharmony_ci u32 reserved; 238c2ecf20Sopenharmony_ci} BM_DESCRIPTOR_ENTRY; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define LAST_DESCRIPTOR (1 << 31) 268c2ecf20Sopenharmony_ci#define SYSTEM_TO_FRAME_BUFFER 0 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic u32 rotation24bpp(u32 dx, u32 direction) 298c2ecf20Sopenharmony_ci{ 308c2ecf20Sopenharmony_ci u32 rotation; 318c2ecf20Sopenharmony_ci if (direction & DST_X_LEFT_TO_RIGHT) { 328c2ecf20Sopenharmony_ci rotation = (dx / 4) % 6; 338c2ecf20Sopenharmony_ci } else { 348c2ecf20Sopenharmony_ci rotation = ((dx + 2) / 4) % 6; 358c2ecf20Sopenharmony_ci } 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci return ((rotation << 8) | DST_24_ROTATION_ENABLE); 388c2ecf20Sopenharmony_ci} 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_civoid aty_reset_engine(struct atyfb_par *par) 418c2ecf20Sopenharmony_ci{ 428c2ecf20Sopenharmony_ci /* reset engine */ 438c2ecf20Sopenharmony_ci aty_st_le32(GEN_TEST_CNTL, 448c2ecf20Sopenharmony_ci aty_ld_le32(GEN_TEST_CNTL, par) & 458c2ecf20Sopenharmony_ci ~(GUI_ENGINE_ENABLE | HWCURSOR_ENABLE), par); 468c2ecf20Sopenharmony_ci /* enable engine */ 478c2ecf20Sopenharmony_ci aty_st_le32(GEN_TEST_CNTL, 488c2ecf20Sopenharmony_ci aty_ld_le32(GEN_TEST_CNTL, par) | GUI_ENGINE_ENABLE, par); 498c2ecf20Sopenharmony_ci /* ensure engine is not locked up by clearing any FIFO or */ 508c2ecf20Sopenharmony_ci /* HOST errors */ 518c2ecf20Sopenharmony_ci aty_st_le32(BUS_CNTL, 528c2ecf20Sopenharmony_ci aty_ld_le32(BUS_CNTL, par) | BUS_HOST_ERR_ACK | BUS_FIFO_ERR_ACK, par); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci par->fifo_space = 0; 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic void reset_GTC_3D_engine(const struct atyfb_par *par) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci aty_st_le32(SCALE_3D_CNTL, 0xc0, par); 608c2ecf20Sopenharmony_ci mdelay(GTC_3D_RESET_DELAY); 618c2ecf20Sopenharmony_ci aty_st_le32(SETUP_CNTL, 0x00, par); 628c2ecf20Sopenharmony_ci mdelay(GTC_3D_RESET_DELAY); 638c2ecf20Sopenharmony_ci aty_st_le32(SCALE_3D_CNTL, 0x00, par); 648c2ecf20Sopenharmony_ci mdelay(GTC_3D_RESET_DELAY); 658c2ecf20Sopenharmony_ci} 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_civoid aty_init_engine(struct atyfb_par *par, struct fb_info *info) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci u32 pitch_value; 708c2ecf20Sopenharmony_ci u32 vxres; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci /* determine modal information from global mode structure */ 738c2ecf20Sopenharmony_ci pitch_value = info->fix.line_length / (info->var.bits_per_pixel / 8); 748c2ecf20Sopenharmony_ci vxres = info->var.xres_virtual; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci if (info->var.bits_per_pixel == 24) { 778c2ecf20Sopenharmony_ci /* In 24 bpp, the engine is in 8 bpp - this requires that all */ 788c2ecf20Sopenharmony_ci /* horizontal coordinates and widths must be adjusted */ 798c2ecf20Sopenharmony_ci pitch_value *= 3; 808c2ecf20Sopenharmony_ci vxres *= 3; 818c2ecf20Sopenharmony_ci } 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci /* On GTC (RagePro), we need to reset the 3D engine before */ 848c2ecf20Sopenharmony_ci if (M64_HAS(RESET_3D)) 858c2ecf20Sopenharmony_ci reset_GTC_3D_engine(par); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci /* Reset engine, enable, and clear any engine errors */ 888c2ecf20Sopenharmony_ci aty_reset_engine(par); 898c2ecf20Sopenharmony_ci /* Ensure that vga page pointers are set to zero - the upper */ 908c2ecf20Sopenharmony_ci /* page pointers are set to 1 to handle overflows in the */ 918c2ecf20Sopenharmony_ci /* lower page */ 928c2ecf20Sopenharmony_ci aty_st_le32(MEM_VGA_WP_SEL, 0x00010000, par); 938c2ecf20Sopenharmony_ci aty_st_le32(MEM_VGA_RP_SEL, 0x00010000, par); 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci /* ---- Setup standard engine context ---- */ 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci /* All GUI registers here are FIFOed - therefore, wait for */ 988c2ecf20Sopenharmony_ci /* the appropriate number of empty FIFO entries */ 998c2ecf20Sopenharmony_ci wait_for_fifo(14, par); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci /* enable all registers to be loaded for context loads */ 1028c2ecf20Sopenharmony_ci aty_st_le32(CONTEXT_MASK, 0xFFFFFFFF, par); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci /* set destination pitch to modal pitch, set offset to zero */ 1058c2ecf20Sopenharmony_ci aty_st_le32(DST_OFF_PITCH, (pitch_value / 8) << 22, par); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci /* zero these registers (set them to a known state) */ 1088c2ecf20Sopenharmony_ci aty_st_le32(DST_Y_X, 0, par); 1098c2ecf20Sopenharmony_ci aty_st_le32(DST_HEIGHT, 0, par); 1108c2ecf20Sopenharmony_ci aty_st_le32(DST_BRES_ERR, 0, par); 1118c2ecf20Sopenharmony_ci aty_st_le32(DST_BRES_INC, 0, par); 1128c2ecf20Sopenharmony_ci aty_st_le32(DST_BRES_DEC, 0, par); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci /* set destination drawing attributes */ 1158c2ecf20Sopenharmony_ci aty_st_le32(DST_CNTL, DST_LAST_PEL | DST_Y_TOP_TO_BOTTOM | 1168c2ecf20Sopenharmony_ci DST_X_LEFT_TO_RIGHT, par); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci /* set source pitch to modal pitch, set offset to zero */ 1198c2ecf20Sopenharmony_ci aty_st_le32(SRC_OFF_PITCH, (pitch_value / 8) << 22, par); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci /* set these registers to a known state */ 1228c2ecf20Sopenharmony_ci aty_st_le32(SRC_Y_X, 0, par); 1238c2ecf20Sopenharmony_ci aty_st_le32(SRC_HEIGHT1_WIDTH1, 1, par); 1248c2ecf20Sopenharmony_ci aty_st_le32(SRC_Y_X_START, 0, par); 1258c2ecf20Sopenharmony_ci aty_st_le32(SRC_HEIGHT2_WIDTH2, 1, par); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci /* set source pixel retrieving attributes */ 1288c2ecf20Sopenharmony_ci aty_st_le32(SRC_CNTL, SRC_LINE_X_LEFT_TO_RIGHT, par); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci /* set host attributes */ 1318c2ecf20Sopenharmony_ci wait_for_fifo(13, par); 1328c2ecf20Sopenharmony_ci aty_st_le32(HOST_CNTL, HOST_BYTE_ALIGN, par); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci /* set pattern attributes */ 1358c2ecf20Sopenharmony_ci aty_st_le32(PAT_REG0, 0, par); 1368c2ecf20Sopenharmony_ci aty_st_le32(PAT_REG1, 0, par); 1378c2ecf20Sopenharmony_ci aty_st_le32(PAT_CNTL, 0, par); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci /* set scissors to modal size */ 1408c2ecf20Sopenharmony_ci aty_st_le32(SC_LEFT, 0, par); 1418c2ecf20Sopenharmony_ci aty_st_le32(SC_TOP, 0, par); 1428c2ecf20Sopenharmony_ci aty_st_le32(SC_BOTTOM, par->crtc.vyres - 1, par); 1438c2ecf20Sopenharmony_ci aty_st_le32(SC_RIGHT, vxres - 1, par); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci /* set background color to minimum value (usually BLACK) */ 1468c2ecf20Sopenharmony_ci aty_st_le32(DP_BKGD_CLR, 0, par); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci /* set foreground color to maximum value (usually WHITE) */ 1498c2ecf20Sopenharmony_ci aty_st_le32(DP_FRGD_CLR, 0xFFFFFFFF, par); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci /* set write mask to effect all pixel bits */ 1528c2ecf20Sopenharmony_ci aty_st_le32(DP_WRITE_MASK, 0xFFFFFFFF, par); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci /* set foreground mix to overpaint and background mix to */ 1558c2ecf20Sopenharmony_ci /* no-effect */ 1568c2ecf20Sopenharmony_ci aty_st_le32(DP_MIX, FRGD_MIX_S | BKGD_MIX_D, par); 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci /* set primary source pixel channel to foreground color */ 1598c2ecf20Sopenharmony_ci /* register */ 1608c2ecf20Sopenharmony_ci aty_st_le32(DP_SRC, FRGD_SRC_FRGD_CLR, par); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci /* set compare functionality to false (no-effect on */ 1638c2ecf20Sopenharmony_ci /* destination) */ 1648c2ecf20Sopenharmony_ci wait_for_fifo(3, par); 1658c2ecf20Sopenharmony_ci aty_st_le32(CLR_CMP_CLR, 0, par); 1668c2ecf20Sopenharmony_ci aty_st_le32(CLR_CMP_MASK, 0xFFFFFFFF, par); 1678c2ecf20Sopenharmony_ci aty_st_le32(CLR_CMP_CNTL, 0, par); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci /* set pixel depth */ 1708c2ecf20Sopenharmony_ci wait_for_fifo(2, par); 1718c2ecf20Sopenharmony_ci aty_st_le32(DP_PIX_WIDTH, par->crtc.dp_pix_width, par); 1728c2ecf20Sopenharmony_ci aty_st_le32(DP_CHAIN_MASK, par->crtc.dp_chain_mask, par); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci wait_for_fifo(5, par); 1758c2ecf20Sopenharmony_ci aty_st_le32(SCALE_3D_CNTL, 0, par); 1768c2ecf20Sopenharmony_ci aty_st_le32(Z_CNTL, 0, par); 1778c2ecf20Sopenharmony_ci aty_st_le32(CRTC_INT_CNTL, aty_ld_le32(CRTC_INT_CNTL, par) & ~0x20, 1788c2ecf20Sopenharmony_ci par); 1798c2ecf20Sopenharmony_ci aty_st_le32(GUI_TRAJ_CNTL, 0x100023, par); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci /* insure engine is idle before leaving */ 1828c2ecf20Sopenharmony_ci wait_for_idle(par); 1838c2ecf20Sopenharmony_ci} 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci /* 1868c2ecf20Sopenharmony_ci * Accelerated functions 1878c2ecf20Sopenharmony_ci */ 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic inline void draw_rect(s16 x, s16 y, u16 width, u16 height, 1908c2ecf20Sopenharmony_ci struct atyfb_par *par) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci /* perform rectangle fill */ 1938c2ecf20Sopenharmony_ci wait_for_fifo(2, par); 1948c2ecf20Sopenharmony_ci aty_st_le32(DST_Y_X, (x << 16) | y, par); 1958c2ecf20Sopenharmony_ci aty_st_le32(DST_HEIGHT_WIDTH, (width << 16) | height, par); 1968c2ecf20Sopenharmony_ci par->blitter_may_be_busy = 1; 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_civoid atyfb_copyarea(struct fb_info *info, const struct fb_copyarea *area) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci struct atyfb_par *par = (struct atyfb_par *) info->par; 2028c2ecf20Sopenharmony_ci u32 dy = area->dy, sy = area->sy, direction = DST_LAST_PEL; 2038c2ecf20Sopenharmony_ci u32 sx = area->sx, dx = area->dx, width = area->width, rotation = 0; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci if (par->asleep) 2068c2ecf20Sopenharmony_ci return; 2078c2ecf20Sopenharmony_ci if (!area->width || !area->height) 2088c2ecf20Sopenharmony_ci return; 2098c2ecf20Sopenharmony_ci if (!par->accel_flags) { 2108c2ecf20Sopenharmony_ci cfb_copyarea(info, area); 2118c2ecf20Sopenharmony_ci return; 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci if (info->var.bits_per_pixel == 24) { 2158c2ecf20Sopenharmony_ci /* In 24 bpp, the engine is in 8 bpp - this requires that all */ 2168c2ecf20Sopenharmony_ci /* horizontal coordinates and widths must be adjusted */ 2178c2ecf20Sopenharmony_ci sx *= 3; 2188c2ecf20Sopenharmony_ci dx *= 3; 2198c2ecf20Sopenharmony_ci width *= 3; 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci if (area->sy < area->dy) { 2238c2ecf20Sopenharmony_ci dy += area->height - 1; 2248c2ecf20Sopenharmony_ci sy += area->height - 1; 2258c2ecf20Sopenharmony_ci } else 2268c2ecf20Sopenharmony_ci direction |= DST_Y_TOP_TO_BOTTOM; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci if (sx < dx) { 2298c2ecf20Sopenharmony_ci dx += width - 1; 2308c2ecf20Sopenharmony_ci sx += width - 1; 2318c2ecf20Sopenharmony_ci } else 2328c2ecf20Sopenharmony_ci direction |= DST_X_LEFT_TO_RIGHT; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci if (info->var.bits_per_pixel == 24) { 2358c2ecf20Sopenharmony_ci rotation = rotation24bpp(dx, direction); 2368c2ecf20Sopenharmony_ci } 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci wait_for_fifo(5, par); 2398c2ecf20Sopenharmony_ci aty_st_le32(DP_PIX_WIDTH, par->crtc.dp_pix_width, par); 2408c2ecf20Sopenharmony_ci aty_st_le32(DP_SRC, FRGD_SRC_BLIT, par); 2418c2ecf20Sopenharmony_ci aty_st_le32(SRC_Y_X, (sx << 16) | sy, par); 2428c2ecf20Sopenharmony_ci aty_st_le32(SRC_HEIGHT1_WIDTH1, (width << 16) | area->height, par); 2438c2ecf20Sopenharmony_ci aty_st_le32(DST_CNTL, direction | rotation, par); 2448c2ecf20Sopenharmony_ci draw_rect(dx, dy, width, area->height, par); 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_civoid atyfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci struct atyfb_par *par = (struct atyfb_par *) info->par; 2508c2ecf20Sopenharmony_ci u32 color, dx = rect->dx, width = rect->width, rotation = 0; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci if (par->asleep) 2538c2ecf20Sopenharmony_ci return; 2548c2ecf20Sopenharmony_ci if (!rect->width || !rect->height) 2558c2ecf20Sopenharmony_ci return; 2568c2ecf20Sopenharmony_ci if (!par->accel_flags) { 2578c2ecf20Sopenharmony_ci cfb_fillrect(info, rect); 2588c2ecf20Sopenharmony_ci return; 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci if (info->fix.visual == FB_VISUAL_TRUECOLOR || 2628c2ecf20Sopenharmony_ci info->fix.visual == FB_VISUAL_DIRECTCOLOR) 2638c2ecf20Sopenharmony_ci color = ((u32 *)(info->pseudo_palette))[rect->color]; 2648c2ecf20Sopenharmony_ci else 2658c2ecf20Sopenharmony_ci color = rect->color; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci if (info->var.bits_per_pixel == 24) { 2688c2ecf20Sopenharmony_ci /* In 24 bpp, the engine is in 8 bpp - this requires that all */ 2698c2ecf20Sopenharmony_ci /* horizontal coordinates and widths must be adjusted */ 2708c2ecf20Sopenharmony_ci dx *= 3; 2718c2ecf20Sopenharmony_ci width *= 3; 2728c2ecf20Sopenharmony_ci rotation = rotation24bpp(dx, DST_X_LEFT_TO_RIGHT); 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci wait_for_fifo(4, par); 2768c2ecf20Sopenharmony_ci aty_st_le32(DP_PIX_WIDTH, par->crtc.dp_pix_width, par); 2778c2ecf20Sopenharmony_ci aty_st_le32(DP_FRGD_CLR, color, par); 2788c2ecf20Sopenharmony_ci aty_st_le32(DP_SRC, 2798c2ecf20Sopenharmony_ci BKGD_SRC_BKGD_CLR | FRGD_SRC_FRGD_CLR | MONO_SRC_ONE, 2808c2ecf20Sopenharmony_ci par); 2818c2ecf20Sopenharmony_ci aty_st_le32(DST_CNTL, 2828c2ecf20Sopenharmony_ci DST_LAST_PEL | DST_Y_TOP_TO_BOTTOM | 2838c2ecf20Sopenharmony_ci DST_X_LEFT_TO_RIGHT | rotation, par); 2848c2ecf20Sopenharmony_ci draw_rect(dx, rect->dy, width, rect->height, par); 2858c2ecf20Sopenharmony_ci} 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_civoid atyfb_imageblit(struct fb_info *info, const struct fb_image *image) 2888c2ecf20Sopenharmony_ci{ 2898c2ecf20Sopenharmony_ci struct atyfb_par *par = (struct atyfb_par *) info->par; 2908c2ecf20Sopenharmony_ci u32 src_bytes, dx = image->dx, dy = image->dy, width = image->width; 2918c2ecf20Sopenharmony_ci u32 pix_width, rotation = 0, src, mix; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci if (par->asleep) 2948c2ecf20Sopenharmony_ci return; 2958c2ecf20Sopenharmony_ci if (!image->width || !image->height) 2968c2ecf20Sopenharmony_ci return; 2978c2ecf20Sopenharmony_ci if (!par->accel_flags || 2988c2ecf20Sopenharmony_ci (image->depth != 1 && info->var.bits_per_pixel != image->depth)) { 2998c2ecf20Sopenharmony_ci cfb_imageblit(info, image); 3008c2ecf20Sopenharmony_ci return; 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci pix_width = par->crtc.dp_pix_width; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci switch (image->depth) { 3068c2ecf20Sopenharmony_ci case 1: 3078c2ecf20Sopenharmony_ci pix_width &= ~(BYTE_ORDER_MASK | HOST_MASK); 3088c2ecf20Sopenharmony_ci pix_width |= (BYTE_ORDER_MSB_TO_LSB | HOST_1BPP); 3098c2ecf20Sopenharmony_ci break; 3108c2ecf20Sopenharmony_ci case 4: 3118c2ecf20Sopenharmony_ci pix_width &= ~(BYTE_ORDER_MASK | HOST_MASK); 3128c2ecf20Sopenharmony_ci pix_width |= (BYTE_ORDER_MSB_TO_LSB | HOST_4BPP); 3138c2ecf20Sopenharmony_ci break; 3148c2ecf20Sopenharmony_ci case 8: 3158c2ecf20Sopenharmony_ci pix_width &= ~HOST_MASK; 3168c2ecf20Sopenharmony_ci pix_width |= HOST_8BPP; 3178c2ecf20Sopenharmony_ci break; 3188c2ecf20Sopenharmony_ci case 15: 3198c2ecf20Sopenharmony_ci pix_width &= ~HOST_MASK; 3208c2ecf20Sopenharmony_ci pix_width |= HOST_15BPP; 3218c2ecf20Sopenharmony_ci break; 3228c2ecf20Sopenharmony_ci case 16: 3238c2ecf20Sopenharmony_ci pix_width &= ~HOST_MASK; 3248c2ecf20Sopenharmony_ci pix_width |= HOST_16BPP; 3258c2ecf20Sopenharmony_ci break; 3268c2ecf20Sopenharmony_ci case 24: 3278c2ecf20Sopenharmony_ci pix_width &= ~HOST_MASK; 3288c2ecf20Sopenharmony_ci pix_width |= HOST_24BPP; 3298c2ecf20Sopenharmony_ci break; 3308c2ecf20Sopenharmony_ci case 32: 3318c2ecf20Sopenharmony_ci pix_width &= ~HOST_MASK; 3328c2ecf20Sopenharmony_ci pix_width |= HOST_32BPP; 3338c2ecf20Sopenharmony_ci break; 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci if (info->var.bits_per_pixel == 24) { 3378c2ecf20Sopenharmony_ci /* In 24 bpp, the engine is in 8 bpp - this requires that all */ 3388c2ecf20Sopenharmony_ci /* horizontal coordinates and widths must be adjusted */ 3398c2ecf20Sopenharmony_ci dx *= 3; 3408c2ecf20Sopenharmony_ci width *= 3; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci rotation = rotation24bpp(dx, DST_X_LEFT_TO_RIGHT); 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci pix_width &= ~DST_MASK; 3458c2ecf20Sopenharmony_ci pix_width |= DST_8BPP; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci /* 3488c2ecf20Sopenharmony_ci * since Rage 3D IIc we have DP_HOST_TRIPLE_EN bit 3498c2ecf20Sopenharmony_ci * this hwaccelerated triple has an issue with not aligned data 3508c2ecf20Sopenharmony_ci */ 3518c2ecf20Sopenharmony_ci if (image->depth == 1 && M64_HAS(HW_TRIPLE) && image->width % 8 == 0) 3528c2ecf20Sopenharmony_ci pix_width |= DP_HOST_TRIPLE_EN; 3538c2ecf20Sopenharmony_ci } 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci if (image->depth == 1) { 3568c2ecf20Sopenharmony_ci u32 fg, bg; 3578c2ecf20Sopenharmony_ci if (info->fix.visual == FB_VISUAL_TRUECOLOR || 3588c2ecf20Sopenharmony_ci info->fix.visual == FB_VISUAL_DIRECTCOLOR) { 3598c2ecf20Sopenharmony_ci fg = ((u32*)(info->pseudo_palette))[image->fg_color]; 3608c2ecf20Sopenharmony_ci bg = ((u32*)(info->pseudo_palette))[image->bg_color]; 3618c2ecf20Sopenharmony_ci } else { 3628c2ecf20Sopenharmony_ci fg = image->fg_color; 3638c2ecf20Sopenharmony_ci bg = image->bg_color; 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci wait_for_fifo(2, par); 3678c2ecf20Sopenharmony_ci aty_st_le32(DP_BKGD_CLR, bg, par); 3688c2ecf20Sopenharmony_ci aty_st_le32(DP_FRGD_CLR, fg, par); 3698c2ecf20Sopenharmony_ci src = MONO_SRC_HOST | FRGD_SRC_FRGD_CLR | BKGD_SRC_BKGD_CLR; 3708c2ecf20Sopenharmony_ci mix = FRGD_MIX_S | BKGD_MIX_S; 3718c2ecf20Sopenharmony_ci } else { 3728c2ecf20Sopenharmony_ci src = MONO_SRC_ONE | FRGD_SRC_HOST; 3738c2ecf20Sopenharmony_ci mix = FRGD_MIX_D_XOR_S | BKGD_MIX_D; 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci wait_for_fifo(5, par); 3778c2ecf20Sopenharmony_ci aty_st_le32(DP_PIX_WIDTH, pix_width, par); 3788c2ecf20Sopenharmony_ci aty_st_le32(DP_MIX, mix, par); 3798c2ecf20Sopenharmony_ci aty_st_le32(DP_SRC, src, par); 3808c2ecf20Sopenharmony_ci aty_st_le32(HOST_CNTL, HOST_BYTE_ALIGN, par); 3818c2ecf20Sopenharmony_ci aty_st_le32(DST_CNTL, DST_Y_TOP_TO_BOTTOM | DST_X_LEFT_TO_RIGHT | rotation, par); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci draw_rect(dx, dy, width, image->height, par); 3848c2ecf20Sopenharmony_ci src_bytes = (((image->width * image->depth) + 7) / 8) * image->height; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci /* manual triple each pixel */ 3878c2ecf20Sopenharmony_ci if (image->depth == 1 && info->var.bits_per_pixel == 24 && !(pix_width & DP_HOST_TRIPLE_EN)) { 3888c2ecf20Sopenharmony_ci int inbit, outbit, mult24, byte_id_in_dword, width; 3898c2ecf20Sopenharmony_ci u8 *pbitmapin = (u8*)image->data, *pbitmapout; 3908c2ecf20Sopenharmony_ci u32 hostdword; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci for (width = image->width, inbit = 7, mult24 = 0; src_bytes; ) { 3938c2ecf20Sopenharmony_ci for (hostdword = 0, pbitmapout = (u8*)&hostdword, byte_id_in_dword = 0; 3948c2ecf20Sopenharmony_ci byte_id_in_dword < 4 && src_bytes; 3958c2ecf20Sopenharmony_ci byte_id_in_dword++, pbitmapout++) { 3968c2ecf20Sopenharmony_ci for (outbit = 7; outbit >= 0; outbit--) { 3978c2ecf20Sopenharmony_ci *pbitmapout |= (((*pbitmapin >> inbit) & 1) << outbit); 3988c2ecf20Sopenharmony_ci mult24++; 3998c2ecf20Sopenharmony_ci /* next bit */ 4008c2ecf20Sopenharmony_ci if (mult24 == 3) { 4018c2ecf20Sopenharmony_ci mult24 = 0; 4028c2ecf20Sopenharmony_ci inbit--; 4038c2ecf20Sopenharmony_ci width--; 4048c2ecf20Sopenharmony_ci } 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci /* next byte */ 4078c2ecf20Sopenharmony_ci if (inbit < 0 || width == 0) { 4088c2ecf20Sopenharmony_ci src_bytes--; 4098c2ecf20Sopenharmony_ci pbitmapin++; 4108c2ecf20Sopenharmony_ci inbit = 7; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci if (width == 0) { 4138c2ecf20Sopenharmony_ci width = image->width; 4148c2ecf20Sopenharmony_ci outbit = 0; 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci } 4188c2ecf20Sopenharmony_ci } 4198c2ecf20Sopenharmony_ci wait_for_fifo(1, par); 4208c2ecf20Sopenharmony_ci aty_st_le32(HOST_DATA0, le32_to_cpu(hostdword), par); 4218c2ecf20Sopenharmony_ci } 4228c2ecf20Sopenharmony_ci } else { 4238c2ecf20Sopenharmony_ci u32 *pbitmap, dwords = (src_bytes + 3) / 4; 4248c2ecf20Sopenharmony_ci for (pbitmap = (u32*)(image->data); dwords; dwords--, pbitmap++) { 4258c2ecf20Sopenharmony_ci wait_for_fifo(1, par); 4268c2ecf20Sopenharmony_ci aty_st_le32(HOST_DATA0, get_unaligned_le32(pbitmap), par); 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci } 4298c2ecf20Sopenharmony_ci} 430