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