1*64b70da0SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2f7018c21STomi Valkeinen /*
3f7018c21STomi Valkeinen * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
4f7018c21STomi Valkeinen * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
5f7018c21STomi Valkeinen
6f7018c21STomi Valkeinen */
7f7018c21STomi Valkeinen #include <linux/via-core.h>
8f7018c21STomi Valkeinen #include "global.h"
9f7018c21STomi Valkeinen
10f7018c21STomi Valkeinen /*
11f7018c21STomi Valkeinen * Figure out an appropriate bytes-per-pixel setting.
12f7018c21STomi Valkeinen */
viafb_set_bpp(void __iomem * engine,u8 bpp)13f7018c21STomi Valkeinen static int viafb_set_bpp(void __iomem *engine, u8 bpp)
14f7018c21STomi Valkeinen {
15f7018c21STomi Valkeinen u32 gemode;
16f7018c21STomi Valkeinen
17f7018c21STomi Valkeinen /* Preserve the reserved bits */
18f7018c21STomi Valkeinen /* Lowest 2 bits to zero gives us no rotation */
19f7018c21STomi Valkeinen gemode = readl(engine + VIA_REG_GEMODE) & 0xfffffcfc;
20f7018c21STomi Valkeinen switch (bpp) {
21f7018c21STomi Valkeinen case 8:
22f7018c21STomi Valkeinen gemode |= VIA_GEM_8bpp;
23f7018c21STomi Valkeinen break;
24f7018c21STomi Valkeinen case 16:
25f7018c21STomi Valkeinen gemode |= VIA_GEM_16bpp;
26f7018c21STomi Valkeinen break;
27f7018c21STomi Valkeinen case 32:
28f7018c21STomi Valkeinen gemode |= VIA_GEM_32bpp;
29f7018c21STomi Valkeinen break;
30f7018c21STomi Valkeinen default:
31f7018c21STomi Valkeinen printk(KERN_WARNING "viafb_set_bpp: Unsupported bpp %d\n", bpp);
32f7018c21STomi Valkeinen return -EINVAL;
33f7018c21STomi Valkeinen }
34f7018c21STomi Valkeinen writel(gemode, engine + VIA_REG_GEMODE);
35f7018c21STomi Valkeinen return 0;
36f7018c21STomi Valkeinen }
37f7018c21STomi Valkeinen
38f7018c21STomi Valkeinen
hw_bitblt_1(void __iomem * engine,u8 op,u32 width,u32 height,u8 dst_bpp,u32 dst_addr,u32 dst_pitch,u32 dst_x,u32 dst_y,u32 * src_mem,u32 src_addr,u32 src_pitch,u32 src_x,u32 src_y,u32 fg_color,u32 bg_color,u8 fill_rop)39f7018c21STomi Valkeinen static int hw_bitblt_1(void __iomem *engine, u8 op, u32 width, u32 height,
40f7018c21STomi Valkeinen u8 dst_bpp, u32 dst_addr, u32 dst_pitch, u32 dst_x, u32 dst_y,
41f7018c21STomi Valkeinen u32 *src_mem, u32 src_addr, u32 src_pitch, u32 src_x, u32 src_y,
42f7018c21STomi Valkeinen u32 fg_color, u32 bg_color, u8 fill_rop)
43f7018c21STomi Valkeinen {
44f7018c21STomi Valkeinen u32 ge_cmd = 0, tmp, i;
45f7018c21STomi Valkeinen int ret;
46f7018c21STomi Valkeinen
47f7018c21STomi Valkeinen if (!op || op > 3) {
48f7018c21STomi Valkeinen printk(KERN_WARNING "hw_bitblt_1: Invalid operation: %d\n", op);
49f7018c21STomi Valkeinen return -EINVAL;
50f7018c21STomi Valkeinen }
51f7018c21STomi Valkeinen
52f7018c21STomi Valkeinen if (op != VIA_BITBLT_FILL && !src_mem && src_addr == dst_addr) {
53f7018c21STomi Valkeinen if (src_x < dst_x) {
54f7018c21STomi Valkeinen ge_cmd |= 0x00008000;
55f7018c21STomi Valkeinen src_x += width - 1;
56f7018c21STomi Valkeinen dst_x += width - 1;
57f7018c21STomi Valkeinen }
58f7018c21STomi Valkeinen if (src_y < dst_y) {
59f7018c21STomi Valkeinen ge_cmd |= 0x00004000;
60f7018c21STomi Valkeinen src_y += height - 1;
61f7018c21STomi Valkeinen dst_y += height - 1;
62f7018c21STomi Valkeinen }
63f7018c21STomi Valkeinen }
64f7018c21STomi Valkeinen
65f7018c21STomi Valkeinen if (op == VIA_BITBLT_FILL) {
66f7018c21STomi Valkeinen switch (fill_rop) {
67f7018c21STomi Valkeinen case 0x00: /* blackness */
68f7018c21STomi Valkeinen case 0x5A: /* pattern inversion */
69f7018c21STomi Valkeinen case 0xF0: /* pattern copy */
70f7018c21STomi Valkeinen case 0xFF: /* whiteness */
71f7018c21STomi Valkeinen break;
72f7018c21STomi Valkeinen default:
73f7018c21STomi Valkeinen printk(KERN_WARNING "hw_bitblt_1: Invalid fill rop: "
74f7018c21STomi Valkeinen "%u\n", fill_rop);
75f7018c21STomi Valkeinen return -EINVAL;
76f7018c21STomi Valkeinen }
77f7018c21STomi Valkeinen }
78f7018c21STomi Valkeinen
79f7018c21STomi Valkeinen ret = viafb_set_bpp(engine, dst_bpp);
80f7018c21STomi Valkeinen if (ret)
81f7018c21STomi Valkeinen return ret;
82f7018c21STomi Valkeinen
83f7018c21STomi Valkeinen if (op != VIA_BITBLT_FILL) {
84f7018c21STomi Valkeinen if (src_x & (op == VIA_BITBLT_MONO ? 0xFFFF8000 : 0xFFFFF000)
85f7018c21STomi Valkeinen || src_y & 0xFFFFF000) {
86f7018c21STomi Valkeinen printk(KERN_WARNING "hw_bitblt_1: Unsupported source "
87f7018c21STomi Valkeinen "x/y %d %d\n", src_x, src_y);
88f7018c21STomi Valkeinen return -EINVAL;
89f7018c21STomi Valkeinen }
90f7018c21STomi Valkeinen tmp = src_x | (src_y << 16);
91f7018c21STomi Valkeinen writel(tmp, engine + 0x08);
92f7018c21STomi Valkeinen }
93f7018c21STomi Valkeinen
94f7018c21STomi Valkeinen if (dst_x & 0xFFFFF000 || dst_y & 0xFFFFF000) {
95f7018c21STomi Valkeinen printk(KERN_WARNING "hw_bitblt_1: Unsupported destination x/y "
96f7018c21STomi Valkeinen "%d %d\n", dst_x, dst_y);
97f7018c21STomi Valkeinen return -EINVAL;
98f7018c21STomi Valkeinen }
99f7018c21STomi Valkeinen tmp = dst_x | (dst_y << 16);
100f7018c21STomi Valkeinen writel(tmp, engine + 0x0C);
101f7018c21STomi Valkeinen
102f7018c21STomi Valkeinen if ((width - 1) & 0xFFFFF000 || (height - 1) & 0xFFFFF000) {
103f7018c21STomi Valkeinen printk(KERN_WARNING "hw_bitblt_1: Unsupported width/height "
104f7018c21STomi Valkeinen "%d %d\n", width, height);
105f7018c21STomi Valkeinen return -EINVAL;
106f7018c21STomi Valkeinen }
107f7018c21STomi Valkeinen tmp = (width - 1) | ((height - 1) << 16);
108f7018c21STomi Valkeinen writel(tmp, engine + 0x10);
109f7018c21STomi Valkeinen
110f7018c21STomi Valkeinen if (op != VIA_BITBLT_COLOR)
111f7018c21STomi Valkeinen writel(fg_color, engine + 0x18);
112f7018c21STomi Valkeinen
113f7018c21STomi Valkeinen if (op == VIA_BITBLT_MONO)
114f7018c21STomi Valkeinen writel(bg_color, engine + 0x1C);
115f7018c21STomi Valkeinen
116f7018c21STomi Valkeinen if (op != VIA_BITBLT_FILL) {
117f7018c21STomi Valkeinen tmp = src_mem ? 0 : src_addr;
118f7018c21STomi Valkeinen if (tmp & 0xE0000007) {
119f7018c21STomi Valkeinen printk(KERN_WARNING "hw_bitblt_1: Unsupported source "
120f7018c21STomi Valkeinen "address %X\n", tmp);
121f7018c21STomi Valkeinen return -EINVAL;
122f7018c21STomi Valkeinen }
123f7018c21STomi Valkeinen tmp >>= 3;
124f7018c21STomi Valkeinen writel(tmp, engine + 0x30);
125f7018c21STomi Valkeinen }
126f7018c21STomi Valkeinen
127f7018c21STomi Valkeinen if (dst_addr & 0xE0000007) {
128f7018c21STomi Valkeinen printk(KERN_WARNING "hw_bitblt_1: Unsupported destination "
129f7018c21STomi Valkeinen "address %X\n", dst_addr);
130f7018c21STomi Valkeinen return -EINVAL;
131f7018c21STomi Valkeinen }
132f7018c21STomi Valkeinen tmp = dst_addr >> 3;
133f7018c21STomi Valkeinen writel(tmp, engine + 0x34);
134f7018c21STomi Valkeinen
135f7018c21STomi Valkeinen if (op == VIA_BITBLT_FILL)
136f7018c21STomi Valkeinen tmp = 0;
137f7018c21STomi Valkeinen else
138f7018c21STomi Valkeinen tmp = src_pitch;
139f7018c21STomi Valkeinen if (tmp & 0xFFFFC007 || dst_pitch & 0xFFFFC007) {
140f7018c21STomi Valkeinen printk(KERN_WARNING "hw_bitblt_1: Unsupported pitch %X %X\n",
141f7018c21STomi Valkeinen tmp, dst_pitch);
142f7018c21STomi Valkeinen return -EINVAL;
143f7018c21STomi Valkeinen }
144f7018c21STomi Valkeinen tmp = VIA_PITCH_ENABLE | (tmp >> 3) | (dst_pitch << (16 - 3));
145f7018c21STomi Valkeinen writel(tmp, engine + 0x38);
146f7018c21STomi Valkeinen
147f7018c21STomi Valkeinen if (op == VIA_BITBLT_FILL)
148f7018c21STomi Valkeinen ge_cmd |= fill_rop << 24 | 0x00002000 | 0x00000001;
149f7018c21STomi Valkeinen else {
150f7018c21STomi Valkeinen ge_cmd |= 0xCC000000; /* ROP=SRCCOPY */
151f7018c21STomi Valkeinen if (src_mem)
152f7018c21STomi Valkeinen ge_cmd |= 0x00000040;
153f7018c21STomi Valkeinen if (op == VIA_BITBLT_MONO)
154f7018c21STomi Valkeinen ge_cmd |= 0x00000002 | 0x00000100 | 0x00020000;
155f7018c21STomi Valkeinen else
156f7018c21STomi Valkeinen ge_cmd |= 0x00000001;
157f7018c21STomi Valkeinen }
158f7018c21STomi Valkeinen writel(ge_cmd, engine);
159f7018c21STomi Valkeinen
160f7018c21STomi Valkeinen if (op == VIA_BITBLT_FILL || !src_mem)
161f7018c21STomi Valkeinen return 0;
162f7018c21STomi Valkeinen
163f7018c21STomi Valkeinen tmp = (width * height * (op == VIA_BITBLT_MONO ? 1 : (dst_bpp >> 3)) +
164f7018c21STomi Valkeinen 3) >> 2;
165f7018c21STomi Valkeinen
166f7018c21STomi Valkeinen for (i = 0; i < tmp; i++)
167f7018c21STomi Valkeinen writel(src_mem[i], engine + VIA_MMIO_BLTBASE);
168f7018c21STomi Valkeinen
169f7018c21STomi Valkeinen return 0;
170f7018c21STomi Valkeinen }
171f7018c21STomi Valkeinen
hw_bitblt_2(void __iomem * engine,u8 op,u32 width,u32 height,u8 dst_bpp,u32 dst_addr,u32 dst_pitch,u32 dst_x,u32 dst_y,u32 * src_mem,u32 src_addr,u32 src_pitch,u32 src_x,u32 src_y,u32 fg_color,u32 bg_color,u8 fill_rop)172f7018c21STomi Valkeinen static int hw_bitblt_2(void __iomem *engine, u8 op, u32 width, u32 height,
173f7018c21STomi Valkeinen u8 dst_bpp, u32 dst_addr, u32 dst_pitch, u32 dst_x, u32 dst_y,
174f7018c21STomi Valkeinen u32 *src_mem, u32 src_addr, u32 src_pitch, u32 src_x, u32 src_y,
175f7018c21STomi Valkeinen u32 fg_color, u32 bg_color, u8 fill_rop)
176f7018c21STomi Valkeinen {
177f7018c21STomi Valkeinen u32 ge_cmd = 0, tmp, i;
178f7018c21STomi Valkeinen int ret;
179f7018c21STomi Valkeinen
180f7018c21STomi Valkeinen if (!op || op > 3) {
181f7018c21STomi Valkeinen printk(KERN_WARNING "hw_bitblt_2: Invalid operation: %d\n", op);
182f7018c21STomi Valkeinen return -EINVAL;
183f7018c21STomi Valkeinen }
184f7018c21STomi Valkeinen
185f7018c21STomi Valkeinen if (op != VIA_BITBLT_FILL && !src_mem && src_addr == dst_addr) {
186f7018c21STomi Valkeinen if (src_x < dst_x) {
187f7018c21STomi Valkeinen ge_cmd |= 0x00008000;
188f7018c21STomi Valkeinen src_x += width - 1;
189f7018c21STomi Valkeinen dst_x += width - 1;
190f7018c21STomi Valkeinen }
191f7018c21STomi Valkeinen if (src_y < dst_y) {
192f7018c21STomi Valkeinen ge_cmd |= 0x00004000;
193f7018c21STomi Valkeinen src_y += height - 1;
194f7018c21STomi Valkeinen dst_y += height - 1;
195f7018c21STomi Valkeinen }
196f7018c21STomi Valkeinen }
197f7018c21STomi Valkeinen
198f7018c21STomi Valkeinen if (op == VIA_BITBLT_FILL) {
199f7018c21STomi Valkeinen switch (fill_rop) {
200f7018c21STomi Valkeinen case 0x00: /* blackness */
201f7018c21STomi Valkeinen case 0x5A: /* pattern inversion */
202f7018c21STomi Valkeinen case 0xF0: /* pattern copy */
203f7018c21STomi Valkeinen case 0xFF: /* whiteness */
204f7018c21STomi Valkeinen break;
205f7018c21STomi Valkeinen default:
206f7018c21STomi Valkeinen printk(KERN_WARNING "hw_bitblt_2: Invalid fill rop: "
207f7018c21STomi Valkeinen "%u\n", fill_rop);
208f7018c21STomi Valkeinen return -EINVAL;
209f7018c21STomi Valkeinen }
210f7018c21STomi Valkeinen }
211f7018c21STomi Valkeinen
212f7018c21STomi Valkeinen ret = viafb_set_bpp(engine, dst_bpp);
213f7018c21STomi Valkeinen if (ret)
214f7018c21STomi Valkeinen return ret;
215f7018c21STomi Valkeinen
216f7018c21STomi Valkeinen if (op == VIA_BITBLT_FILL)
217f7018c21STomi Valkeinen tmp = 0;
218f7018c21STomi Valkeinen else
219f7018c21STomi Valkeinen tmp = src_pitch;
220f7018c21STomi Valkeinen if (tmp & 0xFFFFC007 || dst_pitch & 0xFFFFC007) {
221f7018c21STomi Valkeinen printk(KERN_WARNING "hw_bitblt_2: Unsupported pitch %X %X\n",
222f7018c21STomi Valkeinen tmp, dst_pitch);
223f7018c21STomi Valkeinen return -EINVAL;
224f7018c21STomi Valkeinen }
225f7018c21STomi Valkeinen tmp = (tmp >> 3) | (dst_pitch << (16 - 3));
226f7018c21STomi Valkeinen writel(tmp, engine + 0x08);
227f7018c21STomi Valkeinen
228f7018c21STomi Valkeinen if ((width - 1) & 0xFFFFF000 || (height - 1) & 0xFFFFF000) {
229f7018c21STomi Valkeinen printk(KERN_WARNING "hw_bitblt_2: Unsupported width/height "
230f7018c21STomi Valkeinen "%d %d\n", width, height);
231f7018c21STomi Valkeinen return -EINVAL;
232f7018c21STomi Valkeinen }
233f7018c21STomi Valkeinen tmp = (width - 1) | ((height - 1) << 16);
234f7018c21STomi Valkeinen writel(tmp, engine + 0x0C);
235f7018c21STomi Valkeinen
236f7018c21STomi Valkeinen if (dst_x & 0xFFFFF000 || dst_y & 0xFFFFF000) {
237f7018c21STomi Valkeinen printk(KERN_WARNING "hw_bitblt_2: Unsupported destination x/y "
238f7018c21STomi Valkeinen "%d %d\n", dst_x, dst_y);
239f7018c21STomi Valkeinen return -EINVAL;
240f7018c21STomi Valkeinen }
241f7018c21STomi Valkeinen tmp = dst_x | (dst_y << 16);
242f7018c21STomi Valkeinen writel(tmp, engine + 0x10);
243f7018c21STomi Valkeinen
244f7018c21STomi Valkeinen if (dst_addr & 0xE0000007) {
245f7018c21STomi Valkeinen printk(KERN_WARNING "hw_bitblt_2: Unsupported destination "
246f7018c21STomi Valkeinen "address %X\n", dst_addr);
247f7018c21STomi Valkeinen return -EINVAL;
248f7018c21STomi Valkeinen }
249f7018c21STomi Valkeinen tmp = dst_addr >> 3;
250f7018c21STomi Valkeinen writel(tmp, engine + 0x14);
251f7018c21STomi Valkeinen
252f7018c21STomi Valkeinen if (op != VIA_BITBLT_FILL) {
253f7018c21STomi Valkeinen if (src_x & (op == VIA_BITBLT_MONO ? 0xFFFF8000 : 0xFFFFF000)
254f7018c21STomi Valkeinen || src_y & 0xFFFFF000) {
255f7018c21STomi Valkeinen printk(KERN_WARNING "hw_bitblt_2: Unsupported source "
256f7018c21STomi Valkeinen "x/y %d %d\n", src_x, src_y);
257f7018c21STomi Valkeinen return -EINVAL;
258f7018c21STomi Valkeinen }
259f7018c21STomi Valkeinen tmp = src_x | (src_y << 16);
260f7018c21STomi Valkeinen writel(tmp, engine + 0x18);
261f7018c21STomi Valkeinen
262f7018c21STomi Valkeinen tmp = src_mem ? 0 : src_addr;
263f7018c21STomi Valkeinen if (tmp & 0xE0000007) {
264f7018c21STomi Valkeinen printk(KERN_WARNING "hw_bitblt_2: Unsupported source "
265f7018c21STomi Valkeinen "address %X\n", tmp);
266f7018c21STomi Valkeinen return -EINVAL;
267f7018c21STomi Valkeinen }
268f7018c21STomi Valkeinen tmp >>= 3;
269f7018c21STomi Valkeinen writel(tmp, engine + 0x1C);
270f7018c21STomi Valkeinen }
271f7018c21STomi Valkeinen
272f7018c21STomi Valkeinen if (op == VIA_BITBLT_FILL) {
273f7018c21STomi Valkeinen writel(fg_color, engine + 0x58);
274f7018c21STomi Valkeinen } else if (op == VIA_BITBLT_MONO) {
275f7018c21STomi Valkeinen writel(fg_color, engine + 0x4C);
276f7018c21STomi Valkeinen writel(bg_color, engine + 0x50);
277f7018c21STomi Valkeinen }
278f7018c21STomi Valkeinen
279f7018c21STomi Valkeinen if (op == VIA_BITBLT_FILL)
280f7018c21STomi Valkeinen ge_cmd |= fill_rop << 24 | 0x00002000 | 0x00000001;
281f7018c21STomi Valkeinen else {
282f7018c21STomi Valkeinen ge_cmd |= 0xCC000000; /* ROP=SRCCOPY */
283f7018c21STomi Valkeinen if (src_mem)
284f7018c21STomi Valkeinen ge_cmd |= 0x00000040;
285f7018c21STomi Valkeinen if (op == VIA_BITBLT_MONO)
286f7018c21STomi Valkeinen ge_cmd |= 0x00000002 | 0x00000100 | 0x00020000;
287f7018c21STomi Valkeinen else
288f7018c21STomi Valkeinen ge_cmd |= 0x00000001;
289f7018c21STomi Valkeinen }
290f7018c21STomi Valkeinen writel(ge_cmd, engine);
291f7018c21STomi Valkeinen
292f7018c21STomi Valkeinen if (op == VIA_BITBLT_FILL || !src_mem)
293f7018c21STomi Valkeinen return 0;
294f7018c21STomi Valkeinen
295f7018c21STomi Valkeinen tmp = (width * height * (op == VIA_BITBLT_MONO ? 1 : (dst_bpp >> 3)) +
296f7018c21STomi Valkeinen 3) >> 2;
297f7018c21STomi Valkeinen
298f7018c21STomi Valkeinen for (i = 0; i < tmp; i++)
299f7018c21STomi Valkeinen writel(src_mem[i], engine + VIA_MMIO_BLTBASE);
300f7018c21STomi Valkeinen
301f7018c21STomi Valkeinen return 0;
302f7018c21STomi Valkeinen }
303f7018c21STomi Valkeinen
viafb_setup_engine(struct fb_info * info)304f7018c21STomi Valkeinen int viafb_setup_engine(struct fb_info *info)
305f7018c21STomi Valkeinen {
306f7018c21STomi Valkeinen struct viafb_par *viapar = info->par;
307f7018c21STomi Valkeinen void __iomem *engine;
308f7018c21STomi Valkeinen u32 chip_name = viapar->shared->chip_info.gfx_chip_name;
309f7018c21STomi Valkeinen
310f7018c21STomi Valkeinen engine = viapar->shared->vdev->engine_mmio;
311f7018c21STomi Valkeinen if (!engine) {
312f7018c21STomi Valkeinen printk(KERN_WARNING "viafb_init_accel: ioremap failed, "
313f7018c21STomi Valkeinen "hardware acceleration disabled\n");
314f7018c21STomi Valkeinen return -ENOMEM;
315f7018c21STomi Valkeinen }
316f7018c21STomi Valkeinen
317f7018c21STomi Valkeinen switch (chip_name) {
318f7018c21STomi Valkeinen case UNICHROME_CLE266:
319f7018c21STomi Valkeinen case UNICHROME_K400:
320f7018c21STomi Valkeinen case UNICHROME_K800:
321f7018c21STomi Valkeinen case UNICHROME_PM800:
322f7018c21STomi Valkeinen case UNICHROME_CN700:
323f7018c21STomi Valkeinen case UNICHROME_CX700:
324f7018c21STomi Valkeinen case UNICHROME_CN750:
325f7018c21STomi Valkeinen case UNICHROME_K8M890:
326f7018c21STomi Valkeinen case UNICHROME_P4M890:
327f7018c21STomi Valkeinen case UNICHROME_P4M900:
328f7018c21STomi Valkeinen viapar->shared->hw_bitblt = hw_bitblt_1;
329f7018c21STomi Valkeinen break;
330f7018c21STomi Valkeinen case UNICHROME_VX800:
331f7018c21STomi Valkeinen case UNICHROME_VX855:
332f7018c21STomi Valkeinen case UNICHROME_VX900:
333f7018c21STomi Valkeinen viapar->shared->hw_bitblt = hw_bitblt_2;
334f7018c21STomi Valkeinen break;
335f7018c21STomi Valkeinen default:
336f7018c21STomi Valkeinen viapar->shared->hw_bitblt = NULL;
337f7018c21STomi Valkeinen }
338f7018c21STomi Valkeinen
339f7018c21STomi Valkeinen viapar->fbmem_free -= CURSOR_SIZE;
340f7018c21STomi Valkeinen viapar->shared->cursor_vram_addr = viapar->fbmem_free;
341f7018c21STomi Valkeinen viapar->fbmem_used += CURSOR_SIZE;
342f7018c21STomi Valkeinen
343f7018c21STomi Valkeinen viapar->fbmem_free -= VQ_SIZE;
344f7018c21STomi Valkeinen viapar->shared->vq_vram_addr = viapar->fbmem_free;
345f7018c21STomi Valkeinen viapar->fbmem_used += VQ_SIZE;
346f7018c21STomi Valkeinen
347ab366b40SJavier Martinez Canillas #if IS_ENABLED(CONFIG_VIDEO_VIA_CAMERA)
348f7018c21STomi Valkeinen /*
349f7018c21STomi Valkeinen * Set aside a chunk of framebuffer memory for the camera
350f7018c21STomi Valkeinen * driver. Someday this driver probably needs a proper allocator
351f7018c21STomi Valkeinen * for fbmem; for now, we just have to do this before the
352f7018c21STomi Valkeinen * framebuffer initializes itself.
353f7018c21STomi Valkeinen *
354f7018c21STomi Valkeinen * As for the size: the engine can handle three frames,
355f7018c21STomi Valkeinen * 16 bits deep, up to VGA resolution.
356f7018c21STomi Valkeinen */
357f7018c21STomi Valkeinen viapar->shared->vdev->camera_fbmem_size = 3*VGA_HEIGHT*VGA_WIDTH*2;
358f7018c21STomi Valkeinen viapar->fbmem_free -= viapar->shared->vdev->camera_fbmem_size;
359f7018c21STomi Valkeinen viapar->fbmem_used += viapar->shared->vdev->camera_fbmem_size;
360f7018c21STomi Valkeinen viapar->shared->vdev->camera_fbmem_offset = viapar->fbmem_free;
361f7018c21STomi Valkeinen #endif
362f7018c21STomi Valkeinen
363f7018c21STomi Valkeinen viafb_reset_engine(viapar);
364f7018c21STomi Valkeinen return 0;
365f7018c21STomi Valkeinen }
366f7018c21STomi Valkeinen
viafb_reset_engine(struct viafb_par * viapar)367f7018c21STomi Valkeinen void viafb_reset_engine(struct viafb_par *viapar)
368f7018c21STomi Valkeinen {
369f7018c21STomi Valkeinen void __iomem *engine = viapar->shared->vdev->engine_mmio;
370f7018c21STomi Valkeinen int highest_reg, i;
371f7018c21STomi Valkeinen u32 vq_start_addr, vq_end_addr, vq_start_low, vq_end_low, vq_high,
372f7018c21STomi Valkeinen vq_len, chip_name = viapar->shared->chip_info.gfx_chip_name;
373f7018c21STomi Valkeinen
374f7018c21STomi Valkeinen /* Initialize registers to reset the 2D engine */
375f7018c21STomi Valkeinen switch (viapar->shared->chip_info.twod_engine) {
376f7018c21STomi Valkeinen case VIA_2D_ENG_M1:
377f7018c21STomi Valkeinen highest_reg = 0x5c;
378f7018c21STomi Valkeinen break;
379f7018c21STomi Valkeinen default:
380f7018c21STomi Valkeinen highest_reg = 0x40;
381f7018c21STomi Valkeinen break;
382f7018c21STomi Valkeinen }
383f7018c21STomi Valkeinen for (i = 0; i <= highest_reg; i += 4)
384f7018c21STomi Valkeinen writel(0x0, engine + i);
385f7018c21STomi Valkeinen
386f7018c21STomi Valkeinen /* Init AGP and VQ regs */
387f7018c21STomi Valkeinen switch (chip_name) {
388f7018c21STomi Valkeinen case UNICHROME_K8M890:
389f7018c21STomi Valkeinen case UNICHROME_P4M900:
390f7018c21STomi Valkeinen case UNICHROME_VX800:
391f7018c21STomi Valkeinen case UNICHROME_VX855:
392f7018c21STomi Valkeinen case UNICHROME_VX900:
393f7018c21STomi Valkeinen writel(0x00100000, engine + VIA_REG_CR_TRANSET);
394f7018c21STomi Valkeinen writel(0x680A0000, engine + VIA_REG_CR_TRANSPACE);
395f7018c21STomi Valkeinen writel(0x02000000, engine + VIA_REG_CR_TRANSPACE);
396f7018c21STomi Valkeinen break;
397f7018c21STomi Valkeinen
398f7018c21STomi Valkeinen default:
399f7018c21STomi Valkeinen writel(0x00100000, engine + VIA_REG_TRANSET);
400f7018c21STomi Valkeinen writel(0x00000000, engine + VIA_REG_TRANSPACE);
401f7018c21STomi Valkeinen writel(0x00333004, engine + VIA_REG_TRANSPACE);
402f7018c21STomi Valkeinen writel(0x60000000, engine + VIA_REG_TRANSPACE);
403f7018c21STomi Valkeinen writel(0x61000000, engine + VIA_REG_TRANSPACE);
404f7018c21STomi Valkeinen writel(0x62000000, engine + VIA_REG_TRANSPACE);
405f7018c21STomi Valkeinen writel(0x63000000, engine + VIA_REG_TRANSPACE);
406f7018c21STomi Valkeinen writel(0x64000000, engine + VIA_REG_TRANSPACE);
407f7018c21STomi Valkeinen writel(0x7D000000, engine + VIA_REG_TRANSPACE);
408f7018c21STomi Valkeinen
409f7018c21STomi Valkeinen writel(0xFE020000, engine + VIA_REG_TRANSET);
410f7018c21STomi Valkeinen writel(0x00000000, engine + VIA_REG_TRANSPACE);
411f7018c21STomi Valkeinen break;
412f7018c21STomi Valkeinen }
413f7018c21STomi Valkeinen
414f7018c21STomi Valkeinen /* Enable VQ */
415f7018c21STomi Valkeinen vq_start_addr = viapar->shared->vq_vram_addr;
416f7018c21STomi Valkeinen vq_end_addr = viapar->shared->vq_vram_addr + VQ_SIZE - 1;
417f7018c21STomi Valkeinen
418f7018c21STomi Valkeinen vq_start_low = 0x50000000 | (vq_start_addr & 0xFFFFFF);
419f7018c21STomi Valkeinen vq_end_low = 0x51000000 | (vq_end_addr & 0xFFFFFF);
420f7018c21STomi Valkeinen vq_high = 0x52000000 | ((vq_start_addr & 0xFF000000) >> 24) |
421f7018c21STomi Valkeinen ((vq_end_addr & 0xFF000000) >> 16);
422f7018c21STomi Valkeinen vq_len = 0x53000000 | (VQ_SIZE >> 3);
423f7018c21STomi Valkeinen
424f7018c21STomi Valkeinen switch (chip_name) {
425f7018c21STomi Valkeinen case UNICHROME_K8M890:
426f7018c21STomi Valkeinen case UNICHROME_P4M900:
427f7018c21STomi Valkeinen case UNICHROME_VX800:
428f7018c21STomi Valkeinen case UNICHROME_VX855:
429f7018c21STomi Valkeinen case UNICHROME_VX900:
430f7018c21STomi Valkeinen vq_start_low |= 0x20000000;
431f7018c21STomi Valkeinen vq_end_low |= 0x20000000;
432f7018c21STomi Valkeinen vq_high |= 0x20000000;
433f7018c21STomi Valkeinen vq_len |= 0x20000000;
434f7018c21STomi Valkeinen
435f7018c21STomi Valkeinen writel(0x00100000, engine + VIA_REG_CR_TRANSET);
436f7018c21STomi Valkeinen writel(vq_high, engine + VIA_REG_CR_TRANSPACE);
437f7018c21STomi Valkeinen writel(vq_start_low, engine + VIA_REG_CR_TRANSPACE);
438f7018c21STomi Valkeinen writel(vq_end_low, engine + VIA_REG_CR_TRANSPACE);
439f7018c21STomi Valkeinen writel(vq_len, engine + VIA_REG_CR_TRANSPACE);
440f7018c21STomi Valkeinen writel(0x74301001, engine + VIA_REG_CR_TRANSPACE);
441f7018c21STomi Valkeinen writel(0x00000000, engine + VIA_REG_CR_TRANSPACE);
442f7018c21STomi Valkeinen break;
443f7018c21STomi Valkeinen default:
444f7018c21STomi Valkeinen writel(0x00FE0000, engine + VIA_REG_TRANSET);
445f7018c21STomi Valkeinen writel(0x080003FE, engine + VIA_REG_TRANSPACE);
446f7018c21STomi Valkeinen writel(0x0A00027C, engine + VIA_REG_TRANSPACE);
447f7018c21STomi Valkeinen writel(0x0B000260, engine + VIA_REG_TRANSPACE);
448f7018c21STomi Valkeinen writel(0x0C000274, engine + VIA_REG_TRANSPACE);
449f7018c21STomi Valkeinen writel(0x0D000264, engine + VIA_REG_TRANSPACE);
450f7018c21STomi Valkeinen writel(0x0E000000, engine + VIA_REG_TRANSPACE);
451f7018c21STomi Valkeinen writel(0x0F000020, engine + VIA_REG_TRANSPACE);
452f7018c21STomi Valkeinen writel(0x1000027E, engine + VIA_REG_TRANSPACE);
453f7018c21STomi Valkeinen writel(0x110002FE, engine + VIA_REG_TRANSPACE);
454f7018c21STomi Valkeinen writel(0x200F0060, engine + VIA_REG_TRANSPACE);
455f7018c21STomi Valkeinen
456f7018c21STomi Valkeinen writel(0x00000006, engine + VIA_REG_TRANSPACE);
457f7018c21STomi Valkeinen writel(0x40008C0F, engine + VIA_REG_TRANSPACE);
458f7018c21STomi Valkeinen writel(0x44000000, engine + VIA_REG_TRANSPACE);
459f7018c21STomi Valkeinen writel(0x45080C04, engine + VIA_REG_TRANSPACE);
460f7018c21STomi Valkeinen writel(0x46800408, engine + VIA_REG_TRANSPACE);
461f7018c21STomi Valkeinen
462f7018c21STomi Valkeinen writel(vq_high, engine + VIA_REG_TRANSPACE);
463f7018c21STomi Valkeinen writel(vq_start_low, engine + VIA_REG_TRANSPACE);
464f7018c21STomi Valkeinen writel(vq_end_low, engine + VIA_REG_TRANSPACE);
465f7018c21STomi Valkeinen writel(vq_len, engine + VIA_REG_TRANSPACE);
466f7018c21STomi Valkeinen break;
467f7018c21STomi Valkeinen }
468f7018c21STomi Valkeinen
469f7018c21STomi Valkeinen /* Set Cursor Image Base Address */
470f7018c21STomi Valkeinen writel(viapar->shared->cursor_vram_addr, engine + VIA_REG_CURSOR_MODE);
471f7018c21STomi Valkeinen writel(0x0, engine + VIA_REG_CURSOR_POS);
472f7018c21STomi Valkeinen writel(0x0, engine + VIA_REG_CURSOR_ORG);
473f7018c21STomi Valkeinen writel(0x0, engine + VIA_REG_CURSOR_BG);
474f7018c21STomi Valkeinen writel(0x0, engine + VIA_REG_CURSOR_FG);
475f7018c21STomi Valkeinen return;
476f7018c21STomi Valkeinen }
477f7018c21STomi Valkeinen
viafb_show_hw_cursor(struct fb_info * info,int Status)478f7018c21STomi Valkeinen void viafb_show_hw_cursor(struct fb_info *info, int Status)
479f7018c21STomi Valkeinen {
480f7018c21STomi Valkeinen struct viafb_par *viapar = info->par;
481f7018c21STomi Valkeinen u32 temp, iga_path = viapar->iga_path;
482f7018c21STomi Valkeinen
483f7018c21STomi Valkeinen temp = readl(viapar->shared->vdev->engine_mmio + VIA_REG_CURSOR_MODE);
484f7018c21STomi Valkeinen switch (Status) {
485f7018c21STomi Valkeinen case HW_Cursor_ON:
486f7018c21STomi Valkeinen temp |= 0x1;
487f7018c21STomi Valkeinen break;
488f7018c21STomi Valkeinen case HW_Cursor_OFF:
489f7018c21STomi Valkeinen temp &= 0xFFFFFFFE;
490f7018c21STomi Valkeinen break;
491f7018c21STomi Valkeinen }
492f7018c21STomi Valkeinen switch (iga_path) {
493f7018c21STomi Valkeinen case IGA2:
494f7018c21STomi Valkeinen temp |= 0x80000000;
495f7018c21STomi Valkeinen break;
496f7018c21STomi Valkeinen case IGA1:
497f7018c21STomi Valkeinen default:
498f7018c21STomi Valkeinen temp &= 0x7FFFFFFF;
499f7018c21STomi Valkeinen }
500f7018c21STomi Valkeinen writel(temp, viapar->shared->vdev->engine_mmio + VIA_REG_CURSOR_MODE);
501f7018c21STomi Valkeinen }
502f7018c21STomi Valkeinen
viafb_wait_engine_idle(struct fb_info * info)503f7018c21STomi Valkeinen void viafb_wait_engine_idle(struct fb_info *info)
504f7018c21STomi Valkeinen {
505f7018c21STomi Valkeinen struct viafb_par *viapar = info->par;
506f7018c21STomi Valkeinen int loop = 0;
507f7018c21STomi Valkeinen u32 mask;
508f7018c21STomi Valkeinen void __iomem *engine = viapar->shared->vdev->engine_mmio;
509f7018c21STomi Valkeinen
510f7018c21STomi Valkeinen switch (viapar->shared->chip_info.twod_engine) {
511f7018c21STomi Valkeinen case VIA_2D_ENG_H5:
512f7018c21STomi Valkeinen case VIA_2D_ENG_M1:
513f7018c21STomi Valkeinen mask = VIA_CMD_RGTR_BUSY_M1 | VIA_2D_ENG_BUSY_M1 |
514f7018c21STomi Valkeinen VIA_3D_ENG_BUSY_M1;
515f7018c21STomi Valkeinen break;
516f7018c21STomi Valkeinen default:
517f7018c21STomi Valkeinen while (!(readl(engine + VIA_REG_STATUS) &
518f7018c21STomi Valkeinen VIA_VR_QUEUE_BUSY) && (loop < MAXLOOP)) {
519f7018c21STomi Valkeinen loop++;
520f7018c21STomi Valkeinen cpu_relax();
521f7018c21STomi Valkeinen }
522f7018c21STomi Valkeinen mask = VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY | VIA_3D_ENG_BUSY;
523f7018c21STomi Valkeinen break;
524f7018c21STomi Valkeinen }
525f7018c21STomi Valkeinen
526f7018c21STomi Valkeinen while ((readl(engine + VIA_REG_STATUS) & mask) && (loop < MAXLOOP)) {
527f7018c21STomi Valkeinen loop++;
528f7018c21STomi Valkeinen cpu_relax();
529f7018c21STomi Valkeinen }
530f7018c21STomi Valkeinen
531f7018c21STomi Valkeinen if (loop >= MAXLOOP)
532f7018c21STomi Valkeinen printk(KERN_ERR "viafb_wait_engine_idle: not syncing\n");
533f7018c21STomi Valkeinen }
534