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

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * Permedia2 framebuffer driver.
  3.  * Copyright (c) 1998-1999 Ilario Nardinocchi (nardinoc@CS.UniBO.IT)
  4.  * Copyright (c) 1999 Jakub Jelinek (jakub@redhat.com)
  5.  * Based on linux/drivers/video/skeletonfb.c by Geert Uytterhoeven.
  6.  * --------------------------------------------------------------------------
  7.  * $Id: pm2fb.c,v 1.163 1999/02/21 14:06:49 illo Exp $
  8.  * --------------------------------------------------------------------------
  9.  * TODO multiple boards support
  10.  * --------------------------------------------------------------------------
  11.  * This file is subject to the terms and conditions of the GNU General Public
  12.  * License.  See the file COPYING in the main directory of this archive
  13.  * for more details.
  14.  */
  15. #include <linux/config.h>
  16. #include <linux/module.h>
  17. #include <linux/kernel.h>
  18. #include <linux/errno.h>
  19. #include <linux/string.h>
  20. #include <linux/mm.h>
  21. #include <linux/tty.h>
  22. #include <linux/slab.h>
  23. #include <linux/vmalloc.h>
  24. #include <linux/delay.h>
  25. #include <linux/interrupt.h>
  26. #include <linux/fb.h>
  27. #include <linux/selection.h>
  28. #include <linux/console.h>
  29. #include <linux/init.h>
  30. #include <linux/pci.h>
  31. #include <asm/system.h>
  32. #include <asm/io.h>
  33. #include <asm/uaccess.h>
  34. #include <video/fbcon.h>
  35. #include <video/fbcon-cfb8.h>
  36. #include <video/fbcon-cfb16.h>
  37. #include <video/fbcon-cfb24.h>
  38. #include <video/fbcon-cfb32.h>
  39. #include "pm2fb.h"
  40. #include "cvisionppc.h"
  41. #ifdef __sparc__
  42. #include <asm/pbm.h>
  43. #include <asm/fbio.h>
  44. #endif
  45. #if !defined(__LITTLE_ENDIAN) && !defined(__BIG_ENDIAN)
  46. #error "The endianness of the target host has not been defined."
  47. #endif
  48. #if defined(__BIG_ENDIAN) && !defined(__sparc__)
  49. #define PM2FB_BE_APERTURE
  50. #endif
  51. /* Need to debug this some more */
  52. #undef PM2FB_HW_CURSOR
  53. #if defined(CONFIG_FB_PM2_PCI) && !defined(CONFIG_PCI)
  54. #undef CONFIG_FB_PM2_PCI
  55. #warning "support for Permedia2 PCI boards with no generic PCI support!"
  56. #endif
  57. #undef PM2FB_MASTER_DEBUG
  58. #ifdef PM2FB_MASTER_DEBUG
  59. #define DPRINTK(a,b...) printk(KERN_DEBUG "pm2fb: %s: " a, __FUNCTION__ , ## b)
  60. #else
  61. #define DPRINTK(a,b...)
  62. #endif 
  63. #define PICOS2KHZ(a) (1000000000UL/(a))
  64. #define KHZ2PICOS(a) (1000000000UL/(a))
  65. /*
  66.  * The _DEFINITIVE_ memory mapping/unmapping functions.
  67.  * This is due to the fact that they're changing soooo often...
  68.  */
  69. #define MMAP(a,b) ioremap((unsigned long )(a), b)
  70. #define UNMAP(a,b) iounmap(a)
  71. /*
  72.  * The _DEFINITIVE_ memory i/o barrier functions.
  73.  * This is due to the fact that they're changing soooo often...
  74.  */
  75. #define DEFW() wmb()
  76. #define DEFR() rmb()
  77. #define DEFRW() mb()
  78. #ifndef MIN
  79. #define MIN(a,b) ((a)<(b)?(a):(b))
  80. #endif
  81. #ifndef MAX
  82. #define MAX(a,b) ((a)>(b)?(a):(b))
  83. #endif
  84. struct pm2fb_par {
  85. u32 pixclock; /* pixclock in KHz */
  86. u32 width; /* width of virtual screen */
  87. u32 height; /* height of virtual screen */
  88. u32 hsstart; /* horiz. sync start */
  89. u32 hsend; /* horiz. sync end */
  90. u32 hbend; /* horiz. blank end (also gate end) */
  91. u32 htotal; /* total width (w/ sync & blank) */
  92. u32 vsstart; /* vert. sync start */
  93. u32 vsend; /* vert. sync end */
  94. u32 vbend; /* vert. blank end */
  95. u32 vtotal; /* total height (w/ sync & blank) */
  96. u32 stride; /* screen stride */
  97. u32 base; /* screen base (xoffset+yoffset) */
  98. u32 depth; /* screen depth (8, 16, 24 or 32) */
  99. u32 video; /* video control (hsync,vsync) */
  100. };
  101. #define OPTF_OLD_MEM (1L<<0)
  102. #define OPTF_YPAN (1L<<1)
  103. #define OPTF_VIRTUAL (1L<<2)
  104. #define OPTF_USER (1L<<3)
  105. static struct {
  106. char font[40];
  107. u32 flags;
  108. struct pm2fb_par user_mode;
  109. } pm2fb_options =
  110. #ifdef __sparc__
  111. /* For some reason Raptor is not happy with the low-end mode */
  112. {"", 0L, {31499,640,480,4,20,50,209,0,3,20,499,80,0,8,121}};
  113. #else
  114. {"", 0L, {25174,640,480,4,28,40,199,9,11,45,524,80,0,8,121}};
  115. #endif
  116. static char curblink __initdata = 1;
  117. static const struct {
  118. char name[16];
  119. struct pm2fb_par par;
  120. } user_mode[] __initdata = {
  121. {"640x480-60",
  122. {25174,640,480,4,28,40,199,9,11,45,524,80,0,8,121}},
  123. {"640x480-72",
  124. {31199,640,480,6,16,48,207,8,10,39,518,80,0,8,121}},
  125. {"640x480-75",
  126. {31499,640,480,4,20,50,209,0,3,20,499,80,0,8,121}},
  127. {"640x480-90",
  128. {39909,640,480,8,18,48,207,24,38,53,532,80,0,8,121}},
  129. {"640x480-100",
  130. {44899,640,480,8,40,52,211,21,33,51,530,80,0,8,121}},
  131. {"800x600-56",
  132. {35999,800,600,6,24,56,255,0,2,25,624,100,0,8,41}},
  133. {"800x600-60",
  134. {40000,800,600,10,42,64,263,0,4,28,627,100,0,8,41}},
  135. {"800x600-70",
  136. {44899,800,600,6,42,52,251,8,20,36,635,100,0,8,105}},
  137. {"800x600-72",
  138. {50000,800,600,14,44,60,259,36,42,66,665,100,0,8,41}},
  139. {"800x600-75",
  140. {49497,800,600,4,24,64,263,0,3,25,624,100,0,8,41}},
  141. {"800x600-90",
  142. {56637,800,600,2,18,48,247,7,18,35,634,100,0,8,41}},
  143. {"800x600-100",
  144. {67499,800,600,0,16,70,269,6,10,25,624,100,0,8,41}},
  145. {"1024x768-60",
  146. {64998,1024,768,6,40,80,335,2,8,38,805,128,0,8,121}},
  147. {"1024x768-70",
  148. {74996,1024,768,6,40,76,331,2,8,38,805,128,0,8,121}},
  149. {"1024x768-72",
  150. {74996,1024,768,6,40,66,321,2,8,38,805,128,0,8,121}},
  151. {"1024x768-75",
  152. {78932,1024,768,4,28,72,327,0,3,32,799,128,0,8,41}},
  153. {"1024x768-90",
  154. {100000,1024,768,0,24,72,327,20,35,77,844,128,0,8,121}},
  155. {"1024x768-100",
  156. {109998,1024,768,0,22,92,347,0,7,24,791,128,0,8,121}},
  157. {"1024x768-illo",
  158. {120322,1024,768,12,48,120,375,3,7,32,799,128,0,8,41}},
  159. {"1152x864-60",
  160. {80000,1152,864,16,44,76,363,5,10,52,915,144,0,8,41}},
  161. {"1152x864-70",
  162. {100000,1152,864,10,48,90,377,12,23,81,944,144,0,8,41}},
  163. {"1152x864-75",
  164. {109998,1152,864,6,42,78,365,44,52,138,1001,144,0,8,41}},
  165. {"1152x864-80",
  166. {109998,1152,864,4,32,72,359,29,36,94,957,144,0,8,41}},
  167. {"1280x1024-60",
  168. {107991,1280,1024,12,40,102,421,0,3,42,1065,160,0,8,41}},
  169. {"1280x1024-70",
  170. {125992,1280,1024,20,48,102,421,0,5,42,1065,160,0,8,41}},
  171. {"1280x1024-74",
  172. {134989,1280,1024,8,44,108,427,0,29,40,1063,160,0,8,41}},
  173. {"1280x1024-75",
  174. {134989,1280,1024,4,40,102,421,0,3,42,1065,160,0,8,41}},
  175. {"1600x1200-60",
  176. {155981,1600,1200,8,48,112,511,9,17,70,1269,200,0,8,121}},
  177. {"1600x1200-66",
  178. {171998,1600,1200,10,44,120,519,2,5,53,1252,200,0,8,121}},
  179. {"1600x1200-76",
  180. {197980,1600,1200,10,44,120,519,2,7,50,1249,200,0,8,121}},
  181. {"", },
  182. };
  183. #ifdef CONFIG_FB_PM2_PCI
  184. struct pm2pci_par {
  185. u32 mem_config;
  186. u32 mem_control;
  187. u32 boot_address;
  188. struct pci_dev* dev;
  189. };
  190. #endif
  191. #define DEFAULT_CURSOR_BLINK_RATE       (20)
  192. #define CURSOR_DRAW_DELAY               (2)
  193. struct pm2_cursor {
  194.     int enable;
  195.     int on;
  196.     int vbl_cnt;
  197.     int blink_rate;
  198.     struct {
  199.         u16 x, y;
  200.     } pos, hot, size;
  201.     u8 color[6];
  202.     u8 bits[8][64];
  203.     u8 mask[8][64];
  204.     struct timer_list *timer;
  205. };
  206. static const char permedia2_name[16]="Permedia2";
  207. static struct pm2fb_info {
  208. struct fb_info_gen gen;
  209. int board; /* Permedia2 board index (see
  210.    board_table[] below) */
  211. pm2type_t type;
  212. struct {
  213. unsigned long  fb_base; /* physical framebuffer memory base */
  214. u32 fb_size; /* framebuffer memory size */
  215. unsigned long  rg_base; /* physical register memory base */
  216. unsigned long  p_fb; /* physical address of frame buffer */
  217. unsigned char* v_fb; /* virtual address of frame buffer */
  218. unsigned long  p_regs; /* physical address of registers
  219.    region, must be rg_base or
  220.    rg_base+PM2_REGS_SIZE depending on
  221.    the host endianness */
  222. unsigned char* v_regs; /* virtual address of p_regs */
  223. } regions;
  224. union { /* here, the per-board par structs */
  225. #ifdef CONFIG_FB_PM2_CVPPC
  226. struct cvppc_par cvppc; /* CVisionPPC data */
  227. #endif
  228. #ifdef CONFIG_FB_PM2_PCI
  229. struct pm2pci_par pci; /* Permedia2 PCI boards data */
  230. #endif
  231. } board_par;
  232. struct pm2fb_par current_par; /* displayed screen */
  233. int current_par_valid;
  234. u32 memclock; /* memclock (set by the per-board
  235.     init routine) */
  236. struct display disp;
  237. struct {
  238. u8 transp;
  239. u8 red;
  240. u8 green;
  241. u8 blue;
  242. } palette[256];
  243. union {
  244. #ifdef FBCON_HAS_CFB16
  245. u16 cmap16[16];
  246. #endif
  247. #ifdef FBCON_HAS_CFB24
  248. u32 cmap24[16];
  249. #endif
  250. #ifdef FBCON_HAS_CFB32
  251. u32 cmap32[16];
  252. #endif
  253. } cmap;
  254. struct pm2_cursor *cursor;
  255. } fb_info;
  256. #ifdef CONFIG_FB_PM2_CVPPC
  257. static int cvppc_detect(struct pm2fb_info*);
  258. static void cvppc_init(struct pm2fb_info*);
  259. #endif
  260. #ifdef CONFIG_FB_PM2_PCI
  261. static int pm2pci_detect(struct pm2fb_info*);
  262. static void pm2pci_init(struct pm2fb_info*);
  263. #endif
  264. #ifdef PM2FB_HW_CURSOR
  265. static void pm2fb_cursor(struct display *p, int mode, int x, int y);
  266. static int pm2fb_set_font(struct display *d, int width, int height);
  267. static struct pm2_cursor *pm2_init_cursor(struct pm2fb_info *fb);
  268. static void pm2v_set_cursor_color(struct pm2fb_info *fb, u8 *red, u8 *green, u8 *blue);
  269. static void pm2v_set_cursor_shape(struct pm2fb_info *fb);
  270. static u8 cursor_color_map[2] = { 0, 0xff };
  271. #else
  272. #define pm2fb_cursor NULL
  273. #define pm2fb_set_font NULL
  274. #endif
  275. /*
  276.  * Table of the supported Permedia2 based boards.
  277.  * Three hooks are defined for each board:
  278.  * detect(): should return 1 if the related board has been detected, 0
  279.  *           otherwise. It should also fill the fields 'regions.fb_base',
  280.  *           'regions.fb_size', 'regions.rg_base' and 'memclock' in the
  281.  *           passed pm2fb_info structure.
  282.  * init(): called immediately after the reset of the Permedia2 chip.
  283.  *         It should reset the memory controller if needed (the MClk
  284.  *         is set shortly afterwards by the caller).
  285.  * cleanup(): called after the driver has been unregistered.
  286.  *
  287.  * the init and cleanup pointers can be NULL.
  288.  */
  289. static const struct {
  290. int (*detect)(struct pm2fb_info*);
  291. void (*init)(struct pm2fb_info*);
  292. void (*cleanup)(struct pm2fb_info*);
  293. char name[32];
  294. } board_table[] = {
  295. #ifdef CONFIG_FB_PM2_PCI
  296. { pm2pci_detect, pm2pci_init, NULL, "Permedia2 PCI board" },
  297. #endif
  298. #ifdef CONFIG_FB_PM2_CVPPC
  299. { cvppc_detect, cvppc_init, NULL, "CVisionPPC/BVisionPPC" },
  300. #endif
  301. { NULL, }
  302. };
  303. /*
  304.  * partial products for the supported horizontal resolutions.
  305.  */
  306. #define PACKPP(p0,p1,p2) (((p2)<<6)|((p1)<<3)|(p0))
  307. static const struct {
  308. u16 width;
  309. u16 pp;
  310. } pp_table[] = {
  311. { 32, PACKPP(1, 0, 0) }, { 64, PACKPP(1, 1, 0) },
  312. { 96, PACKPP(1, 1, 1) }, { 128, PACKPP(2, 1, 1) },
  313. { 160, PACKPP(2, 2, 1) }, { 192, PACKPP(2, 2, 2) },
  314. { 224, PACKPP(3, 2, 1) }, { 256, PACKPP(3, 2, 2) },
  315. { 288, PACKPP(3, 3, 1) }, { 320, PACKPP(3, 3, 2) },
  316. { 384, PACKPP(3, 3, 3) }, { 416, PACKPP(4, 3, 1) },
  317. { 448, PACKPP(4, 3, 2) }, { 512, PACKPP(4, 3, 3) },
  318. { 544, PACKPP(4, 4, 1) }, { 576, PACKPP(4, 4, 2) },
  319. { 640, PACKPP(4, 4, 3) }, { 768, PACKPP(4, 4, 4) },
  320. { 800, PACKPP(5, 4, 1) }, { 832, PACKPP(5, 4, 2) },
  321. { 896, PACKPP(5, 4, 3) }, { 1024, PACKPP(5, 4, 4) },
  322. { 1056, PACKPP(5, 5, 1) }, { 1088, PACKPP(5, 5, 2) },
  323. { 1152, PACKPP(5, 5, 3) }, { 1280, PACKPP(5, 5, 4) },
  324. { 1536, PACKPP(5, 5, 5) }, { 1568, PACKPP(6, 5, 1) },
  325. { 1600, PACKPP(6, 5, 2) }, { 1664, PACKPP(6, 5, 3) },
  326. { 1792, PACKPP(6, 5, 4) }, { 2048, PACKPP(6, 5, 5) },
  327. { 0, 0 } };
  328. static void pm2fb_detect(void);
  329. static int pm2fb_encode_fix(struct fb_fix_screeninfo* fix,
  330. const void* par, struct fb_info_gen* info);
  331. static int pm2fb_decode_var(const struct fb_var_screeninfo* var,
  332. void* par, struct fb_info_gen* info);
  333. static int pm2fb_encode_var(struct fb_var_screeninfo* var,
  334. const void* par, struct fb_info_gen* info);
  335. static void pm2fb_get_par(void* par, struct fb_info_gen* info);
  336. static void pm2fb_set_par(const void* par, struct fb_info_gen* info);
  337. static int pm2fb_getcolreg(unsigned regno,
  338. unsigned* red, unsigned* green, unsigned* blue,
  339. unsigned* transp, struct fb_info* info);
  340. static int pm2fb_setcolreg(unsigned regno,
  341. unsigned red, unsigned green, unsigned blue,
  342. unsigned transp, struct fb_info* info);
  343. static int pm2fb_blank(int blank_mode, struct fb_info_gen* info);
  344. static int pm2fb_pan_display(const struct fb_var_screeninfo* var,
  345. struct fb_info_gen* info);
  346. static void pm2fb_set_disp(const void* par, struct display* disp,
  347. struct fb_info_gen* info);
  348. static struct fbgen_hwswitch pm2fb_hwswitch={
  349. pm2fb_detect, pm2fb_encode_fix, pm2fb_decode_var,
  350. pm2fb_encode_var, pm2fb_get_par, pm2fb_set_par,
  351. pm2fb_getcolreg, pm2fb_setcolreg, pm2fb_pan_display,
  352. pm2fb_blank, pm2fb_set_disp
  353. };
  354. static struct fb_ops pm2fb_ops={
  355. owner: THIS_MODULE,
  356. fb_get_fix: fbgen_get_fix,
  357. fb_get_var: fbgen_get_var,
  358. fb_set_var: fbgen_set_var,
  359. fb_get_cmap: fbgen_get_cmap,
  360. fb_set_cmap: fbgen_set_cmap,
  361. fb_pan_display: fbgen_pan_display,
  362. };
  363. /***************************************************************************
  364.  * Begin of Permedia2 specific functions
  365.  ***************************************************************************/
  366. inline static u32 RD32(unsigned char* base, s32 off) {
  367. return readl(base+off);
  368. }
  369. inline static void WR32(unsigned char* base, s32 off, u32 v) {
  370. writel(v, base+off);
  371. }
  372. inline static u32 pm2_RD(struct pm2fb_info* p, s32 off) {
  373. return RD32(p->regions.v_regs, off);
  374. }
  375. inline static void pm2_WR(struct pm2fb_info* p, s32 off, u32 v) {
  376. WR32(p->regions.v_regs, off, v);
  377. }
  378. inline static u32 pm2_RDAC_RD(struct pm2fb_info* p, s32 idx) {
  379. int index = PM2R_RD_INDEXED_DATA;
  380. switch (p->type) {
  381. case PM2_TYPE_PERMEDIA2:
  382. pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx);
  383. break;
  384. case PM2_TYPE_PERMEDIA2V:
  385. pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);
  386. index = PM2VR_RD_INDEXED_DATA;
  387. break;
  388. }
  389. DEFRW();
  390. return pm2_RD(p, index);
  391. }
  392. inline static void pm2_RDAC_WR(struct pm2fb_info* p, s32 idx,
  393. u32 v) {
  394. int index = PM2R_RD_INDEXED_DATA;
  395. switch (p->type) {
  396. case PM2_TYPE_PERMEDIA2:
  397. pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx);
  398. break;
  399. case PM2_TYPE_PERMEDIA2V:
  400. pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);
  401. index = PM2VR_RD_INDEXED_DATA;
  402. break;
  403. }
  404. DEFRW();
  405. pm2_WR(p, index, v);
  406. }
  407. inline static u32 pm2v_RDAC_RD(struct pm2fb_info* p, s32 idx) {
  408. pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);
  409. DEFRW();
  410. return pm2_RD(p, PM2VR_RD_INDEXED_DATA);
  411. }
  412. inline static void pm2v_RDAC_WR(struct pm2fb_info* p, s32 idx,
  413. u32 v) {
  414. pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);
  415. DEFRW();
  416. pm2_WR(p, PM2VR_RD_INDEXED_DATA, v);
  417. }
  418. #ifdef CONFIG_FB_PM2_FIFO_DISCONNECT
  419. #define WAIT_FIFO(p,a)
  420. #else
  421. inline static void WAIT_FIFO(struct pm2fb_info* p, u32 a) {
  422. while(pm2_RD(p, PM2R_IN_FIFO_SPACE)<a);
  423. DEFRW();
  424. }
  425. #endif
  426. static u32 partprod(u32 xres) {
  427. int i;
  428. for (i=0; pp_table[i].width && pp_table[i].width!=xres; i++);
  429. if (!pp_table[i].width)
  430. DPRINTK("invalid width %un", xres);
  431. return pp_table[i].pp;
  432. }
  433. static u32 to3264(u32 timing, int bpp, int is64) {
  434. switch (bpp) {
  435. case 8:
  436. timing=timing>>(2+is64);
  437. break;
  438. case 16:
  439. timing=timing>>(1+is64);
  440. break;
  441. case 24:
  442. timing=(timing*3)>>(2+is64);
  443. break;
  444. case 32:
  445. if (is64)
  446. timing=timing>>1;
  447. break;
  448. }
  449. return timing;
  450. }
  451. static u32 from3264(u32 timing, int bpp, int is64) {
  452. switch (bpp) {
  453. case 8:
  454. timing=timing<<(2+is64);
  455. break;
  456. case 16:
  457. timing=timing<<(1+is64);
  458. break;
  459. case 24:
  460. timing=(timing<<(2+is64))/3;
  461. break;
  462. case 32:
  463. if (is64)
  464. timing=timing<<1;
  465. break;
  466. }
  467. return timing;
  468. }
  469. static void pm2_mnp(u32 clk, unsigned char* mm, unsigned char* nn,
  470. unsigned char* pp) {
  471. unsigned char m;
  472. unsigned char n;
  473. unsigned char p;
  474. u32 f;
  475. s32 curr;
  476. s32 delta=100000;
  477. *mm=*nn=*pp=0;
  478. for (n=2; n<15; n++) {
  479. for (m=2; m; m++) {
  480. f=PM2_REFERENCE_CLOCK*m/n;
  481. if (f>=150000 && f<=300000) {
  482. for (p=0; p<5; p++, f>>=1) {
  483. curr=clk>f?clk-f:f-clk;
  484. if (curr<delta) {
  485. delta=curr;
  486. *mm=m;
  487. *nn=n;
  488. *pp=p;
  489. }
  490. }
  491. }
  492. }
  493. }
  494. }
  495. static void pm2v_mnp(u32 clk, unsigned char* mm, unsigned char* nn,
  496. unsigned char* pp) {
  497. unsigned char m;
  498. unsigned char n;
  499. unsigned char p;
  500. u32 f;
  501. s32 delta=1000;
  502. *mm=*nn=*pp=0;
  503. for (n=1; n; n++) {
  504. for (m=1; m; m++) {
  505. for (p=0; p<2; p++) {
  506. f=PM2_REFERENCE_CLOCK*n/(m * (1<<(p+1)));
  507. if (clk>f-delta && clk<f+delta) {
  508. delta=clk>f?clk-f:f-clk;
  509. *mm=m;
  510. *nn=n;
  511. *pp=p;
  512. }
  513. }
  514. }
  515. }
  516. }
  517. static void wait_pm2(struct pm2fb_info* i) {
  518. WAIT_FIFO(i, 1);
  519. pm2_WR(i, PM2R_SYNC, 0);
  520. DEFRW();
  521. do {
  522. while (pm2_RD(i, PM2R_OUT_FIFO_WORDS)==0);
  523. DEFR();
  524. } while (pm2_RD(i, PM2R_OUT_FIFO)!=PM2TAG(PM2R_SYNC));
  525. }
  526. static void pm2_set_memclock(struct pm2fb_info* info, u32 clk) {
  527. int i;
  528. unsigned char m, n, p;
  529. pm2_mnp(clk, &m, &n, &p);
  530. WAIT_FIFO(info, 10);
  531. pm2_RDAC_WR(info, PM2I_RD_MEMORY_CLOCK_3, 6);
  532. DEFW();
  533. pm2_RDAC_WR(info, PM2I_RD_MEMORY_CLOCK_1, m);
  534. pm2_RDAC_WR(info, PM2I_RD_MEMORY_CLOCK_2, n);
  535. DEFW();
  536. pm2_RDAC_WR(info, PM2I_RD_MEMORY_CLOCK_3, 8|p);
  537. DEFW();
  538. pm2_RDAC_RD(info, PM2I_RD_MEMORY_CLOCK_STATUS);
  539. DEFR();
  540. for (i=256; i &&
  541. !(pm2_RD(info, PM2R_RD_INDEXED_DATA)&PM2F_PLL_LOCKED); i--);
  542. }
  543. static void pm2_set_pixclock(struct pm2fb_info* info, u32 clk) {
  544. int i;
  545. unsigned char m, n, p;
  546. switch (info->type) {
  547. case PM2_TYPE_PERMEDIA2:
  548. pm2_mnp(clk, &m, &n, &p);
  549. WAIT_FIFO(info, 10);
  550. pm2_RDAC_WR(info, PM2I_RD_PIXEL_CLOCK_A3, 0);
  551. DEFW();
  552. pm2_RDAC_WR(info, PM2I_RD_PIXEL_CLOCK_A1, m);
  553. pm2_RDAC_WR(info, PM2I_RD_PIXEL_CLOCK_A2, n);
  554. DEFW();
  555. pm2_RDAC_WR(info, PM2I_RD_PIXEL_CLOCK_A3, 8|p);
  556. DEFW();
  557. pm2_RDAC_RD(info, PM2I_RD_PIXEL_CLOCK_STATUS);
  558. DEFR();
  559. for (i=256; i &&
  560.      !(pm2_RD(info, PM2R_RD_INDEXED_DATA)&PM2F_PLL_LOCKED); i--);
  561. break;
  562. case PM2_TYPE_PERMEDIA2V:
  563. pm2v_mnp(clk/2, &m, &n, &p);
  564. WAIT_FIFO(info, 8);
  565. pm2_WR(info, PM2VR_RD_INDEX_HIGH, PM2VI_RD_CLK0_PRESCALE >> 8);
  566. pm2v_RDAC_WR(info, PM2VI_RD_CLK0_PRESCALE, m);
  567. pm2v_RDAC_WR(info, PM2VI_RD_CLK0_FEEDBACK, n);
  568. pm2v_RDAC_WR(info, PM2VI_RD_CLK0_POSTSCALE, p);
  569. pm2_WR(info, PM2VR_RD_INDEX_HIGH, 0);
  570. break;
  571. }
  572. }
  573. static void clear_palette(struct pm2fb_info* p) {
  574. int i=256;
  575. WAIT_FIFO(p, 1);
  576. pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, 0);
  577. DEFW();
  578. while (i--) {
  579. WAIT_FIFO(p, 3);
  580. pm2_WR(p, PM2R_RD_PALETTE_DATA, 0);
  581. pm2_WR(p, PM2R_RD_PALETTE_DATA, 0);
  582. pm2_WR(p, PM2R_RD_PALETTE_DATA, 0);
  583. }
  584. }
  585. static void set_color(struct pm2fb_info* p, unsigned char regno,
  586. unsigned char r, unsigned char g, unsigned char b) {
  587. WAIT_FIFO(p, 4);
  588. pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, regno);
  589. DEFW();
  590. pm2_WR(p, PM2R_RD_PALETTE_DATA, r);
  591. DEFW();
  592. pm2_WR(p, PM2R_RD_PALETTE_DATA, g);
  593. DEFW();
  594. pm2_WR(p, PM2R_RD_PALETTE_DATA, b);
  595. }
  596. static void set_aperture(struct pm2fb_info* i, struct pm2fb_par* p) {
  597. WAIT_FIFO(i, 2);
  598. #ifdef __LITTLE_ENDIAN
  599. pm2_WR(i, PM2R_APERTURE_ONE, 0);
  600. pm2_WR(i, PM2R_APERTURE_TWO, 0);
  601. #else
  602. switch (p->depth) {
  603. case 8:
  604. case 24:
  605. pm2_WR(i, PM2R_APERTURE_ONE, 0);
  606. pm2_WR(i, PM2R_APERTURE_TWO, 1);
  607. break;
  608. case 16:
  609. pm2_WR(i, PM2R_APERTURE_ONE, 2);
  610. pm2_WR(i, PM2R_APERTURE_TWO, 1);
  611. break;
  612. case 32:
  613. pm2_WR(i, PM2R_APERTURE_ONE, 1);
  614. pm2_WR(i, PM2R_APERTURE_TWO, 1);
  615. break;
  616. }
  617. #endif
  618. }
  619. static void set_screen(struct pm2fb_info* i, struct pm2fb_par* p) {
  620. u32 clrmode=0;
  621. u32 txtmap=0;
  622. u32 pixsize=0;
  623. u32 clrformat=0;
  624. u32 xres;
  625. u32 video, tmp;
  626. if (i->type == PM2_TYPE_PERMEDIA2V) {
  627. WAIT_FIFO(i, 1);
  628. pm2_WR(i, PM2VR_RD_INDEX_HIGH, 0);
  629. }
  630. xres=(p->width+31)&~31;
  631. set_aperture(i, p);
  632. DEFRW();
  633. WAIT_FIFO(i, 27);
  634. pm2_RDAC_WR(i, PM2I_RD_COLOR_KEY_CONTROL, p->depth==8?0:
  635. PM2F_COLOR_KEY_TEST_OFF);
  636. switch (p->depth) {
  637. case 8:
  638. pm2_WR(i, PM2R_FB_READ_PIXEL, 0);
  639. clrformat=0x0e;
  640. break;
  641. case 16:
  642. pm2_WR(i, PM2R_FB_READ_PIXEL, 1);
  643. clrmode=PM2F_RD_TRUECOLOR|0x06;
  644. txtmap=PM2F_TEXTEL_SIZE_16;
  645. pixsize=1;
  646. clrformat=0x70;
  647. break;
  648. case 32:
  649. pm2_WR(i, PM2R_FB_READ_PIXEL, 2);
  650. clrmode=PM2F_RD_TRUECOLOR|0x08;
  651. txtmap=PM2F_TEXTEL_SIZE_32;
  652. pixsize=2;
  653. clrformat=0x20;
  654. break;
  655. case 24:
  656. pm2_WR(i, PM2R_FB_READ_PIXEL, 4);
  657. clrmode=PM2F_RD_TRUECOLOR|0x09;
  658. txtmap=PM2F_TEXTEL_SIZE_24;
  659. pixsize=4;
  660. clrformat=0x20;
  661. break;
  662. }
  663. pm2_WR(i, PM2R_SCREEN_SIZE, (p->height<<16)|p->width);
  664. pm2_WR(i, PM2R_SCISSOR_MODE, PM2F_SCREEN_SCISSOR_ENABLE);
  665. pm2_WR(i, PM2R_FB_WRITE_MODE, PM2F_FB_WRITE_ENABLE);
  666. pm2_WR(i, PM2R_FB_READ_MODE, partprod(xres));
  667. pm2_WR(i, PM2R_LB_READ_MODE, partprod(xres));
  668. pm2_WR(i, PM2R_TEXTURE_MAP_FORMAT, txtmap|partprod(xres));
  669. pm2_WR(i, PM2R_H_TOTAL, p->htotal);
  670. pm2_WR(i, PM2R_HS_START, p->hsstart);
  671. pm2_WR(i, PM2R_HS_END, p->hsend);
  672. pm2_WR(i, PM2R_HG_END, p->hbend);
  673. pm2_WR(i, PM2R_HB_END, p->hbend);
  674. pm2_WR(i, PM2R_V_TOTAL, p->vtotal);
  675. pm2_WR(i, PM2R_VS_START, p->vsstart);
  676. pm2_WR(i, PM2R_VS_END, p->vsend);
  677. pm2_WR(i, PM2R_VB_END, p->vbend);
  678. pm2_WR(i, PM2R_SCREEN_STRIDE, p->stride);
  679. DEFW();
  680. pm2_WR(i, PM2R_SCREEN_BASE, p->base);
  681. /* HW cursor needs /VSYNC for recognizing vert retrace */
  682. video=p->video & ~(PM2F_HSYNC_ACT_LOW|PM2F_VSYNC_ACT_LOW);
  683. video|=PM2F_HSYNC_ACT_HIGH|PM2F_VSYNC_ACT_HIGH;
  684. switch (i->type) {
  685. case PM2_TYPE_PERMEDIA2:
  686. tmp = PM2F_RD_PALETTE_WIDTH_8;
  687. pm2_RDAC_WR(i, PM2I_RD_COLOR_MODE, PM2F_RD_COLOR_MODE_RGB|
  688.    PM2F_RD_GUI_ACTIVE|clrmode);
  689. if ((p->video & PM2F_HSYNC_ACT_LOW) == PM2F_HSYNC_ACT_LOW)
  690. tmp |= 4; /* invert hsync */
  691. if ((p->video & PM2F_HSYNC_ACT_LOW) == PM2F_HSYNC_ACT_LOW)
  692. tmp |= 8; /* invert vsync */
  693. pm2_RDAC_WR(i, PM2I_RD_MISC_CONTROL, tmp);
  694. break;
  695. case PM2_TYPE_PERMEDIA2V:
  696. tmp = 0;
  697. pm2v_RDAC_WR(i, PM2VI_RD_PIXEL_SIZE, pixsize);
  698. pm2v_RDAC_WR(i, PM2VI_RD_COLOR_FORMAT, clrformat);
  699. if ((p->video & PM2F_HSYNC_ACT_LOW) == PM2F_HSYNC_ACT_LOW)
  700. tmp |= 1; /* invert hsync */
  701. if ((p->video & PM2F_HSYNC_ACT_LOW) == PM2F_HSYNC_ACT_LOW)
  702. tmp |= 4; /* invert vsync */
  703. pm2v_RDAC_WR(i, PM2VI_RD_SYNC_CONTROL, tmp);
  704. pm2v_RDAC_WR(i, PM2VI_RD_MISC_CONTROL, 1);
  705. break;
  706. }
  707. pm2_WR(i, PM2R_VIDEO_CONTROL, video);
  708. pm2_set_pixclock(i, p->pixclock);
  709. };
  710. /*
  711.  * copy with packed pixels (8/16bpp only).
  712.  */
  713. static void pm2fb_pp_copy(struct pm2fb_info* i, s32 xsrc, s32 ysrc,
  714. s32 x, s32 y, s32 w, s32 h) {
  715. s32 scale=i->current_par.depth==8?2:1;
  716. s32 offset;
  717. if (!w || !h)
  718. return;
  719. WAIT_FIFO(i, 7);
  720. pm2_WR(i, PM2R_CONFIG, PM2F_CONFIG_FB_WRITE_ENABLE|
  721. PM2F_CONFIG_FB_PACKED_DATA|
  722. PM2F_CONFIG_FB_READ_SOURCE_ENABLE);
  723. pm2_WR(i, PM2R_FB_PIXEL_OFFSET, 0);
  724. pm2_WR(i, PM2R_FB_SOURCE_DELTA, ((ysrc-y)&0xfff)<<16|
  725. ((xsrc-x)&0xfff));
  726. offset=(x&0x3)-(xsrc&0x3);
  727. pm2_WR(i, PM2R_RECTANGLE_ORIGIN, (y<<16)|(x>>scale));
  728. pm2_WR(i, PM2R_RECTANGLE_SIZE, (h<<16)|((w+7)>>scale));
  729. pm2_WR(i, PM2R_PACKED_DATA_LIMITS, (offset<<29)|(x<<16)|(x+w));
  730. DEFW();
  731. pm2_WR(i, PM2R_RENDER, PM2F_RENDER_RECTANGLE|
  732. (x<xsrc?PM2F_INCREASE_X:0)|
  733. (y<ysrc?PM2F_INCREASE_Y:0));
  734. wait_pm2(i);
  735. }
  736. /*
  737.  * block operation. copy=0: rectangle fill, copy=1: rectangle copy.
  738.  */
  739. static void pm2fb_block_op(struct pm2fb_info* i, int copy,
  740. s32 xsrc, s32 ysrc,
  741. s32 x, s32 y, s32 w, s32 h,
  742. u32 color) {
  743. if (!w || !h)
  744. return;
  745. WAIT_FIFO(i, 6);
  746. pm2_WR(i, PM2R_CONFIG, PM2F_CONFIG_FB_WRITE_ENABLE|
  747. PM2F_CONFIG_FB_READ_SOURCE_ENABLE);
  748. pm2_WR(i, PM2R_FB_PIXEL_OFFSET, 0);
  749. if (copy)
  750. pm2_WR(i, PM2R_FB_SOURCE_DELTA, ((ysrc-y)&0xfff)<<16|
  751. ((xsrc-x)&0xfff));
  752. else
  753. pm2_WR(i, PM2R_FB_BLOCK_COLOR, color);
  754. pm2_WR(i, PM2R_RECTANGLE_ORIGIN, (y<<16)|x);
  755. pm2_WR(i, PM2R_RECTANGLE_SIZE, (h<<16)|w);
  756. DEFW();
  757. pm2_WR(i, PM2R_RENDER, PM2F_RENDER_RECTANGLE|
  758. (x<xsrc?PM2F_INCREASE_X:0)|
  759. (y<ysrc?PM2F_INCREASE_Y:0)|
  760. (copy?0:PM2F_RENDER_FASTFILL));
  761. wait_pm2(i);
  762. }
  763. /***************************************************************************
  764.  * Begin of generic initialization functions
  765.  ***************************************************************************/
  766. static void pm2fb_reset(struct pm2fb_info* p) {
  767. if (p->type == PM2_TYPE_PERMEDIA2V)
  768. pm2_WR(p, PM2VR_RD_INDEX_HIGH, 0);
  769. pm2_WR(p, PM2R_RESET_STATUS, 0);
  770. DEFRW();
  771. while (pm2_RD(p, PM2R_RESET_STATUS)&PM2F_BEING_RESET);
  772. DEFRW();
  773. #ifdef CONFIG_FB_PM2_FIFO_DISCONNECT
  774. DPRINTK("FIFO disconnect enabledn");
  775. pm2_WR(p, PM2R_FIFO_DISCON, 1);
  776. DEFRW();
  777. #endif
  778. if (board_table[p->board].init)
  779. board_table[p->board].init(p);
  780. WAIT_FIFO(p, 48);
  781. pm2_WR(p, PM2R_CHIP_CONFIG, pm2_RD(p, PM2R_CHIP_CONFIG)&
  782. ~(PM2F_VGA_ENABLE|PM2F_VGA_FIXED));
  783. pm2_WR(p, PM2R_BYPASS_WRITE_MASK, ~(0L));
  784. pm2_WR(p, PM2R_FRAMEBUFFER_WRITE_MASK, ~(0L));
  785. pm2_WR(p, PM2R_FIFO_CONTROL, 0);
  786. pm2_WR(p, PM2R_FILTER_MODE, PM2F_SYNCHRONIZATION);
  787. pm2_WR(p, PM2R_APERTURE_ONE, 0);
  788. pm2_WR(p, PM2R_APERTURE_TWO, 0);
  789. pm2_WR(p, PM2R_LB_READ_FORMAT, 0);
  790. pm2_WR(p, PM2R_LB_WRITE_FORMAT, 0); 
  791. pm2_WR(p, PM2R_LB_READ_MODE, 0);
  792. pm2_WR(p, PM2R_LB_SOURCE_OFFSET, 0);
  793. pm2_WR(p, PM2R_FB_SOURCE_OFFSET, 0);
  794. pm2_WR(p, PM2R_FB_PIXEL_OFFSET, 0);
  795. pm2_WR(p, PM2R_WINDOW_ORIGIN, 0);
  796. pm2_WR(p, PM2R_FB_WINDOW_BASE, 0);
  797. pm2_WR(p, PM2R_LB_WINDOW_BASE, 0);
  798. pm2_WR(p, PM2R_FB_SOFT_WRITE_MASK, ~(0L));
  799. pm2_WR(p, PM2R_FB_HARD_WRITE_MASK, ~(0L));
  800. pm2_WR(p, PM2R_FB_READ_PIXEL, 0);
  801. pm2_WR(p, PM2R_DITHER_MODE, 0);
  802. pm2_WR(p, PM2R_AREA_STIPPLE_MODE, 0);
  803. pm2_WR(p, PM2R_DEPTH_MODE, 0);
  804. pm2_WR(p, PM2R_STENCIL_MODE, 0);
  805. pm2_WR(p, PM2R_TEXTURE_ADDRESS_MODE, 0);
  806. pm2_WR(p, PM2R_TEXTURE_READ_MODE, 0);
  807. pm2_WR(p, PM2R_TEXEL_LUT_MODE, 0);
  808. pm2_WR(p, PM2R_YUV_MODE, 0);
  809. pm2_WR(p, PM2R_COLOR_DDA_MODE, 0);
  810. pm2_WR(p, PM2R_TEXTURE_COLOR_MODE, 0);
  811. pm2_WR(p, PM2R_FOG_MODE, 0);
  812. pm2_WR(p, PM2R_ALPHA_BLEND_MODE, 0);
  813. pm2_WR(p, PM2R_LOGICAL_OP_MODE, 0);
  814. pm2_WR(p, PM2R_STATISTICS_MODE, 0);
  815. pm2_WR(p, PM2R_SCISSOR_MODE, 0);
  816. switch (p->type) {
  817. case PM2_TYPE_PERMEDIA2:
  818. pm2_RDAC_WR(p, PM2I_RD_MODE_CONTROL, 0); /* no overlay */
  819. pm2_RDAC_WR(p, PM2I_RD_CURSOR_CONTROL, 0);
  820. pm2_RDAC_WR(p, PM2I_RD_MISC_CONTROL, PM2F_RD_PALETTE_WIDTH_8);
  821. break;
  822. case PM2_TYPE_PERMEDIA2V:
  823. pm2v_RDAC_WR(p, PM2VI_RD_MISC_CONTROL, 1); /* 8bit */
  824. break;
  825. }
  826. pm2_RDAC_WR(p, PM2I_RD_COLOR_KEY_CONTROL, 0);
  827. pm2_RDAC_WR(p, PM2I_RD_OVERLAY_KEY, 0);
  828. pm2_RDAC_WR(p, PM2I_RD_RED_KEY, 0);
  829. pm2_RDAC_WR(p, PM2I_RD_GREEN_KEY, 0);
  830. pm2_RDAC_WR(p, PM2I_RD_BLUE_KEY, 0);
  831. clear_palette(p);
  832. if (p->memclock)
  833. pm2_set_memclock(p, p->memclock);
  834. }
  835. static int __init pm2fb_conf(struct pm2fb_info* p){
  836. for (p->board=0; board_table[p->board].detect &&
  837. !(board_table[p->board].detect(p)); p->board++);
  838. if (!board_table[p->board].detect) {
  839. DPRINTK("no board found.n");
  840. return 0;
  841. }
  842. DPRINTK("found board: %sn", board_table[p->board].name);
  843. p->regions.p_fb=p->regions.fb_base;
  844. if (!request_mem_region(p->regions.p_fb, p->regions.fb_size,
  845.      "pm2fb")) {
  846. printk (KERN_ERR "pm2fb: cannot reserve fb memory, abortn");
  847. return 0;
  848. }
  849. p->regions.v_fb=MMAP(p->regions.p_fb, p->regions.fb_size);
  850. #ifndef PM2FB_BE_APERTURE
  851. p->regions.p_regs=p->regions.rg_base;
  852. #else
  853. p->regions.p_regs=p->regions.rg_base+PM2_REGS_SIZE;
  854. #endif
  855. if (!request_mem_region(p->regions.p_regs, PM2_REGS_SIZE, "pm2fb")) {
  856. printk (KERN_ERR "pm2fb: cannot reserve mmio memory, abortn");
  857. UNMAP(p->regions.v_fb, p->regions.fb_size);
  858. return 0;
  859. }
  860. p->regions.v_regs=MMAP(p->regions.p_regs, PM2_REGS_SIZE);
  861. #ifdef PM2FB_HW_CURSOR
  862. p->cursor = pm2_init_cursor(p);
  863. #endif
  864. return 1;
  865. }
  866. /***************************************************************************
  867.  * Begin of per-board initialization functions
  868.  ***************************************************************************/
  869. /*
  870.  * Phase5 CvisionPPC/BVisionPPC
  871.  */
  872. #ifdef CONFIG_FB_PM2_CVPPC
  873. static int cvppc_PCI_init(struct cvppc_par* p) {
  874. extern u32 powerup_PCI_present;
  875. if (!powerup_PCI_present) {
  876. DPRINTK("no PCI bridge detectedn");
  877. return 0;
  878. }
  879. if (!(p->pci_config=MMAP(CVPPC_PCI_CONFIG, 256))) {
  880. DPRINTK("unable to map PCI config regionn");
  881. return 0;
  882. }
  883. if (RD32(p->pci_config, PCI_VENDOR_ID)!=
  884. ((PCI_DEVICE_ID_TI_TVP4020<<16)|PCI_VENDOR_ID_TI)) {
  885. DPRINTK("bad vendorID/deviceIDn");
  886. return 0;
  887. }
  888. if (!(p->pci_bridge=MMAP(CSPPC_PCI_BRIDGE, 256))) {
  889. DPRINTK("unable to map PCI bridgen");
  890. return 0;
  891. }
  892. WR32(p->pci_bridge, CSPPC_BRIDGE_ENDIAN, CSPPCF_BRIDGE_BIG_ENDIAN);
  893. DEFW();
  894. if (pm2fb_options.flags & OPTF_OLD_MEM)
  895. WR32(p->pci_config, PCI_CACHE_LINE_SIZE, 0xff00);
  896. WR32(p->pci_config, PCI_BASE_ADDRESS_0, CVPPC_REGS_REGION);
  897. WR32(p->pci_config, PCI_BASE_ADDRESS_1, CVPPC_FB_APERTURE_ONE);
  898. WR32(p->pci_config, PCI_BASE_ADDRESS_2, CVPPC_FB_APERTURE_TWO);
  899. WR32(p->pci_config, PCI_ROM_ADDRESS, CVPPC_ROM_ADDRESS);
  900. DEFW();
  901. WR32(p->pci_config, PCI_COMMAND, 0xef000000 |
  902. PCI_COMMAND_IO |
  903. PCI_COMMAND_MEMORY |
  904. PCI_COMMAND_MASTER);
  905. return 1;
  906. }
  907. static int __init cvppc_detect(struct pm2fb_info* p) {
  908. if (!cvppc_PCI_init(&p->board_par.cvppc))
  909. return 0;
  910. p->type = PM2_TYPE_PERMEDIA2;
  911. p->regions.fb_base=CVPPC_FB_APERTURE_ONE;
  912. p->regions.fb_size=CVPPC_FB_SIZE;
  913. p->regions.rg_base=CVPPC_REGS_REGION;
  914. p->memclock=CVPPC_MEMCLOCK;
  915. return 1;
  916. }
  917. static void cvppc_init(struct pm2fb_info* p) {
  918. WAIT_FIFO(p, 3);
  919. pm2_WR(p, PM2R_MEM_CONTROL, 0);
  920. pm2_WR(p, PM2R_BOOT_ADDRESS, 0x30);
  921. DEFW();
  922. if (pm2fb_options.flags & OPTF_OLD_MEM)
  923. pm2_WR(p, PM2R_MEM_CONFIG, CVPPC_MEM_CONFIG_OLD);
  924. else
  925. pm2_WR(p, PM2R_MEM_CONFIG, CVPPC_MEM_CONFIG_NEW);
  926. }
  927. #endif /* CONFIG_FB_PM2_CVPPC */
  928. /*
  929.  * Generic PCI detection routines
  930.  */
  931. #ifdef CONFIG_FB_PM2_PCI
  932. struct {
  933. unsigned short vendor, device;
  934. char *name;
  935. pm2type_t type;
  936. } pm2pci_cards[] __initdata = {
  937. { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TVP4020, "Texas Instruments TVP4020", PM2_TYPE_PERMEDIA2 },
  938. { PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2, "3dLabs Permedia 2", PM2_TYPE_PERMEDIA2 },
  939. { PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2V, "3dLabs Permedia 2v", PM2_TYPE_PERMEDIA2V },
  940. { 0, 0 }
  941. };
  942. static int __init pm2pci_detect(struct pm2fb_info* p) {
  943. struct pm2pci_par* pci=&p->board_par.pci;
  944. struct pci_dev* dev;
  945. int i;
  946. unsigned char* m;
  947. #ifdef __sparc__
  948. struct pcidev_cookie *pcp;
  949. #endif
  950. memset(pci, 0, sizeof(struct pm2pci_par));
  951. if (!pci_present()) {
  952. DPRINTK("no PCI bus found.n");
  953. return 0;
  954. }
  955. DPRINTK("scanning PCI bus for known chipsets...n");
  956. pci_for_each_dev(dev) {
  957. for (i = 0; pm2pci_cards[i].vendor; i++)
  958. if (pm2pci_cards[i].vendor == dev->vendor &&
  959.     pm2pci_cards[i].device == dev->device) {
  960. pci->dev = dev;
  961. p->type = pm2pci_cards[i].type;
  962. DPRINTK("... found %sn", pm2pci_cards[i].name);
  963. break;
  964. }
  965. if (pci->dev)
  966. break;
  967. }
  968. if (!pci->dev) {
  969. DPRINTK("no PCI board found.n");
  970. return 0;
  971. }
  972. DPRINTK("PCI board @%08lx %08lx %08lx rom %08lxn",
  973. pci->dev->resource[0].start,
  974. pci->dev->resource[1].start,
  975. pci->dev->resource[2].start,
  976. pci->dev->resource[PCI_ROM_RESOURCE].start);
  977. #ifdef __sparc__
  978. p->regions.rg_base= pci->dev->resource[0].start;
  979. p->regions.fb_base= pci->dev->resource[1].start;
  980. pcp = pci->dev->sysdata;
  981. /* If the user has not asked for a particular mode, lets guess */
  982. if (pcp->prom_node && !(pm2fb_options.flags & OPTF_USER)) {
  983. char timing[256], *q, *r;
  984. unsigned long w, h;
  985. int i;
  986. prom_getstring(pcp->prom_node, "timing-numbers", timing, 256);
  987. /* FIXME: Find out what the actual pixclock is and other values as well */
  988. if (timing[0]) {
  989. w = simple_strtoul(timing, &q, 0);
  990. h = 0;
  991. if (q == timing) w = 0;
  992. if (w) {
  993. for (i = 0; i < 3; i++) {
  994. for (r = q; *r && (*r < '0' || *r > '9'); r++);
  995. simple_strtoul(r, &q, 0);
  996. if (r == q) break;
  997. }
  998. if (i < 3) w = 0;
  999. }
  1000. if (w) {
  1001. for (r = q; *r && (*r < '0' || *r > '9'); r++);
  1002. h = simple_strtoul(r, &q, 0);
  1003. if (r == q) w = 0;
  1004. }
  1005. if (w == 640 && h == 480) w = 0;
  1006. if (w) {
  1007. for (i=0; user_mode[i].name[0] &&
  1008.   (w != user_mode[i].par.width ||
  1009.    h != user_mode[i].par.height); i++);
  1010. if (user_mode[i].name[0])
  1011. memcpy(&p->current_par, &user_mode[i].par, sizeof(user_mode[i].par));
  1012. }
  1013. }
  1014. }
  1015. #else
  1016. if (pm2fb_options.flags & OPTF_VIRTUAL) {
  1017. p->regions.rg_base = __pa(pci_resource_start(pci->dev, 0));
  1018. p->regions.fb_base = __pa(pci_resource_start(pci->dev, 1));
  1019. }
  1020. else {
  1021. p->regions.rg_base = pci_resource_start(pci->dev, 0);
  1022. p->regions.fb_base = pci_resource_start(pci->dev, 1);
  1023. }
  1024. #endif
  1025. #ifdef PM2FB_BE_APERTURE
  1026. p->regions.rg_base += PM2_REGS_SIZE;
  1027. #endif
  1028. if ((m=MMAP(p->regions.rg_base, PM2_REGS_SIZE))) {
  1029. pci->mem_control=RD32(m, PM2R_MEM_CONTROL);
  1030. pci->boot_address=RD32(m, PM2R_BOOT_ADDRESS);
  1031. pci->mem_config=RD32(m, PM2R_MEM_CONFIG);
  1032. switch (pci->mem_config & PM2F_MEM_CONFIG_RAM_MASK) {
  1033. case PM2F_MEM_BANKS_1:
  1034. p->regions.fb_size=0x200000;
  1035. break;
  1036. case PM2F_MEM_BANKS_2:
  1037. p->regions.fb_size=0x400000;
  1038. break;
  1039. case PM2F_MEM_BANKS_3:
  1040. p->regions.fb_size=0x600000;
  1041. break;
  1042. case PM2F_MEM_BANKS_4:
  1043. p->regions.fb_size=0x800000;
  1044. break;
  1045. }
  1046. p->memclock=CVPPC_MEMCLOCK;
  1047. UNMAP(m, PM2_REGS_SIZE);
  1048. return 1;
  1049. }
  1050. DPRINTK("MMAP() failed.n");
  1051. return 0;
  1052. }
  1053. static void pm2pci_init(struct pm2fb_info* p) {
  1054. struct pm2pci_par* pci=&p->board_par.pci;
  1055. WAIT_FIFO(p, 3);
  1056. pm2_WR(p, PM2R_MEM_CONTROL, pci->mem_control);
  1057. pm2_WR(p, PM2R_BOOT_ADDRESS, pci->boot_address);
  1058. DEFW();
  1059. pm2_WR(p, PM2R_MEM_CONFIG, pci->mem_config);
  1060. }
  1061. #endif /* CONFIG_FB_PM2_PCI */
  1062. /***************************************************************************
  1063.  * Console hw acceleration
  1064.  ***************************************************************************/
  1065. static int pm2fb_blank(int blank_mode, struct fb_info_gen* info) {
  1066. struct pm2fb_info* i=(struct pm2fb_info* )info;
  1067. u32 video;
  1068. if (!i->current_par_valid)
  1069. return 1;
  1070. video=i->current_par.video;
  1071. if (blank_mode>0) {
  1072. switch (blank_mode-1) {
  1073. case VESA_NO_BLANKING: /* FIXME */
  1074. video=video&~(PM2F_VIDEO_ENABLE);
  1075. break;
  1076. case VESA_HSYNC_SUSPEND:
  1077. video=video&~(PM2F_HSYNC_MASK|
  1078. PM2F_BLANK_LOW);
  1079. break;
  1080. case VESA_VSYNC_SUSPEND:
  1081. video=video&~(PM2F_VSYNC_MASK|
  1082. PM2F_BLANK_LOW);
  1083. break;
  1084. case VESA_POWERDOWN:
  1085. video=video&~(PM2F_VSYNC_MASK|
  1086. PM2F_HSYNC_MASK|
  1087. PM2F_BLANK_LOW);
  1088. break;
  1089. }
  1090. }
  1091. WAIT_FIFO(i, 1);
  1092. pm2_WR(i, PM2R_VIDEO_CONTROL, video);
  1093. return 0;
  1094. }
  1095. static int pm2fb_pan_display(const struct fb_var_screeninfo* var,
  1096. struct fb_info_gen* info) {
  1097. struct pm2fb_info* i=(struct pm2fb_info* )info;
  1098. if (!i->current_par_valid)
  1099. return -EINVAL;
  1100. i->current_par.base=to3264(var->yoffset*i->current_par.width+
  1101. var->xoffset, i->current_par.depth, 1);
  1102. WAIT_FIFO(i, 1);
  1103. pm2_WR(i, PM2R_SCREEN_BASE, i->current_par.base);
  1104. return 0;
  1105. }
  1106. static void pm2fb_pp_bmove(struct display* p, int sy, int sx,
  1107. int dy, int dx, int height, int width) {
  1108. if (fontwidthlog(p)) {
  1109. sx=sx<<fontwidthlog(p);
  1110. dx=dx<<fontwidthlog(p);
  1111. width=width<<fontwidthlog(p);
  1112. }
  1113. else {
  1114. sx=sx*fontwidth(p);
  1115. dx=dx*fontwidth(p);
  1116. width=width*fontwidth(p);
  1117. }
  1118. sy=sy*fontheight(p);
  1119. dy=dy*fontheight(p);
  1120. height=height*fontheight(p);
  1121. pm2fb_pp_copy((struct pm2fb_info* )p->fb_info, sx, sy, dx,
  1122. dy, width, height);
  1123. }
  1124. static void pm2fb_bmove(struct display* p, int sy, int sx,
  1125. int dy, int dx, int height, int width) {
  1126. if (fontwidthlog(p)) {
  1127. sx=sx<<fontwidthlog(p);
  1128. dx=dx<<fontwidthlog(p);
  1129. width=width<<fontwidthlog(p);
  1130. }
  1131. else {
  1132. sx=sx*fontwidth(p);
  1133. dx=dx*fontwidth(p);
  1134. width=width*fontwidth(p);
  1135. }
  1136. sy=sy*fontheight(p);
  1137. dy=dy*fontheight(p);
  1138. height=height*fontheight(p);
  1139. pm2fb_block_op((struct pm2fb_info* )p->fb_info, 1, sx, sy, dx, dy,
  1140. width, height, 0);
  1141. }
  1142. #ifdef FBCON_HAS_CFB8
  1143. static void pm2fb_clear8(struct vc_data* conp, struct display* p,
  1144. int sy, int sx, int height, int width) {
  1145. u32 c;
  1146. sx=sx*fontwidth(p);
  1147. width=width*fontwidth(p);
  1148. sy=sy*fontheight(p);
  1149. height=height*fontheight(p);
  1150. c=attr_bgcol_ec(p, conp);
  1151. c|=c<<8;
  1152. c|=c<<16;
  1153. pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0, sx, sy,
  1154. width, height, c);
  1155. }
  1156. static void pm2fb_clear_margins8(struct vc_data* conp, struct display* p,
  1157. int bottom_only) {
  1158. u32 c;
  1159. u32 sx;
  1160. u32 sy;
  1161. c=attr_bgcol_ec(p, conp);
  1162. c|=c<<8;
  1163. c|=c<<16;
  1164. sx=conp->vc_cols*fontwidth(p);
  1165. sy=conp->vc_rows*fontheight(p);
  1166. if (!bottom_only)
  1167. pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0,
  1168. sx, 0, (p->var.xres-sx), p->var.yres_virtual, c);
  1169. pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0,
  1170. 0, p->var.yoffset+sy, sx, p->var.yres-sy, c);
  1171. }
  1172. static struct display_switch pm2_cfb8 = {
  1173. setup: fbcon_cfb8_setup,
  1174. bmove: pm2fb_pp_bmove,
  1175. #ifdef __alpha__
  1176. /* Not sure why, but this works and the other does not. */
  1177. /* Also, perhaps we need a separate routine to wait for the
  1178.    blitter to stop before doing this? */
  1179. /* In addition, maybe we need to do this for 16 and 32 bit depths? */
  1180. clear: fbcon_cfb8_clear,
  1181. #else
  1182. clear: pm2fb_clear8,
  1183. #endif
  1184. putc: fbcon_cfb8_putc,
  1185. putcs: fbcon_cfb8_putcs,
  1186. revc: fbcon_cfb8_revc,
  1187. cursor: pm2fb_cursor,
  1188. set_font: pm2fb_set_font,
  1189. clear_margins: pm2fb_clear_margins8,
  1190. fontwidthmask: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) };
  1191. #endif /* FBCON_HAS_CFB8 */
  1192. #ifdef FBCON_HAS_CFB16
  1193. static void pm2fb_clear16(struct vc_data* conp, struct display* p,
  1194. int sy, int sx, int height, int width) {
  1195. u32 c;
  1196. sx=sx*fontwidth(p);
  1197. width=width*fontwidth(p);
  1198. sy=sy*fontheight(p);
  1199. height=height*fontheight(p);
  1200. c=((u16 *)p->dispsw_data)[attr_bgcol_ec(p, conp)];
  1201. c|=c<<16;
  1202. pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0, sx, sy,
  1203. width, height, c);
  1204. }
  1205. static void pm2fb_clear_margins16(struct vc_data* conp, struct display* p,
  1206. int bottom_only) {
  1207. u32 c;
  1208. u32 sx;
  1209. u32 sy;
  1210. c = ((u16 *)p->dispsw_data)[attr_bgcol_ec(p, conp)];
  1211. c|=c<<16;
  1212. sx=conp->vc_cols*fontwidth(p);
  1213. sy=conp->vc_rows*fontheight(p);
  1214. if (!bottom_only)
  1215. pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0,
  1216. sx, 0, (p->var.xres-sx), p->var.yres_virtual, c);
  1217. pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0,
  1218. 0, p->var.yoffset+sy, sx, p->var.yres-sy, c);
  1219. }
  1220. static struct display_switch pm2_cfb16 = {
  1221. setup: fbcon_cfb16_setup,
  1222. bmove: pm2fb_pp_bmove,
  1223. clear: pm2fb_clear16,
  1224. putc: fbcon_cfb16_putc,
  1225. putcs: fbcon_cfb16_putcs,
  1226. revc: fbcon_cfb16_revc,
  1227. cursor: pm2fb_cursor,
  1228. set_font: pm2fb_set_font,
  1229. clear_margins: pm2fb_clear_margins16,
  1230. fontwidthmask: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
  1231. };
  1232. #endif /* FBCON_HAS_CFB16 */
  1233. #ifdef FBCON_HAS_CFB24
  1234. /*
  1235.  * fast fill for 24bpp works only when red==green==blue
  1236.  */
  1237. static void pm2fb_clear24(struct vc_data* conp, struct display* p,
  1238. int sy, int sx, int height, int width) {
  1239. struct pm2fb_info* i=(struct pm2fb_info* )p->fb_info;
  1240. u32 c;
  1241. c=attr_bgcol_ec(p, conp);
  1242. if ( i->palette[c].red==i->palette[c].green &&
  1243. i->palette[c].green==i->palette[c].blue) {
  1244. c=((u32 *)p->dispsw_data)[c];
  1245. c|=(c&0xff0000)<<8;
  1246. sx=sx*fontwidth(p);
  1247. width=width*fontwidth(p);
  1248. sy=sy*fontheight(p);
  1249. height=height*fontheight(p);
  1250. pm2fb_block_op(i, 0, 0, 0, sx, sy, width, height, c);
  1251. }
  1252. else
  1253. fbcon_cfb24_clear(conp, p, sy, sx, height, width);
  1254. }
  1255. static void pm2fb_clear_margins24(struct vc_data* conp, struct display* p,
  1256. int bottom_only) {
  1257. struct pm2fb_info* i=(struct pm2fb_info* )p->fb_info;
  1258. u32 c;
  1259. u32 sx;
  1260. u32 sy;
  1261. c=attr_bgcol_ec(p, conp);
  1262. if ( i->palette[c].red==i->palette[c].green &&
  1263. i->palette[c].green==i->palette[c].blue) {
  1264. c=((u32 *)p->dispsw_data)[c];
  1265. c|=(c&0xff0000)<<8;
  1266. sx=conp->vc_cols*fontwidth(p);
  1267. sy=conp->vc_rows*fontheight(p);
  1268. if (!bottom_only)
  1269. pm2fb_block_op(i, 0, 0, 0, sx, 0, (p->var.xres-sx),
  1270. p->var.yres_virtual, c);
  1271. pm2fb_block_op(i, 0, 0, 0, 0, p->var.yoffset+sy,
  1272. sx, p->var.yres-sy, c);
  1273. }
  1274. else
  1275. fbcon_cfb24_clear_margins(conp, p, bottom_only);
  1276. }
  1277. static struct display_switch pm2_cfb24 = {
  1278. setup: fbcon_cfb24_setup,
  1279. bmove: pm2fb_bmove,
  1280. clear: pm2fb_clear24,
  1281. putc: fbcon_cfb24_putc,
  1282. putcs: fbcon_cfb24_putcs,
  1283. revc: fbcon_cfb24_revc,
  1284. cursor: pm2fb_cursor,
  1285. set_font: pm2fb_set_font,
  1286. clear_margins: pm2fb_clear_margins24,
  1287. fontwidthmask: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
  1288. };
  1289. #endif /* FBCON_HAS_CFB24 */
  1290. #ifdef FBCON_HAS_CFB32
  1291. static void pm2fb_clear32(struct vc_data* conp, struct display* p,
  1292. int sy, int sx, int height, int width) {
  1293. u32 c;
  1294. sx=sx*fontwidth(p);
  1295. width=width*fontwidth(p);
  1296. sy=sy*fontheight(p);
  1297. height=height*fontheight(p);
  1298. c=((u32 *)p->dispsw_data)[attr_bgcol_ec(p, conp)];
  1299. pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0, sx, sy,
  1300. width, height, c);
  1301. }
  1302. static void pm2fb_clear_margins32(struct vc_data* conp, struct display* p,
  1303. int bottom_only) {
  1304. u32 c;
  1305. u32 sx;
  1306. u32 sy;
  1307. c = ((u32 *)p->dispsw_data)[attr_bgcol_ec(p, conp)];
  1308. sx=conp->vc_cols*fontwidth(p);
  1309. sy=conp->vc_rows*fontheight(p);
  1310. if (!bottom_only)
  1311. pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0,
  1312. sx, 0, (p->var.xres-sx), p->var.yres_virtual, c);
  1313. pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0,
  1314. 0, p->var.yoffset+sy, sx, p->var.yres-sy, c);
  1315. }
  1316. static struct display_switch pm2_cfb32 = {
  1317. setup: fbcon_cfb32_setup,
  1318. bmove: pm2fb_bmove,
  1319. clear: pm2fb_clear32,
  1320. putc: fbcon_cfb32_putc,
  1321. putcs: fbcon_cfb32_putcs,
  1322. revc: fbcon_cfb32_revc,
  1323. cursor: pm2fb_cursor,
  1324. set_font: pm2fb_set_font,
  1325. clear_margins: pm2fb_clear_margins32,
  1326. fontwidthmask: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
  1327. };
  1328. #endif /* FBCON_HAS_CFB32 */
  1329. /***************************************************************************
  1330.  * Framebuffer functions
  1331.  ***************************************************************************/
  1332. static void pm2fb_detect(void) {}
  1333. static int pm2fb_encode_fix(struct fb_fix_screeninfo* fix,
  1334. const void* par, struct fb_info_gen* info) {
  1335. struct pm2fb_info* i=(struct pm2fb_info* )info;
  1336. struct pm2fb_par* p=(struct pm2fb_par* )par;
  1337. strcpy(fix->id, permedia2_name);
  1338. fix->smem_start=i->regions.p_fb;
  1339. fix->smem_len=i->regions.fb_size;
  1340. fix->mmio_start=i->regions.p_regs;
  1341. fix->mmio_len=PM2_REGS_SIZE;
  1342. fix->accel=FB_ACCEL_3DLABS_PERMEDIA2;
  1343. fix->type=FB_TYPE_PACKED_PIXELS;
  1344. fix->visual=p->depth==8?FB_VISUAL_PSEUDOCOLOR:FB_VISUAL_TRUECOLOR;
  1345. if (i->current_par_valid)
  1346. fix->line_length=i->current_par.width*(i->current_par.depth/8);
  1347. else
  1348. fix->line_length=0;
  1349. fix->xpanstep=p->depth==24?8:64/p->depth;
  1350. fix->ypanstep=1;
  1351. fix->ywrapstep=0;
  1352. return 0;
  1353. }
  1354. #ifdef PM2FB_MASTER_DEBUG
  1355. static void pm2fb_display_var(const struct fb_var_screeninfo* var) {
  1356. printk( KERN_DEBUG
  1357. "- struct fb_var_screeninfo ---------------------------------------------------n");
  1358. printk( KERN_DEBUG
  1359. "resolution: %ux%ux%u (virtual %ux%u+%u+%u)n",
  1360. var->xres, var->yres, var->bits_per_pixel,
  1361. var->xres_virtual, var->yres_virtual,
  1362. var->xoffset, var->yoffset);
  1363. printk( KERN_DEBUG
  1364. "color: %c%c "
  1365. "R(%u,%u,%u), G(%u,%u,%u), B(%u,%u,%u), T(%u,%u,%u)n",
  1366. var->grayscale?'G':'C', var->nonstd?'N':'S',
  1367. var->red.offset, var->red.length, var->red.msb_right,
  1368. var->green.offset, var->green.length, var->green.msb_right,
  1369. var->blue.offset, var->blue.length, var->blue.msb_right,
  1370. var->transp.offset, var->transp.length,
  1371. var->transp.msb_right);
  1372. printk( KERN_DEBUG
  1373. "timings: %ups (%u,%u)-(%u,%u)+%u+%un",
  1374. var->pixclock,
  1375. var->left_margin, var->upper_margin, var->right_margin,
  1376. var->lower_margin, var->hsync_len, var->vsync_len);
  1377. printk( KERN_DEBUG
  1378. "activate %08x accel_flags %08x sync %08x vmode %08xn",
  1379. var->activate, var->accel_flags, var->sync, var->vmode);
  1380. printk( KERN_DEBUG
  1381. "------------------------------------------------------------------------------n");
  1382. }
  1383. #define pm2fb_decode_var pm2fb_wrapped_decode_var
  1384. #endif
  1385. static int pm2fb_decode_var(const struct fb_var_screeninfo* var,
  1386. void* par, struct fb_info_gen* info) {
  1387. struct pm2fb_info* i=(struct pm2fb_info* )info;
  1388. struct pm2fb_par p;
  1389. u32 xres;
  1390. int data64;
  1391. memset(&p, 0, sizeof(struct pm2fb_par));
  1392. p.width=(var->xres_virtual+7)&~7;
  1393. p.height=var->yres_virtual;
  1394. p.depth=(var->bits_per_pixel+7)&~7;
  1395. p.depth=p.depth>32?32:p.depth;
  1396. data64=p.depth>8 || i->type == PM2_TYPE_PERMEDIA2V;
  1397. xres=(var->xres+31)&~31;
  1398. if (p.width<xres+var->xoffset)
  1399. p.width=xres+var->xoffset;
  1400. if (p.height<var->yres+var->yoffset)
  1401. p.height=var->yres+var->yoffset;
  1402. if (!partprod(xres)) {
  1403. DPRINTK("width not supported: %un", xres);
  1404. return -EINVAL;
  1405. }
  1406. if (p.width>2047) {
  1407. DPRINTK("virtual width not supported: %un", p.width);
  1408. return -EINVAL;
  1409. }
  1410. if (var->yres<200) {
  1411. DPRINTK("height not supported: %un",
  1412. (u32 )var->yres);
  1413. return -EINVAL;
  1414. }
  1415. if (p.height<200 || p.height>2047) {
  1416. DPRINTK("virtual height not supported: %un", p.height);
  1417. return -EINVAL;
  1418. }
  1419. if (p.depth>32) {
  1420. DPRINTK("depth not supported: %un", p.depth);
  1421. return -EINVAL;
  1422. }
  1423. if (p.width*p.height*p.depth/8>i->regions.fb_size) {
  1424. DPRINTK("no memory for screen (%ux%ux%u)n",
  1425. p.width, p.height, p.depth);
  1426. return -EINVAL;
  1427. }
  1428. p.pixclock=PICOS2KHZ(var->pixclock);
  1429. if (p.pixclock>PM2_MAX_PIXCLOCK) {
  1430. DPRINTK("pixclock too high (%uKHz)n", p.pixclock);
  1431. return -EINVAL;
  1432. }
  1433. p.hsstart=to3264(var->right_margin, p.depth, data64);
  1434. p.hsend=p.hsstart+to3264(var->hsync_len, p.depth, data64);
  1435. p.hbend=p.hsend+to3264(var->left_margin, p.depth, data64);
  1436. p.htotal=to3264(xres, p.depth, data64)+p.hbend-1;
  1437. p.vsstart=var->lower_margin?var->lower_margin-1:0; /* FIXME! */
  1438. p.vsend=var->lower_margin+var->vsync_len-1;
  1439. p.vbend=var->lower_margin+var->vsync_len+var->upper_margin;
  1440. p.vtotal=var->yres+p.vbend-1;
  1441. p.stride=to3264(p.width, p.depth, 1);
  1442. p.base=to3264(var->yoffset*xres+var->xoffset, p.depth, 1);
  1443. if (data64)
  1444. p.video|=PM2F_DATA_64_ENABLE;
  1445. if (var->sync & FB_SYNC_HOR_HIGH_ACT)
  1446. p.video|=PM2F_HSYNC_ACT_HIGH;
  1447. else
  1448. p.video|=PM2F_HSYNC_ACT_LOW;
  1449. if (var->sync & FB_SYNC_VERT_HIGH_ACT)
  1450. p.video|=PM2F_VSYNC_ACT_HIGH;
  1451. else
  1452. p.video|=PM2F_VSYNC_ACT_LOW;
  1453. if ((var->vmode & FB_VMODE_MASK)==FB_VMODE_INTERLACED) {
  1454. DPRINTK("interlaced not supportedn");
  1455. return -EINVAL;
  1456. }
  1457. if ((var->vmode & FB_VMODE_MASK)==FB_VMODE_DOUBLE)
  1458. p.video|=PM2F_LINE_DOUBLE;
  1459. if (var->activate==FB_ACTIVATE_NOW)
  1460. p.video|=PM2F_VIDEO_ENABLE;
  1461. *((struct pm2fb_par* )par)=p;
  1462. return 0;
  1463. }
  1464. #ifdef PM2FB_MASTER_DEBUG
  1465. #undef pm2fb_decode_var
  1466. static int pm2fb_decode_var(const struct fb_var_screeninfo* var,
  1467. void* par, struct fb_info_gen* info) {
  1468. int result;
  1469. result=pm2fb_wrapped_decode_var(var, par, info);
  1470. pm2fb_display_var(var);
  1471. return result;
  1472. }
  1473. #endif
  1474. static int pm2fb_encode_var(struct fb_var_screeninfo* var,
  1475. const void* par, struct fb_info_gen* info) {
  1476. struct pm2fb_par* p=(struct pm2fb_par* )par;
  1477. struct fb_var_screeninfo v;
  1478. u32 base;
  1479. memset(&v, 0, sizeof(struct fb_var_screeninfo));
  1480. v.xres_virtual=p->width;
  1481. v.yres_virtual=p->height;
  1482. v.xres=(p->htotal+1)-p->hbend;
  1483. v.yres=(p->vtotal+1)-p->vbend;
  1484. v.right_margin=p->hsstart;
  1485. v.hsync_len=p->hsend-p->hsstart;
  1486. v.left_margin=p->hbend-p->hsend;
  1487. v.lower_margin=p->vsstart+1;
  1488. v.vsync_len=p->vsend-v.lower_margin+1;
  1489. v.upper_margin=p->vbend-v.lower_margin-v.vsync_len;
  1490. v.bits_per_pixel=p->depth;
  1491. if (p->video & PM2F_DATA_64_ENABLE) {
  1492. v.xres=v.xres<<1;
  1493. v.right_margin=v.right_margin<<1;
  1494. v.hsync_len=v.hsync_len<<1;
  1495. v.left_margin=v.left_margin<<1;
  1496. }
  1497. switch (p->depth) {
  1498. case 8:
  1499. v.red.length=v.green.length=v.blue.length=8;
  1500. v.xres=v.xres<<2;
  1501. v.right_margin=v.right_margin<<2;
  1502. v.hsync_len=v.hsync_len<<2;
  1503. v.left_margin=v.left_margin<<2;
  1504. break;
  1505. case 16:
  1506. v.red.offset=11;
  1507. v.red.length=5;
  1508. v.green.offset=5;
  1509. v.green.length=6;
  1510. v.blue.length=5;
  1511. v.xres=v.xres<<1;
  1512. v.right_margin=v.right_margin<<1;
  1513. v.hsync_len=v.hsync_len<<1;
  1514. v.left_margin=v.left_margin<<1;
  1515. break;
  1516. case 32:
  1517. v.transp.offset=24;
  1518. v.red.offset=16;
  1519. v.green.offset=8;
  1520. v.red.length=v.green.length=v.blue.length=
  1521. v.transp.length=8;
  1522. break;
  1523. case 24:
  1524. v.blue.offset=16;
  1525. v.green.offset=8;
  1526. v.red.length=v.green.length=v.blue.length=8;
  1527. v.xres=(v.xres<<2)/3;
  1528. v.right_margin=(v.right_margin<<2)/3;
  1529. v.hsync_len=(v.hsync_len<<2)/3;
  1530. v.left_margin=(v.left_margin<<2)/3;
  1531. break;
  1532. }
  1533. base=from3264(p->base, p->depth, 1);
  1534. v.xoffset=base%v.xres;
  1535. v.yoffset=base/v.xres;
  1536. v.height=v.width=-1;
  1537. v.pixclock=KHZ2PICOS(p->pixclock);
  1538. if ((p->video & PM2F_HSYNC_MASK)==PM2F_HSYNC_ACT_HIGH)
  1539. v.sync|=FB_SYNC_HOR_HIGH_ACT;
  1540. if ((p->video & PM2F_VSYNC_MASK)==PM2F_VSYNC_ACT_HIGH)
  1541. v.sync|=FB_SYNC_VERT_HIGH_ACT;
  1542. if (p->video & PM2F_LINE_DOUBLE)
  1543. v.vmode=FB_VMODE_DOUBLE;
  1544. *var=v;
  1545. return 0;
  1546. }
  1547. static void set_user_mode(struct pm2fb_info* i) {
  1548. if (pm2fb_options.flags & OPTF_YPAN) {
  1549. int h = i->current_par.height;
  1550. i->current_par.height=i->regions.fb_size/
  1551. (i->current_par.width*i->current_par.depth/8);
  1552. i->current_par.height=MIN(i->current_par.height,2047);
  1553. i->current_par.height=MAX(i->current_par.height,h);
  1554. }
  1555. }
  1556. static void pm2fb_get_par(void* par, struct fb_info_gen* info) {
  1557. struct pm2fb_info* i=(struct pm2fb_info* )info;
  1558. if (!i->current_par_valid) {
  1559. set_user_mode(i);
  1560. pm2fb_reset(i);
  1561. set_screen(i, &i->current_par);
  1562. i->current_par_valid=1;
  1563. }
  1564. *((struct pm2fb_par* )par)=i->current_par;
  1565. }
  1566. static void pm2fb_set_par(const void* par, struct fb_info_gen* info) {
  1567. struct pm2fb_info* i=(struct pm2fb_info* )info;
  1568. struct pm2fb_par* p;
  1569. p=(struct pm2fb_par* )par;
  1570. if (i->current_par_valid) {
  1571. i->current_par.base=p->base;
  1572. if (!memcmp(p, &i->current_par, sizeof(struct pm2fb_par))) {
  1573. WAIT_FIFO(i, 1);
  1574. pm2_WR(i, PM2R_SCREEN_BASE, p->base);
  1575. return;
  1576. }
  1577. }
  1578. set_screen(i, p);
  1579. i->current_par=*p;
  1580. i->current_par_valid=1;
  1581. #ifdef PM2FB_HW_CURSOR
  1582. if (i->cursor) {
  1583. pm2v_set_cursor_color(i, cursor_color_map, cursor_color_map, cursor_color_map);
  1584. pm2v_set_cursor_shape(i);
  1585. }
  1586. #endif
  1587. }
  1588. static int pm2fb_getcolreg(unsigned regno,
  1589. unsigned* red, unsigned* green, unsigned* blue,
  1590. unsigned* transp, struct fb_info* info) {
  1591. struct pm2fb_info* i=(struct pm2fb_info* )info;
  1592. if (regno<256) {
  1593. *red=i->palette[regno].red<<8|i->palette[regno].red;
  1594. *green=i->palette[regno].green<<8|i->palette[regno].green;
  1595. *blue=i->palette[regno].blue<<8|i->palette[regno].blue;
  1596. *transp=i->palette[regno].transp<<8|i->palette[regno].transp;
  1597. }
  1598. return regno>255;
  1599. }
  1600. static int pm2fb_setcolreg(unsigned regno,
  1601. unsigned red, unsigned green, unsigned blue,
  1602. unsigned transp, struct fb_info* info) {
  1603. struct pm2fb_info* i=(struct pm2fb_info* )info;
  1604. if (regno<16) {
  1605. switch (i->current_par.depth) {
  1606. #ifdef FBCON_HAS_CFB8
  1607. case 8:
  1608. break;
  1609. #endif
  1610. #ifdef FBCON_HAS_CFB16
  1611. case 16:
  1612. i->cmap.cmap16[regno]=
  1613. ((u32 )red & 0xf800) |
  1614. (((u32 )green & 0xfc00)>>5) |
  1615. (((u32 )blue & 0xf800)>>11);
  1616. break;
  1617. #endif
  1618. #ifdef FBCON_HAS_CFB24
  1619. case 24:
  1620. i->cmap.cmap24[regno]=
  1621. (((u32 )blue & 0xff00) << 8) |
  1622. ((u32 )green & 0xff00) |
  1623. (((u32 )red & 0xff00) >> 8);
  1624. break;
  1625. #endif
  1626. #ifdef FBCON_HAS_CFB32
  1627. case 32:
  1628.     i->cmap.cmap32[regno]=
  1629. (((u32 )transp & 0xff00) << 16) |
  1630.      (((u32 )red & 0xff00) << 8) |
  1631. (((u32 )green & 0xff00)) |
  1632.   (((u32 )blue & 0xff00) >> 8);
  1633. break;
  1634. #endif
  1635. default:
  1636. DPRINTK("bad depth %un",
  1637. i->current_par.depth);
  1638. break;
  1639. }
  1640. }
  1641. if (regno<256) {
  1642. i->palette[regno].red=red >> 8;
  1643. i->palette[regno].green=green >> 8;
  1644. i->palette[regno].blue=blue >> 8;
  1645. i->palette[regno].transp=transp >> 8;
  1646. if (i->current_par.depth==8)
  1647. set_color(i, regno, red>>8, green>>8, blue>>8);
  1648. }
  1649. return regno>255;
  1650. }
  1651. static void pm2fb_set_disp(const void* par, struct display* disp,
  1652.    struct fb_info_gen* info) {
  1653. struct pm2fb_info* i=(struct pm2fb_info* )info;
  1654. unsigned long flags;
  1655. unsigned long depth;
  1656. save_flags(flags);
  1657. cli();
  1658. disp->screen_base = i->regions.v_fb;
  1659. switch (depth=((struct pm2fb_par* )par)->depth) {
  1660. #ifdef FBCON_HAS_CFB8
  1661. case 8:
  1662. disp->dispsw=&pm2_cfb8;
  1663. break;
  1664. #endif
  1665. #ifdef FBCON_HAS_CFB16
  1666. case 16:
  1667. disp->dispsw=&pm2_cfb16;
  1668. disp->dispsw_data=i->cmap.cmap16;
  1669. break;
  1670. #endif
  1671. #ifdef FBCON_HAS_CFB24
  1672. case 24:
  1673. disp->dispsw=&pm2_cfb24;
  1674. disp->dispsw_data=i->cmap.cmap24;
  1675. break;
  1676. #endif
  1677. #ifdef FBCON_HAS_CFB32
  1678. case 32:
  1679. disp->dispsw=&pm2_cfb32;
  1680. disp->dispsw_data=i->cmap.cmap32;
  1681. break;
  1682. #endif
  1683. default:
  1684. disp->dispsw=&fbcon_dummy;
  1685. break;
  1686. }
  1687. restore_flags(flags);
  1688. }
  1689. #ifdef PM2FB_HW_CURSOR
  1690. /***************************************************************************
  1691.  * Hardware cursor support
  1692.  ***************************************************************************/
  1693.  
  1694. static u8 cursor_bits_lookup[16] = {
  1695. 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
  1696. 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55
  1697. };
  1698. static u8 cursor_mask_lookup[16] = {
  1699. 0x00, 0x80, 0x20, 0xa0, 0x08, 0x88, 0x28, 0xa8,
  1700. 0x02, 0x82, 0x22, 0xa2, 0x0a, 0x8a, 0x2a, 0xaa
  1701. };
  1702. static void pm2v_set_cursor_color(struct pm2fb_info *fb, u8 *red, u8 *green, u8 *blue)
  1703. {
  1704. struct pm2_cursor *c = fb->cursor;
  1705. int i;
  1706. for (i = 0; i < 2; i++) {
  1707. c->color[3*i] = red[i];
  1708. c->color[3*i+1] = green[i];
  1709. c->color[3*i+2] = blue[i];
  1710. }
  1711. WAIT_FIFO(fb, 14);
  1712. pm2_WR(fb, PM2VR_RD_INDEX_HIGH, PM2VI_RD_CURSOR_PALETTE >> 8);
  1713. for (i = 0; i < 6; i++)
  1714. pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PALETTE+i, c->color[i]);
  1715. pm2_WR(fb, PM2VR_RD_INDEX_HIGH, 0);
  1716. }
  1717. static void pm2v_set_cursor_shape(struct pm2fb_info *fb)
  1718. {
  1719. struct pm2_cursor *c = fb->cursor;
  1720. u8 m, b;
  1721. int i, x, y;
  1722. WAIT_FIFO(fb, 1);
  1723. pm2_WR(fb, PM2VR_RD_INDEX_HIGH, PM2VI_RD_CURSOR_PATTERN >> 8);
  1724. for (y = 0, i = 0; y < c->size.y; y++) {
  1725. WAIT_FIFO(fb, 32);
  1726. for (x = 0; x < c->size.x >> 3; x++) {
  1727. m = c->mask[x][y];
  1728. b = c->bits[x][y];
  1729. pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PATTERN + i,
  1730.      cursor_mask_lookup[m >> 4] |
  1731.      cursor_bits_lookup[(b & m) >> 4]);
  1732. pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PATTERN + i + 1,
  1733.      cursor_mask_lookup[m & 0x0f] |
  1734.      cursor_bits_lookup[(b & m) & 0x0f]);
  1735. i+=2;
  1736. }
  1737. for ( ; x < 8; x++) {
  1738. pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PATTERN + i, 0);
  1739. pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PATTERN + i + 1, 0);
  1740. i+=2;
  1741. }
  1742. }
  1743. for (; y < 64; y++) {
  1744. WAIT_FIFO(fb, 32);
  1745. for (x = 0; x < 8; x++) {
  1746. pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PATTERN + i, 0);
  1747. pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PATTERN + i + 1, 0);
  1748. i+=2;
  1749. }
  1750. }
  1751. WAIT_FIFO(fb, 1);
  1752. pm2_WR(fb, PM2VR_RD_INDEX_HIGH, 0);
  1753. }
  1754. static void pm2v_set_cursor(struct pm2fb_info *fb, int on)
  1755. {
  1756. struct pm2_cursor *c = fb->cursor;
  1757. int x = c->pos.x;
  1758. if (!on) x = 4000;
  1759. WAIT_FIFO(fb, 14);
  1760. pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_X_LOW, x & 0xff);
  1761. pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_X_HIGH, (x >> 8) & 0x0f);
  1762. pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_Y_LOW, c->pos.y & 0xff);
  1763. pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_Y_HIGH, (c->pos.y >> 8) & 0x0f);
  1764. pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_X_HOT, c->hot.x & 0x3f);
  1765. pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_Y_HOT, c->hot.y & 0x3f);
  1766. pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_MODE, 0x11);
  1767. }
  1768. static void pm2_cursor_timer_handler(unsigned long dev_addr)
  1769. {
  1770. struct pm2fb_info *fb = (struct pm2fb_info *)dev_addr;
  1771. if (!fb->cursor->enable)
  1772. goto out;
  1773. if (fb->cursor->vbl_cnt && --fb->cursor->vbl_cnt == 0) {
  1774. fb->cursor->on ^= 1;
  1775. pm2v_set_cursor(fb, fb->cursor->on);
  1776. fb->cursor->vbl_cnt = fb->cursor->blink_rate;
  1777. }
  1778. out:
  1779. fb->cursor->timer->expires = jiffies + (HZ / 50);
  1780. add_timer(fb->cursor->timer);
  1781. }
  1782. static void pm2fb_cursor(struct display *p, int mode, int x, int y)
  1783. {
  1784. struct pm2fb_info *fb = (struct pm2fb_info *)p->fb_info;
  1785. struct pm2_cursor *c = fb->cursor;
  1786. if (!c) return;
  1787. x *= fontwidth(p);
  1788. y *= fontheight(p);
  1789. if (c->pos.x == x && c->pos.y == y && (mode == CM_ERASE) == !c->enable)
  1790. return;
  1791. c->enable = 0;
  1792. if (c->on)
  1793. pm2v_set_cursor(fb, 0);
  1794. c->pos.x = x;
  1795. c->pos.y = y;
  1796. switch (mode) {
  1797. case CM_ERASE:
  1798. c->on = 0;
  1799. break;
  1800. case CM_DRAW:
  1801. case CM_MOVE:
  1802. if (c->on)
  1803. pm2v_set_cursor(fb, 1);
  1804. else
  1805. c->vbl_cnt = CURSOR_DRAW_DELAY;
  1806. c->enable = 1;
  1807. break;
  1808. }
  1809. }
  1810. static struct pm2_cursor * __init pm2_init_cursor(struct pm2fb_info *fb)
  1811. {
  1812. struct pm2_cursor *cursor;
  1813. if (fb->type != PM2_TYPE_PERMEDIA2V)
  1814. return 0; /* FIXME: Support hw cursor everywhere */
  1815. cursor = kmalloc(sizeof(struct pm2_cursor), GFP_ATOMIC);
  1816. if (!cursor)
  1817. return 0;
  1818. memset(cursor, 0, sizeof(*cursor));
  1819. cursor->timer = kmalloc(sizeof(*cursor->timer), GFP_KERNEL);
  1820. if (!cursor->timer) {
  1821. kfree(cursor);
  1822. return 0;
  1823. }
  1824. memset(cursor->timer, 0, sizeof(*cursor->timer));
  1825. cursor->blink_rate = DEFAULT_CURSOR_BLINK_RATE;
  1826. if (curblink) {
  1827. init_timer(cursor->timer);
  1828. cursor->timer->expires = jiffies + (HZ / 50);
  1829. cursor->timer->data = (unsigned long)fb;
  1830. cursor->timer->function = pm2_cursor_timer_handler;
  1831. add_timer(cursor->timer);
  1832. }
  1833. return cursor;
  1834. }
  1835. static int pm2fb_set_font(struct display *d, int width, int height)
  1836. {
  1837. struct pm2fb_info *fb = (struct pm2fb_info *)d->fb_info;
  1838. struct pm2_cursor *c = fb->cursor;
  1839. int i, j;
  1840. if (c) {
  1841. if (!width || !height) {
  1842. width = 8;
  1843. height = 16;
  1844. }
  1845. c->hot.x = 0;
  1846. c->hot.y = 0;
  1847. c->size.x = width;
  1848. c->size.y = height;
  1849. memset(c->bits, 0xff, sizeof(c->bits));
  1850. memset(c->mask, 0, sizeof(c->mask));
  1851. for (i = 0, j = width; j >= 0; j -= 8, i++) {
  1852. c->mask[i][height-2] = (j >= 8) ? 0xff : (0xff << (8 - j));
  1853. c->mask[i][height-1] = (j >= 8) ? 0xff : (0xff << (8 - j));
  1854. }
  1855. pm2v_set_cursor_color(fb, cursor_color_map, cursor_color_map, cursor_color_map);
  1856. pm2v_set_cursor_shape(fb);
  1857. }
  1858. return 1;
  1859. }
  1860. #endif /* PM2FB_HW_CURSOR */
  1861. /***************************************************************************
  1862.  * Begin of public functions
  1863.  ***************************************************************************/
  1864. #ifdef MODULE
  1865. static void pm2fb_cleanup(void) {
  1866. struct pm2fb_info* i = &fb_info;
  1867. unregister_framebuffer((struct fb_info *)i);
  1868. pm2fb_reset(i);
  1869. UNMAP(i->regions.v_fb, i->regions.fb_size);
  1870. release_mem_region(i->regions.p_fb, i->regions.fb_size);
  1871. UNMAP(i->regions.v_regs, PM2_REGS_SIZE);
  1872. release_mem_region(i->regions.p_regs, PM2_REGS_SIZE);
  1873. if (board_table[i->board].cleanup)
  1874. board_table[i->board].cleanup(i);
  1875. }
  1876. #endif /* MODULE */
  1877. int __init pm2fb_init(void){
  1878. MOD_INC_USE_COUNT;
  1879. memset(&fb_info, 0, sizeof(fb_info));
  1880. memcpy(&fb_info.current_par, &pm2fb_options.user_mode, sizeof(fb_info.current_par));
  1881. if (!pm2fb_conf(&fb_info)) {
  1882. MOD_DEC_USE_COUNT;
  1883. return -ENXIO;
  1884. }
  1885. pm2fb_reset(&fb_info);
  1886. fb_info.disp.scrollmode=SCROLL_YNOMOVE;
  1887. fb_info.gen.parsize=sizeof(struct pm2fb_par);
  1888. fb_info.gen.fbhw=&pm2fb_hwswitch;
  1889. strcpy(fb_info.gen.info.modename, permedia2_name);
  1890. fb_info.gen.info.flags=FBINFO_FLAG_DEFAULT;
  1891. fb_info.gen.info.fbops=&pm2fb_ops;
  1892. fb_info.gen.info.disp=&fb_info.disp;
  1893. strcpy(fb_info.gen.info.fontname, pm2fb_options.font);
  1894. fb_info.gen.info.switch_con=&fbgen_switch;
  1895. fb_info.gen.info.updatevar=&fbgen_update_var;
  1896. fb_info.gen.info.blank=&fbgen_blank;
  1897. fbgen_get_var(&fb_info.disp.var, -1, &fb_info.gen.info);
  1898. fbgen_do_set_var(&fb_info.disp.var, 1, &fb_info.gen);
  1899. fbgen_set_disp(-1, &fb_info.gen);
  1900. fbgen_install_cmap(0, &fb_info.gen);
  1901. if (register_framebuffer(&fb_info.gen.info)<0) {
  1902. printk(KERN_ERR "pm2fb: unable to register.n");
  1903. MOD_DEC_USE_COUNT;
  1904. return -EINVAL;
  1905. }
  1906. printk(KERN_INFO "fb%d: %s (%s), using %uK of video memory.n",
  1907. GET_FB_IDX(fb_info.gen.info.node),
  1908. board_table[fb_info.board].name,
  1909. permedia2_name,
  1910. (u32 )(fb_info.regions.fb_size>>10));
  1911. return 0;
  1912. }
  1913. static void __init pm2fb_mode_setup(char* options){
  1914. int i;
  1915. for (i=0; user_mode[i].name[0] &&
  1916. strcmp(options, user_mode[i].name); i++);
  1917. if (user_mode[i].name[0]) {
  1918. memcpy(&pm2fb_options.user_mode, &user_mode[i].par,
  1919. sizeof(pm2fb_options.user_mode));
  1920. pm2fb_options.flags |= OPTF_USER;
  1921. }
  1922. }
  1923. static void __init pm2fb_font_setup(char* options){
  1924. strncpy(pm2fb_options.font, options, sizeof(pm2fb_options.font));
  1925. pm2fb_options.font[sizeof(pm2fb_options.font)-1]='';
  1926. }
  1927. int __init pm2fb_setup(char* options){
  1928. char* next;
  1929. while (options) {
  1930. if ((next=strchr(options, ',')))
  1931. *(next++)='';
  1932. if (!strncmp(options, "font:", 5))
  1933. pm2fb_font_setup(options+5);
  1934. else if (!strncmp(options, "mode:", 5))
  1935. pm2fb_mode_setup(options+5);
  1936. else if (!strcmp(options, "ypan"))
  1937. pm2fb_options.flags |= OPTF_YPAN;
  1938. else if (!strcmp(options, "oldmem"))
  1939. pm2fb_options.flags |= OPTF_OLD_MEM;
  1940. else if (!strcmp(options, "virtual"))
  1941. pm2fb_options.flags |= OPTF_VIRTUAL;
  1942. else if (!strcmp(options, "noblink"))
  1943. curblink = 0;
  1944. options=next;
  1945. }
  1946. return 0;
  1947. }
  1948. /***************************************************************************
  1949.  * Begin of module functions
  1950.  ***************************************************************************/
  1951. #ifdef MODULE
  1952. MODULE_LICENSE("GPL");
  1953. static char *mode = NULL;
  1954. MODULE_PARM(mode, "s");
  1955. int __init init_module(void) {
  1956. if (mode) pm2fb_mode_setup(mode);
  1957. return pm2fb_init();
  1958. }
  1959. void cleanup_module(void) {
  1960. pm2fb_cleanup();
  1961. }
  1962. #endif /* MODULE */
  1963. /***************************************************************************
  1964.  * That's all folks!
  1965.  ***************************************************************************/