0001
0002
0003
0004
0005
0006
0007 #include <linux/delay.h>
0008 #include <asm/unaligned.h>
0009 #include <linux/fb.h>
0010 #include <video/mach64.h>
0011 #include "atyfb.h"
0012
0013
0014
0015
0016
0017
0018 typedef struct {
0019 u32 frame_buf_offset;
0020 u32 system_mem_addr;
0021 u32 command;
0022 u32 reserved;
0023 } BM_DESCRIPTOR_ENTRY;
0024
0025 #define LAST_DESCRIPTOR (1 << 31)
0026 #define SYSTEM_TO_FRAME_BUFFER 0
0027
0028 static u32 rotation24bpp(u32 dx, u32 direction)
0029 {
0030 u32 rotation;
0031 if (direction & DST_X_LEFT_TO_RIGHT) {
0032 rotation = (dx / 4) % 6;
0033 } else {
0034 rotation = ((dx + 2) / 4) % 6;
0035 }
0036
0037 return ((rotation << 8) | DST_24_ROTATION_ENABLE);
0038 }
0039
0040 void aty_reset_engine(struct atyfb_par *par)
0041 {
0042
0043 aty_st_le32(GEN_TEST_CNTL,
0044 aty_ld_le32(GEN_TEST_CNTL, par) &
0045 ~(GUI_ENGINE_ENABLE | HWCURSOR_ENABLE), par);
0046
0047 aty_st_le32(GEN_TEST_CNTL,
0048 aty_ld_le32(GEN_TEST_CNTL, par) | GUI_ENGINE_ENABLE, par);
0049
0050
0051 aty_st_le32(BUS_CNTL,
0052 aty_ld_le32(BUS_CNTL, par) | BUS_HOST_ERR_ACK | BUS_FIFO_ERR_ACK, par);
0053
0054 par->fifo_space = 0;
0055 }
0056
0057 static void reset_GTC_3D_engine(const struct atyfb_par *par)
0058 {
0059 aty_st_le32(SCALE_3D_CNTL, 0xc0, par);
0060 mdelay(GTC_3D_RESET_DELAY);
0061 aty_st_le32(SETUP_CNTL, 0x00, par);
0062 mdelay(GTC_3D_RESET_DELAY);
0063 aty_st_le32(SCALE_3D_CNTL, 0x00, par);
0064 mdelay(GTC_3D_RESET_DELAY);
0065 }
0066
0067 void aty_init_engine(struct atyfb_par *par, struct fb_info *info)
0068 {
0069 u32 pitch_value;
0070 u32 vxres;
0071
0072
0073 pitch_value = info->fix.line_length / (info->var.bits_per_pixel / 8);
0074 vxres = info->var.xres_virtual;
0075
0076 if (info->var.bits_per_pixel == 24) {
0077
0078
0079 pitch_value *= 3;
0080 vxres *= 3;
0081 }
0082
0083
0084 if (M64_HAS(RESET_3D))
0085 reset_GTC_3D_engine(par);
0086
0087
0088 aty_reset_engine(par);
0089
0090
0091
0092 aty_st_le32(MEM_VGA_WP_SEL, 0x00010000, par);
0093 aty_st_le32(MEM_VGA_RP_SEL, 0x00010000, par);
0094
0095
0096
0097
0098
0099 wait_for_fifo(14, par);
0100
0101
0102 aty_st_le32(CONTEXT_MASK, 0xFFFFFFFF, par);
0103
0104
0105 aty_st_le32(DST_OFF_PITCH, (pitch_value / 8) << 22, par);
0106
0107
0108 aty_st_le32(DST_Y_X, 0, par);
0109 aty_st_le32(DST_HEIGHT, 0, par);
0110 aty_st_le32(DST_BRES_ERR, 0, par);
0111 aty_st_le32(DST_BRES_INC, 0, par);
0112 aty_st_le32(DST_BRES_DEC, 0, par);
0113
0114
0115 aty_st_le32(DST_CNTL, DST_LAST_PEL | DST_Y_TOP_TO_BOTTOM |
0116 DST_X_LEFT_TO_RIGHT, par);
0117
0118
0119 aty_st_le32(SRC_OFF_PITCH, (pitch_value / 8) << 22, par);
0120
0121
0122 aty_st_le32(SRC_Y_X, 0, par);
0123 aty_st_le32(SRC_HEIGHT1_WIDTH1, 1, par);
0124 aty_st_le32(SRC_Y_X_START, 0, par);
0125 aty_st_le32(SRC_HEIGHT2_WIDTH2, 1, par);
0126
0127
0128 aty_st_le32(SRC_CNTL, SRC_LINE_X_LEFT_TO_RIGHT, par);
0129
0130
0131 wait_for_fifo(13, par);
0132 aty_st_le32(HOST_CNTL, HOST_BYTE_ALIGN, par);
0133
0134
0135 aty_st_le32(PAT_REG0, 0, par);
0136 aty_st_le32(PAT_REG1, 0, par);
0137 aty_st_le32(PAT_CNTL, 0, par);
0138
0139
0140 aty_st_le32(SC_LEFT, 0, par);
0141 aty_st_le32(SC_TOP, 0, par);
0142 aty_st_le32(SC_BOTTOM, par->crtc.vyres - 1, par);
0143 aty_st_le32(SC_RIGHT, vxres - 1, par);
0144
0145
0146 aty_st_le32(DP_BKGD_CLR, 0, par);
0147
0148
0149 aty_st_le32(DP_FRGD_CLR, 0xFFFFFFFF, par);
0150
0151
0152 aty_st_le32(DP_WRITE_MASK, 0xFFFFFFFF, par);
0153
0154
0155
0156 aty_st_le32(DP_MIX, FRGD_MIX_S | BKGD_MIX_D, par);
0157
0158
0159
0160 aty_st_le32(DP_SRC, FRGD_SRC_FRGD_CLR, par);
0161
0162
0163
0164 wait_for_fifo(3, par);
0165 aty_st_le32(CLR_CMP_CLR, 0, par);
0166 aty_st_le32(CLR_CMP_MASK, 0xFFFFFFFF, par);
0167 aty_st_le32(CLR_CMP_CNTL, 0, par);
0168
0169
0170 wait_for_fifo(2, par);
0171 aty_st_le32(DP_PIX_WIDTH, par->crtc.dp_pix_width, par);
0172 aty_st_le32(DP_CHAIN_MASK, par->crtc.dp_chain_mask, par);
0173
0174 wait_for_fifo(5, par);
0175 aty_st_le32(SCALE_3D_CNTL, 0, par);
0176 aty_st_le32(Z_CNTL, 0, par);
0177 aty_st_le32(CRTC_INT_CNTL, aty_ld_le32(CRTC_INT_CNTL, par) & ~0x20,
0178 par);
0179 aty_st_le32(GUI_TRAJ_CNTL, 0x100023, par);
0180
0181
0182 wait_for_idle(par);
0183 }
0184
0185
0186
0187
0188
0189 static inline void draw_rect(s16 x, s16 y, u16 width, u16 height,
0190 struct atyfb_par *par)
0191 {
0192
0193 wait_for_fifo(2, par);
0194 aty_st_le32(DST_Y_X, (x << 16) | y, par);
0195 aty_st_le32(DST_HEIGHT_WIDTH, (width << 16) | height, par);
0196 par->blitter_may_be_busy = 1;
0197 }
0198
0199 void atyfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
0200 {
0201 struct atyfb_par *par = (struct atyfb_par *) info->par;
0202 u32 dy = area->dy, sy = area->sy, direction = DST_LAST_PEL;
0203 u32 sx = area->sx, dx = area->dx, width = area->width, rotation = 0;
0204
0205 if (par->asleep)
0206 return;
0207 if (!area->width || !area->height)
0208 return;
0209 if (!par->accel_flags) {
0210 cfb_copyarea(info, area);
0211 return;
0212 }
0213
0214 if (info->var.bits_per_pixel == 24) {
0215
0216
0217 sx *= 3;
0218 dx *= 3;
0219 width *= 3;
0220 }
0221
0222 if (area->sy < area->dy) {
0223 dy += area->height - 1;
0224 sy += area->height - 1;
0225 } else
0226 direction |= DST_Y_TOP_TO_BOTTOM;
0227
0228 if (sx < dx) {
0229 dx += width - 1;
0230 sx += width - 1;
0231 } else
0232 direction |= DST_X_LEFT_TO_RIGHT;
0233
0234 if (info->var.bits_per_pixel == 24) {
0235 rotation = rotation24bpp(dx, direction);
0236 }
0237
0238 wait_for_fifo(5, par);
0239 aty_st_le32(DP_PIX_WIDTH, par->crtc.dp_pix_width, par);
0240 aty_st_le32(DP_SRC, FRGD_SRC_BLIT, par);
0241 aty_st_le32(SRC_Y_X, (sx << 16) | sy, par);
0242 aty_st_le32(SRC_HEIGHT1_WIDTH1, (width << 16) | area->height, par);
0243 aty_st_le32(DST_CNTL, direction | rotation, par);
0244 draw_rect(dx, dy, width, area->height, par);
0245 }
0246
0247 void atyfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
0248 {
0249 struct atyfb_par *par = (struct atyfb_par *) info->par;
0250 u32 color, dx = rect->dx, width = rect->width, rotation = 0;
0251
0252 if (par->asleep)
0253 return;
0254 if (!rect->width || !rect->height)
0255 return;
0256 if (!par->accel_flags) {
0257 cfb_fillrect(info, rect);
0258 return;
0259 }
0260
0261 if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
0262 info->fix.visual == FB_VISUAL_DIRECTCOLOR)
0263 color = ((u32 *)(info->pseudo_palette))[rect->color];
0264 else
0265 color = rect->color;
0266
0267 if (info->var.bits_per_pixel == 24) {
0268
0269
0270 dx *= 3;
0271 width *= 3;
0272 rotation = rotation24bpp(dx, DST_X_LEFT_TO_RIGHT);
0273 }
0274
0275 wait_for_fifo(4, par);
0276 aty_st_le32(DP_PIX_WIDTH, par->crtc.dp_pix_width, par);
0277 aty_st_le32(DP_FRGD_CLR, color, par);
0278 aty_st_le32(DP_SRC,
0279 BKGD_SRC_BKGD_CLR | FRGD_SRC_FRGD_CLR | MONO_SRC_ONE,
0280 par);
0281 aty_st_le32(DST_CNTL,
0282 DST_LAST_PEL | DST_Y_TOP_TO_BOTTOM |
0283 DST_X_LEFT_TO_RIGHT | rotation, par);
0284 draw_rect(dx, rect->dy, width, rect->height, par);
0285 }
0286
0287 void atyfb_imageblit(struct fb_info *info, const struct fb_image *image)
0288 {
0289 struct atyfb_par *par = (struct atyfb_par *) info->par;
0290 u32 src_bytes, dx = image->dx, dy = image->dy, width = image->width;
0291 u32 pix_width, rotation = 0, src, mix;
0292
0293 if (par->asleep)
0294 return;
0295 if (!image->width || !image->height)
0296 return;
0297 if (!par->accel_flags ||
0298 (image->depth != 1 && info->var.bits_per_pixel != image->depth)) {
0299 cfb_imageblit(info, image);
0300 return;
0301 }
0302
0303 pix_width = par->crtc.dp_pix_width;
0304
0305 switch (image->depth) {
0306 case 1:
0307 pix_width &= ~(BYTE_ORDER_MASK | HOST_MASK);
0308 pix_width |= (BYTE_ORDER_MSB_TO_LSB | HOST_1BPP);
0309 break;
0310 case 4:
0311 pix_width &= ~(BYTE_ORDER_MASK | HOST_MASK);
0312 pix_width |= (BYTE_ORDER_MSB_TO_LSB | HOST_4BPP);
0313 break;
0314 case 8:
0315 pix_width &= ~HOST_MASK;
0316 pix_width |= HOST_8BPP;
0317 break;
0318 case 15:
0319 pix_width &= ~HOST_MASK;
0320 pix_width |= HOST_15BPP;
0321 break;
0322 case 16:
0323 pix_width &= ~HOST_MASK;
0324 pix_width |= HOST_16BPP;
0325 break;
0326 case 24:
0327 pix_width &= ~HOST_MASK;
0328 pix_width |= HOST_24BPP;
0329 break;
0330 case 32:
0331 pix_width &= ~HOST_MASK;
0332 pix_width |= HOST_32BPP;
0333 break;
0334 }
0335
0336 if (info->var.bits_per_pixel == 24) {
0337
0338
0339 dx *= 3;
0340 width *= 3;
0341
0342 rotation = rotation24bpp(dx, DST_X_LEFT_TO_RIGHT);
0343
0344 pix_width &= ~DST_MASK;
0345 pix_width |= DST_8BPP;
0346
0347
0348
0349
0350
0351 if (image->depth == 1 && M64_HAS(HW_TRIPLE) && image->width % 8 == 0)
0352 pix_width |= DP_HOST_TRIPLE_EN;
0353 }
0354
0355 if (image->depth == 1) {
0356 u32 fg, bg;
0357 if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
0358 info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
0359 fg = ((u32*)(info->pseudo_palette))[image->fg_color];
0360 bg = ((u32*)(info->pseudo_palette))[image->bg_color];
0361 } else {
0362 fg = image->fg_color;
0363 bg = image->bg_color;
0364 }
0365
0366 wait_for_fifo(2, par);
0367 aty_st_le32(DP_BKGD_CLR, bg, par);
0368 aty_st_le32(DP_FRGD_CLR, fg, par);
0369 src = MONO_SRC_HOST | FRGD_SRC_FRGD_CLR | BKGD_SRC_BKGD_CLR;
0370 mix = FRGD_MIX_S | BKGD_MIX_S;
0371 } else {
0372 src = MONO_SRC_ONE | FRGD_SRC_HOST;
0373 mix = FRGD_MIX_D_XOR_S | BKGD_MIX_D;
0374 }
0375
0376 wait_for_fifo(5, par);
0377 aty_st_le32(DP_PIX_WIDTH, pix_width, par);
0378 aty_st_le32(DP_MIX, mix, par);
0379 aty_st_le32(DP_SRC, src, par);
0380 aty_st_le32(HOST_CNTL, HOST_BYTE_ALIGN, par);
0381 aty_st_le32(DST_CNTL, DST_Y_TOP_TO_BOTTOM | DST_X_LEFT_TO_RIGHT | rotation, par);
0382
0383 draw_rect(dx, dy, width, image->height, par);
0384 src_bytes = (((image->width * image->depth) + 7) / 8) * image->height;
0385
0386
0387 if (image->depth == 1 && info->var.bits_per_pixel == 24 && !(pix_width & DP_HOST_TRIPLE_EN)) {
0388 int inbit, outbit, mult24, byte_id_in_dword, width;
0389 u8 *pbitmapin = (u8*)image->data, *pbitmapout;
0390 u32 hostdword;
0391
0392 for (width = image->width, inbit = 7, mult24 = 0; src_bytes; ) {
0393 for (hostdword = 0, pbitmapout = (u8*)&hostdword, byte_id_in_dword = 0;
0394 byte_id_in_dword < 4 && src_bytes;
0395 byte_id_in_dword++, pbitmapout++) {
0396 for (outbit = 7; outbit >= 0; outbit--) {
0397 *pbitmapout |= (((*pbitmapin >> inbit) & 1) << outbit);
0398 mult24++;
0399
0400 if (mult24 == 3) {
0401 mult24 = 0;
0402 inbit--;
0403 width--;
0404 }
0405
0406
0407 if (inbit < 0 || width == 0) {
0408 src_bytes--;
0409 pbitmapin++;
0410 inbit = 7;
0411
0412 if (width == 0) {
0413 width = image->width;
0414 outbit = 0;
0415 }
0416 }
0417 }
0418 }
0419 wait_for_fifo(1, par);
0420 aty_st_le32(HOST_DATA0, le32_to_cpu(hostdword), par);
0421 }
0422 } else {
0423 u32 *pbitmap, dwords = (src_bytes + 3) / 4;
0424 for (pbitmap = (u32*)(image->data); dwords; dwords--, pbitmap++) {
0425 wait_for_fifo(1, par);
0426 aty_st_le32(HOST_DATA0, get_unaligned_le32(pbitmap), par);
0427 }
0428 }
0429 }