Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 | /* * ATI Mach64 CT/VT/GT/LT Cursor Support */ #include <linux/slab.h> #include <linux/fb.h> #include <linux/init.h> #include <linux/string.h> #include <asm/io.h> #include <asm/uaccess.h> #ifdef __sparc__ #include <asm/pbm.h> #include <asm/fbio.h> #endif #include <video/mach64.h> #include "atyfb.h" /* * The hardware cursor definition requires 2 bits per pixel. The * Cursor size reguardless of the visible cursor size is 64 pixels * by 64 lines. The total memory required to define the cursor is * 16 bytes / line for 64 lines or 1024 bytes of data. The data * must be in a contigiuos format. The 2 bit cursor code values are * as follows: * * 00 - pixel colour = CURSOR_CLR_0 * 01 - pixel colour = CURSOR_CLR_1 * 10 - pixel colour = transparent (current display pixel) * 11 - pixel colour = 1's complement of current display pixel * * Cursor Offset 64 pixels Actual Displayed Area * \_________________________/ * | | | | * |<--------------->| | | * | CURS_HORZ_OFFSET| | | * | |_______| | 64 Lines * | ^ | | * | | | | * | CURS_VERT_OFFSET| | * | | | | * |____________________|____| | * * * The Screen position of the top left corner of the displayed * cursor is specificed by CURS_HORZ_VERT_POSN. Care must be taken * when the cursor hot spot is not the top left corner and the * physical cursor position becomes negative. It will be be displayed * if either the horizontal or vertical cursor position is negative * * If x becomes negative the cursor manager must adjust the CURS_HORZ_OFFSET * to a larger number and saturate CUR_HORZ_POSN to zero. * * if Y becomes negative, CUR_VERT_OFFSET must be adjusted to a larger number, * CUR_OFFSET must be adjusted to a point to the appropraite line in the cursor * definitation and CUR_VERT_POSN must be saturated to zero. */ /* * Hardware Cursor support. */ static const u8 cursor_bits_lookup[16] = { 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54, 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55 }; static const u8 cursor_mask_lookup[16] = { 0xaa, 0x2a, 0x8a, 0x0a, 0xa2, 0x22, 0x82, 0x02, 0xa8, 0x28, 0x88, 0x08, 0xa0, 0x20, 0x80, 0x00 }; static int atyfb_cursor(struct fb_info *info, struct fb_cursor *cursor) { struct atyfb_par *par = (struct atyfb_par *) info->par; u16 xoff, yoff; int x, y, h; #ifdef __sparc__ if (par->mmaped) return -EPERM; #endif if (par->asleep) return -EPERM; /* Hide cursor */ wait_for_fifo(1, par); aty_st_le32(GEN_TEST_CNTL, aty_ld_le32(GEN_TEST_CNTL, par) & ~HWCURSOR_ENABLE, par); /* set position */ if (cursor->set & FB_CUR_SETPOS) { x = cursor->image.dx - cursor->hot.x - info->var.xoffset; if (x < 0) { xoff = -x; x = 0; } else { xoff = 0; } y = cursor->image.dy - cursor->hot.y - info->var.yoffset; if (y < 0) { yoff = -y; y = 0; } else { yoff = 0; } h = cursor->image.height; /* * In doublescan mode, the cursor location * and heigh also needs to be doubled. */ if (par->crtc.gen_cntl & CRTC_DBL_SCAN_EN) { y<<=1; h<<=1; } wait_for_fifo(4, par); aty_st_le32(CUR_OFFSET, (info->fix.smem_len >> 3) + (yoff << 1), par); aty_st_le32(CUR_HORZ_VERT_OFF, ((u32) (64 - h + yoff) << 16) | xoff, par); aty_st_le32(CUR_HORZ_VERT_POSN, ((u32) y << 16) | x, par); } /* Set color map */ if (cursor->set & FB_CUR_SETCMAP) { u32 fg_idx, bg_idx, fg, bg; fg_idx = cursor->image.fg_color; bg_idx = cursor->image.bg_color; fg = (info->cmap.red[fg_idx] << 24) | (info->cmap.green[fg_idx] << 16) | (info->cmap.blue[fg_idx] << 8) | 15; bg = (info->cmap.red[bg_idx] << 24) | (info->cmap.green[bg_idx] << 16) | (info->cmap.blue[bg_idx] << 8); wait_for_fifo(2, par); aty_st_le32(CUR_CLR0, bg, par); aty_st_le32(CUR_CLR1, fg, par); } if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) { u8 *src = (u8 *)cursor->image.data; u8 *msk = (u8 *)cursor->mask; u8 __iomem *dst = (u8 __iomem *)info->sprite.addr; unsigned int width = (cursor->image.width + 7) >> 3; unsigned int height = cursor->image.height; unsigned int align = info->sprite.scan_align; unsigned int i, j, offset; u8 m, b; // Clear cursor image with 1010101010... fb_memset(dst, 0xaa, 1024); offset = align - width*2; for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { b = *src++; m = *msk++; switch (cursor->rop) { case ROP_XOR: // Upper 4 bits of mask data fb_writeb(cursor_mask_lookup[m >> 4 ] | cursor_bits_lookup[(b ^ m) >> 4], dst++); // Lower 4 bits of mask fb_writeb(cursor_mask_lookup[m & 0x0f ] | cursor_bits_lookup[(b ^ m) & 0x0f], dst++); break; case ROP_COPY: // Upper 4 bits of mask data fb_writeb(cursor_mask_lookup[m >> 4 ] | cursor_bits_lookup[(b & m) >> 4], dst++); // Lower 4 bits of mask fb_writeb(cursor_mask_lookup[m & 0x0f ] | cursor_bits_lookup[(b & m) & 0x0f], dst++); break; } } dst += offset; } } if (cursor->enable) { wait_for_fifo(1, par); aty_st_le32(GEN_TEST_CNTL, aty_ld_le32(GEN_TEST_CNTL, par) | HWCURSOR_ENABLE, par); } return 0; } int __init aty_init_cursor(struct fb_info *info) { unsigned long addr; info->fix.smem_len -= PAGE_SIZE; #ifdef __sparc__ addr = (unsigned long) info->screen_base - 0x800000 + info->fix.smem_len; info->sprite.addr = (u8 *) addr; #else #ifdef __BIG_ENDIAN addr = info->fix.smem_start - 0x800000 + info->fix.smem_len; info->sprite.addr = (u8 *) ioremap(addr, 1024); #else addr = (unsigned long) info->screen_base + info->fix.smem_len; info->sprite.addr = (u8 *) addr; #endif #endif if (!info->sprite.addr) return -ENXIO; info->sprite.size = PAGE_SIZE; info->sprite.scan_align = 16; /* Scratch pad 64 bytes wide */ info->sprite.buf_align = 16; /* and 64 lines tall. */ info->sprite.flags = FB_PIXMAP_IO; info->fbops->fb_cursor = atyfb_cursor; return 0; } |