accel.c 14 KB

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