Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  *  ATI Mach64 CT/VT/GT/LT Cursor Support
0004  */
0005 
0006 #include <linux/fb.h>
0007 #include <linux/init.h>
0008 #include <linux/string.h>
0009 #include "../core/fb_draw.h"
0010 
0011 #include <asm/io.h>
0012 
0013 #ifdef __sparc__
0014 #include <asm/fbio.h>
0015 #endif
0016 
0017 #include <video/mach64.h>
0018 #include "atyfb.h"
0019 
0020 /*
0021  * The hardware cursor definition requires 2 bits per pixel. The
0022  * Cursor size reguardless of the visible cursor size is 64 pixels
0023  * by 64 lines. The total memory required to define the cursor is
0024  * 16 bytes / line for 64 lines or 1024 bytes of data. The data
0025  * must be in a contigiuos format. The 2 bit cursor code values are
0026  * as follows:
0027  *
0028  *  00 - pixel colour = CURSOR_CLR_0
0029  *  01 - pixel colour = CURSOR_CLR_1
0030  *  10 - pixel colour = transparent (current display pixel)
0031  *  11 - pixel colour = 1's complement of current display pixel
0032  *
0033  *  Cursor Offset        64 pixels       Actual Displayed Area
0034  *            \_________________________/
0035  *        |         |   |   |
0036  *        |<--------------->|   |   |
0037  *        | CURS_HORZ_OFFSET|   |   |
0038  *        |         |_______|   |  64 Lines
0039  *        |            ^    |   |
0040  *        |            |    |   |
0041  *        |     CURS_VERT_OFFSET|   |
0042  *        |            |    |   |
0043  *        |____________________|____|   |
0044  *
0045  *
0046  * The Screen position of the top left corner of the displayed
0047  * cursor is specificed by CURS_HORZ_VERT_POSN. Care must be taken
0048  * when the cursor hot spot is not the top left corner and the
0049  * physical cursor position becomes negative. It will be displayed
0050  * if either the horizontal or vertical cursor position is negative
0051  *
0052  * If x becomes negative the cursor manager must adjust the CURS_HORZ_OFFSET
0053  * to a larger number and saturate CUR_HORZ_POSN to zero.
0054  *
0055  * if Y becomes negative, CUR_VERT_OFFSET must be adjusted to a larger number,
0056  * CUR_OFFSET must be adjusted to a point to the appropriate line in the cursor
0057  * definitation and CUR_VERT_POSN must be saturated to zero.
0058  */
0059 
0060     /*
0061      *  Hardware Cursor support.
0062      */
0063 static const u8 cursor_bits_lookup[16] = {
0064     0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
0065     0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55
0066 };
0067 
0068 static int atyfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
0069 {
0070     struct atyfb_par *par = (struct atyfb_par *) info->par;
0071     u16 xoff, yoff;
0072     int x, y, h;
0073 
0074 #ifdef __sparc__
0075     if (par->mmaped)
0076         return -EPERM;
0077 #endif
0078     if (par->asleep)
0079         return -EPERM;
0080 
0081     wait_for_fifo(1, par);
0082     if (cursor->enable)
0083         aty_st_le32(GEN_TEST_CNTL, aty_ld_le32(GEN_TEST_CNTL, par)
0084                 | HWCURSOR_ENABLE, par);
0085     else
0086         aty_st_le32(GEN_TEST_CNTL, aty_ld_le32(GEN_TEST_CNTL, par)
0087                 & ~HWCURSOR_ENABLE, par);
0088 
0089     /* set position */
0090     if (cursor->set & FB_CUR_SETPOS) {
0091         x = cursor->image.dx - cursor->hot.x - info->var.xoffset;
0092         if (x < 0) {
0093             xoff = -x;
0094             x = 0;
0095         } else {
0096             xoff = 0;
0097         }
0098 
0099         y = cursor->image.dy - cursor->hot.y - info->var.yoffset;
0100         if (y < 0) {
0101             yoff = -y;
0102             y = 0;
0103         } else {
0104             yoff = 0;
0105         }
0106 
0107         h = cursor->image.height;
0108 
0109         /*
0110          * In doublescan mode, the cursor location
0111          * and heigh also needs to be doubled.
0112          */
0113                 if (par->crtc.gen_cntl & CRTC_DBL_SCAN_EN) {
0114             y<<=1;
0115             h<<=1;
0116         }
0117         wait_for_fifo(3, par);
0118         aty_st_le32(CUR_OFFSET, (info->fix.smem_len >> 3) + (yoff << 1), par);
0119         aty_st_le32(CUR_HORZ_VERT_OFF,
0120                 ((u32) (64 - h + yoff) << 16) | xoff, par);
0121         aty_st_le32(CUR_HORZ_VERT_POSN, ((u32) y << 16) | x, par);
0122     }
0123 
0124     /* Set color map */
0125     if (cursor->set & FB_CUR_SETCMAP) {
0126         u32 fg_idx, bg_idx, fg, bg;
0127 
0128         fg_idx = cursor->image.fg_color;
0129         bg_idx = cursor->image.bg_color;
0130 
0131         fg = ((info->cmap.red[fg_idx] & 0xff) << 24) |
0132              ((info->cmap.green[fg_idx] & 0xff) << 16) |
0133              ((info->cmap.blue[fg_idx] & 0xff) << 8) | 0xff;
0134 
0135         bg = ((info->cmap.red[bg_idx] & 0xff) << 24) |
0136              ((info->cmap.green[bg_idx] & 0xff) << 16) |
0137              ((info->cmap.blue[bg_idx] & 0xff) << 8);
0138 
0139         wait_for_fifo(2, par);
0140         aty_st_le32(CUR_CLR0, bg, par);
0141         aty_st_le32(CUR_CLR1, fg, par);
0142     }
0143 
0144     if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) {
0145         u8 *src = (u8 *)cursor->image.data;
0146         u8 *msk = (u8 *)cursor->mask;
0147         u8 __iomem *dst = (u8 __iomem *)info->sprite.addr;
0148         unsigned int width = (cursor->image.width + 7) >> 3;
0149         unsigned int height = cursor->image.height;
0150         unsigned int align = info->sprite.scan_align;
0151 
0152         unsigned int i, j, offset;
0153         u8 m, b;
0154 
0155         // Clear cursor image with 1010101010...
0156         fb_memset(dst, 0xaa, 1024);
0157 
0158         offset = align - width*2;
0159 
0160         for (i = 0; i < height; i++) {
0161         for (j = 0; j < width; j++) {
0162             u16 l = 0xaaaa;
0163             b = *src++;
0164             m = *msk++;
0165             switch (cursor->rop) {
0166             case ROP_XOR:
0167                 // Upper 4 bits of mask data
0168                 l = cursor_bits_lookup[(b ^ m) >> 4] |
0169                 // Lower 4 bits of mask
0170                     (cursor_bits_lookup[(b ^ m) & 0x0f] << 8);
0171                 break;
0172             case ROP_COPY:
0173                 // Upper 4 bits of mask data
0174                 l = cursor_bits_lookup[(b & m) >> 4] |
0175                 // Lower 4 bits of mask
0176                     (cursor_bits_lookup[(b & m) & 0x0f] << 8);
0177                 break;
0178             }
0179             /*
0180              * If cursor size is not a multiple of 8 characters
0181              * we must pad it with transparent pattern (0xaaaa).
0182              */
0183             if ((j + 1) * 8 > cursor->image.width) {
0184                 l = comp(l, 0xaaaa,
0185                     (1 << ((cursor->image.width & 7) * 2)) - 1);
0186             }
0187             fb_writeb(l & 0xff, dst++);
0188             fb_writeb(l >> 8, dst++);
0189         }
0190         dst += offset;
0191         }
0192     }
0193 
0194     return 0;
0195 }
0196 
0197 int aty_init_cursor(struct fb_info *info, struct fb_ops *atyfb_ops)
0198 {
0199     unsigned long addr;
0200 
0201     info->fix.smem_len -= PAGE_SIZE;
0202 
0203 #ifdef __sparc__
0204     addr = (unsigned long) info->screen_base - 0x800000 + info->fix.smem_len;
0205     info->sprite.addr = (u8 *) addr;
0206 #else
0207 #ifdef __BIG_ENDIAN
0208     addr = info->fix.smem_start - 0x800000 + info->fix.smem_len;
0209     info->sprite.addr = (u8 *) ioremap(addr, 1024);
0210 #else
0211     addr = (unsigned long) info->screen_base + info->fix.smem_len;
0212     info->sprite.addr = (u8 *) addr;
0213 #endif
0214 #endif
0215     if (!info->sprite.addr)
0216         return -ENXIO;
0217     info->sprite.size = PAGE_SIZE;
0218     info->sprite.scan_align = 16;   /* Scratch pad 64 bytes wide */
0219     info->sprite.buf_align = 16;    /* and 64 lines tall. */
0220     info->sprite.flags = FB_PIXMAP_IO;
0221 
0222     atyfb_ops->fb_cursor = atyfb_cursor;
0223 
0224     return 0;
0225 }
0226