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