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