| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 |  | 
 | 2 | /* | 
 | 3 |  *  ATI Mach64 Hardware Acceleration | 
 | 4 |  */ | 
 | 5 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6 | #include <linux/delay.h> | 
 | 7 | #include <linux/fb.h> | 
 | 8 | #include <video/mach64.h> | 
 | 9 | #include "atyfb.h" | 
 | 10 |  | 
 | 11 |     /* | 
 | 12 |      *  Generic Mach64 routines | 
 | 13 |      */ | 
 | 14 |  | 
 | 15 | /* this is for DMA GUI engine! work in progress */ | 
 | 16 | typedef struct { | 
 | 17 | 	u32 frame_buf_offset; | 
 | 18 | 	u32 system_mem_addr; | 
 | 19 | 	u32 command; | 
 | 20 | 	u32 reserved; | 
 | 21 | } BM_DESCRIPTOR_ENTRY; | 
 | 22 |  | 
 | 23 | #define LAST_DESCRIPTOR (1 << 31) | 
 | 24 | #define SYSTEM_TO_FRAME_BUFFER 0 | 
 | 25 |  | 
 | 26 | static u32 rotation24bpp(u32 dx, u32 direction) | 
 | 27 | { | 
 | 28 | 	u32 rotation; | 
 | 29 | 	if (direction & DST_X_LEFT_TO_RIGHT) { | 
 | 30 | 		rotation = (dx / 4) % 6; | 
 | 31 | 	} else { | 
 | 32 | 		rotation = ((dx + 2) / 4) % 6; | 
 | 33 | 	} | 
 | 34 |  | 
 | 35 | 	return ((rotation << 8) | DST_24_ROTATION_ENABLE); | 
 | 36 | } | 
 | 37 |  | 
 | 38 | void aty_reset_engine(const struct atyfb_par *par) | 
 | 39 | { | 
 | 40 | 	/* reset engine */ | 
 | 41 | 	aty_st_le32(GEN_TEST_CNTL, | 
 | 42 | 		aty_ld_le32(GEN_TEST_CNTL, par) & ~GUI_ENGINE_ENABLE, par); | 
 | 43 | 	/* enable engine */ | 
 | 44 | 	aty_st_le32(GEN_TEST_CNTL, | 
 | 45 | 		aty_ld_le32(GEN_TEST_CNTL, par) | GUI_ENGINE_ENABLE, par); | 
 | 46 | 	/* ensure engine is not locked up by clearing any FIFO or */ | 
 | 47 | 	/* HOST errors */ | 
 | 48 | 	aty_st_le32(BUS_CNTL, | 
 | 49 | 		aty_ld_le32(BUS_CNTL, par) | BUS_HOST_ERR_ACK | BUS_FIFO_ERR_ACK, par); | 
 | 50 | } | 
 | 51 |  | 
 | 52 | static void reset_GTC_3D_engine(const struct atyfb_par *par) | 
 | 53 | { | 
 | 54 | 	aty_st_le32(SCALE_3D_CNTL, 0xc0, par); | 
 | 55 | 	mdelay(GTC_3D_RESET_DELAY); | 
 | 56 | 	aty_st_le32(SETUP_CNTL, 0x00, par); | 
 | 57 | 	mdelay(GTC_3D_RESET_DELAY); | 
 | 58 | 	aty_st_le32(SCALE_3D_CNTL, 0x00, par); | 
 | 59 | 	mdelay(GTC_3D_RESET_DELAY); | 
 | 60 | } | 
 | 61 |  | 
 | 62 | void aty_init_engine(struct atyfb_par *par, struct fb_info *info) | 
 | 63 | { | 
 | 64 | 	u32 pitch_value; | 
 | 65 |  | 
 | 66 | 	/* determine modal information from global mode structure */ | 
 | 67 | 	pitch_value = info->var.xres_virtual; | 
 | 68 |  | 
 | 69 | 	if (info->var.bits_per_pixel == 24) { | 
 | 70 | 		/* In 24 bpp, the engine is in 8 bpp - this requires that all */ | 
 | 71 | 		/* horizontal coordinates and widths must be adjusted */ | 
 | 72 | 		pitch_value *= 3; | 
 | 73 | 	} | 
 | 74 |  | 
 | 75 | 	/* On GTC (RagePro), we need to reset the 3D engine before */ | 
 | 76 | 	if (M64_HAS(RESET_3D)) | 
 | 77 | 		reset_GTC_3D_engine(par); | 
 | 78 |  | 
 | 79 | 	/* Reset engine, enable, and clear any engine errors */ | 
 | 80 | 	aty_reset_engine(par); | 
 | 81 | 	/* Ensure that vga page pointers are set to zero - the upper */ | 
 | 82 | 	/* page pointers are set to 1 to handle overflows in the */ | 
 | 83 | 	/* lower page */ | 
 | 84 | 	aty_st_le32(MEM_VGA_WP_SEL, 0x00010000, par); | 
 | 85 | 	aty_st_le32(MEM_VGA_RP_SEL, 0x00010000, par); | 
 | 86 |  | 
 | 87 | 	/* ---- Setup standard engine context ---- */ | 
 | 88 |  | 
 | 89 | 	/* All GUI registers here are FIFOed - therefore, wait for */ | 
 | 90 | 	/* the appropriate number of empty FIFO entries */ | 
 | 91 | 	wait_for_fifo(14, par); | 
 | 92 |  | 
 | 93 | 	/* enable all registers to be loaded for context loads */ | 
 | 94 | 	aty_st_le32(CONTEXT_MASK, 0xFFFFFFFF, par); | 
 | 95 |  | 
 | 96 | 	/* set destination pitch to modal pitch, set offset to zero */ | 
 | 97 | 	aty_st_le32(DST_OFF_PITCH, (pitch_value / 8) << 22, par); | 
 | 98 |  | 
 | 99 | 	/* zero these registers (set them to a known state) */ | 
 | 100 | 	aty_st_le32(DST_Y_X, 0, par); | 
 | 101 | 	aty_st_le32(DST_HEIGHT, 0, par); | 
 | 102 | 	aty_st_le32(DST_BRES_ERR, 0, par); | 
 | 103 | 	aty_st_le32(DST_BRES_INC, 0, par); | 
 | 104 | 	aty_st_le32(DST_BRES_DEC, 0, par); | 
 | 105 |  | 
 | 106 | 	/* set destination drawing attributes */ | 
 | 107 | 	aty_st_le32(DST_CNTL, DST_LAST_PEL | DST_Y_TOP_TO_BOTTOM | | 
 | 108 | 		    DST_X_LEFT_TO_RIGHT, par); | 
 | 109 |  | 
 | 110 | 	/* set source pitch to modal pitch, set offset to zero */ | 
 | 111 | 	aty_st_le32(SRC_OFF_PITCH, (pitch_value / 8) << 22, par); | 
 | 112 |  | 
 | 113 | 	/* set these registers to a known state */ | 
 | 114 | 	aty_st_le32(SRC_Y_X, 0, par); | 
 | 115 | 	aty_st_le32(SRC_HEIGHT1_WIDTH1, 1, par); | 
 | 116 | 	aty_st_le32(SRC_Y_X_START, 0, par); | 
 | 117 | 	aty_st_le32(SRC_HEIGHT2_WIDTH2, 1, par); | 
 | 118 |  | 
 | 119 | 	/* set source pixel retrieving attributes */ | 
 | 120 | 	aty_st_le32(SRC_CNTL, SRC_LINE_X_LEFT_TO_RIGHT, par); | 
 | 121 |  | 
 | 122 | 	/* set host attributes */ | 
 | 123 | 	wait_for_fifo(13, par); | 
 | 124 | 	aty_st_le32(HOST_CNTL, 0, par); | 
 | 125 |  | 
 | 126 | 	/* set pattern attributes */ | 
 | 127 | 	aty_st_le32(PAT_REG0, 0, par); | 
 | 128 | 	aty_st_le32(PAT_REG1, 0, par); | 
 | 129 | 	aty_st_le32(PAT_CNTL, 0, par); | 
 | 130 |  | 
 | 131 | 	/* set scissors to modal size */ | 
 | 132 | 	aty_st_le32(SC_LEFT, 0, par); | 
 | 133 | 	aty_st_le32(SC_TOP, 0, par); | 
 | 134 | 	aty_st_le32(SC_BOTTOM, par->crtc.vyres - 1, par); | 
 | 135 | 	aty_st_le32(SC_RIGHT, pitch_value - 1, par); | 
 | 136 |  | 
 | 137 | 	/* set background color to minimum value (usually BLACK) */ | 
 | 138 | 	aty_st_le32(DP_BKGD_CLR, 0, par); | 
 | 139 |  | 
 | 140 | 	/* set foreground color to maximum value (usually WHITE) */ | 
 | 141 | 	aty_st_le32(DP_FRGD_CLR, 0xFFFFFFFF, par); | 
 | 142 |  | 
 | 143 | 	/* set write mask to effect all pixel bits */ | 
 | 144 | 	aty_st_le32(DP_WRITE_MASK, 0xFFFFFFFF, par); | 
 | 145 |  | 
 | 146 | 	/* set foreground mix to overpaint and background mix to */ | 
 | 147 | 	/* no-effect */ | 
 | 148 | 	aty_st_le32(DP_MIX, FRGD_MIX_S | BKGD_MIX_D, par); | 
 | 149 |  | 
 | 150 | 	/* set primary source pixel channel to foreground color */ | 
 | 151 | 	/* register */ | 
 | 152 | 	aty_st_le32(DP_SRC, FRGD_SRC_FRGD_CLR, par); | 
 | 153 |  | 
 | 154 | 	/* set compare functionality to false (no-effect on */ | 
 | 155 | 	/* destination) */ | 
 | 156 | 	wait_for_fifo(3, par); | 
 | 157 | 	aty_st_le32(CLR_CMP_CLR, 0, par); | 
 | 158 | 	aty_st_le32(CLR_CMP_MASK, 0xFFFFFFFF, par); | 
 | 159 | 	aty_st_le32(CLR_CMP_CNTL, 0, par); | 
 | 160 |  | 
 | 161 | 	/* set pixel depth */ | 
 | 162 | 	wait_for_fifo(2, par); | 
 | 163 | 	aty_st_le32(DP_PIX_WIDTH, par->crtc.dp_pix_width, par); | 
 | 164 | 	aty_st_le32(DP_CHAIN_MASK, par->crtc.dp_chain_mask, par); | 
 | 165 |  | 
 | 166 | 	wait_for_fifo(5, par); | 
 | 167 |  	aty_st_le32(SCALE_3D_CNTL, 0, par); | 
 | 168 | 	aty_st_le32(Z_CNTL, 0, par); | 
 | 169 | 	aty_st_le32(CRTC_INT_CNTL, aty_ld_le32(CRTC_INT_CNTL, par) & ~0x20, | 
 | 170 | 		    par); | 
 | 171 | 	aty_st_le32(GUI_TRAJ_CNTL, 0x100023, par); | 
 | 172 |  | 
 | 173 | 	/* insure engine is idle before leaving */ | 
 | 174 | 	wait_for_idle(par); | 
 | 175 | } | 
 | 176 |  | 
 | 177 |     /* | 
 | 178 |      *  Accelerated functions | 
 | 179 |      */ | 
 | 180 |  | 
 | 181 | static inline void draw_rect(s16 x, s16 y, u16 width, u16 height, | 
 | 182 | 			     struct atyfb_par *par) | 
 | 183 | { | 
 | 184 | 	/* perform rectangle fill */ | 
 | 185 | 	wait_for_fifo(2, par); | 
 | 186 | 	aty_st_le32(DST_Y_X, (x << 16) | y, par); | 
 | 187 | 	aty_st_le32(DST_HEIGHT_WIDTH, (width << 16) | height, par); | 
 | 188 | 	par->blitter_may_be_busy = 1; | 
 | 189 | } | 
 | 190 |  | 
 | 191 | void atyfb_copyarea(struct fb_info *info, const struct fb_copyarea *area) | 
 | 192 | { | 
 | 193 | 	struct atyfb_par *par = (struct atyfb_par *) info->par; | 
 | 194 | 	u32 dy = area->dy, sy = area->sy, direction = DST_LAST_PEL; | 
 | 195 | 	u32 sx = area->sx, dx = area->dx, width = area->width, rotation = 0; | 
 | 196 |  | 
 | 197 | 	if (par->asleep) | 
 | 198 | 		return; | 
 | 199 | 	if (!area->width || !area->height) | 
 | 200 | 		return; | 
 | 201 | 	if (!par->accel_flags) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 202 | 		cfb_copyarea(info, area); | 
 | 203 | 		return; | 
 | 204 | 	} | 
 | 205 |  | 
 | 206 | 	if (info->var.bits_per_pixel == 24) { | 
 | 207 | 		/* In 24 bpp, the engine is in 8 bpp - this requires that all */ | 
 | 208 | 		/* horizontal coordinates and widths must be adjusted */ | 
 | 209 | 		sx *= 3; | 
 | 210 | 		dx *= 3; | 
 | 211 | 		width *= 3; | 
 | 212 | 	} | 
 | 213 |  | 
 | 214 | 	if (area->sy < area->dy) { | 
 | 215 | 		dy += area->height - 1; | 
 | 216 | 		sy += area->height - 1; | 
 | 217 | 	} else | 
 | 218 | 		direction |= DST_Y_TOP_TO_BOTTOM; | 
 | 219 |  | 
 | 220 | 	if (sx < dx) { | 
 | 221 | 		dx += width - 1; | 
 | 222 | 		sx += width - 1; | 
 | 223 | 	} else | 
 | 224 | 		direction |= DST_X_LEFT_TO_RIGHT; | 
 | 225 |  | 
 | 226 | 	if (info->var.bits_per_pixel == 24) { | 
 | 227 | 		rotation = rotation24bpp(dx, direction); | 
 | 228 | 	} | 
 | 229 |  | 
 | 230 | 	wait_for_fifo(4, par); | 
 | 231 | 	aty_st_le32(DP_SRC, FRGD_SRC_BLIT, par); | 
 | 232 | 	aty_st_le32(SRC_Y_X, (sx << 16) | sy, par); | 
 | 233 | 	aty_st_le32(SRC_HEIGHT1_WIDTH1, (width << 16) | area->height, par); | 
 | 234 | 	aty_st_le32(DST_CNTL, direction | rotation, par); | 
 | 235 | 	draw_rect(dx, dy, width, area->height, par); | 
 | 236 | } | 
 | 237 |  | 
 | 238 | void atyfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) | 
 | 239 | { | 
 | 240 | 	struct atyfb_par *par = (struct atyfb_par *) info->par; | 
 | 241 | 	u32 color = rect->color, dx = rect->dx, width = rect->width, rotation = 0; | 
 | 242 |  | 
 | 243 | 	if (par->asleep) | 
 | 244 | 		return; | 
 | 245 | 	if (!rect->width || !rect->height) | 
 | 246 | 		return; | 
 | 247 | 	if (!par->accel_flags) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 248 | 		cfb_fillrect(info, rect); | 
 | 249 | 		return; | 
 | 250 | 	} | 
 | 251 |  | 
 | 252 | 	color |= (rect->color << 8); | 
 | 253 | 	color |= (rect->color << 16); | 
 | 254 |  | 
 | 255 | 	if (info->var.bits_per_pixel == 24) { | 
 | 256 | 		/* In 24 bpp, the engine is in 8 bpp - this requires that all */ | 
 | 257 | 		/* horizontal coordinates and widths must be adjusted */ | 
 | 258 | 		dx *= 3; | 
 | 259 | 		width *= 3; | 
 | 260 | 		rotation = rotation24bpp(dx, DST_X_LEFT_TO_RIGHT); | 
 | 261 | 	} | 
 | 262 |  | 
 | 263 | 	wait_for_fifo(3, par); | 
 | 264 | 	aty_st_le32(DP_FRGD_CLR, color, par); | 
 | 265 | 	aty_st_le32(DP_SRC, | 
 | 266 | 		    BKGD_SRC_BKGD_CLR | FRGD_SRC_FRGD_CLR | MONO_SRC_ONE, | 
 | 267 | 		    par); | 
 | 268 | 	aty_st_le32(DST_CNTL, | 
 | 269 | 		    DST_LAST_PEL | DST_Y_TOP_TO_BOTTOM | | 
 | 270 | 		    DST_X_LEFT_TO_RIGHT | rotation, par); | 
 | 271 | 	draw_rect(dx, rect->dy, width, rect->height, par); | 
 | 272 | } | 
 | 273 |  | 
 | 274 | void atyfb_imageblit(struct fb_info *info, const struct fb_image *image) | 
 | 275 | { | 
 | 276 | 	struct atyfb_par *par = (struct atyfb_par *) info->par; | 
 | 277 | 	u32 src_bytes, dx = image->dx, dy = image->dy, width = image->width; | 
 | 278 | 	u32 pix_width_save, pix_width, host_cntl, rotation = 0, src, mix; | 
 | 279 |  | 
 | 280 | 	if (par->asleep) | 
 | 281 | 		return; | 
 | 282 | 	if (!image->width || !image->height) | 
 | 283 | 		return; | 
 | 284 | 	if (!par->accel_flags || | 
 | 285 | 	    (image->depth != 1 && info->var.bits_per_pixel != image->depth)) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 286 | 		cfb_imageblit(info, image); | 
 | 287 | 		return; | 
 | 288 | 	} | 
 | 289 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 290 | 	pix_width = pix_width_save = aty_ld_le32(DP_PIX_WIDTH, par); | 
 | 291 | 	host_cntl = aty_ld_le32(HOST_CNTL, par) | HOST_BYTE_ALIGN; | 
 | 292 |  | 
 | 293 | 	switch (image->depth) { | 
 | 294 | 	case 1: | 
 | 295 | 	    pix_width &= ~(BYTE_ORDER_MASK | HOST_MASK); | 
 | 296 | 	    pix_width |= (BYTE_ORDER_MSB_TO_LSB | HOST_1BPP); | 
 | 297 | 	    break; | 
 | 298 | 	case 4: | 
 | 299 | 	    pix_width &= ~(BYTE_ORDER_MASK | HOST_MASK); | 
 | 300 | 	    pix_width |= (BYTE_ORDER_MSB_TO_LSB | HOST_4BPP); | 
 | 301 | 	    break; | 
 | 302 | 	case 8: | 
 | 303 | 	    pix_width &= ~HOST_MASK; | 
 | 304 | 	    pix_width |= HOST_8BPP; | 
 | 305 | 	    break; | 
 | 306 | 	case 15: | 
 | 307 | 	    pix_width &= ~HOST_MASK; | 
 | 308 | 	    pix_width |= HOST_15BPP; | 
 | 309 | 	    break; | 
 | 310 | 	case 16: | 
 | 311 | 	    pix_width &= ~HOST_MASK; | 
 | 312 | 	    pix_width |= HOST_16BPP; | 
 | 313 | 	    break; | 
 | 314 | 	case 24: | 
 | 315 | 	    pix_width &= ~HOST_MASK; | 
 | 316 | 	    pix_width |= HOST_24BPP; | 
 | 317 | 	    break; | 
 | 318 | 	case 32: | 
 | 319 | 	    pix_width &= ~HOST_MASK; | 
 | 320 | 	    pix_width |= HOST_32BPP; | 
 | 321 | 	    break; | 
 | 322 | 	} | 
 | 323 |  | 
 | 324 | 	if (info->var.bits_per_pixel == 24) { | 
 | 325 | 		/* In 24 bpp, the engine is in 8 bpp - this requires that all */ | 
 | 326 | 		/* horizontal coordinates and widths must be adjusted */ | 
 | 327 | 		dx *= 3; | 
 | 328 | 		width *= 3; | 
 | 329 |  | 
 | 330 | 		rotation = rotation24bpp(dx, DST_X_LEFT_TO_RIGHT); | 
 | 331 |  | 
 | 332 | 		pix_width &= ~DST_MASK; | 
 | 333 | 		pix_width |= DST_8BPP; | 
 | 334 |  | 
 | 335 | 		/* | 
 | 336 | 		 * since Rage 3D IIc we have DP_HOST_TRIPLE_EN bit | 
 | 337 | 		 * this hwaccelerated triple has an issue with not aligned data | 
 | 338 | 		 */ | 
 | 339 | 		if (M64_HAS(HW_TRIPLE) && image->width % 8 == 0) | 
 | 340 | 			pix_width |= DP_HOST_TRIPLE_EN; | 
 | 341 | 	} | 
 | 342 |  | 
 | 343 | 	if (image->depth == 1) { | 
 | 344 | 		u32 fg, bg; | 
 | 345 | 		if (info->fix.visual == FB_VISUAL_TRUECOLOR || | 
 | 346 | 		    info->fix.visual == FB_VISUAL_DIRECTCOLOR) { | 
 | 347 | 			fg = ((u32*)(info->pseudo_palette))[image->fg_color]; | 
 | 348 | 			bg = ((u32*)(info->pseudo_palette))[image->bg_color]; | 
 | 349 | 		} else { | 
 | 350 | 			fg = image->fg_color; | 
 | 351 | 			bg = image->bg_color; | 
 | 352 | 		} | 
 | 353 |  | 
 | 354 | 		wait_for_fifo(2, par); | 
 | 355 | 		aty_st_le32(DP_BKGD_CLR, bg, par); | 
 | 356 | 		aty_st_le32(DP_FRGD_CLR, fg, par); | 
 | 357 | 		src = MONO_SRC_HOST | FRGD_SRC_FRGD_CLR | BKGD_SRC_BKGD_CLR; | 
 | 358 | 		mix = FRGD_MIX_S | BKGD_MIX_S; | 
 | 359 | 	} else { | 
 | 360 | 		src = MONO_SRC_ONE | FRGD_SRC_HOST; | 
 | 361 | 		mix = FRGD_MIX_D_XOR_S | BKGD_MIX_D; | 
 | 362 | 	} | 
 | 363 |  | 
 | 364 | 	wait_for_fifo(6, par); | 
 | 365 | 	aty_st_le32(DP_WRITE_MASK, 0xFFFFFFFF, par); | 
 | 366 | 	aty_st_le32(DP_PIX_WIDTH, pix_width, par); | 
 | 367 | 	aty_st_le32(DP_MIX, mix, par); | 
 | 368 | 	aty_st_le32(DP_SRC, src, par); | 
 | 369 | 	aty_st_le32(HOST_CNTL, host_cntl, par); | 
 | 370 | 	aty_st_le32(DST_CNTL, DST_Y_TOP_TO_BOTTOM | DST_X_LEFT_TO_RIGHT | rotation, par); | 
 | 371 |  | 
 | 372 | 	draw_rect(dx, dy, width, image->height, par); | 
 | 373 | 	src_bytes = (((image->width * image->depth) + 7) / 8) * image->height; | 
 | 374 |  | 
 | 375 | 	/* manual triple each pixel */ | 
 | 376 | 	if (info->var.bits_per_pixel == 24 && !(pix_width & DP_HOST_TRIPLE_EN)) { | 
 | 377 | 		int inbit, outbit, mult24, byte_id_in_dword, width; | 
 | 378 | 		u8 *pbitmapin = (u8*)image->data, *pbitmapout; | 
 | 379 | 		u32 hostdword; | 
 | 380 |  | 
 | 381 | 		for (width = image->width, inbit = 7, mult24 = 0; src_bytes; ) { | 
 | 382 | 			for (hostdword = 0, pbitmapout = (u8*)&hostdword, byte_id_in_dword = 0; | 
 | 383 | 				byte_id_in_dword < 4 && src_bytes; | 
 | 384 | 				byte_id_in_dword++, pbitmapout++) { | 
 | 385 | 				for (outbit = 7; outbit >= 0; outbit--) { | 
 | 386 | 					*pbitmapout |= (((*pbitmapin >> inbit) & 1) << outbit); | 
 | 387 | 					mult24++; | 
 | 388 | 					/* next bit */ | 
 | 389 | 					if (mult24 == 3) { | 
 | 390 | 						mult24 = 0; | 
 | 391 | 						inbit--; | 
 | 392 | 						width--; | 
 | 393 | 					} | 
 | 394 |  | 
 | 395 | 					/* next byte */ | 
 | 396 | 					if (inbit < 0 || width == 0) { | 
 | 397 | 						src_bytes--; | 
 | 398 | 						pbitmapin++; | 
 | 399 | 						inbit = 7; | 
 | 400 |  | 
 | 401 | 						if (width == 0) { | 
 | 402 | 						    width = image->width; | 
 | 403 | 						    outbit = 0; | 
 | 404 | 						} | 
 | 405 | 					} | 
 | 406 | 				} | 
 | 407 | 			} | 
 | 408 | 			wait_for_fifo(1, par); | 
 | 409 | 			aty_st_le32(HOST_DATA0, hostdword, par); | 
 | 410 | 		} | 
 | 411 | 	} else { | 
 | 412 | 		u32 *pbitmap, dwords = (src_bytes + 3) / 4; | 
 | 413 | 		for (pbitmap = (u32*)(image->data); dwords; dwords--, pbitmap++) { | 
 | 414 | 			wait_for_fifo(1, par); | 
 | 415 | 			aty_st_le32(HOST_DATA0, le32_to_cpup(pbitmap), par); | 
 | 416 | 		} | 
 | 417 | 	} | 
 | 418 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 419 | 	/* restore pix_width */ | 
 | 420 | 	wait_for_fifo(1, par); | 
 | 421 | 	aty_st_le32(DP_PIX_WIDTH, pix_width_save, par); | 
 | 422 | } |