cyber2000fb.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:42k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  *  linux/drivers/video/cyber2000fb.c
  3.  *
  4.  *  Copyright (C) 1998-2000 Russell King
  5.  *
  6.  *  MIPS and 50xx clock support
  7.  *  Copyright (C) 2001 Bradley D. LaRonde <brad@ltc.com>
  8.  *
  9.  *  32 bit support, text color and panning fixes for modes != 8 bit
  10.  *  Copyright (C) 2002 Denis Oliver Kropp <dok@directfb.org>
  11.  *
  12.  * This program is free software; you can redistribute it and/or modify
  13.  * it under the terms of the GNU General Public License version 2 as
  14.  * published by the Free Software Foundation.
  15.  *
  16.  * Intergraphics CyberPro 2000, 2010 and 5000 frame buffer device
  17.  *
  18.  * Based on cyberfb.c.
  19.  *
  20.  * Note that we now use the new fbcon fix, var and cmap scheme.  We do still
  21.  * have to check which console is the currently displayed one however, since
  22.  * especially for the colourmap stuff.  Once fbcon has been fully migrated,
  23.  * we can kill the last 5 references to cfb->currcon.
  24.  *
  25.  * We also use the new hotplug PCI subsystem.  I'm not sure if there are any
  26.  * such cards, but I'm erring on the side of caution.  We don't want to go
  27.  * pop just because someone does have one.
  28.  *
  29.  * Note that this doesn't work fully in the case of multiple CyberPro cards
  30.  * with grabbers.  We currently can only attach to the first CyberPro card
  31.  * found.
  32.  */
  33. #include <linux/config.h>
  34. #include <linux/module.h>
  35. #include <linux/kernel.h>
  36. #include <linux/errno.h>
  37. #include <linux/string.h>
  38. #include <linux/mm.h>
  39. #include <linux/tty.h>
  40. #include <linux/slab.h>
  41. #include <linux/delay.h>
  42. #include <linux/fb.h>
  43. #include <linux/pci.h>
  44. #include <linux/init.h>
  45. #include <asm/io.h>
  46. #include <asm/irq.h>
  47. #include <asm/pgtable.h>
  48. #include <asm/system.h>
  49. #include <asm/uaccess.h>
  50. #include <video/fbcon.h>
  51. #include <video/fbcon-cfb8.h>
  52. #include <video/fbcon-cfb16.h>
  53. #include <video/fbcon-cfb24.h>
  54. #include <video/fbcon-cfb32.h>
  55. /*
  56.  * Define this if you don't want RGB565, but RGB555 for 16bpp displays.
  57.  */
  58. /*#define CFB16_IS_CFB15*/
  59. #include "cyber2000fb.h"
  60. struct cfb_info {
  61. struct fb_info fb;
  62. struct display_switch *dispsw;
  63. struct pci_dev *dev;
  64. unsigned char  *region;
  65. unsigned char *regs;
  66. signed int currcon;
  67. int func_use_count;
  68. u_long ref_ps;
  69. /*
  70.  * Clock divisors
  71.  */
  72. u_int divisors[4];
  73. struct {
  74. u8 red, green, blue;
  75. } palette[NR_PALETTE];
  76. u_char mem_ctl1;
  77. u_char mem_ctl2;
  78. u_char mclk_mult;
  79. u_char mclk_div;
  80. };
  81. static char default_font_storage[40];
  82. static char *default_font = "Acorn8x8";
  83. MODULE_PARM(default_font, "s");
  84. MODULE_PARM_DESC(default_font, "Default font name");
  85. /*
  86.  * Our access methods.
  87.  */
  88. #define cyber2000fb_writel(val,reg,cfb) writel(val, (cfb)->regs + (reg))
  89. #define cyber2000fb_writew(val,reg,cfb) writew(val, (cfb)->regs + (reg))
  90. #define cyber2000fb_writeb(val,reg,cfb) writeb(val, (cfb)->regs + (reg))
  91. #define cyber2000fb_readb(reg,cfb) readb((cfb)->regs + (reg))
  92. static inline void
  93. cyber2000_crtcw(unsigned int reg, unsigned int val, struct cfb_info *cfb)
  94. {
  95. cyber2000fb_writew((reg & 255) | val << 8, 0x3d4, cfb);
  96. }
  97. static inline void
  98. cyber2000_grphw(unsigned int reg, unsigned int val, struct cfb_info *cfb)
  99. {
  100. cyber2000fb_writew((reg & 255) | val << 8, 0x3ce, cfb);
  101. }
  102. static inline unsigned int
  103. cyber2000_grphr(unsigned int reg, struct cfb_info *cfb)
  104. {
  105. cyber2000fb_writeb(reg, 0x3ce, cfb);
  106. return cyber2000fb_readb(0x3cf, cfb);
  107. }
  108. static inline void
  109. cyber2000_attrw(unsigned int reg, unsigned int val, struct cfb_info *cfb)
  110. {
  111. cyber2000fb_readb(0x3da, cfb);
  112. cyber2000fb_writeb(reg, 0x3c0, cfb);
  113. cyber2000fb_readb(0x3c1, cfb);
  114. cyber2000fb_writeb(val, 0x3c0, cfb);
  115. }
  116. static inline void
  117. cyber2000_seqw(unsigned int reg, unsigned int val, struct cfb_info *cfb)
  118. {
  119. cyber2000fb_writew((reg & 255) | val << 8, 0x3c4, cfb);
  120. }
  121. /* -------------------- Hardware specific routines ------------------------- */
  122. /*
  123.  * Hardware Cyber2000 Acceleration
  124.  */
  125. static void cyber2000_accel_wait(struct cfb_info *cfb)
  126. {
  127. int count = 100000;
  128. while (cyber2000fb_readb(CO_REG_CONTROL, cfb) & 0x80) {
  129. if (!count--) {
  130. debug_printf("accel_wait timed outn");
  131. cyber2000fb_writeb(0, CO_REG_CONTROL, cfb);
  132. return;
  133. }
  134. udelay(1);
  135. }
  136. }
  137. static void cyber2000_accel_setup(struct display *p)
  138. {
  139. struct cfb_info *cfb = (struct cfb_info *)p->fb_info;
  140. cfb->dispsw->setup(p);
  141. }
  142. static void
  143. cyber2000_accel_bmove(struct display *p, int sy, int sx, int dy, int dx,
  144.       int height, int width)
  145. {
  146. struct cfb_info *cfb = (struct cfb_info *)p->fb_info;
  147. struct fb_var_screeninfo *var = &p->fb_info->var;
  148. u_long src, dst;
  149. u_int fh, fw;
  150. int cmd = CO_CMD_L_PATTERN_FGCOL;
  151. fw    = fontwidth(p);
  152. sx    *= fw;
  153. dx    *= fw;
  154. width *= fw;
  155. width -= 1;
  156. if (sx < dx) {
  157. sx += width;
  158. dx += width;
  159. cmd |= CO_CMD_L_INC_LEFT;
  160. }
  161. fh     = fontheight(p);
  162. sy     *= fh;
  163. dy     *= fh;
  164. height *= fh;
  165. height -= 1;
  166. if (sy < dy) {
  167. sy += height;
  168. dy += height;
  169. cmd |= CO_CMD_L_INC_UP;
  170. }
  171. src    = sx + sy * var->xres_virtual;
  172. dst    = dx + dy * var->xres_virtual;
  173. cyber2000_accel_wait(cfb);
  174. cyber2000fb_writeb(0x00,  CO_REG_CONTROL, cfb);
  175. cyber2000fb_writeb(0x03,  CO_REG_FORE_MIX, cfb);
  176. cyber2000fb_writew(width, CO_REG_WIDTH, cfb);
  177. if (var->bits_per_pixel != 24) {
  178. cyber2000fb_writel(dst, CO_REG_DEST_PTR, cfb);
  179. cyber2000fb_writel(src, CO_REG_SRC_PTR, cfb);
  180. } else {
  181. cyber2000fb_writel(dst * 3, CO_REG_DEST_PTR, cfb);
  182. cyber2000fb_writeb(dst,     CO_REG_X_PHASE, cfb);
  183. cyber2000fb_writel(src * 3, CO_REG_SRC_PTR, cfb);
  184. }
  185. cyber2000fb_writew(height, CO_REG_HEIGHT, cfb);
  186. cyber2000fb_writew(cmd,    CO_REG_CMD_L, cfb);
  187. cyber2000fb_writew(0x2800, CO_REG_CMD_H, cfb);
  188. }
  189. static void
  190. cyber2000_accel_clear(struct vc_data *conp, struct display *p, int sy, int sx,
  191.       int height, int width)
  192. {
  193. struct cfb_info *cfb = (struct cfb_info *)p->fb_info;
  194. struct fb_var_screeninfo *var = &p->fb_info->var;
  195. u_long dst;
  196. u_int fw, fh;
  197. u32 bgx = attr_bgcol_ec(p, conp);
  198. fw = fontwidth(p);
  199. fh = fontheight(p);
  200. dst    = sx * fw + sy * var->xres_virtual * fh;
  201. width  = width * fw - 1;
  202. height = height * fh - 1;
  203. cyber2000_accel_wait(cfb);
  204. cyber2000fb_writeb(0x00,   CO_REG_CONTROL,  cfb);
  205. cyber2000fb_writeb(0x03,   CO_REG_FORE_MIX, cfb);
  206. cyber2000fb_writew(width,  CO_REG_WIDTH,    cfb);
  207. cyber2000fb_writew(height, CO_REG_HEIGHT,   cfb);
  208. switch (var->bits_per_pixel) {
  209. case 15:
  210. case 16:
  211. bgx = ((u16 *)p->dispsw_data)[bgx];
  212. case 8:
  213. cyber2000fb_writel(dst, CO_REG_DEST_PTR, cfb);
  214. break;
  215. case 24:
  216. cyber2000fb_writel(dst * 3, CO_REG_DEST_PTR, cfb);
  217. cyber2000fb_writeb(dst, CO_REG_X_PHASE, cfb);
  218. bgx = ((u32 *)p->dispsw_data)[bgx];
  219. break;
  220. case 32:
  221. bgx = ((u32 *)p->dispsw_data)[bgx];
  222. cyber2000fb_writel(dst, CO_REG_DEST_PTR, cfb);
  223. break;
  224. }
  225. cyber2000fb_writel(bgx, CO_REG_FOREGROUND, cfb);
  226. cyber2000fb_writew(CO_CMD_L_PATTERN_FGCOL, CO_REG_CMD_L, cfb);
  227. cyber2000fb_writew(0x0800, CO_REG_CMD_H, cfb);
  228. }
  229. static void
  230. cyber2000_accel_putc(struct vc_data *conp, struct display *p, int c,
  231.      int yy, int xx)
  232. {
  233. struct cfb_info *cfb = (struct cfb_info *)p->fb_info;
  234. cyber2000_accel_wait(cfb);
  235. cfb->dispsw->putc(conp, p, c, yy, xx);
  236. }
  237. static void
  238. cyber2000_accel_putcs(struct vc_data *conp, struct display *p,
  239.       const unsigned short *s, int count, int yy, int xx)
  240. {
  241. struct cfb_info *cfb = (struct cfb_info *)p->fb_info;
  242. cyber2000_accel_wait(cfb);
  243. cfb->dispsw->putcs(conp, p, s, count, yy, xx);
  244. }
  245. static void cyber2000_accel_revc(struct display *p, int xx, int yy)
  246. {
  247. struct cfb_info *cfb = (struct cfb_info *)p->fb_info;
  248. cyber2000_accel_wait(cfb);
  249. cfb->dispsw->revc(p, xx, yy);
  250. }
  251. static void
  252. cyber2000_accel_clear_margins(struct vc_data *conp, struct display *p,
  253.       int bottom_only)
  254. {
  255. struct cfb_info *cfb = (struct cfb_info *)p->fb_info;
  256. cfb->dispsw->clear_margins(conp, p, bottom_only);
  257. }
  258. static struct display_switch fbcon_cyber_accel = {
  259. setup: cyber2000_accel_setup,
  260. bmove: cyber2000_accel_bmove,
  261. clear: cyber2000_accel_clear,
  262. putc: cyber2000_accel_putc,
  263. putcs: cyber2000_accel_putcs,
  264. revc: cyber2000_accel_revc,
  265. clear_margins: cyber2000_accel_clear_margins,
  266. fontwidthmask: FONTWIDTH(8)|FONTWIDTH(16)
  267. };
  268. /*
  269.  *    Set a single color register. Return != 0 for invalid regno.
  270.  */
  271. static int
  272. cyber2000_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
  273.     u_int transp, struct fb_info *info)
  274. {
  275. struct cfb_info *cfb = (struct cfb_info *)info;
  276. u_int alpha = transp ^ 0xFFFF;
  277. if (regno >= NR_PALETTE)
  278. return 1;
  279. red   >>= 8;
  280. green >>= 8;
  281. blue  >>= 8;
  282. alpha >>= 8;
  283. cfb->palette[regno].red   = red;
  284. cfb->palette[regno].green = green;
  285. cfb->palette[regno].blue  = blue;
  286. switch (cfb->fb.var.bits_per_pixel) {
  287. #ifdef FBCON_HAS_CFB8
  288. case 8:
  289. cyber2000fb_writeb(regno, 0x3c8, cfb);
  290. cyber2000fb_writeb(red,   0x3c9, cfb);
  291. cyber2000fb_writeb(green, 0x3c9, cfb);
  292. cyber2000fb_writeb(blue,  0x3c9, cfb);
  293. break;
  294. #endif
  295. #ifdef FBCON_HAS_CFB16
  296. case 16:
  297. #ifndef CFB16_IS_CFB15
  298. if (regno < 64) {
  299. /* write green */
  300. cyber2000fb_writeb(regno << 2, 0x3c8, cfb);
  301. cyber2000fb_writeb(cfb->palette[regno >> 1].red, 0x3c9, cfb);
  302. cyber2000fb_writeb(green, 0x3c9, cfb);
  303. cyber2000fb_writeb(cfb->palette[regno >> 1].blue, 0x3c9, cfb);
  304. }
  305. if (regno < 32) {
  306. /* write red,blue */
  307. cyber2000fb_writeb(regno << 3, 0x3c8, cfb);
  308. cyber2000fb_writeb(red, 0x3c9, cfb);
  309. cyber2000fb_writeb(cfb->palette[regno << 1].green, 0x3c9, cfb);
  310. cyber2000fb_writeb(blue, 0x3c9, cfb);
  311. }
  312. if (regno < 16)
  313. ((u16 *)cfb->fb.pseudo_palette)[regno] =
  314. ((red   << 8) & 0xf800) |
  315. ((green << 3) & 0x07e0) |
  316. ((blue  >> 3));
  317. break;
  318. #endif
  319. case 15:
  320. if (regno < 32) {
  321. cyber2000fb_writeb(regno << 3, 0x3c8, cfb);
  322. cyber2000fb_writeb(red, 0x3c9, cfb);
  323. cyber2000fb_writeb(green, 0x3c9, cfb);
  324. cyber2000fb_writeb(blue, 0x3c9, cfb);
  325. }
  326. if (regno < 16)
  327. ((u16 *)cfb->fb.pseudo_palette)[regno] =
  328. ((red   << 7) & 0x7c00) |
  329. ((green << 2) & 0x03e0) |
  330. ((blue  >> 3));
  331. break;
  332. #endif
  333. #ifdef FBCON_HAS_CFB24
  334. case 24:
  335. cyber2000fb_writeb(regno, 0x3c8, cfb);
  336. cyber2000fb_writeb(red,   0x3c9, cfb);
  337. cyber2000fb_writeb(green, 0x3c9, cfb);
  338. cyber2000fb_writeb(blue,  0x3c9, cfb);
  339. if (regno < 16)
  340. ((u32 *)cfb->fb.pseudo_palette)[regno] =
  341. (red << 16) | (green << 8) | blue;
  342. break;
  343. #endif
  344. #ifdef FBCON_HAS_CFB32
  345. case 32:
  346. cyber2000fb_writeb(regno, 0x3c8, cfb);
  347. cyber2000fb_writeb(red,   0x3c9, cfb);
  348. cyber2000fb_writeb(green, 0x3c9, cfb);
  349. cyber2000fb_writeb(blue,  0x3c9, cfb);
  350. if (regno < 16)
  351. ((u32 *)cfb->fb.pseudo_palette)[regno] =
  352. (alpha << 24) | (red << 16) | (green << 8) | blue;
  353. break;
  354. #endif
  355. default:
  356. return 1;
  357. }
  358. return 0;
  359. }
  360. struct par_info {
  361. /*
  362.  * Hardware
  363.  */
  364. u_char clock_mult;
  365. u_char clock_div;
  366. u_char visualid;
  367. u_char pixformat;
  368. u_char crtc_ofl;
  369. u_char crtc[19];
  370. u_int width;
  371. u_int pitch;
  372. u_int fetch;
  373. /*
  374.  * Other
  375.  */
  376. u_char palette_ctrl;
  377. u_int vmode;
  378. };
  379. static const u_char crtc_idx[] = {
  380. 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
  381. 0x08, 0x09,
  382. 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18
  383. };
  384. static void cyber2000fb_set_timing(struct cfb_info *cfb, struct par_info *hw)
  385. {
  386. u_int i;
  387. /*
  388.  * Blank palette
  389.  */
  390. for (i = 0; i < NR_PALETTE; i++) {
  391. cyber2000fb_writeb(i, 0x3c8, cfb);
  392. cyber2000fb_writeb(0, 0x3c9, cfb);
  393. cyber2000fb_writeb(0, 0x3c9, cfb);
  394. cyber2000fb_writeb(0, 0x3c9, cfb);
  395. }
  396. cyber2000fb_writeb(0xef, 0x3c2, cfb);
  397. cyber2000_crtcw(0x11, 0x0b, cfb);
  398. cyber2000_attrw(0x11, 0x00, cfb);
  399. cyber2000_seqw(0x00, 0x01, cfb);
  400. cyber2000_seqw(0x01, 0x01, cfb);
  401. cyber2000_seqw(0x02, 0x0f, cfb);
  402. cyber2000_seqw(0x03, 0x00, cfb);
  403. cyber2000_seqw(0x04, 0x0e, cfb);
  404. cyber2000_seqw(0x00, 0x03, cfb);
  405. for (i = 0; i < sizeof(crtc_idx); i++)
  406. cyber2000_crtcw(crtc_idx[i], hw->crtc[i], cfb);
  407. for (i = 0x0a; i < 0x10; i++)
  408. cyber2000_crtcw(i, 0, cfb);
  409. cyber2000_grphw(0x11, hw->crtc_ofl, cfb);
  410. cyber2000_grphw(0x00, 0x00, cfb);
  411. cyber2000_grphw(0x01, 0x00, cfb);
  412. cyber2000_grphw(0x02, 0x00, cfb);
  413. cyber2000_grphw(0x03, 0x00, cfb);
  414. cyber2000_grphw(0x04, 0x00, cfb);
  415. cyber2000_grphw(0x05, 0x60, cfb);
  416. cyber2000_grphw(0x06, 0x05, cfb);
  417. cyber2000_grphw(0x07, 0x0f, cfb);
  418. cyber2000_grphw(0x08, 0xff, cfb);
  419. /* Attribute controller registers */
  420. for (i = 0; i < 16; i++)
  421. cyber2000_attrw(i, i, cfb);
  422. cyber2000_attrw(0x10, 0x01, cfb);
  423. cyber2000_attrw(0x11, 0x00, cfb);
  424. cyber2000_attrw(0x12, 0x0f, cfb);
  425. cyber2000_attrw(0x13, 0x00, cfb);
  426. cyber2000_attrw(0x14, 0x00, cfb);
  427. /* woody: set the interlaced bit... */
  428. /* FIXME: what about doublescan? */
  429. cyber2000fb_writeb(0x11, 0x3ce, cfb);
  430. i = cyber2000fb_readb(0x3cf, cfb);
  431. if (hw->vmode == FB_VMODE_INTERLACED)
  432. i |= 0x20;
  433. else
  434. i &= ~0x20;
  435. cyber2000fb_writeb(i, 0x3cf, cfb);
  436. /* PLL registers */
  437. cyber2000_grphw(DCLK_MULT, hw->clock_mult, cfb);
  438. cyber2000_grphw(DCLK_DIV,  hw->clock_div, cfb);
  439. cyber2000_grphw(MCLK_MULT, cfb->mclk_mult, cfb);
  440. cyber2000_grphw(MCLK_DIV,  cfb->mclk_div, cfb);
  441. cyber2000_grphw(0x90, 0x01, cfb);
  442. cyber2000_grphw(0xb9, 0x80, cfb);
  443. cyber2000_grphw(0xb9, 0x00, cfb);
  444. cyber2000fb_writeb(0x56, 0x3ce, cfb);
  445. i = cyber2000fb_readb(0x3cf, cfb);
  446. cyber2000fb_writeb(i | 4, 0x3cf, cfb);
  447. cyber2000fb_writeb(hw->palette_ctrl, 0x3c6, cfb);
  448. cyber2000fb_writeb(i,    0x3cf, cfb);
  449. cyber2000fb_writeb(0x20, 0x3c0, cfb);
  450. cyber2000fb_writeb(0xff, 0x3c6, cfb);
  451. cyber2000_grphw(0x14, hw->fetch, cfb);
  452. cyber2000_grphw(0x15, ((hw->fetch >> 8) & 0x03) |
  453.       ((hw->pitch >> 4) & 0x30), cfb);
  454. cyber2000_grphw(0x77, hw->visualid, cfb);
  455. /* make sure we stay in linear mode */
  456. cyber2000_grphw(0x33, 0x0d, cfb);
  457. /*
  458.  * Set up accelerator registers
  459.  */
  460. cyber2000fb_writew(hw->width,     CO_REG_SRC_WIDTH,  cfb);
  461. cyber2000fb_writew(hw->width,     CO_REG_DEST_WIDTH, cfb);
  462. cyber2000fb_writeb(hw->pixformat, CO_REG_PIX_FORMAT, cfb);
  463. }
  464. static inline int
  465. cyber2000fb_update_start(struct cfb_info *cfb, struct fb_var_screeninfo *var)
  466. {
  467. u_int base;
  468. base = var->yoffset * var->xres_virtual + var->xoffset;
  469. /* have to be careful, because bits_per_pixel might be 15
  470.    in this version of the driver -- dok@directfb.org 2002/06/13 */
  471. base *= (var->bits_per_pixel + 7) >> 3;
  472. base >>= 2;
  473. if (base >= 1 << 20)
  474. return -EINVAL;
  475. cyber2000_grphw(0x10, base >> 16 | 0x10, cfb);
  476. cyber2000_crtcw(0x0c, base >> 8, cfb);
  477. cyber2000_crtcw(0x0d, base, cfb);
  478. return 0;
  479. }
  480. /*
  481.  * Set the Colormap
  482.  */
  483. static int
  484. cyber2000fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
  485.      struct fb_info *info)
  486. {
  487. struct cfb_info *cfb = (struct cfb_info *)info;
  488. struct fb_cmap *dcmap = &fb_display[con].cmap;
  489. int err = 0;
  490. /* no colormap allocated? */
  491. if (!dcmap->len) {
  492. int size;
  493. if (cfb->fb.var.bits_per_pixel == 16)
  494. size = 32;
  495. else
  496. size = 256;
  497. err = fb_alloc_cmap(dcmap, size, 0);
  498. }
  499. /*
  500.  * we should be able to remove this test once fbcon has been
  501.  * "improved" --rmk
  502.  */
  503. if (!err && con == cfb->currcon) {
  504. err = fb_set_cmap(cmap, kspc, cyber2000_setcolreg, &cfb->fb);
  505. dcmap = &cfb->fb.cmap;
  506. }
  507. if (!err)
  508. fb_copy_cmap(cmap, dcmap, kspc ? 0 : 1);
  509. return err;
  510. }
  511. static int
  512. cyber2000fb_decode_crtc(struct par_info *hw, struct cfb_info *cfb,
  513. struct fb_var_screeninfo *var)
  514. {
  515. u_int Htotal, Hblankend, Hsyncend;
  516. u_int Vtotal, Vdispend, Vblankstart, Vblankend, Vsyncstart, Vsyncend;
  517. #define BIT(v,b1,m,b2) (((v >> b1) & m) << b2)
  518. hw->crtc[13] = hw->pitch;
  519. hw->crtc[17] = 0xe3;
  520. hw->crtc[14] = 0;
  521. hw->crtc[8]  = 0;
  522. Htotal      = var->xres + var->right_margin +
  523.       var->hsync_len + var->left_margin;
  524. if (Htotal > 2080)
  525. return -EINVAL;
  526. hw->crtc[0] = (Htotal >> 3) - 5;
  527. hw->crtc[1] = (var->xres >> 3) - 1;
  528. hw->crtc[2] = var->xres >> 3;
  529. hw->crtc[4] = (var->xres + var->right_margin) >> 3;
  530. Hblankend   = (Htotal - 4*8) >> 3;
  531. hw->crtc[3] = BIT(Hblankend,  0, 0x1f,  0) |
  532.       BIT(1,          0, 0x01,  7);
  533. Hsyncend    = (var->xres + var->right_margin + var->hsync_len) >> 3;
  534. hw->crtc[5] = BIT(Hsyncend,   0, 0x1f,  0) |
  535.       BIT(Hblankend,  5, 0x01,  7);
  536. Vdispend    = var->yres - 1;
  537. Vsyncstart  = var->yres + var->lower_margin;
  538. Vsyncend    = var->yres + var->lower_margin + var->vsync_len;
  539. Vtotal      = var->yres + var->lower_margin + var->vsync_len +
  540.       var->upper_margin - 2;
  541. if (Vtotal > 2047)
  542. return -EINVAL;
  543. Vblankstart = var->yres + 6;
  544. Vblankend   = Vtotal - 10;
  545. hw->crtc[6]  = Vtotal;
  546. hw->crtc[7]  = BIT(Vtotal,     8, 0x01,  0) |
  547. BIT(Vdispend,   8, 0x01,  1) |
  548. BIT(Vsyncstart, 8, 0x01,  2) |
  549. BIT(Vblankstart,8, 0x01,  3) |
  550. BIT(1,          0, 0x01,  4) |
  551.          BIT(Vtotal,     9, 0x01,  5) |
  552. BIT(Vdispend,   9, 0x01,  6) |
  553. BIT(Vsyncstart, 9, 0x01,  7);
  554. hw->crtc[9]  = BIT(0,          0, 0x1f,  0) |
  555.         BIT(Vblankstart,9, 0x01,  5) |
  556. BIT(1,          0, 0x01,  6);
  557. hw->crtc[10] = Vsyncstart;
  558. hw->crtc[11] = BIT(Vsyncend,   0, 0x0f,  0) |
  559.        BIT(1,          0, 0x01,  7);
  560. hw->crtc[12] = Vdispend;
  561. hw->crtc[15] = Vblankstart;
  562. hw->crtc[16] = Vblankend;
  563. hw->crtc[18] = 0xff;
  564. /* overflow - graphics reg 0x11 */
  565. /* 0=VTOTAL:10 1=VDEND:10 2=VRSTART:10 3=VBSTART:10
  566.  * 4=LINECOMP:10 5-IVIDEO 6=FIXCNT
  567.  */
  568. hw->crtc_ofl =
  569. BIT(Vtotal,     10, 0x01,  0) |
  570. BIT(Vdispend,   10, 0x01,  1) |
  571. BIT(Vsyncstart, 10, 0x01,  2) |
  572. BIT(Vblankstart,10, 0x01,  3) |
  573. 1 << 4;
  574. return 0;
  575. }
  576. /*
  577.  * The following was discovered by a good monitor, bit twiddling, theorising
  578.  * and but mostly luck.  Strangely, it looks like everyone elses' PLL!
  579.  *
  580.  * Clock registers:
  581.  *   fclock = fpll / div2
  582.  *   fpll   = fref * mult / div1
  583.  * where:
  584.  *   fref = 14.318MHz (69842ps)
  585.  *   mult = reg0xb0.7:0
  586.  *   div1 = (reg0xb1.5:0 + 1)
  587.  *   div2 =  2^(reg0xb1.7:6)
  588.  *   fpll should be between 115 and 260 MHz
  589.  *  (8696ps and 3846ps)
  590.  */
  591. static int
  592. cyber2000fb_decode_clock(struct par_info *hw, struct cfb_info *cfb,
  593.  struct fb_var_screeninfo *var)
  594. {
  595. u_long pll_ps = var->pixclock;
  596. const u_long ref_ps = cfb->ref_ps;
  597. u_int div2, t_div1, best_div1, best_mult;
  598. int best_diff;
  599. int vco;
  600. /*
  601.  * Step 1:
  602.  *   find div2 such that 115MHz < fpll < 260MHz
  603.  *   and 0 <= div2 < 4
  604.  */
  605. for (div2 = 0; div2 < 4; div2++) {
  606. u_long new_pll;
  607. new_pll = pll_ps / cfb->divisors[div2];
  608. if (8696 > new_pll && new_pll > 3846) {
  609. pll_ps = new_pll;
  610. break;
  611. }
  612. }
  613. if (div2 == 4)
  614. return -EINVAL;
  615. /*
  616.  * Step 2:
  617.  *  Given pll_ps and ref_ps, find:
  618.  *    pll_ps * 0.995 < pll_ps_calc < pll_ps * 1.005
  619.  *  where { 1 < best_div1 < 32, 1 < best_mult < 256 }
  620.  *    pll_ps_calc = best_div1 / (ref_ps * best_mult)
  621.  */
  622. best_diff = 0x7fffffff;
  623. best_mult = 32;
  624. best_div1 = 255;
  625. for (t_div1 = 32; t_div1 > 1; t_div1 -= 1) {
  626. u_int rr, t_mult, t_pll_ps;
  627. int diff;
  628. /*
  629.  * Find the multiplier for this divisor
  630.  */
  631. rr = ref_ps * t_div1;
  632. t_mult = (rr + pll_ps / 2) / pll_ps;
  633. /*
  634.  * Is the multiplier within the correct range?
  635.  */
  636. if (t_mult > 256 || t_mult < 2)
  637. continue;
  638. /*
  639.  * Calculate the actual clock period from this multiplier
  640.  * and divisor, and estimate the error.
  641.  */
  642. t_pll_ps = (rr + t_mult / 2) / t_mult;
  643. diff = pll_ps - t_pll_ps;
  644. if (diff < 0)
  645. diff = -diff;
  646. if (diff < best_diff) {
  647. best_diff = diff;
  648. best_mult = t_mult;
  649. best_div1 = t_div1;
  650. }
  651. /*
  652.  * If we hit an exact value, there is no point in continuing.
  653.  */
  654. if (diff == 0)
  655. break;
  656. }
  657. /*
  658.  * Step 3:
  659.  *  combine values
  660.  */
  661. hw->clock_mult = best_mult - 1;
  662. hw->clock_div  = div2 << 6 | (best_div1 - 1);
  663. vco = ref_ps * best_div1 / best_mult;
  664. if ((ref_ps == 40690) && (vco < 5556))
  665. /* Set VFSEL when VCO > 180MHz (5.556 ps). */
  666. hw->clock_div |= DCLK_DIV_VFSEL;
  667. return 0;
  668. }
  669. /*
  670.  * Decode the info required for the hardware.
  671.  * This involves the PLL parameters for the dot clock,
  672.  * CRTC registers, and accelerator settings.
  673.  */
  674. static int
  675. cyber2000fb_decode_var(struct fb_var_screeninfo *var, struct cfb_info *cfb,
  676.        struct par_info *hw)
  677. {
  678. int err;
  679. hw->width = var->xres_virtual;
  680. hw->palette_ctrl = 0x06;
  681. hw->vmode = var->vmode;
  682. switch (var->bits_per_pixel) {
  683. #ifdef FBCON_HAS_CFB8
  684. case 8: /* PSEUDOCOLOUR, 256 */
  685. hw->pixformat = PIXFORMAT_8BPP;
  686. hw->visualid = VISUALID_256;
  687. hw->pitch = hw->width >> 3;
  688. break;
  689. #endif
  690. #ifdef FBCON_HAS_CFB16
  691. case 16:/* DIRECTCOLOUR, 64k */
  692. #ifndef CFB16_IS_CFB15
  693. hw->pixformat = PIXFORMAT_16BPP;
  694. hw->visualid = VISUALID_64K;
  695. hw->pitch = hw->width >> 2;
  696. hw->palette_ctrl |= 0x10;
  697. break;
  698. #endif
  699. case 15:/* DIRECTCOLOUR, 32k */
  700. hw->pixformat = PIXFORMAT_16BPP;
  701. hw->visualid = VISUALID_32K;
  702. hw->pitch = hw->width >> 2;
  703. hw->palette_ctrl |= 0x10;
  704. break;
  705. #endif
  706. #ifdef FBCON_HAS_CFB24
  707. case 24:/* TRUECOLOUR, 16m */
  708. hw->pixformat = PIXFORMAT_24BPP;
  709. hw->visualid = VISUALID_16M;
  710. hw->width *= 3;
  711. hw->pitch = hw->width >> 3;
  712. hw->palette_ctrl |= 0x10;
  713. break;
  714. #endif
  715. #ifdef FBCON_HAS_CFB32
  716. case 32:/* TRUECOLOUR, 16m */
  717. hw->pixformat = PIXFORMAT_32BPP;
  718. hw->visualid = VISUALID_16M_32;
  719. hw->pitch = hw->width >> 1;
  720. hw->palette_ctrl |= 0x10;
  721. break;
  722. #endif
  723. default:
  724. return -EINVAL;
  725. }
  726. err = cyber2000fb_decode_clock(hw, cfb, var);
  727. if (err)
  728. return err;
  729. err = cyber2000fb_decode_crtc(hw, cfb, var);
  730. if (err)
  731. return err;
  732. hw->width -= 1;
  733. hw->fetch = hw->pitch;
  734. if (!(cfb->mem_ctl2 & MEM_CTL2_64BIT))
  735. hw->fetch <<= 1;
  736. hw->fetch += 1;
  737. return 0;
  738. }
  739. /*
  740.  *    Set the User Defined Part of the Display
  741.  */
  742. static int
  743. cyber2000fb_set_var(struct fb_var_screeninfo *var, int con,
  744.     struct fb_info *info)
  745. {
  746. struct cfb_info *cfb = (struct cfb_info *)info;
  747. struct display *display;
  748. struct par_info hw;
  749. int err, chgvar = 0;
  750. /*
  751.  * CONUPDATE and SMOOTH_XPAN are equal.  However,
  752.  * SMOOTH_XPAN is only used internally by fbcon.
  753.  */
  754. if (var->vmode & FB_VMODE_CONUPDATE) {
  755. var->vmode |= FB_VMODE_YWRAP;
  756. var->xoffset = cfb->fb.var.xoffset;
  757. var->yoffset = cfb->fb.var.yoffset;
  758. }
  759. err = cyber2000fb_decode_var(var, (struct cfb_info *)info, &hw);
  760. if (err)
  761. return err;
  762. if (var->activate & FB_ACTIVATE_TEST)
  763. return 0;
  764. if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW)
  765. return -EINVAL;
  766. if (cfb->fb.var.xres != var->xres)
  767. chgvar = 1;
  768. if (cfb->fb.var.yres != var->yres)
  769. chgvar = 1;
  770. if (cfb->fb.var.xres_virtual != var->xres_virtual)
  771. chgvar = 1;
  772. if (cfb->fb.var.yres_virtual != var->yres_virtual)
  773. chgvar = 1;
  774. if (cfb->fb.var.bits_per_pixel != var->bits_per_pixel)
  775. chgvar = 1;
  776. if (con < 0) {
  777. display = cfb->fb.disp;
  778. chgvar = 0;
  779. } else {
  780. display = fb_display + con;
  781. }
  782. var->red.msb_right = 0;
  783. var->green.msb_right = 0;
  784. var->blue.msb_right = 0;
  785. switch (var->bits_per_pixel) {
  786. #ifdef FBCON_HAS_CFB8
  787. case 8: /* PSEUDOCOLOUR, 256 */
  788. var->red.offset = 0;
  789. var->red.length = 8;
  790. var->green.offset = 0;
  791. var->green.length = 8;
  792. var->blue.offset = 0;
  793. var->blue.length = 8;
  794. cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
  795. cfb->dispsw = &fbcon_cfb8;
  796. display->dispsw_data = NULL;
  797. display->next_line = var->xres_virtual;
  798. break;
  799. #endif
  800. #ifdef FBCON_HAS_CFB16
  801. case 16:/* DIRECTCOLOUR, 64k */
  802. #ifndef CFB16_IS_CFB15
  803. var->red.offset = 11;
  804. var->red.length = 5;
  805. var->green.offset = 5;
  806. var->green.length = 6;
  807. var->blue.offset = 0;
  808. var->blue.length = 5;
  809. cfb->fb.fix.visual = FB_VISUAL_DIRECTCOLOR;
  810. cfb->dispsw = &fbcon_cfb16;
  811. display->dispsw_data = cfb->fb.pseudo_palette;
  812. display->next_line = var->xres_virtual * 2;
  813. break;
  814. #endif
  815. case 15:/* DIRECTCOLOUR, 32k */
  816. var->bits_per_pixel = 15;
  817. var->red.offset = 10;
  818. var->red.length = 5;
  819. var->green.offset = 5;
  820. var->green.length = 5;
  821. var->blue.offset = 0;
  822. var->blue.length = 5;
  823. cfb->fb.fix.visual = FB_VISUAL_DIRECTCOLOR;
  824. cfb->dispsw = &fbcon_cfb16;
  825. display->dispsw_data = cfb->fb.pseudo_palette;
  826. display->next_line = var->xres_virtual * 2;
  827. break;
  828. #endif
  829. #ifdef FBCON_HAS_CFB24
  830. case 24:/* TRUECOLOUR, 16m */
  831. var->red.offset = 16;
  832. var->red.length = 8;
  833. var->green.offset = 8;
  834. var->green.length = 8;
  835. var->blue.offset = 0;
  836. var->blue.length = 8;
  837. cfb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
  838. cfb->dispsw = &fbcon_cfb24;
  839. display->dispsw_data = cfb->fb.pseudo_palette;
  840. display->next_line = var->xres_virtual * 3;
  841. break;
  842. #endif
  843. #ifdef FBCON_HAS_CFB32
  844. case 32:/* TRUECOLOUR, 16m */
  845. var->transp.offset = 24;
  846. var->transp.length = 8;
  847. var->red.offset = 16;
  848. var->red.length = 8;
  849. var->green.offset = 8;
  850. var->green.length = 8;
  851. var->blue.offset = 0;
  852. var->blue.length = 8;
  853. cfb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
  854. cfb->dispsw = &fbcon_cfb32;
  855. display->dispsw_data = cfb->fb.pseudo_palette;
  856. display->next_line = var->xres_virtual * 4;
  857. break;
  858. #endif
  859. default:/* in theory this should never happen */
  860. printk(KERN_WARNING "%s: no support for %dbppn",
  861.        cfb->fb.fix.id, var->bits_per_pixel);
  862. cfb->dispsw = &fbcon_dummy;
  863. break;
  864. }
  865. if (var->accel_flags & FB_ACCELF_TEXT && cfb->dispsw != &fbcon_dummy)
  866. display->dispsw = &fbcon_cyber_accel;
  867. else
  868. display->dispsw = cfb->dispsw;
  869. cfb->fb.fix.line_length = display->next_line;
  870. display->screen_base = cfb->fb.screen_base;
  871. display->line_length = cfb->fb.fix.line_length;
  872. display->visual = cfb->fb.fix.visual;
  873. display->type = cfb->fb.fix.type;
  874. display->type_aux = cfb->fb.fix.type_aux;
  875. display->ypanstep = cfb->fb.fix.ypanstep;
  876. display->ywrapstep = cfb->fb.fix.ywrapstep;
  877. display->can_soft_blank = 1;
  878. display->inverse = 0;
  879. cfb->fb.var = *var;
  880. cfb->fb.var.activate &= ~FB_ACTIVATE_ALL;
  881. /*
  882.  * Update the old var.  The fbcon drivers still use this.
  883.  * Once they are using cfb->fb.var, this can be dropped.
  884.  * --rmk
  885.  */
  886. display->var = cfb->fb.var;
  887. /*
  888.  * If we are setting all the virtual consoles, also set the
  889.  * defaults used to create new consoles.
  890.  */
  891. if (var->activate & FB_ACTIVATE_ALL)
  892. cfb->fb.disp->var = cfb->fb.var;
  893. if (chgvar && info && cfb->fb.changevar)
  894. cfb->fb.changevar(con);
  895. cyber2000fb_update_start(cfb, var);
  896. cyber2000fb_set_timing(cfb, &hw);
  897. fb_set_cmap(&cfb->fb.cmap, 1, cyber2000_setcolreg, &cfb->fb);
  898. return 0;
  899. }
  900. /*
  901.  *    Pan or Wrap the Display
  902.  */
  903. static int
  904. cyber2000fb_pan_display(struct fb_var_screeninfo *var, int con,
  905. struct fb_info *info)
  906. {
  907. struct cfb_info *cfb = (struct cfb_info *)info;
  908. u_int y_bottom;
  909. y_bottom = var->yoffset;
  910. if (!(var->vmode & FB_VMODE_YWRAP))
  911. y_bottom += var->yres;
  912. if (var->xoffset > (var->xres_virtual - var->xres))
  913. return -EINVAL;
  914. if (y_bottom > cfb->fb.var.yres_virtual)
  915. return -EINVAL;
  916. if (cyber2000fb_update_start(cfb, var))
  917. return -EINVAL;
  918. cfb->fb.var.xoffset = var->xoffset;
  919. cfb->fb.var.yoffset = var->yoffset;
  920. if (var->vmode & FB_VMODE_YWRAP) {
  921. cfb->fb.var.vmode |= FB_VMODE_YWRAP;
  922. } else {
  923. cfb->fb.var.vmode &= ~FB_VMODE_YWRAP;
  924. }
  925. return 0;
  926. }
  927. /*
  928.  *    Update the `var' structure (called by fbcon.c)
  929.  *
  930.  *    This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'.
  931.  *    Since it's called by a kernel driver, no range checking is done.
  932.  */
  933. static int cyber2000fb_updatevar(int con, struct fb_info *info)
  934. {
  935. struct cfb_info *cfb = (struct cfb_info *)info;
  936. return cyber2000fb_update_start(cfb, &fb_display[con].var);
  937. }
  938. static int cyber2000fb_switch(int con, struct fb_info *info)
  939. {
  940. struct cfb_info *cfb = (struct cfb_info *)info;
  941. struct display *disp;
  942. struct fb_cmap *cmap;
  943. if (cfb->currcon >= 0) {
  944. disp = fb_display + cfb->currcon;
  945. /*
  946.  * Save the old colormap and video mode.
  947.  */
  948. disp->var = cfb->fb.var;
  949. if (disp->cmap.len)
  950. fb_copy_cmap(&cfb->fb.cmap, &disp->cmap, 0);
  951. }
  952. cfb->currcon = con;
  953. disp = fb_display + con;
  954. /*
  955.  * Install the new colormap and change the video mode.  By default,
  956.  * fbcon sets all the colormaps and video modes to the default
  957.  * values at bootup.
  958.  *
  959.  * Really, we want to set the colourmap size depending on the
  960.  * depth of the new video mode.  For now, we leave it at its
  961.  * default 256 entry.
  962.  */
  963. if (disp->cmap.len)
  964. cmap = &disp->cmap;
  965. else
  966. cmap = fb_default_cmap(1 << disp->var.bits_per_pixel);
  967. fb_copy_cmap(cmap, &cfb->fb.cmap, 0);
  968. cfb->fb.var = disp->var;
  969. cfb->fb.var.activate = FB_ACTIVATE_NOW;
  970. cyber2000fb_set_var(&cfb->fb.var, con, &cfb->fb);
  971. return 0;
  972. }
  973. /*
  974.  *    (Un)Blank the display.
  975.  */
  976. static void cyber2000fb_blank(int blank, struct fb_info *info)
  977. {
  978. struct cfb_info *cfb = (struct cfb_info *)info;
  979. int i;
  980. /*
  981.  *  Blank the screen if blank_mode != 0, else unblank. If
  982.  *  blank == NULL then the caller blanks by setting the CLUT
  983.  *  (Color Look Up Table) to all black. Return 0 if blanking
  984.  *  succeeded, != 0 if un-/blanking failed due to e.g. a
  985.  *  video mode which doesn't support it. Implements VESA
  986.  *  suspend and powerdown modes on hardware that supports
  987.  *  disabling hsync/vsync:
  988.  *    blank_mode == 2: suspend vsync
  989.  *    blank_mode == 3: suspend hsync
  990.  *    blank_mode == 4: powerdown
  991.  *
  992.  *  wms...Enable VESA DMPS compatible powerdown mode
  993.  *  run "setterm -powersave powerdown" to take advantage
  994.  */
  995.      
  996. switch (blank) {
  997. case 4: /* powerdown - both sync lines down */
  998.      cyber2000_grphw(0x16, 0x05, cfb);
  999. break;
  1000. case 3: /* hsync off */
  1001.      cyber2000_grphw(0x16, 0x01, cfb);
  1002. break;
  1003. case 2: /* vsync off */
  1004.      cyber2000_grphw(0x16, 0x04, cfb);
  1005. break;
  1006. case 1: /* soft blank */
  1007. cyber2000_grphw(0x16, 0x00, cfb);
  1008. for (i = 0; i < NR_PALETTE; i++) {
  1009. cyber2000fb_writeb(i, 0x3c8, cfb);
  1010. cyber2000fb_writeb(0, 0x3c9, cfb);
  1011. cyber2000fb_writeb(0, 0x3c9, cfb);
  1012. cyber2000fb_writeb(0, 0x3c9, cfb);
  1013. }
  1014. break;
  1015. default: /* unblank */
  1016. cyber2000_grphw(0x16, 0x00, cfb);
  1017. for (i = 0; i < NR_PALETTE; i++) {
  1018. cyber2000fb_writeb(i, 0x3c8, cfb);
  1019. cyber2000fb_writeb(cfb->palette[i].red, 0x3c9, cfb);
  1020. cyber2000fb_writeb(cfb->palette[i].green, 0x3c9, cfb);
  1021. cyber2000fb_writeb(cfb->palette[i].blue, 0x3c9, cfb);
  1022. }
  1023. break;
  1024. }
  1025. }
  1026. /*
  1027.  * Get the currently displayed virtual consoles colormap.
  1028.  */
  1029. static int
  1030. gen_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
  1031. {
  1032. fb_copy_cmap(&info->cmap, cmap, kspc ? 0 : 2);
  1033. return 0;
  1034. }
  1035. /*
  1036.  * Get the currently displayed virtual consoles fixed part of the display.
  1037.  */
  1038. static int
  1039. gen_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
  1040. {
  1041. *fix = info->fix;
  1042. return 0;
  1043. }
  1044. /*
  1045.  * Get the current user defined part of the display.
  1046.  */
  1047. static int
  1048. gen_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
  1049. {
  1050. *var = info->var;
  1051. return 0;
  1052. }
  1053. static struct fb_ops cyber2000fb_ops = {
  1054. owner: THIS_MODULE,
  1055. fb_set_var: cyber2000fb_set_var,
  1056. fb_set_cmap: cyber2000fb_set_cmap,
  1057. fb_pan_display: cyber2000fb_pan_display,
  1058. fb_get_fix: gen_get_fix,
  1059. fb_get_var: gen_get_var,
  1060. fb_get_cmap: gen_get_cmap,
  1061. };
  1062. /*
  1063.  * Enable access to the extended registers
  1064.  */
  1065. static void cyber2000fb_enable_extregs(struct cfb_info *cfb)
  1066. {
  1067. cfb->func_use_count += 1;
  1068. if (cfb->func_use_count == 1) {
  1069. int old;
  1070. old = cyber2000_grphr(FUNC_CTL, cfb);
  1071. cyber2000_grphw(FUNC_CTL, old | FUNC_CTL_EXTREGENBL, cfb);
  1072. }
  1073. }
  1074. /*
  1075.  * Disable access to the extended registers
  1076.  */
  1077. static void cyber2000fb_disable_extregs(struct cfb_info *cfb)
  1078. {
  1079. if (cfb->func_use_count == 1) {
  1080. int old;
  1081. old = cyber2000_grphr(FUNC_CTL, cfb);
  1082. cyber2000_grphw(FUNC_CTL, old & ~FUNC_CTL_EXTREGENBL, cfb);
  1083. }
  1084. cfb->func_use_count -= 1;
  1085. }
  1086. /*
  1087.  * This is the only "static" reference to the internal data structures
  1088.  * of this driver.  It is here solely at the moment to support the other
  1089.  * CyberPro modules external to this driver.
  1090.  */
  1091. static struct cfb_info *int_cfb_info;
  1092. /*
  1093.  * Attach a capture/tv driver to the core CyberX0X0 driver.
  1094.  */
  1095. int cyber2000fb_attach(struct cyberpro_info *info, int idx)
  1096. {
  1097. if (int_cfb_info != NULL) {
  1098. info->dev       = int_cfb_info->dev;
  1099. info->regs       = int_cfb_info->regs;
  1100. info->fb       = int_cfb_info->fb.screen_base;
  1101. info->fb_size       = int_cfb_info->fb.fix.smem_len;
  1102. info->enable_extregs  = cyber2000fb_enable_extregs;
  1103. info->disable_extregs = cyber2000fb_disable_extregs;
  1104. info->info            = int_cfb_info;
  1105. strncpy(info->dev_name, int_cfb_info->fb.fix.id, sizeof(info->dev_name));
  1106. MOD_INC_USE_COUNT;
  1107. }
  1108. return int_cfb_info != NULL;
  1109. }
  1110. /*
  1111.  * Detach a capture/tv driver from the core CyberX0X0 driver.
  1112.  */
  1113. void cyber2000fb_detach(int idx)
  1114. {
  1115. MOD_DEC_USE_COUNT;
  1116. }
  1117. EXPORT_SYMBOL(cyber2000fb_attach);
  1118. EXPORT_SYMBOL(cyber2000fb_detach);
  1119. /*
  1120.  * These parameters give
  1121.  * 640x480, hsync 31.5kHz, vsync 60Hz
  1122.  */
  1123. static struct fb_videomode __devinitdata cyber2000fb_default_mode = {
  1124. refresh: 60,
  1125. xres: 640,
  1126. yres: 480,
  1127. pixclock: 39722,
  1128. left_margin: 56,
  1129. right_margin: 16,
  1130. upper_margin: 34,
  1131. lower_margin: 9,
  1132. hsync_len: 88,
  1133. vsync_len: 2,
  1134. sync: FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
  1135. vmode: FB_VMODE_NONINTERLACED
  1136. };
  1137. static char igs_regs[] __devinitdata = {
  1138. 0x12, 0x00, 0x13, 0x00,
  1139. 0x16, 0x00,
  1140. 0x31, 0x00, 0x32, 0x00,
  1141. 0x50, 0x00, 0x51, 0x00, 0x52, 0x00, 0x53, 0x00,
  1142. 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x01,
  1143. 0x58, 0x00, 0x59, 0x00, 0x5a, 0x00,
  1144. 0x70, 0x0b, 0x73, 0x30,
  1145. 0x74, 0x0b, 0x75, 0x17, 0x76, 0x00, 0x7a, 0xc8
  1146. };
  1147. /*
  1148.  * We need to wake up the CyberPro, and make sure its in linear memory
  1149.  * mode.  Unfortunately, this is specific to the platform and card that
  1150.  * we are running on.
  1151.  *
  1152.  * On x86 and ARM, should we be initialising the CyberPro first via the
  1153.  * IO registers, and then the MMIO registers to catch all cases?  Can we
  1154.  * end up in the situation where the chip is in MMIO mode, but not awake
  1155.  * on an x86 system?
  1156.  *
  1157.  * Note that on the NetWinder, the firmware automatically detects the
  1158.  * type, width and size, and leaves this in extended registers 0x71 and
  1159.  * 0x72 for us.
  1160.  */
  1161. static inline void cyberpro_init_hw(struct cfb_info *cfb, int at_boot)
  1162. {
  1163. int i;
  1164. /*
  1165.  * Wake up the CyberPro.
  1166.  */
  1167. #ifdef __sparc__
  1168. #ifdef __sparc_v9__
  1169. #error "You loose, consult DaveM."
  1170. #else
  1171. /*
  1172.  * SPARC does not have an "outb" instruction, so we generate
  1173.  * I/O cycles storing into a reserved memory space at
  1174.  * physical address 0x3000000
  1175.  */
  1176. {
  1177. unsigned char *iop;
  1178. iop = ioremap(0x3000000, 0x5000);
  1179. if (iop == NULL) {
  1180. prom_printf("iga5000: cannot map I/On");
  1181. return -ENOMEM;
  1182. }
  1183. writeb(0x18, iop + 0x46e8);
  1184. writeb(0x01, iop + 0x102);
  1185. writeb(0x08, iop + 0x46e8);
  1186. writeb(0x33, iop + 0x3ce);
  1187. writeb(0x01, iop + 0x3cf);
  1188. iounmap((void *)iop);
  1189. }
  1190. #endif
  1191. if (at_boot) {
  1192. /*
  1193.  * Use mclk from BIOS.  Only read this if we're
  1194.  * initialising this card for the first time.
  1195.  * FIXME: what about hotplug?
  1196.  */
  1197. cfb->mclk_mult = cyber2000_grphr(MCLK_MULT, cfb);
  1198. cfb->mclk_div  = cyber2000_grphr(MCLK_DIV, cfb);
  1199. }
  1200. #endif
  1201. #if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
  1202. /*
  1203.  * x86 and MIPS are simple, we just do regular
  1204.  * outb's instead of cyber2000fb_writeb.
  1205.  */
  1206. outb(0x18, 0x46e8);
  1207. outb(0x01, 0x102);
  1208. outb(0x08, 0x46e8);
  1209. outb(0x33, 0x3ce);
  1210. outb(0x01, 0x3cf);
  1211. if (at_boot) {
  1212. /*
  1213.  * Use mclk from BIOS.  Only read this if we're
  1214.  * initialising this card for the first time.
  1215.  * FIXME: what about hotplug?
  1216.  */
  1217. cfb->mclk_mult = cyber2000_grphr(MCLK_MULT, cfb);
  1218. cfb->mclk_div  = cyber2000_grphr(MCLK_DIV, cfb);
  1219. }
  1220. #endif
  1221. #ifdef __arm__
  1222. cyber2000fb_writeb(0x18, 0x46e8, cfb);
  1223. cyber2000fb_writeb(0x01, 0x102, cfb);
  1224. cyber2000fb_writeb(0x08, 0x46e8, cfb);
  1225. cyber2000fb_writeb(0x33, 0x3ce, cfb);
  1226. cyber2000fb_writeb(0x01, 0x3cf, cfb);
  1227. /*
  1228.  * MCLK on the NetWinder and the Shark is fixed at 75MHz
  1229.  */
  1230. cfb->mclk_mult = 0xdb;
  1231. cfb->mclk_div  = 0x54;
  1232. #endif
  1233. /*
  1234.  * Initialise the CyberPro
  1235.  */
  1236. for (i = 0; i < sizeof(igs_regs); i += 2)
  1237. cyber2000_grphw(igs_regs[i], igs_regs[i+1], cfb);
  1238. if (at_boot) {
  1239. /*
  1240.  * get the video RAM size and width from the VGA register.
  1241.  * This should have been already initialised by the BIOS,
  1242.  * but if it's garbage, claim default 1MB VRAM (woody)
  1243.  */
  1244. cfb->mem_ctl1 = cyber2000_grphr(MEM_CTL1, cfb);
  1245. cfb->mem_ctl2 = cyber2000_grphr(MEM_CTL2, cfb);
  1246. } else {
  1247. /*
  1248.  * Reprogram the MEM_CTL1 and MEM_CTL2 registers
  1249.  */
  1250. cyber2000_grphw(MEM_CTL1, cfb->mem_ctl1, cfb);
  1251. cyber2000_grphw(MEM_CTL2, cfb->mem_ctl2, cfb);
  1252. }
  1253. /*
  1254.  * Ensure thatwe are using the correct PLL.
  1255.  * (CyberPro 5000's may be programmed to use
  1256.  * an additional set of PLLs.
  1257.  */
  1258. cyber2000fb_writeb(0xba, 0x3ce, cfb);
  1259. cyber2000fb_writeb(cyber2000fb_readb(0x3cf, cfb) & 0x80, 0x3cf, cfb);
  1260. }
  1261. static struct cfb_info * __devinit
  1262. cyberpro_alloc_fb_info(struct pci_dev *dev, const struct pci_device_id *id, char *name)
  1263. {
  1264. struct cfb_info *cfb;
  1265. cfb = kmalloc(sizeof(struct cfb_info) + sizeof(struct display) +
  1266.        sizeof(u32) * 16, GFP_KERNEL);
  1267. if (!cfb)
  1268. return NULL;
  1269. memset(cfb, 0, sizeof(struct cfb_info) + sizeof(struct display));
  1270. cfb->currcon = -1;
  1271. cfb->dev = dev;
  1272. if (id->driver_data == FB_ACCEL_IGS_CYBER5000)
  1273. cfb->ref_ps = 40690; // 24.576 MHz
  1274. else
  1275. cfb->ref_ps = 69842; // 14.31818 MHz (69841?)
  1276. cfb->divisors[0] = 1;
  1277. cfb->divisors[1] = 2;
  1278. cfb->divisors[2] = 4;
  1279. if (id->driver_data == FB_ACCEL_IGS_CYBER2000)
  1280. cfb->divisors[3] = 8;
  1281. else
  1282. cfb->divisors[3] = 6;
  1283. strcpy(cfb->fb.fix.id, name);
  1284. cfb->fb.fix.type = FB_TYPE_PACKED_PIXELS;
  1285. cfb->fb.fix.type_aux = 0;
  1286. cfb->fb.fix.xpanstep = 0;
  1287. cfb->fb.fix.ypanstep = 1;
  1288. cfb->fb.fix.ywrapstep = 0;
  1289. cfb->fb.fix.accel = id->driver_data;
  1290. cfb->fb.var.nonstd = 0;
  1291. cfb->fb.var.activate = FB_ACTIVATE_NOW;
  1292. cfb->fb.var.height = -1;
  1293. cfb->fb.var.width = -1;
  1294. cfb->fb.var.accel_flags = FB_ACCELF_TEXT;
  1295. strcpy(cfb->fb.modename, cfb->fb.fix.id);
  1296. strcpy(cfb->fb.fontname, default_font);
  1297. cfb->fb.fbops = &cyber2000fb_ops;
  1298. cfb->fb.changevar = NULL;
  1299. cfb->fb.switch_con = cyber2000fb_switch;
  1300. cfb->fb.updatevar = cyber2000fb_updatevar;
  1301. cfb->fb.blank = cyber2000fb_blank;
  1302. cfb->fb.flags = FBINFO_FLAG_DEFAULT;
  1303. cfb->fb.disp = (struct display *)(cfb + 1);
  1304. cfb->fb.pseudo_palette = (void *)(cfb->fb.disp + 1);
  1305. fb_alloc_cmap(&cfb->fb.cmap, NR_PALETTE, 0);
  1306. return cfb;
  1307. }
  1308. static void __devinit
  1309. cyberpro_free_fb_info(struct cfb_info *cfb)
  1310. {
  1311. if (cfb) {
  1312. /*
  1313.  * Free the colourmap
  1314.  */
  1315. fb_alloc_cmap(&cfb->fb.cmap, 0, 0);
  1316. kfree(cfb);
  1317. }
  1318. }
  1319. /*
  1320.  * Parse Cyber2000fb options.  Usage:
  1321.  *  video=cyber2000:font:fontname
  1322.  */
  1323. int
  1324. cyber2000fb_setup(char *options)
  1325. {
  1326. char *opt;
  1327. if (!options || !*options)
  1328. return 0;
  1329. while ((opt = strsep(&options, ",")) != NULL) {
  1330. if (!*opt)
  1331. continue;
  1332. if (strncmp(opt, "font:", 5) == 0) {
  1333. strncpy(default_font_storage, opt + 5, sizeof(default_font_storage));
  1334. default_font = default_font_storage;
  1335. continue;
  1336. }
  1337. printk(KERN_ERR "CyberPro20x0: unknown parameter: %sn", opt);
  1338. }
  1339. return 0;
  1340. }
  1341. static int __devinit
  1342. cyberpro_probe(struct pci_dev *dev, const struct pci_device_id *id)
  1343. {
  1344. struct cfb_info *cfb;
  1345. u_int h_sync, v_sync;
  1346. u_long smem_size;
  1347. char name[16];
  1348. int err;
  1349. sprintf(name, "CyberPro%4X", id->device);
  1350. err = pci_enable_device(dev);
  1351. if (err)
  1352. return err;
  1353. err = pci_request_regions(dev, name);
  1354. if (err)
  1355. return err;
  1356. err = -ENOMEM;
  1357. cfb = cyberpro_alloc_fb_info(dev, id, name);
  1358. if (!cfb)
  1359. goto failed_release;
  1360. cfb->region = ioremap(pci_resource_start(dev, 0),
  1361.       pci_resource_len(dev, 0));
  1362. if (!cfb->region)
  1363. goto failed_ioremap;
  1364. cfb->regs = cfb->region + MMIO_OFFSET;
  1365. cyberpro_init_hw(cfb, 1);
  1366. switch (cfb->mem_ctl2 & MEM_CTL2_SIZE_MASK) {
  1367. case MEM_CTL2_SIZE_4MB: smem_size = 0x00400000; break;
  1368. case MEM_CTL2_SIZE_2MB: smem_size = 0x00200000; break;
  1369. default: smem_size = 0x00100000; break;
  1370. }
  1371. /*
  1372.  * Hmm, we _need_ a portable way of finding the address for
  1373.  * the remap stuff, both for mmio and for smem.
  1374.  */
  1375. cfb->fb.fix.mmio_start = pci_resource_start(dev, 0) + MMIO_OFFSET;
  1376. cfb->fb.fix.smem_start = pci_resource_start(dev, 0);
  1377. cfb->fb.fix.mmio_len   = MMIO_SIZE;
  1378. cfb->fb.fix.smem_len   = smem_size;
  1379. cfb->fb.screen_base    = cfb->region;
  1380. if (!fb_find_mode(&cfb->fb.var, &cfb->fb, NULL, NULL, 0,
  1381.        &cyber2000fb_default_mode, 8)) {
  1382. printk("%s: no valid mode foundn", cfb->fb.fix.id);
  1383. goto failed;
  1384. }
  1385. cfb->fb.var.yres_virtual = cfb->fb.fix.smem_len * 8 /
  1386. (cfb->fb.var.bits_per_pixel * cfb->fb.var.xres_virtual);
  1387. if (cfb->fb.var.yres_virtual < cfb->fb.var.yres)
  1388. cfb->fb.var.yres_virtual = cfb->fb.var.yres;
  1389. cyber2000fb_set_var(&cfb->fb.var, -1, &cfb->fb);
  1390. /*
  1391.  * Calculate the hsync and vsync frequencies.  Note that
  1392.  * we split the 1e12 constant up so that we can preserve
  1393.  * the precision and fit the results into 32-bit registers.
  1394.  *  (1953125000 * 512 = 1e12)
  1395.  */
  1396. h_sync = 1953125000 / cfb->fb.var.pixclock;
  1397. h_sync = h_sync * 512 / (cfb->fb.var.xres + cfb->fb.var.left_margin +
  1398.  cfb->fb.var.right_margin + cfb->fb.var.hsync_len);
  1399. v_sync = h_sync / (cfb->fb.var.yres + cfb->fb.var.upper_margin +
  1400.  cfb->fb.var.lower_margin + cfb->fb.var.vsync_len);
  1401. printk(KERN_INFO "%s: %dkB VRAM, using %dx%d, %d.%03dkHz, %dHzn",
  1402. cfb->fb.fix.id, cfb->fb.fix.smem_len >> 10,
  1403. cfb->fb.var.xres, cfb->fb.var.yres,
  1404. h_sync / 1000, h_sync % 1000, v_sync);
  1405. err = register_framebuffer(&cfb->fb);
  1406. if (err < 0)
  1407. goto failed;
  1408. /*
  1409.  * Our driver data
  1410.  */
  1411. pci_set_drvdata(dev, cfb);
  1412. if (int_cfb_info == NULL)
  1413. int_cfb_info = cfb;
  1414. return 0;
  1415. failed:
  1416. iounmap(cfb->region);
  1417. failed_ioremap:
  1418. cyberpro_free_fb_info(cfb);
  1419. failed_release:
  1420. pci_release_regions(dev);
  1421. return err;
  1422. }
  1423. static void __devexit cyberpro_remove(struct pci_dev *dev)
  1424. {
  1425. struct cfb_info *cfb = pci_get_drvdata(dev);
  1426. if (cfb) {
  1427. /*
  1428.  * If unregister_framebuffer fails, then
  1429.  * we will be leaving hooks that could cause
  1430.  * oopsen laying around.
  1431.  */
  1432. if (unregister_framebuffer(&cfb->fb))
  1433. printk(KERN_WARNING "%s: danger Will Robinson, "
  1434. "danger danger!  Oopsen imminent!n",
  1435. cfb->fb.fix.id);
  1436. iounmap(cfb->region);
  1437. cyberpro_free_fb_info(cfb);
  1438. /*
  1439.  * Ensure that the driver data is no longer
  1440.  * valid.
  1441.  */
  1442. pci_set_drvdata(dev, NULL);
  1443. if (cfb == int_cfb_info)
  1444. int_cfb_info = NULL;
  1445. pci_release_regions(dev);
  1446. }
  1447. }
  1448. static int cyberpro_suspend(struct pci_dev *dev, u32 state)
  1449. {
  1450. return 0;
  1451. }
  1452. /*
  1453.  * Re-initialise the CyberPro hardware
  1454.  */
  1455. static int cyberpro_resume(struct pci_dev *dev)
  1456. {
  1457. struct cfb_info *cfb = pci_get_drvdata(dev);
  1458. if (cfb) {
  1459. cyberpro_init_hw(cfb, 0);
  1460. /*
  1461.  * Restore the old video mode and the palette.
  1462.  * We also need to tell fbcon to redraw the console.
  1463.  */
  1464. cfb->fb.var.activate = FB_ACTIVATE_NOW;
  1465. cyber2000fb_set_var(&cfb->fb.var, -1, &cfb->fb);
  1466. }
  1467. return 0;
  1468. }
  1469. static struct pci_device_id cyberpro_pci_table[] __devinitdata = {
  1470. { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2000,
  1471. PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_IGS_CYBER2000 },
  1472. { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2010,
  1473. PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_IGS_CYBER2010 },
  1474. { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_5000,
  1475. PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_IGS_CYBER5000 },
  1476. { 0, }
  1477. };
  1478. static struct pci_driver cyberpro_driver = {
  1479. name: "CyberPro",
  1480. probe: cyberpro_probe,
  1481. remove: __devexit_p(cyberpro_remove),
  1482. suspend: cyberpro_suspend,
  1483. resume: cyberpro_resume,
  1484. id_table: cyberpro_pci_table
  1485. };
  1486. /*
  1487.  * I don't think we can use the "module_init" stuff here because
  1488.  * the fbcon stuff may not be initialised yet.  Hence the #ifdef
  1489.  * around module_init.
  1490.  */
  1491. int __init cyber2000fb_init(void)
  1492. {
  1493. return pci_module_init(&cyberpro_driver);
  1494. }
  1495. static void __exit cyberpro_exit(void)
  1496. {
  1497. pci_unregister_driver(&cyberpro_driver);
  1498. }
  1499. #ifdef MODULE
  1500. module_init(cyber2000fb_init);
  1501. #endif
  1502. module_exit(cyberpro_exit);
  1503. MODULE_AUTHOR("Russell King");
  1504. MODULE_DESCRIPTION("CyberPro 2000, 2010 and 5000 framebuffer driver");
  1505. MODULE_DEVICE_TABLE(pci,cyberpro_pci_table);
  1506. MODULE_LICENSE("GPL");