sis_accel.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  1. /*
  2. * SiS 300/540/630[S]/730[S],
  3. * SiS 315[E|PRO]/550/[M]650/651/[M]661[F|M]X/740/[M]741[GX]/330/[M]760[GX],
  4. * XGI V3XT/V5/V8, Z7
  5. * frame buffer driver for Linux kernels >= 2.4.14 and >=2.6.3
  6. *
  7. * 2D acceleration part
  8. *
  9. * This program is free software; you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation; either version 2 of the named License,
  12. * or any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, write to the Free Software
  21. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
  22. *
  23. * Based on the XFree86/X.org driver which is
  24. * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria
  25. *
  26. * Author: Thomas Winischhofer <thomas@winischhofer.net>
  27. * (see http://www.winischhofer.net/
  28. * for more information and updates)
  29. */
  30. #include <linux/version.h>
  31. #include <linux/module.h>
  32. #include <linux/kernel.h>
  33. #include <linux/fb.h>
  34. #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
  35. #include <linux/console.h>
  36. #endif
  37. #include <linux/ioport.h>
  38. #include <linux/types.h>
  39. #include <asm/io.h>
  40. #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
  41. #include <video/fbcon.h>
  42. #include <video/fbcon-cfb8.h>
  43. #include <video/fbcon-cfb16.h>
  44. #include <video/fbcon-cfb24.h>
  45. #include <video/fbcon-cfb32.h>
  46. #endif
  47. #include "sis.h"
  48. #include "sis_accel.h"
  49. static const u8 sisALUConv[] =
  50. {
  51. 0x00, /* dest = 0; 0, GXclear, 0 */
  52. 0x88, /* dest &= src; DSa, GXand, 0x1 */
  53. 0x44, /* dest = src & ~dest; SDna, GXandReverse, 0x2 */
  54. 0xCC, /* dest = src; S, GXcopy, 0x3 */
  55. 0x22, /* dest &= ~src; DSna, GXandInverted, 0x4 */
  56. 0xAA, /* dest = dest; D, GXnoop, 0x5 */
  57. 0x66, /* dest = ^src; DSx, GXxor, 0x6 */
  58. 0xEE, /* dest |= src; DSo, GXor, 0x7 */
  59. 0x11, /* dest = ~src & ~dest; DSon, GXnor, 0x8 */
  60. 0x99, /* dest ^= ~src ; DSxn, GXequiv, 0x9 */
  61. 0x55, /* dest = ~dest; Dn, GXInvert, 0xA */
  62. 0xDD, /* dest = src|~dest ; SDno, GXorReverse, 0xB */
  63. 0x33, /* dest = ~src; Sn, GXcopyInverted, 0xC */
  64. 0xBB, /* dest |= ~src; DSno, GXorInverted, 0xD */
  65. 0x77, /* dest = ~src|~dest; DSan, GXnand, 0xE */
  66. 0xFF, /* dest = 0xFF; 1, GXset, 0xF */
  67. };
  68. /* same ROP but with Pattern as Source */
  69. static const u8 sisPatALUConv[] =
  70. {
  71. 0x00, /* dest = 0; 0, GXclear, 0 */
  72. 0xA0, /* dest &= src; DPa, GXand, 0x1 */
  73. 0x50, /* dest = src & ~dest; PDna, GXandReverse, 0x2 */
  74. 0xF0, /* dest = src; P, GXcopy, 0x3 */
  75. 0x0A, /* dest &= ~src; DPna, GXandInverted, 0x4 */
  76. 0xAA, /* dest = dest; D, GXnoop, 0x5 */
  77. 0x5A, /* dest = ^src; DPx, GXxor, 0x6 */
  78. 0xFA, /* dest |= src; DPo, GXor, 0x7 */
  79. 0x05, /* dest = ~src & ~dest; DPon, GXnor, 0x8 */
  80. 0xA5, /* dest ^= ~src ; DPxn, GXequiv, 0x9 */
  81. 0x55, /* dest = ~dest; Dn, GXInvert, 0xA */
  82. 0xF5, /* dest = src|~dest ; PDno, GXorReverse, 0xB */
  83. 0x0F, /* dest = ~src; Pn, GXcopyInverted, 0xC */
  84. 0xAF, /* dest |= ~src; DPno, GXorInverted, 0xD */
  85. 0x5F, /* dest = ~src|~dest; DPan, GXnand, 0xE */
  86. 0xFF, /* dest = 0xFF; 1, GXset, 0xF */
  87. };
  88. #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)
  89. static const int myrops[] = {
  90. 3, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3
  91. };
  92. #endif
  93. /* 300 series ----------------------------------------------------- */
  94. #ifdef CONFIG_FB_SIS_300
  95. static void
  96. SiS300Sync(struct sis_video_info *ivideo)
  97. {
  98. SiS300Idle
  99. }
  100. static void
  101. SiS300SetupForScreenToScreenCopy(struct sis_video_info *ivideo, int xdir, int ydir,
  102. int rop, int trans_color)
  103. {
  104. SiS300SetupDSTColorDepth(ivideo->DstColor);
  105. SiS300SetupSRCPitch(ivideo->video_linelength)
  106. SiS300SetupDSTRect(ivideo->video_linelength, 0xffff)
  107. if(trans_color != -1) {
  108. SiS300SetupROP(0x0A)
  109. SiS300SetupSRCTrans(trans_color)
  110. SiS300SetupCMDFlag(TRANSPARENT_BITBLT)
  111. } else {
  112. SiS300SetupROP(sisALUConv[rop])
  113. }
  114. if(xdir > 0) {
  115. SiS300SetupCMDFlag(X_INC)
  116. }
  117. if(ydir > 0) {
  118. SiS300SetupCMDFlag(Y_INC)
  119. }
  120. }
  121. static void
  122. SiS300SubsequentScreenToScreenCopy(struct sis_video_info *ivideo, int src_x,
  123. int src_y, int dst_x, int dst_y, int width, int height)
  124. {
  125. u32 srcbase = 0, dstbase = 0;
  126. if(src_y >= 2048) {
  127. srcbase = ivideo->video_linelength * src_y;
  128. src_y = 0;
  129. }
  130. if(dst_y >= 2048) {
  131. dstbase = ivideo->video_linelength * dst_y;
  132. dst_y = 0;
  133. }
  134. SiS300SetupSRCBase(srcbase);
  135. SiS300SetupDSTBase(dstbase);
  136. if(!(ivideo->CommandReg & X_INC)) {
  137. src_x += width-1;
  138. dst_x += width-1;
  139. }
  140. if(!(ivideo->CommandReg & Y_INC)) {
  141. src_y += height-1;
  142. dst_y += height-1;
  143. }
  144. SiS300SetupRect(width, height)
  145. SiS300SetupSRCXY(src_x, src_y)
  146. SiS300SetupDSTXY(dst_x, dst_y)
  147. SiS300DoCMD
  148. }
  149. static void
  150. SiS300SetupForSolidFill(struct sis_video_info *ivideo, u32 color, int rop)
  151. {
  152. SiS300SetupPATFG(color)
  153. SiS300SetupDSTRect(ivideo->video_linelength, 0xffff)
  154. SiS300SetupDSTColorDepth(ivideo->DstColor);
  155. SiS300SetupROP(sisPatALUConv[rop])
  156. SiS300SetupCMDFlag(PATFG)
  157. }
  158. static void
  159. SiS300SubsequentSolidFillRect(struct sis_video_info *ivideo, int x, int y, int w, int h)
  160. {
  161. u32 dstbase = 0;
  162. if(y >= 2048) {
  163. dstbase = ivideo->video_linelength * y;
  164. y = 0;
  165. }
  166. SiS300SetupDSTBase(dstbase)
  167. SiS300SetupDSTXY(x,y)
  168. SiS300SetupRect(w,h)
  169. SiS300SetupCMDFlag(X_INC | Y_INC | BITBLT)
  170. SiS300DoCMD
  171. }
  172. #endif
  173. /* 315/330/340 series ---------------------------------------------- */
  174. #ifdef CONFIG_FB_SIS_315
  175. static void
  176. SiS310Sync(struct sis_video_info *ivideo)
  177. {
  178. SiS310Idle
  179. }
  180. static void
  181. SiS310SetupForScreenToScreenCopy(struct sis_video_info *ivideo, int rop, int trans_color)
  182. {
  183. SiS310SetupDSTColorDepth(ivideo->DstColor);
  184. SiS310SetupSRCPitch(ivideo->video_linelength)
  185. SiS310SetupDSTRect(ivideo->video_linelength, 0x0fff)
  186. if(trans_color != -1) {
  187. SiS310SetupROP(0x0A)
  188. SiS310SetupSRCTrans(trans_color)
  189. SiS310SetupCMDFlag(TRANSPARENT_BITBLT)
  190. } else {
  191. SiS310SetupROP(sisALUConv[rop])
  192. /* Set command - not needed, both 0 */
  193. /* SiSSetupCMDFlag(BITBLT | SRCVIDEO) */
  194. }
  195. SiS310SetupCMDFlag(ivideo->SiS310_AccelDepth)
  196. /* The chip is smart enough to know the direction */
  197. }
  198. static void
  199. SiS310SubsequentScreenToScreenCopy(struct sis_video_info *ivideo, int src_x, int src_y,
  200. int dst_x, int dst_y, int width, int height)
  201. {
  202. u32 srcbase = 0, dstbase = 0;
  203. int mymin = min(src_y, dst_y);
  204. int mymax = max(src_y, dst_y);
  205. /* Although the chip knows the direction to use
  206. * if the source and destination areas overlap,
  207. * that logic fails if we fiddle with the bitmap
  208. * addresses. Therefore, we check if the source
  209. * and destination blitting areas overlap and
  210. * adapt the bitmap addresses synchronously
  211. * if the coordinates exceed the valid range.
  212. * The the areas do not overlap, we do our
  213. * normal check.
  214. */
  215. if((mymax - mymin) < height) {
  216. if((src_y >= 2048) || (dst_y >= 2048)) {
  217. srcbase = ivideo->video_linelength * mymin;
  218. dstbase = ivideo->video_linelength * mymin;
  219. src_y -= mymin;
  220. dst_y -= mymin;
  221. }
  222. } else {
  223. if(src_y >= 2048) {
  224. srcbase = ivideo->video_linelength * src_y;
  225. src_y = 0;
  226. }
  227. if(dst_y >= 2048) {
  228. dstbase = ivideo->video_linelength * dst_y;
  229. dst_y = 0;
  230. }
  231. }
  232. srcbase += ivideo->video_offset;
  233. dstbase += ivideo->video_offset;
  234. SiS310SetupSRCBase(srcbase);
  235. SiS310SetupDSTBase(dstbase);
  236. SiS310SetupRect(width, height)
  237. SiS310SetupSRCXY(src_x, src_y)
  238. SiS310SetupDSTXY(dst_x, dst_y)
  239. SiS310DoCMD
  240. }
  241. static void
  242. SiS310SetupForSolidFill(struct sis_video_info *ivideo, u32 color, int rop)
  243. {
  244. SiS310SetupPATFG(color)
  245. SiS310SetupDSTRect(ivideo->video_linelength, 0x0fff)
  246. SiS310SetupDSTColorDepth(ivideo->DstColor);
  247. SiS310SetupROP(sisPatALUConv[rop])
  248. SiS310SetupCMDFlag(PATFG | ivideo->SiS310_AccelDepth)
  249. }
  250. static void
  251. SiS310SubsequentSolidFillRect(struct sis_video_info *ivideo, int x, int y, int w, int h)
  252. {
  253. u32 dstbase = 0;
  254. if(y >= 2048) {
  255. dstbase = ivideo->video_linelength * y;
  256. y = 0;
  257. }
  258. dstbase += ivideo->video_offset;
  259. SiS310SetupDSTBase(dstbase)
  260. SiS310SetupDSTXY(x,y)
  261. SiS310SetupRect(w,h)
  262. SiS310SetupCMDFlag(BITBLT)
  263. SiS310DoCMD
  264. }
  265. #endif
  266. /* --------------------------------------------------------------------- */
  267. /* The exported routines */
  268. int sisfb_initaccel(struct sis_video_info *ivideo)
  269. {
  270. #ifdef SISFB_USE_SPINLOCKS
  271. spin_lock_init(&ivideo->lockaccel);
  272. #endif
  273. return 0;
  274. }
  275. void sisfb_syncaccel(struct sis_video_info *ivideo)
  276. {
  277. if(ivideo->sisvga_engine == SIS_300_VGA) {
  278. #ifdef CONFIG_FB_SIS_300
  279. SiS300Sync(ivideo);
  280. #endif
  281. } else {
  282. #ifdef CONFIG_FB_SIS_315
  283. SiS310Sync(ivideo);
  284. #endif
  285. }
  286. }
  287. #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) /* --------------- 2.5 --------------- */
  288. int fbcon_sis_sync(struct fb_info *info)
  289. {
  290. struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
  291. CRITFLAGS
  292. if((!ivideo->accel) || (!ivideo->engineok))
  293. return 0;
  294. CRITBEGIN
  295. sisfb_syncaccel(ivideo);
  296. CRITEND
  297. return 0;
  298. }
  299. void fbcon_sis_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
  300. {
  301. struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
  302. u32 col = 0;
  303. u32 vxres = info->var.xres_virtual;
  304. u32 vyres = info->var.yres_virtual;
  305. int width, height;
  306. CRITFLAGS
  307. if(info->state != FBINFO_STATE_RUNNING)
  308. return;
  309. if((!ivideo->accel) || (!ivideo->engineok)) {
  310. cfb_fillrect(info, rect);
  311. return;
  312. }
  313. if(!rect->width || !rect->height || rect->dx >= vxres || rect->dy >= vyres)
  314. return;
  315. /* Clipping */
  316. width = ((rect->dx + rect->width) > vxres) ? (vxres - rect->dx) : rect->width;
  317. height = ((rect->dy + rect->height) > vyres) ? (vyres - rect->dy) : rect->height;
  318. switch(info->var.bits_per_pixel) {
  319. case 8: col = rect->color;
  320. break;
  321. case 16:
  322. case 32: col = ((u32 *)(info->pseudo_palette))[rect->color];
  323. break;
  324. }
  325. if(ivideo->sisvga_engine == SIS_300_VGA) {
  326. #ifdef CONFIG_FB_SIS_300
  327. CRITBEGIN
  328. SiS300SetupForSolidFill(ivideo, col, myrops[rect->rop]);
  329. SiS300SubsequentSolidFillRect(ivideo, rect->dx, rect->dy, width, height);
  330. CRITEND
  331. #endif
  332. } else {
  333. #ifdef CONFIG_FB_SIS_315
  334. CRITBEGIN
  335. SiS310SetupForSolidFill(ivideo, col, myrops[rect->rop]);
  336. SiS310SubsequentSolidFillRect(ivideo, rect->dx, rect->dy, width, height);
  337. CRITEND
  338. #endif
  339. }
  340. sisfb_syncaccel(ivideo);
  341. }
  342. void fbcon_sis_copyarea(struct fb_info *info, const struct fb_copyarea *area)
  343. {
  344. struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
  345. u32 vxres = info->var.xres_virtual;
  346. u32 vyres = info->var.yres_virtual;
  347. int width = area->width;
  348. int height = area->height;
  349. CRITFLAGS
  350. if(info->state != FBINFO_STATE_RUNNING)
  351. return;
  352. if((!ivideo->accel) || (!ivideo->engineok)) {
  353. cfb_copyarea(info, area);
  354. return;
  355. }
  356. if(!width || !height ||
  357. area->sx >= vxres || area->sy >= vyres ||
  358. area->dx >= vxres || area->dy >= vyres)
  359. return;
  360. /* Clipping */
  361. if((area->sx + width) > vxres) width = vxres - area->sx;
  362. if((area->dx + width) > vxres) width = vxres - area->dx;
  363. if((area->sy + height) > vyres) height = vyres - area->sy;
  364. if((area->dy + height) > vyres) height = vyres - area->dy;
  365. if(ivideo->sisvga_engine == SIS_300_VGA) {
  366. #ifdef CONFIG_FB_SIS_300
  367. int xdir, ydir;
  368. if(area->sx < area->dx) xdir = 0;
  369. else xdir = 1;
  370. if(area->sy < area->dy) ydir = 0;
  371. else ydir = 1;
  372. CRITBEGIN
  373. SiS300SetupForScreenToScreenCopy(ivideo, xdir, ydir, 3, -1);
  374. SiS300SubsequentScreenToScreenCopy(ivideo, area->sx, area->sy,
  375. area->dx, area->dy, width, height);
  376. CRITEND
  377. #endif
  378. } else {
  379. #ifdef CONFIG_FB_SIS_315
  380. CRITBEGIN
  381. SiS310SetupForScreenToScreenCopy(ivideo, 3, -1);
  382. SiS310SubsequentScreenToScreenCopy(ivideo, area->sx, area->sy,
  383. area->dx, area->dy, width, height);
  384. CRITEND
  385. #endif
  386. }
  387. sisfb_syncaccel(ivideo);
  388. }
  389. #endif
  390. #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* -------------- 2.4 --------------- */
  391. #include "sisfb_accel_2_4.h"
  392. #endif /* KERNEL VERSION */