1 | // SPDX-License-Identifier: GPL-2.0 |
2 | #include <linux/module.h> |
3 | #include <linux/kernel.h> |
4 | #include <linux/errno.h> |
5 | #include <linux/string.h> |
6 | #include <linux/mm.h> |
7 | #include <linux/slab.h> |
8 | #include <linux/delay.h> |
9 | #include <linux/fb.h> |
10 | #include <linux/ioport.h> |
11 | #include <linux/init.h> |
12 | #include <linux/pci.h> |
13 | #include <linux/vmalloc.h> |
14 | #include <linux/pagemap.h> |
15 | #include <linux/console.h> |
16 | #include <linux/platform_device.h> |
17 | |
18 | #include "sm750.h" |
19 | #include "sm750_cursor.h" |
20 | |
21 | #define poke32(addr, data) \ |
22 | writel((data), cursor->mmio + (addr)) |
23 | |
24 | /* cursor control for voyager and 718/750*/ |
25 | #define HWC_ADDRESS 0x0 |
26 | #define HWC_ADDRESS_ENABLE BIT(31) |
27 | #define HWC_ADDRESS_EXT BIT(27) |
28 | #define HWC_ADDRESS_CS BIT(26) |
29 | #define HWC_ADDRESS_ADDRESS_MASK 0x3ffffff |
30 | |
31 | #define HWC_LOCATION 0x4 |
32 | #define HWC_LOCATION_TOP BIT(27) |
33 | #define HWC_LOCATION_Y_SHIFT 16 |
34 | #define HWC_LOCATION_Y_MASK (0x7ff << 16) |
35 | #define HWC_LOCATION_LEFT BIT(11) |
36 | #define HWC_LOCATION_X_MASK 0x7ff |
37 | |
38 | #define HWC_COLOR_12 0x8 |
39 | #define HWC_COLOR_12_2_RGB565_SHIFT 16 |
40 | #define HWC_COLOR_12_2_RGB565_MASK (0xffff << 16) |
41 | #define HWC_COLOR_12_1_RGB565_MASK 0xffff |
42 | |
43 | #define HWC_COLOR_3 0xC |
44 | #define HWC_COLOR_3_RGB565_MASK 0xffff |
45 | |
46 | /* hw_cursor_xxx works for voyager,718 and 750 */ |
47 | void sm750_hw_cursor_enable(struct lynx_cursor *cursor) |
48 | { |
49 | u32 reg; |
50 | |
51 | reg = (cursor->offset & HWC_ADDRESS_ADDRESS_MASK) | HWC_ADDRESS_ENABLE; |
52 | poke32(HWC_ADDRESS, reg); |
53 | } |
54 | |
55 | void sm750_hw_cursor_disable(struct lynx_cursor *cursor) |
56 | { |
57 | poke32(HWC_ADDRESS, 0); |
58 | } |
59 | |
60 | void sm750_hw_cursor_setSize(struct lynx_cursor *cursor, int w, int h) |
61 | { |
62 | cursor->w = w; |
63 | cursor->h = h; |
64 | } |
65 | |
66 | void sm750_hw_cursor_setPos(struct lynx_cursor *cursor, int x, int y) |
67 | { |
68 | u32 reg; |
69 | |
70 | reg = ((y << HWC_LOCATION_Y_SHIFT) & HWC_LOCATION_Y_MASK) | |
71 | (x & HWC_LOCATION_X_MASK); |
72 | poke32(HWC_LOCATION, reg); |
73 | } |
74 | |
75 | void sm750_hw_cursor_setColor(struct lynx_cursor *cursor, u32 fg, u32 bg) |
76 | { |
77 | u32 reg = (fg << HWC_COLOR_12_2_RGB565_SHIFT) & |
78 | HWC_COLOR_12_2_RGB565_MASK; |
79 | |
80 | poke32(HWC_COLOR_12, reg | (bg & HWC_COLOR_12_1_RGB565_MASK)); |
81 | poke32(HWC_COLOR_3, 0xffe0); |
82 | } |
83 | |
84 | void sm750_hw_cursor_setData(struct lynx_cursor *cursor, u16 rop, |
85 | const u8 *pcol, const u8 *pmsk) |
86 | { |
87 | int i, j, count, pitch, offset; |
88 | u8 color, mask, opr; |
89 | u16 data; |
90 | void __iomem *pbuffer, *pstart; |
91 | |
92 | /* in byte*/ |
93 | pitch = cursor->w >> 3; |
94 | |
95 | /* in byte */ |
96 | count = pitch * cursor->h; |
97 | |
98 | /* in byte */ |
99 | offset = cursor->max_w * 2 / 8; |
100 | |
101 | data = 0; |
102 | pstart = cursor->vstart; |
103 | pbuffer = pstart; |
104 | |
105 | for (i = 0; i < count; i++) { |
106 | color = *pcol++; |
107 | mask = *pmsk++; |
108 | data = 0; |
109 | |
110 | for (j = 0; j < 8; j++) { |
111 | if (mask & (0x80 >> j)) { |
112 | if (rop == ROP_XOR) |
113 | opr = mask ^ color; |
114 | else |
115 | opr = mask & color; |
116 | |
117 | /* 2 stands for forecolor and 1 for backcolor */ |
118 | data |= ((opr & (0x80 >> j)) ? 2 : 1) << (j * 2); |
119 | } |
120 | } |
121 | iowrite16(data, pbuffer); |
122 | |
123 | /* assume pitch is 1,2,4,8,...*/ |
124 | if ((i + 1) % pitch == 0) { |
125 | /* need a return */ |
126 | pstart += offset; |
127 | pbuffer = pstart; |
128 | } else { |
129 | pbuffer += sizeof(u16); |
130 | } |
131 | } |
132 | } |
133 | |
134 | void sm750_hw_cursor_setData2(struct lynx_cursor *cursor, u16 rop, |
135 | const u8 *pcol, const u8 *pmsk) |
136 | { |
137 | int i, j, count, pitch, offset; |
138 | u8 color, mask; |
139 | u16 data; |
140 | void __iomem *pbuffer, *pstart; |
141 | |
142 | /* in byte*/ |
143 | pitch = cursor->w >> 3; |
144 | |
145 | /* in byte */ |
146 | count = pitch * cursor->h; |
147 | |
148 | /* in byte */ |
149 | offset = cursor->max_w * 2 / 8; |
150 | |
151 | data = 0; |
152 | pstart = cursor->vstart; |
153 | pbuffer = pstart; |
154 | |
155 | for (i = 0; i < count; i++) { |
156 | color = *pcol++; |
157 | mask = *pmsk++; |
158 | data = 0; |
159 | |
160 | for (j = 0; j < 8; j++) { |
161 | if (mask & (1 << j)) |
162 | data |= ((color & (1 << j)) ? 1 : 2) << (j * 2); |
163 | } |
164 | iowrite16(data, pbuffer); |
165 | |
166 | /* assume pitch is 1,2,4,8,...*/ |
167 | if (!(i & (pitch - 1))) { |
168 | /* need a return */ |
169 | pstart += offset; |
170 | pbuffer = pstart; |
171 | } else { |
172 | pbuffer += sizeof(u16); |
173 | } |
174 | } |
175 | } |
176 | |