xref: /openbmc/linux/drivers/video/fbdev/via/accel.c (revision 94b00cd6)
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 (tmp & 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 (tmp & 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 }
534