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