Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
accel.c
Go to the documentation of this file.
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  */
27 static 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 
53 static 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 
186 static 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 
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 
381 void 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 
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 
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:
529  break;
530  default:
531  while (!(readl(engine + VIA_REG_STATUS) &
532  VIA_VR_QUEUE_BUSY) && (loop < MAXLOOP)) {
533  loop++;
534  cpu_relax();
535  }
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 }