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