cgsixfb.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:24k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /* $Id: cgsixfb.c,v 1.26 2001/10/16 05:44:44 davem Exp $
  2.  * cgsixfb.c: CGsix (GX,GXplus) frame buffer driver
  3.  *
  4.  * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
  5.  * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
  6.  * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
  7.  */
  8. #include <linux/module.h>
  9. #include <linux/sched.h>
  10. #include <linux/kernel.h>
  11. #include <linux/errno.h>
  12. #include <linux/string.h>
  13. #include <linux/mm.h>
  14. #include <linux/tty.h>
  15. #include <linux/slab.h>
  16. #include <linux/vmalloc.h>
  17. #include <linux/delay.h>
  18. #include <linux/interrupt.h>
  19. #include <linux/fb.h>
  20. #include <linux/init.h>
  21. #include <linux/selection.h>
  22. #include <video/sbusfb.h>
  23. #include <asm/io.h>
  24. /* Offset of interesting structures in the OBIO space */
  25. /*
  26.  * Brooktree is the video dac and is funny to program on the cg6.
  27.  * (it's even funnier on the cg3)
  28.  * The FBC could be the frame buffer control
  29.  * The FHC could is the frame buffer hardware control.
  30.  */
  31. #define CG6_ROM_OFFSET       0x0UL
  32. #define CG6_BROOKTREE_OFFSET 0x200000UL
  33. #define CG6_DHC_OFFSET       0x240000UL
  34. #define CG6_ALT_OFFSET       0x280000UL
  35. #define CG6_FHC_OFFSET       0x300000UL
  36. #define CG6_THC_OFFSET       0x301000UL
  37. #define CG6_FBC_OFFSET       0x700000UL
  38. #define CG6_TEC_OFFSET       0x701000UL
  39. #define CG6_RAM_OFFSET       0x800000UL
  40. /* FHC definitions */
  41. #define CG6_FHC_FBID_SHIFT           24
  42. #define CG6_FHC_FBID_MASK            255
  43. #define CG6_FHC_REV_SHIFT            20
  44. #define CG6_FHC_REV_MASK             15
  45. #define CG6_FHC_FROP_DISABLE         (1 << 19)
  46. #define CG6_FHC_ROW_DISABLE          (1 << 18)
  47. #define CG6_FHC_SRC_DISABLE          (1 << 17)
  48. #define CG6_FHC_DST_DISABLE          (1 << 16)
  49. #define CG6_FHC_RESET                (1 << 15)
  50. #define CG6_FHC_LITTLE_ENDIAN        (1 << 13)
  51. #define CG6_FHC_RES_MASK             (3 << 11)
  52. #define CG6_FHC_1024                 (0 << 11)
  53. #define CG6_FHC_1152                 (1 << 11)
  54. #define CG6_FHC_1280                 (2 << 11)
  55. #define CG6_FHC_1600                 (3 << 11)
  56. #define CG6_FHC_CPU_MASK             (3 << 9)
  57. #define CG6_FHC_CPU_SPARC            (0 << 9)
  58. #define CG6_FHC_CPU_68020            (1 << 9)
  59. #define CG6_FHC_CPU_386              (2 << 9)
  60. #define CG6_FHC_TEST      (1 << 8)
  61. #define CG6_FHC_TEST_X_SHIFT      4
  62. #define CG6_FHC_TEST_X_MASK      15
  63. #define CG6_FHC_TEST_Y_SHIFT      0
  64. #define CG6_FHC_TEST_Y_MASK      15
  65. /* FBC mode definitions */
  66. #define CG6_FBC_BLIT_IGNORE 0x00000000
  67. #define CG6_FBC_BLIT_NOSRC 0x00100000
  68. #define CG6_FBC_BLIT_SRC 0x00200000
  69. #define CG6_FBC_BLIT_ILLEGAL 0x00300000
  70. #define CG6_FBC_BLIT_MASK 0x00300000
  71. #define CG6_FBC_VBLANK 0x00080000
  72. #define CG6_FBC_MODE_IGNORE 0x00000000
  73. #define CG6_FBC_MODE_COLOR8 0x00020000
  74. #define CG6_FBC_MODE_COLOR1 0x00040000
  75. #define CG6_FBC_MODE_HRMONO 0x00060000
  76. #define CG6_FBC_MODE_MASK 0x00060000
  77. #define CG6_FBC_DRAW_IGNORE 0x00000000
  78. #define CG6_FBC_DRAW_RENDER 0x00008000
  79. #define CG6_FBC_DRAW_PICK 0x00010000
  80. #define CG6_FBC_DRAW_ILLEGAL 0x00018000
  81. #define CG6_FBC_DRAW_MASK 0x00018000
  82. #define CG6_FBC_BWRITE0_IGNORE 0x00000000
  83. #define CG6_FBC_BWRITE0_ENABLE 0x00002000
  84. #define CG6_FBC_BWRITE0_DISABLE 0x00004000
  85. #define CG6_FBC_BWRITE0_ILLEGAL 0x00006000
  86. #define CG6_FBC_BWRITE0_MASK 0x00006000
  87. #define CG6_FBC_BWRITE1_IGNORE 0x00000000
  88. #define CG6_FBC_BWRITE1_ENABLE 0x00000800
  89. #define CG6_FBC_BWRITE1_DISABLE 0x00001000
  90. #define CG6_FBC_BWRITE1_ILLEGAL 0x00001800
  91. #define CG6_FBC_BWRITE1_MASK 0x00001800
  92. #define CG6_FBC_BREAD_IGNORE 0x00000000
  93. #define CG6_FBC_BREAD_0 0x00000200
  94. #define CG6_FBC_BREAD_1 0x00000400
  95. #define CG6_FBC_BREAD_ILLEGAL 0x00000600
  96. #define CG6_FBC_BREAD_MASK 0x00000600
  97. #define CG6_FBC_BDISP_IGNORE 0x00000000
  98. #define CG6_FBC_BDISP_0 0x00000080
  99. #define CG6_FBC_BDISP_1 0x00000100
  100. #define CG6_FBC_BDISP_ILLEGAL 0x00000180
  101. #define CG6_FBC_BDISP_MASK 0x00000180
  102. #define CG6_FBC_INDEX_MOD 0x00000040
  103. #define CG6_FBC_INDEX_MASK 0x00000030
  104. /* THC definitions */
  105. #define CG6_THC_MISC_REV_SHIFT       16
  106. #define CG6_THC_MISC_REV_MASK        15
  107. #define CG6_THC_MISC_RESET           (1 << 12)
  108. #define CG6_THC_MISC_VIDEO           (1 << 10)
  109. #define CG6_THC_MISC_SYNC            (1 << 9)
  110. #define CG6_THC_MISC_VSYNC           (1 << 8)
  111. #define CG6_THC_MISC_SYNC_ENAB       (1 << 7)
  112. #define CG6_THC_MISC_CURS_RES        (1 << 6)
  113. #define CG6_THC_MISC_INT_ENAB        (1 << 5)
  114. #define CG6_THC_MISC_INT             (1 << 4)
  115. #define CG6_THC_MISC_INIT            0x9f
  116. MODULE_LICENSE("GPL");
  117. /* The contents are unknown */
  118. struct cg6_tec {
  119. volatile int tec_matrix;
  120. volatile int tec_clip;
  121. volatile int tec_vdc;
  122. };
  123. struct cg6_thc {
  124.         uint thc_pad0[512];
  125. volatile uint thc_hs; /* hsync timing */
  126. volatile uint thc_hsdvs;
  127. volatile uint thc_hd;
  128. volatile uint thc_vs; /* vsync timing */
  129. volatile uint thc_vd;
  130. volatile uint thc_refresh;
  131. volatile uint thc_misc;
  132. uint thc_pad1[56];
  133. volatile uint thc_cursxy; /* cursor x,y position (16 bits each) */
  134. volatile uint thc_cursmask[32]; /* cursor mask bits */
  135. volatile uint thc_cursbits[32]; /* what to show where mask enabled */
  136. };
  137. struct cg6_fbc {
  138. u32 xxx0[1];
  139. volatile u32 mode;
  140. volatile u32 clip;
  141. u32 xxx1[1];     
  142. volatile u32 s;
  143. volatile u32 draw;
  144. volatile u32 blit;
  145. volatile u32 font;
  146. u32 xxx2[24];
  147. volatile u32 x0, y0, z0, color0;
  148. volatile u32 x1, y1, z1, color1;
  149. volatile u32 x2, y2, z2, color2;
  150. volatile u32 x3, y3, z3, color3;
  151. volatile u32 offx, offy;
  152. u32 xxx3[2];
  153. volatile u32 incx, incy;
  154. u32 xxx4[2];
  155. volatile u32 clipminx, clipminy;
  156. u32 xxx5[2];
  157. volatile u32 clipmaxx, clipmaxy;
  158. u32 xxx6[2];
  159. volatile u32 fg;
  160. volatile u32 bg;
  161. volatile u32 alu;
  162. volatile u32 pm;
  163. volatile u32 pixelm;
  164. u32 xxx7[2];
  165. volatile u32 patalign;
  166. volatile u32 pattern[8];
  167. u32 xxx8[432];
  168. volatile u32 apointx, apointy, apointz;
  169. u32 xxx9[1];
  170. volatile u32 rpointx, rpointy, rpointz;
  171. u32 xxx10[5];
  172. volatile u32 pointr, pointg, pointb, pointa;
  173. volatile u32 alinex, aliney, alinez;
  174. u32 xxx11[1];
  175. volatile u32 rlinex, rliney, rlinez;
  176. u32 xxx12[5];
  177. volatile u32 liner, lineg, lineb, linea;
  178. volatile u32 atrix, atriy, atriz;
  179. u32 xxx13[1];
  180. volatile u32 rtrix, rtriy, rtriz;
  181. u32 xxx14[5];
  182. volatile u32 trir, trig, trib, tria;
  183. volatile u32 aquadx, aquady, aquadz;
  184. u32 xxx15[1];
  185. volatile u32 rquadx, rquady, rquadz;
  186. u32 xxx16[5];
  187. volatile u32 quadr, quadg, quadb, quada;
  188. volatile u32 arectx, arecty, arectz;
  189. u32 xxx17[1];
  190. volatile u32 rrectx, rrecty, rrectz;
  191. u32 xxx18[5];
  192. volatile u32 rectr, rectg, rectb, recta;
  193. };
  194. static struct sbus_mmap_map cg6_mmap_map[] = {
  195. { CG6_FBC, CG6_FBC_OFFSET, PAGE_SIZE  },
  196. { CG6_TEC, CG6_TEC_OFFSET, PAGE_SIZE  },
  197. { CG6_BTREGS, CG6_BROOKTREE_OFFSET, PAGE_SIZE  },
  198. { CG6_FHC, CG6_FHC_OFFSET, PAGE_SIZE  },
  199. { CG6_THC, CG6_THC_OFFSET, PAGE_SIZE  },
  200. { CG6_ROM, CG6_ROM_OFFSET, 0x10000    },
  201. { CG6_RAM, CG6_RAM_OFFSET, SBUS_MMAP_FBSIZE(1)   },
  202. { CG6_DHC, CG6_DHC_OFFSET, 0x40000    },
  203. { 0, 0, 0    }
  204. };
  205. static void cg6_setup(struct display *p)
  206. {
  207. p->next_line = sbusfbinfo(p->fb_info)->var.xres_virtual;
  208. p->next_plane = 0;
  209. }
  210. static void cg6_clear(struct vc_data *conp, struct display *p, int sy, int sx,
  211.       int height, int width)
  212. {
  213. struct fb_info_sbusfb *fb = (struct fb_info_sbusfb *)p->fb_info;
  214. register struct cg6_fbc *fbc = fb->s.cg6.fbc;
  215. unsigned long flags;
  216. int x, y, w, h;
  217. int i;
  218. spin_lock_irqsave(&fb->lock, flags);
  219. do {
  220. i = sbus_readl(&fbc->s);
  221. } while (i & 0x10000000);
  222. sbus_writel(attr_bgcol_ec(p,conp), &fbc->fg);
  223. sbus_writel(attr_bgcol_ec(p,conp), &fbc->bg);
  224. sbus_writel(~0, &fbc->pixelm);
  225. sbus_writel(0xea80ff00, &fbc->alu);
  226. sbus_writel(0, &fbc->s);
  227. sbus_writel(0, &fbc->clip);
  228. sbus_writel(~0, &fbc->pm);
  229.         if (fontheightlog(p)) {
  230. y = sy << fontheightlog(p); h = height << fontheightlog(p);
  231. } else {
  232. y = sy * fontheight(p); h = height * fontheight(p);
  233. }
  234. if (fontwidthlog(p)) {
  235. x = sx << fontwidthlog(p); w = width << fontwidthlog(p);
  236. } else {
  237. x = sx * fontwidth(p); w = width * fontwidth(p);
  238. }
  239. sbus_writel(y + fb->y_margin, &fbc->arecty);
  240. sbus_writel(x + fb->x_margin, &fbc->arectx);
  241. sbus_writel(y + fb->y_margin + h, &fbc->arecty);
  242. sbus_writel(x + fb->x_margin + w, &fbc->arectx);
  243. do {
  244. i = sbus_readl(&fbc->draw);
  245. } while (i < 0 && (i & 0x20000000));
  246. spin_unlock_irqrestore(&fb->lock, flags);
  247. }
  248. static void cg6_fill(struct fb_info_sbusfb *fb, struct display *p, int s,
  249.      int count, unsigned short *boxes)
  250. {
  251. int i;
  252. register struct cg6_fbc *fbc = fb->s.cg6.fbc;
  253. unsigned long flags;
  254. spin_lock_irqsave(&fb->lock, flags);
  255. do {
  256. i = sbus_readl(&fbc->s);
  257. } while (i & 0x10000000);
  258. sbus_writel(attr_bgcol(p,s), &fbc->fg);
  259. sbus_writel(attr_bgcol(p,s), &fbc->bg);
  260. sbus_writel(~0, &fbc->pixelm);
  261. sbus_writel(0xea80ff00, &fbc->alu);
  262. sbus_writel(0, &fbc->s);
  263. sbus_writel(0, &fbc->clip);
  264. sbus_writel(~0, &fbc->pm);
  265. while (count-- > 0) {
  266. sbus_writel(boxes[1], &fbc->arecty);
  267. sbus_writel(boxes[0], &fbc->arectx);
  268. sbus_writel(boxes[3], &fbc->arecty);
  269. sbus_writel(boxes[2], &fbc->arectx);
  270. boxes += 4;
  271. do {
  272. i = sbus_readl(&fbc->draw);
  273. } while (i < 0 && (i & 0x20000000));
  274. }
  275. spin_unlock_irqrestore(&fb->lock, flags);
  276. }
  277. static void cg6_putc(struct vc_data *conp, struct display *p, int c, int yy, int xx)
  278. {
  279. struct fb_info_sbusfb *fb = (struct fb_info_sbusfb *)p->fb_info;
  280. register struct cg6_fbc *fbc = fb->s.cg6.fbc;
  281. unsigned long flags;
  282. int i, x, y;
  283. u8 *fd;
  284. spin_lock_irqsave(&fb->lock, flags);
  285. if (fontheightlog(p)) {
  286. y = fb->y_margin + (yy << fontheightlog(p));
  287. i = ((c & p->charmask) << fontheightlog(p));
  288. } else {
  289. y = fb->y_margin + (yy * fontheight(p));
  290. i = (c & p->charmask) * fontheight(p);
  291. }
  292. if (fontwidth(p) <= 8)
  293. fd = p->fontdata + i;
  294. else
  295. fd = p->fontdata + (i << 1);
  296. if (fontwidthlog(p))
  297. x = fb->x_margin + (xx << fontwidthlog(p));
  298. else
  299. x = fb->x_margin + (xx * fontwidth(p));
  300. do {
  301. i = sbus_readl(&fbc->s);
  302. } while (i & 0x10000000);
  303. sbus_writel(attr_fgcol(p,c), &fbc->fg);
  304. sbus_writel(attr_bgcol(p,c), &fbc->bg);
  305. sbus_writel(0x140000, &fbc->mode);
  306. sbus_writel(0xe880fc30, &fbc->alu);
  307. sbus_writel(~0, &fbc->pixelm);
  308. sbus_writel(0, &fbc->s);
  309. sbus_writel(0, &fbc->clip);
  310. sbus_writel(0xff, &fbc->pm);
  311. sbus_writel(0, &fbc->incx);
  312. sbus_writel(1, &fbc->incy);
  313. sbus_writel(x, &fbc->x0);
  314. sbus_writel(x + fontwidth(p) - 1, &fbc->x1);
  315. sbus_writel(y, &fbc->y0);
  316. if (fontwidth(p) <= 8) {
  317. for (i = 0; i < fontheight(p); i++) {
  318. u32 val = *fd++ << 24;
  319. sbus_writel(val, &fbc->font);
  320. }
  321. } else {
  322. for (i = 0; i < fontheight(p); i++) {
  323. u32 val = *(u16 *)fd << 16;
  324. sbus_writel(val, &fbc->font);
  325. fd += 2;
  326. }
  327. }
  328. spin_unlock_irqrestore(&fb->lock, flags);
  329. }
  330. static void cg6_putcs(struct vc_data *conp, struct display *p, const unsigned short *s,
  331.       int count, int yy, int xx)
  332. {
  333. struct fb_info_sbusfb *fb = (struct fb_info_sbusfb *)p->fb_info;
  334. register struct cg6_fbc *fbc = fb->s.cg6.fbc;
  335. unsigned long flags;
  336. int i, x, y;
  337. u8 *fd1, *fd2, *fd3, *fd4;
  338. u16 c;
  339. spin_lock_irqsave(&fb->lock, flags);
  340. do {
  341. i = sbus_readl(&fbc->s);
  342. } while (i & 0x10000000);
  343. c = scr_readw(s);
  344. sbus_writel(attr_fgcol(p, c), &fbc->fg);
  345. sbus_writel(attr_bgcol(p, c), &fbc->bg);
  346. sbus_writel(0x140000, &fbc->mode);
  347. sbus_writel(0xe880fc30, &fbc->alu);
  348. sbus_writel(~0, &fbc->pixelm);
  349. sbus_writel(0, &fbc->s);
  350. sbus_writel(0, &fbc->clip);
  351. sbus_writel(0xff, &fbc->pm);
  352. x = fb->x_margin;
  353. y = fb->y_margin;
  354. if (fontwidthlog(p))
  355. x += (xx << fontwidthlog(p));
  356. else
  357. x += xx * fontwidth(p);
  358. if (fontheightlog(p))
  359. y += (yy << fontheightlog(p));
  360. else
  361. y += (yy * fontheight(p));
  362. if (fontwidth(p) <= 8) {
  363. while (count >= 4) {
  364. count -= 4;
  365. sbus_writel(0, &fbc->incx);
  366. sbus_writel(1, &fbc->incy);
  367. sbus_writel(x, &fbc->x0);
  368. sbus_writel((x += 4 * fontwidth(p)) - 1, &fbc->x1);
  369. sbus_writel(y, &fbc->y0);
  370. if (fontheightlog(p)) {
  371. fd1 = p->fontdata + ((scr_readw(s++) & p->charmask) << fontheightlog(p));
  372. fd2 = p->fontdata + ((scr_readw(s++) & p->charmask) << fontheightlog(p));
  373. fd3 = p->fontdata + ((scr_readw(s++) & p->charmask) << fontheightlog(p));
  374. fd4 = p->fontdata + ((scr_readw(s++) & p->charmask) << fontheightlog(p));
  375. } else {
  376. fd1 = p->fontdata + ((scr_readw(s++) & p->charmask) * fontheight(p));
  377. fd2 = p->fontdata + ((scr_readw(s++) & p->charmask) * fontheight(p));
  378. fd3 = p->fontdata + ((scr_readw(s++) & p->charmask) * fontheight(p));
  379. fd4 = p->fontdata + ((scr_readw(s++) & p->charmask) * fontheight(p));
  380. }
  381. if (fontwidth(p) == 8) {
  382. for (i = 0; i < fontheight(p); i++) {
  383. u32 val = ((u32)*fd4++) |
  384. ((((u32)*fd3++) |
  385.   ((((u32)*fd2++) |
  386.     (((u32)*fd1++)
  387.      << 8)) << 8)) << 8);
  388. sbus_writel(val, &fbc->font);
  389. }
  390. } else {
  391. for (i = 0; i < fontheight(p); i++) {
  392. u32 val = (((u32)*fd4++) |
  393.    ((((u32)*fd3++) |
  394.      ((((u32)*fd2++) |
  395.        (((u32)*fd1++) 
  396. << fontwidth(p))) <<
  397.       fontwidth(p))) <<
  398.     fontwidth(p))) <<
  399. (24 - 3 * fontwidth(p));
  400. sbus_writel(val, &fbc->font);
  401. }
  402. }
  403. }
  404. } else {
  405. while (count >= 2) {
  406. count -= 2;
  407. sbus_writel(0, &fbc->incx);
  408. sbus_writel(1, &fbc->incy);
  409. sbus_writel(x, &fbc->x0);
  410. sbus_writel((x += 2 * fontwidth(p)) - 1, &fbc->x1);
  411. sbus_writel(y, &fbc->y0);
  412. if (fontheightlog(p)) {
  413. fd1 = p->fontdata + ((scr_readw(s++) & p->charmask) << (fontheightlog(p) + 1));
  414. fd2 = p->fontdata + ((scr_readw(s++) & p->charmask) << (fontheightlog(p) + 1));
  415. } else {
  416. fd1 = p->fontdata + (((scr_readw(s++) & p->charmask) * fontheight(p)) << 1);
  417. fd2 = p->fontdata + (((scr_readw(s++) & p->charmask) * fontheight(p)) << 1);
  418. }
  419. for (i = 0; i < fontheight(p); i++) {
  420. u32 val = ((((u32)*(u16 *)fd1) << fontwidth(p)) |
  421.    ((u32)*(u16 *)fd2)) << (16 - fontwidth(p));
  422. sbus_writel(val, &fbc->font);
  423. fd1 += 2; fd2 += 2;
  424. }
  425. }
  426. }
  427. while (count) {
  428. count--;
  429. sbus_writel(0, &fbc->incx);
  430. sbus_writel(1, &fbc->incy);
  431. sbus_writel(x, &fbc->x0);
  432. sbus_writel((x += fontwidth(p)) - 1, &fbc->x1);
  433. sbus_writel(y, &fbc->y0);
  434. if (fontheightlog(p))
  435. i = ((scr_readw(s++) & p->charmask) << fontheightlog(p));
  436. else
  437. i = ((scr_readw(s++) & p->charmask) * fontheight(p));
  438. if (fontwidth(p) <= 8) {
  439. fd1 = p->fontdata + i;
  440. for (i = 0; i < fontheight(p); i++) {
  441. u32 val = *fd1++ << 24;
  442. sbus_writel(val, &fbc->font);
  443. }
  444. } else {
  445. fd1 = p->fontdata + (i << 1);
  446. for (i = 0; i < fontheight(p); i++) {
  447. u32 val = *(u16 *)fd1 << 16;
  448. sbus_writel(val, &fbc->font);
  449. fd1 += 2;
  450. }
  451. }
  452. }
  453. spin_unlock_irqrestore(&fb->lock, flags);
  454. }
  455. static void cg6_revc(struct display *p, int xx, int yy)
  456. {
  457. /* Not used if hw cursor */
  458. }
  459. static void cg6_loadcmap (struct fb_info_sbusfb *fb, struct display *p, int index, int count)
  460. {
  461. struct bt_regs *bt = fb->s.cg6.bt;
  462. unsigned long flags;
  463. int i;
  464.                 
  465. spin_lock_irqsave(&fb->lock, flags);
  466. sbus_writel(index << 24, &bt->addr);
  467. for (i = index; count--; i++){
  468. sbus_writel(fb->color_map CM(i,0) << 24,
  469.     &bt->color_map);
  470. sbus_writel(fb->color_map CM(i,1) << 24,
  471.     &bt->color_map);
  472. sbus_writel(fb->color_map CM(i,2) << 24,
  473.     &bt->color_map);
  474. }
  475. spin_unlock_irqrestore(&fb->lock, flags);
  476. }
  477. static void cg6_restore_palette (struct fb_info_sbusfb *fb)
  478. {
  479. struct bt_regs *bt = fb->s.cg6.bt;
  480. unsigned long flags;
  481.                 
  482. spin_lock_irqsave(&fb->lock, flags);
  483. sbus_writel(0, &bt->addr);
  484. sbus_writel(0xffffffff, &bt->color_map);
  485. sbus_writel(0xffffffff, &bt->color_map);
  486. sbus_writel(0xffffffff, &bt->color_map);
  487. spin_unlock_irqrestore(&fb->lock, flags);
  488. }
  489. static struct display_switch cg6_dispsw __initdata = {
  490. setup: cg6_setup,
  491. bmove: fbcon_redraw_bmove,
  492. clear: cg6_clear,
  493. putc: cg6_putc,
  494. putcs: cg6_putcs,
  495. revc: cg6_revc, 
  496. fontwidthmask: FONTWIDTHRANGE(1,16) /* Allow fontwidths up to 16 */
  497. };
  498. static void cg6_setcursormap (struct fb_info_sbusfb *fb, u8 *red, u8 *green, u8 *blue)
  499. {
  500.         struct bt_regs *bt = fb->s.cg6.bt;
  501. unsigned long flags;
  502.         
  503. spin_lock_irqsave(&fb->lock, flags);
  504. sbus_writel(1 << 24, &bt->addr);
  505. sbus_writel(red[0] << 24, &bt->cursor);
  506. sbus_writel(green[0] << 24, &bt->cursor);
  507. sbus_writel(blue[0] << 24, &bt->cursor);
  508. sbus_writel(3 << 24, &bt->addr);
  509. sbus_writel(red[1] << 24, &bt->cursor);
  510. sbus_writel(green[1] << 24, &bt->cursor);
  511. sbus_writel(blue[1] << 24, &bt->cursor);
  512. spin_unlock_irqrestore(&fb->lock, flags);
  513. }
  514. /* Set cursor shape */
  515. static void cg6_setcurshape (struct fb_info_sbusfb *fb)
  516. {
  517. struct cg6_thc *thc = fb->s.cg6.thc;
  518. unsigned long flags;
  519. int i;
  520. spin_lock_irqsave(&fb->lock, flags);
  521. for (i = 0; i < 32; i++) {
  522. sbus_writel(fb->cursor.bits[0][i],
  523.     &thc->thc_cursmask [i]);
  524. sbus_writel(fb->cursor.bits[1][i],
  525.     &thc->thc_cursbits [i]);
  526. }
  527. spin_unlock_irqrestore(&fb->lock, flags);
  528. }
  529. /* Load cursor information */
  530. static void cg6_setcursor (struct fb_info_sbusfb *fb)
  531. {
  532. unsigned int v;
  533. unsigned long flags;
  534. struct cg_cursor *c = &fb->cursor;
  535. spin_lock_irqsave(&fb->lock, flags);
  536. if (c->enable)
  537. v = ((c->cpos.fbx - c->chot.fbx) << 16)
  538.     |((c->cpos.fby - c->chot.fby) & 0xffff);
  539. else
  540. /* Magic constant to turn off the cursor */
  541. v = ((65536-32) << 16) | (65536-32);
  542. sbus_writel(v, &fb->s.cg6.thc->thc_cursxy);
  543. spin_unlock_irqrestore(&fb->lock, flags);
  544. }
  545. static void cg6_blank (struct fb_info_sbusfb *fb)
  546. {
  547. unsigned long flags;
  548. u32 tmp;
  549. spin_lock_irqsave(&fb->lock, flags);
  550. tmp = sbus_readl(&fb->s.cg6.thc->thc_misc);
  551. tmp &= ~CG6_THC_MISC_VIDEO;
  552. sbus_writel(tmp, &fb->s.cg6.thc->thc_misc);
  553. spin_unlock_irqrestore(&fb->lock, flags);
  554. }
  555. static void cg6_unblank (struct fb_info_sbusfb *fb)
  556. {
  557. unsigned long flags;
  558. u32 tmp;
  559. spin_lock_irqsave(&fb->lock, flags);
  560. tmp = sbus_readl(&fb->s.cg6.thc->thc_misc);
  561. tmp |= CG6_THC_MISC_VIDEO;
  562. sbus_writel(tmp, &fb->s.cg6.thc->thc_misc);
  563. spin_unlock_irqrestore(&fb->lock, flags);
  564. }
  565. static void cg6_reset (struct fb_info_sbusfb *fb)
  566. {
  567. unsigned int rev, conf;
  568. struct cg6_tec *tec = fb->s.cg6.tec;
  569. struct cg6_fbc *fbc = fb->s.cg6.fbc;
  570. unsigned long flags;
  571. u32 mode, tmp;
  572. int i;
  573. spin_lock_irqsave(&fb->lock, flags);
  574. /* Turn off stuff in the Transform Engine. */
  575. sbus_writel(0, &tec->tec_matrix);
  576. sbus_writel(0, &tec->tec_clip);
  577. sbus_writel(0, &tec->tec_vdc);
  578. /* Take care of bugs in old revisions. */
  579. rev = (sbus_readl(fb->s.cg6.fhc) >> CG6_FHC_REV_SHIFT) & CG6_FHC_REV_MASK;
  580. if (rev < 5) {
  581. conf = (sbus_readl(fb->s.cg6.fhc) & CG6_FHC_RES_MASK) |
  582. CG6_FHC_CPU_68020 | CG6_FHC_TEST |
  583. (11 << CG6_FHC_TEST_X_SHIFT) |
  584. (11 << CG6_FHC_TEST_Y_SHIFT);
  585. if (rev < 2)
  586. conf |= CG6_FHC_DST_DISABLE;
  587. sbus_writel(conf, fb->s.cg6.fhc);
  588. }
  589. /* Set things in the FBC. Bad things appear to happen if we do
  590.  * back to back store/loads on the mode register, so copy it
  591.  * out instead. */
  592. mode = sbus_readl(&fbc->mode);
  593. do {
  594. i = sbus_readl(&fbc->s);
  595. } while (i & 0x10000000);
  596. mode &= ~(CG6_FBC_BLIT_MASK | CG6_FBC_MODE_MASK |
  597.        CG6_FBC_DRAW_MASK | CG6_FBC_BWRITE0_MASK |
  598.        CG6_FBC_BWRITE1_MASK | CG6_FBC_BREAD_MASK |
  599.        CG6_FBC_BDISP_MASK);
  600. mode |= (CG6_FBC_BLIT_SRC | CG6_FBC_MODE_COLOR8 |
  601.       CG6_FBC_DRAW_RENDER | CG6_FBC_BWRITE0_ENABLE |
  602.       CG6_FBC_BWRITE1_DISABLE | CG6_FBC_BREAD_0 |
  603.       CG6_FBC_BDISP_0);
  604. sbus_writel(mode, &fbc->mode);
  605. sbus_writel(0, &fbc->clip);
  606. sbus_writel(0, &fbc->offx);
  607. sbus_writel(0, &fbc->offy);
  608. sbus_writel(0, &fbc->clipminx);
  609. sbus_writel(0, &fbc->clipminy);
  610. sbus_writel(fb->type.fb_width - 1, &fbc->clipmaxx);
  611. sbus_writel(fb->type.fb_height - 1, &fbc->clipmaxy);
  612. /* Enable cursor in Brooktree DAC. */
  613. sbus_writel(0x06 << 24, &fb->s.cg6.bt->addr);
  614. tmp = sbus_readl(&fb->s.cg6.bt->control);
  615. tmp |= 0x03 << 24;
  616. sbus_writel(tmp, &fb->s.cg6.bt->control);
  617. spin_unlock_irqrestore(&fb->lock, flags);
  618. }
  619. static void cg6_margins (struct fb_info_sbusfb *fb, struct display *p, int x_margin, int y_margin)
  620. {
  621. p->screen_base += (y_margin - fb->y_margin) *
  622. p->line_length + (x_margin - fb->x_margin);
  623. }
  624. static int __init cg6_rasterimg (struct fb_info *info, int start)
  625. {
  626. struct fb_info_sbusfb *fb = sbusfbinfo(info);
  627. register struct cg6_fbc *fbc = fb->s.cg6.fbc;
  628. int i;
  629. do {
  630. i = sbus_readl(&fbc->s);
  631. } while (i & 0x10000000);
  632. return 0;
  633. }
  634. static char idstring[70] __initdata = { 0 };
  635. char __init *cgsixfb_init(struct fb_info_sbusfb *fb)
  636. {
  637. struct fb_fix_screeninfo *fix = &fb->fix;
  638. struct fb_var_screeninfo *var = &fb->var;
  639. struct display *disp = &fb->disp;
  640. struct fbtype *type = &fb->type;
  641. struct sbus_dev *sdev = fb->sbdp;
  642. unsigned long phys = sdev->reg_addrs[0].phys_addr;
  643. u32 conf;
  644. char *p;
  645. char *cardtype;
  646. struct bt_regs *bt;
  647. struct fb_ops *fbops;
  648. fbops = kmalloc(sizeof(*fbops), GFP_KERNEL);
  649. if (fbops == NULL)
  650. return NULL;
  651. *fbops = *fb->info.fbops;
  652. fbops->fb_rasterimg = cg6_rasterimg;
  653. fb->info.fbops = fbops;
  654. if (prom_getbool (fb->prom_node, "dblbuf")) {
  655. type->fb_size *= 4;
  656. fix->smem_len *= 4;
  657. }
  658. fix->line_length = fb->var.xres_virtual;
  659. fix->accel = FB_ACCEL_SUN_CGSIX;
  660. var->accel_flags = FB_ACCELF_TEXT;
  661. disp->scrollmode = SCROLL_YREDRAW;
  662. if (!disp->screen_base) {
  663. disp->screen_base = (char *)
  664. sbus_ioremap(&sdev->resource[0], CG6_RAM_OFFSET,
  665.      type->fb_size, "cgsix ram");
  666. }
  667. disp->screen_base += fix->line_length * fb->y_margin + fb->x_margin;
  668. fb->s.cg6.fbc = (struct cg6_fbc *)
  669. sbus_ioremap(&sdev->resource[0], CG6_FBC_OFFSET,
  670.      4096, "cgsix fbc");
  671. fb->s.cg6.tec = (struct cg6_tec *)
  672. sbus_ioremap(&sdev->resource[0], CG6_TEC_OFFSET,
  673.      sizeof(struct cg6_tec), "cgsix tec");
  674. fb->s.cg6.thc = (struct cg6_thc *)
  675. sbus_ioremap(&sdev->resource[0], CG6_THC_OFFSET,
  676.      sizeof(struct cg6_thc), "cgsix thc");
  677. fb->s.cg6.bt = bt = (struct bt_regs *)
  678. sbus_ioremap(&sdev->resource[0], CG6_BROOKTREE_OFFSET,
  679.      sizeof(struct bt_regs), "cgsix dac");
  680. fb->s.cg6.fhc = (u32 *)
  681. sbus_ioremap(&sdev->resource[0], CG6_FHC_OFFSET,
  682.      sizeof(u32), "cgsix fhc");
  683. #if 0
  684. prom_printf("CG6: RES[%016lx:%016lx:%016lx]n",
  685.     sdev->resource[0].start,
  686.     sdev->resource[0].end,
  687.     sdev->resource[0].flags);
  688. prom_printf("CG6: fbc(%p) tec(%p) thc(%p) bt(%p) fhc(%p)n",
  689.     fb->s.cg6.fbc,
  690.     fb->s.cg6.tec,
  691.     fb->s.cg6.thc,
  692.     fb->s.cg6.bt,
  693.     fb->s.cg6.fhc);
  694. prom_halt();
  695. #endif
  696. fb->dispsw = cg6_dispsw;
  697. fb->margins = cg6_margins;
  698. fb->loadcmap = cg6_loadcmap;
  699. fb->setcursor = cg6_setcursor;
  700. fb->setcursormap = cg6_setcursormap;
  701. fb->setcurshape = cg6_setcurshape;
  702. fb->restore_palette = cg6_restore_palette;
  703. fb->fill = cg6_fill;
  704. fb->blank = cg6_blank;
  705. fb->unblank = cg6_unblank;
  706. fb->reset = cg6_reset;
  707. fb->physbase = phys;
  708. fb->mmap_map = cg6_mmap_map;
  709. /* Initialize Brooktree DAC */
  710. sbus_writel(0x04 << 24, &bt->addr);         /* color planes */
  711. sbus_writel(0xff << 24, &bt->control);
  712. sbus_writel(0x05 << 24, &bt->addr);
  713. sbus_writel(0x00 << 24, &bt->control);
  714. sbus_writel(0x06 << 24, &bt->addr);         /* overlay plane */
  715. sbus_writel(0x73 << 24, &bt->control);
  716. sbus_writel(0x07 << 24, &bt->addr);
  717. sbus_writel(0x00 << 24, &bt->control);
  718. conf = sbus_readl(fb->s.cg6.fhc);
  719. switch(conf & CG6_FHC_CPU_MASK) {
  720. case CG6_FHC_CPU_SPARC: p = "sparc"; break;
  721. case CG6_FHC_CPU_68020: p = "68020"; break;
  722. default: p = "i386"; break;
  723. }
  724. if (((conf >> CG6_FHC_REV_SHIFT) & CG6_FHC_REV_MASK) >= 11) {
  725. if (fix->smem_len <= 0x100000) {
  726. cardtype = "TGX";
  727. } else {
  728. cardtype = "TGX+";
  729. }
  730. } else {
  731. if (fix->smem_len <= 0x100000) {
  732. cardtype = "GX";
  733. } else {
  734. cardtype = "GX+";
  735. }
  736. }
  737.                                                                         
  738. sprintf(idstring, 
  739. #ifdef __sparc_v9__
  740.     "cgsix at %016lx TEC Rev %x CPU %s Rev %x [%s]", phys,
  741. #else
  742.     "cgsix at %x.%08lx TEC Rev %x CPU %s Rev %x [%s]",
  743.     fb->iospace, phys, 
  744. #endif
  745.     ((sbus_readl(&fb->s.cg6.thc->thc_misc) >> CG6_THC_MISC_REV_SHIFT) &
  746.      CG6_THC_MISC_REV_MASK),
  747.     p, (conf >> CG6_FHC_REV_SHIFT) & CG6_FHC_REV_MASK, cardtype);
  748. sprintf(fb->info.modename, "CGsix [%s]", cardtype);
  749. sprintf(fix->id, "CGsix [%s]", cardtype);
  750.     
  751. cg6_reset(fb);
  752.     
  753. return idstring;
  754. }