1
2
3
4
5#include <linux/fb.h>
6#include <linux/init.h>
7#include <linux/string.h>
8
9#include <asm/io.h>
10
11#ifdef __sparc__
12#include <asm/fbio.h>
13#endif
14
15#include <video/mach64.h>
16#include "atyfb.h"
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
61static const u8 cursor_bits_lookup[16] = {
62 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
63 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55
64};
65
66static int atyfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
67{
68 struct atyfb_par *par = (struct atyfb_par *) info->par;
69 u16 xoff, yoff;
70 int x, y, h;
71
72#ifdef __sparc__
73 if (par->mmaped)
74 return -EPERM;
75#endif
76 if (par->asleep)
77 return -EPERM;
78
79 wait_for_fifo(1, par);
80 if (cursor->enable)
81 aty_st_le32(GEN_TEST_CNTL, aty_ld_le32(GEN_TEST_CNTL, par)
82 | HWCURSOR_ENABLE, par);
83 else
84 aty_st_le32(GEN_TEST_CNTL, aty_ld_le32(GEN_TEST_CNTL, par)
85 & ~HWCURSOR_ENABLE, par);
86
87
88 if (cursor->set & FB_CUR_SETPOS) {
89 x = cursor->image.dx - cursor->hot.x - info->var.xoffset;
90 if (x < 0) {
91 xoff = -x;
92 x = 0;
93 } else {
94 xoff = 0;
95 }
96
97 y = cursor->image.dy - cursor->hot.y - info->var.yoffset;
98 if (y < 0) {
99 yoff = -y;
100 y = 0;
101 } else {
102 yoff = 0;
103 }
104
105 h = cursor->image.height;
106
107
108
109
110
111 if (par->crtc.gen_cntl & CRTC_DBL_SCAN_EN) {
112 y<<=1;
113 h<<=1;
114 }
115 wait_for_fifo(3, par);
116 aty_st_le32(CUR_OFFSET, (info->fix.smem_len >> 3) + (yoff << 1), par);
117 aty_st_le32(CUR_HORZ_VERT_OFF,
118 ((u32) (64 - h + yoff) << 16) | xoff, par);
119 aty_st_le32(CUR_HORZ_VERT_POSN, ((u32) y << 16) | x, par);
120 }
121
122
123 if (cursor->set & FB_CUR_SETCMAP) {
124 u32 fg_idx, bg_idx, fg, bg;
125
126 fg_idx = cursor->image.fg_color;
127 bg_idx = cursor->image.bg_color;
128
129 fg = ((info->cmap.red[fg_idx] & 0xff) << 24) |
130 ((info->cmap.green[fg_idx] & 0xff) << 16) |
131 ((info->cmap.blue[fg_idx] & 0xff) << 8) | 0xff;
132
133 bg = ((info->cmap.red[bg_idx] & 0xff) << 24) |
134 ((info->cmap.green[bg_idx] & 0xff) << 16) |
135 ((info->cmap.blue[bg_idx] & 0xff) << 8);
136
137 wait_for_fifo(2, par);
138 aty_st_le32(CUR_CLR0, bg, par);
139 aty_st_le32(CUR_CLR1, fg, par);
140 }
141
142 if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) {
143 u8 *src = (u8 *)cursor->image.data;
144 u8 *msk = (u8 *)cursor->mask;
145 u8 __iomem *dst = (u8 __iomem *)info->sprite.addr;
146 unsigned int width = (cursor->image.width + 7) >> 3;
147 unsigned int height = cursor->image.height;
148 unsigned int align = info->sprite.scan_align;
149
150 unsigned int i, j, offset;
151 u8 m, b;
152
153
154 fb_memset(dst, 0xaa, 1024);
155
156 offset = align - width*2;
157
158 for (i = 0; i < height; i++) {
159 for (j = 0; j < width; j++) {
160 b = *src++;
161 m = *msk++;
162 switch (cursor->rop) {
163 case ROP_XOR:
164
165 fb_writeb(cursor_bits_lookup[(b ^ m) >> 4], dst++);
166
167 fb_writeb(cursor_bits_lookup[(b ^ m) & 0x0f],
168 dst++);
169 break;
170 case ROP_COPY:
171
172 fb_writeb(cursor_bits_lookup[(b & m) >> 4], dst++);
173
174 fb_writeb(cursor_bits_lookup[(b & m) & 0x0f],
175 dst++);
176 break;
177 }
178 }
179 dst += offset;
180 }
181 }
182
183 return 0;
184}
185
186int aty_init_cursor(struct fb_info *info)
187{
188 unsigned long addr;
189
190 info->fix.smem_len -= PAGE_SIZE;
191
192#ifdef __sparc__
193 addr = (unsigned long) info->screen_base - 0x800000 + info->fix.smem_len;
194 info->sprite.addr = (u8 *) addr;
195#else
196#ifdef __BIG_ENDIAN
197 addr = info->fix.smem_start - 0x800000 + info->fix.smem_len;
198 info->sprite.addr = (u8 *) ioremap(addr, 1024);
199#else
200 addr = (unsigned long) info->screen_base + info->fix.smem_len;
201 info->sprite.addr = (u8 *) addr;
202#endif
203#endif
204 if (!info->sprite.addr)
205 return -ENXIO;
206 info->sprite.size = PAGE_SIZE;
207 info->sprite.scan_align = 16;
208 info->sprite.buf_align = 16;
209 info->sprite.flags = FB_PIXMAP_IO;
210
211 info->fbops->fb_cursor = atyfb_cursor;
212
213 return 0;
214}
215
216