Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
stifb.c
Go to the documentation of this file.
1 /*
2  * linux/drivers/video/stifb.c -
3  * Low level Frame buffer driver for HP workstations with
4  * STI (standard text interface) video firmware.
5  *
6  * Copyright (C) 2001-2006 Helge Deller <[email protected]>
7  * Portions Copyright (C) 2001 Thomas Bogendoerfer <[email protected]>
8  *
9  * Based on:
10  * - linux/drivers/video/artistfb.c -- Artist frame buffer driver
11  * Copyright (C) 2000 Philipp Rumpf <[email protected]>
12  * - based on skeletonfb, which was
13  * Created 28 Dec 1997 by Geert Uytterhoeven
14  * - HP Xhp cfb-based X11 window driver for XFree86
15  * (c)Copyright 1992 Hewlett-Packard Co.
16  *
17  *
18  * The following graphics display devices (NGLE family) are supported by this driver:
19  *
20  * HPA4070A known as "HCRX", a 1280x1024 color device with 8 planes
21  * HPA4071A known as "HCRX24", a 1280x1024 color device with 24 planes,
22  * optionally available with a hardware accelerator as HPA4071A_Z
23  * HPA1659A known as "CRX", a 1280x1024 color device with 8 planes
24  * HPA1439A known as "CRX24", a 1280x1024 color device with 24 planes,
25  * optionally available with a hardware accelerator.
26  * HPA1924A known as "GRX", a 1280x1024 grayscale device with 8 planes
27  * HPA2269A known as "Dual CRX", a 1280x1024 color device with 8 planes,
28  * implements support for two displays on a single graphics card.
29  * HP710C internal graphics support optionally available on the HP9000s710 SPU,
30  * supports 1280x1024 color displays with 8 planes.
31  * HP710G same as HP710C, 1280x1024 grayscale only
32  * HP710L same as HP710C, 1024x768 color only
33  * HP712 internal graphics support on HP9000s712 SPU, supports 640x480,
34  * 1024x768 or 1280x1024 color displays on 8 planes (Artist)
35  *
36  * This file is subject to the terms and conditions of the GNU General Public
37  * License. See the file COPYING in the main directory of this archive
38  * for more details.
39  */
40 
41 /* TODO:
42  * - 1bpp mode is completely untested
43  * - add support for h/w acceleration
44  * - add hardware cursor
45  * - automatically disable double buffering (e.g. on RDI precisionbook laptop)
46  */
47 
48 
49 /* on supported graphic devices you may:
50  * #define FALLBACK_TO_1BPP to fall back to 1 bpp, or
51  * #undef FALLBACK_TO_1BPP to reject support for unsupported cards */
52 #undef FALLBACK_TO_1BPP
53 
54 #undef DEBUG_STIFB_REGS /* debug sti register accesses */
55 
56 
57 #include <linux/module.h>
58 #include <linux/kernel.h>
59 #include <linux/errno.h>
60 #include <linux/string.h>
61 #include <linux/mm.h>
62 #include <linux/slab.h>
63 #include <linux/delay.h>
64 #include <linux/fb.h>
65 #include <linux/init.h>
66 #include <linux/ioport.h>
67 
68 #include <asm/grfioctl.h> /* for HP-UX compatibility */
69 #include <asm/uaccess.h>
70 
71 #include "sticore.h"
72 
73 /* REGION_BASE(fb_info, index) returns the virtual address for region <index> */
74 #define REGION_BASE(fb_info, index) \
75  F_EXTEND(fb_info->sti->glob_cfg->region_ptrs[index])
76 
77 #define NGLEDEVDEPROM_CRT_REGION 1
78 
79 #define NR_PALETTE 256
80 
81 typedef struct {
93 
94 typedef struct {
96  __s16 x_size_visible; /* visible screen dim in pixels */
98  __s16 pad2[15];
101  __s32 pad3[11];
102 } ngle_rom_t;
103 
104 struct stifb_info {
105  struct fb_info info;
106  unsigned int id;
108  struct sti_struct *sti;
111 };
112 
113 static int __initdata stifb_bpp_pref[MAX_STI_ROMS];
114 
115 /* ------------------- chipset specific functions -------------------------- */
116 
117 /* offsets to graphic-chip internal registers */
118 
119 #define REG_1 0x000118
120 #define REG_2 0x000480
121 #define REG_3 0x0004a0
122 #define REG_4 0x000600
123 #define REG_6 0x000800
124 #define REG_8 0x000820
125 #define REG_9 0x000a04
126 #define REG_10 0x018000
127 #define REG_11 0x018004
128 #define REG_12 0x01800c
129 #define REG_13 0x018018
130 #define REG_14 0x01801c
131 #define REG_15 0x200000
132 #define REG_15b0 0x200000
133 #define REG_16b1 0x200005
134 #define REG_16b3 0x200007
135 #define REG_21 0x200218
136 #define REG_22 0x0005a0
137 #define REG_23 0x0005c0
138 #define REG_26 0x200118
139 #define REG_27 0x200308
140 #define REG_32 0x21003c
141 #define REG_33 0x210040
142 #define REG_34 0x200008
143 #define REG_35 0x018010
144 #define REG_38 0x210020
145 #define REG_39 0x210120
146 #define REG_40 0x210130
147 #define REG_42 0x210028
148 #define REG_43 0x21002c
149 #define REG_44 0x210030
150 #define REG_45 0x210034
151 
152 #define READ_BYTE(fb,reg) gsc_readb((fb)->info.fix.mmio_start + (reg))
153 #define READ_WORD(fb,reg) gsc_readl((fb)->info.fix.mmio_start + (reg))
154 
155 
156 #ifndef DEBUG_STIFB_REGS
157 # define DEBUG_OFF()
158 # define DEBUG_ON()
159 # define WRITE_BYTE(value,fb,reg) gsc_writeb((value),(fb)->info.fix.mmio_start + (reg))
160 # define WRITE_WORD(value,fb,reg) gsc_writel((value),(fb)->info.fix.mmio_start + (reg))
161 #else
162  static int debug_on = 1;
163 # define DEBUG_OFF() debug_on=0
164 # define DEBUG_ON() debug_on=1
165 # define WRITE_BYTE(value,fb,reg) do { if (debug_on) \
166  printk(KERN_DEBUG "%30s: WRITE_BYTE(0x%06x) = 0x%02x (old=0x%02x)\n", \
167  __func__, reg, value, READ_BYTE(fb,reg)); \
168  gsc_writeb((value),(fb)->info.fix.mmio_start + (reg)); } while (0)
169 # define WRITE_WORD(value,fb,reg) do { if (debug_on) \
170  printk(KERN_DEBUG "%30s: WRITE_WORD(0x%06x) = 0x%08x (old=0x%08x)\n", \
171  __func__, reg, value, READ_WORD(fb,reg)); \
172  gsc_writel((value),(fb)->info.fix.mmio_start + (reg)); } while (0)
173 #endif /* DEBUG_STIFB_REGS */
174 
175 
176 #define ENABLE 1 /* for enabling/disabling screen */
177 #define DISABLE 0
178 
179 #define NGLE_LOCK(fb_info) do { } while (0)
180 #define NGLE_UNLOCK(fb_info) do { } while (0)
181 
182 static void
183 SETUP_HW(struct stifb_info *fb)
184 {
185  char stat;
186 
187  do {
188  stat = READ_BYTE(fb, REG_15b0);
189  if (!stat)
190  stat = READ_BYTE(fb, REG_15b0);
191  } while (stat);
192 }
193 
194 
195 static void
196 SETUP_FB(struct stifb_info *fb)
197 {
198  unsigned int reg10_value = 0;
199 
200  SETUP_HW(fb);
201  switch (fb->id)
202  {
203  case CRT_ID_VISUALIZE_EG:
204  case S9000_ID_ARTIST:
205  case S9000_ID_A1659A:
206  reg10_value = 0x13601000;
207  break;
208  case S9000_ID_A1439A:
209  if (fb->info.var.bits_per_pixel == 32)
210  reg10_value = 0xBBA0A000;
211  else
212  reg10_value = 0x13601000;
213  break;
214  case S9000_ID_HCRX:
215  if (fb->info.var.bits_per_pixel == 32)
216  reg10_value = 0xBBA0A000;
217  else
218  reg10_value = 0x13602000;
219  break;
220  case S9000_ID_TIMBER:
222  reg10_value = 0x13602000;
223  break;
224  }
225  if (reg10_value)
226  WRITE_WORD(reg10_value, fb, REG_10);
227  WRITE_WORD(0x83000300, fb, REG_14);
228  SETUP_HW(fb);
229  WRITE_BYTE(1, fb, REG_16b1);
230 }
231 
232 static void
233 START_IMAGE_COLORMAP_ACCESS(struct stifb_info *fb)
234 {
235  SETUP_HW(fb);
236  WRITE_WORD(0xBBE0F000, fb, REG_10);
237  WRITE_WORD(0x03000300, fb, REG_14);
238  WRITE_WORD(~0, fb, REG_13);
239 }
240 
241 static void
242 WRITE_IMAGE_COLOR(struct stifb_info *fb, int index, int color)
243 {
244  SETUP_HW(fb);
245  WRITE_WORD(((0x100+index)<<2), fb, REG_3);
246  WRITE_WORD(color, fb, REG_4);
247 }
248 
249 static void
250 FINISH_IMAGE_COLORMAP_ACCESS(struct stifb_info *fb)
251 {
252  WRITE_WORD(0x400, fb, REG_2);
253  if (fb->info.var.bits_per_pixel == 32) {
254  WRITE_WORD(0x83000100, fb, REG_1);
255  } else {
256  if (fb->id == S9000_ID_ARTIST || fb->id == CRT_ID_VISUALIZE_EG)
257  WRITE_WORD(0x80000100, fb, REG_26);
258  else
259  WRITE_WORD(0x80000100, fb, REG_1);
260  }
261  SETUP_FB(fb);
262 }
263 
264 static void
265 SETUP_RAMDAC(struct stifb_info *fb)
266 {
267  SETUP_HW(fb);
268  WRITE_WORD(0x04000000, fb, 0x1020);
269  WRITE_WORD(0xff000000, fb, 0x1028);
270 }
271 
272 static void
273 CRX24_SETUP_RAMDAC(struct stifb_info *fb)
274 {
275  SETUP_HW(fb);
276  WRITE_WORD(0x04000000, fb, 0x1000);
277  WRITE_WORD(0x02000000, fb, 0x1004);
278  WRITE_WORD(0xff000000, fb, 0x1008);
279  WRITE_WORD(0x05000000, fb, 0x1000);
280  WRITE_WORD(0x02000000, fb, 0x1004);
281  WRITE_WORD(0x03000000, fb, 0x1008);
282 }
283 
284 #if 0
285 static void
286 HCRX_SETUP_RAMDAC(struct stifb_info *fb)
287 {
288  WRITE_WORD(0xffffffff, fb, REG_32);
289 }
290 #endif
291 
292 static void
293 CRX24_SET_OVLY_MASK(struct stifb_info *fb)
294 {
295  SETUP_HW(fb);
296  WRITE_WORD(0x13a02000, fb, REG_11);
297  WRITE_WORD(0x03000300, fb, REG_14);
298  WRITE_WORD(0x000017f0, fb, REG_3);
299  WRITE_WORD(0xffffffff, fb, REG_13);
300  WRITE_WORD(0xffffffff, fb, REG_22);
301  WRITE_WORD(0x00000000, fb, REG_23);
302 }
303 
304 static void
305 ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
306 {
307  unsigned int value = enable ? 0x43000000 : 0x03000000;
308  SETUP_HW(fb);
309  WRITE_WORD(0x06000000, fb, 0x1030);
310  WRITE_WORD(value, fb, 0x1038);
311 }
312 
313 static void
314 CRX24_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
315 {
316  unsigned int value = enable ? 0x10000000 : 0x30000000;
317  SETUP_HW(fb);
318  WRITE_WORD(0x01000000, fb, 0x1000);
319  WRITE_WORD(0x02000000, fb, 0x1004);
320  WRITE_WORD(value, fb, 0x1008);
321 }
322 
323 static void
324 ARTIST_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
325 {
326  u32 DregsMiscVideo = REG_21;
327  u32 DregsMiscCtl = REG_27;
328 
329  SETUP_HW(fb);
330  if (enable) {
331  WRITE_WORD(READ_WORD(fb, DregsMiscVideo) | 0x0A000000, fb, DregsMiscVideo);
332  WRITE_WORD(READ_WORD(fb, DregsMiscCtl) | 0x00800000, fb, DregsMiscCtl);
333  } else {
334  WRITE_WORD(READ_WORD(fb, DregsMiscVideo) & ~0x0A000000, fb, DregsMiscVideo);
335  WRITE_WORD(READ_WORD(fb, DregsMiscCtl) & ~0x00800000, fb, DregsMiscCtl);
336  }
337 }
338 
339 #define GET_ROMTABLE_INDEX(fb) \
340  (READ_BYTE(fb, REG_16b3) - 1)
341 
342 #define HYPER_CONFIG_PLANES_24 0x00000100
343 
344 #define IS_24_DEVICE(fb) \
345  (fb->deviceSpecificConfig & HYPER_CONFIG_PLANES_24)
346 
347 #define IS_888_DEVICE(fb) \
348  (!(IS_24_DEVICE(fb)))
349 
350 #define GET_FIFO_SLOTS(fb, cnt, numslots) \
351 { while (cnt < numslots) \
352  cnt = READ_WORD(fb, REG_34); \
353  cnt -= numslots; \
354 }
355 
356 #define IndexedDcd 0 /* Pixel data is indexed (pseudo) color */
357 #define Otc04 2 /* Pixels in each longword transfer (4) */
358 #define Otc32 5 /* Pixels in each longword transfer (32) */
359 #define Ots08 3 /* Each pixel is size (8)d transfer (1) */
360 #define OtsIndirect 6 /* Each bit goes through FG/BG color(8) */
361 #define AddrLong 5 /* FB address is Long aligned (pixel) */
362 #define BINovly 0x2 /* 8 bit overlay */
363 #define BINapp0I 0x0 /* Application Buffer 0, Indexed */
364 #define BINapp1I 0x1 /* Application Buffer 1, Indexed */
365 #define BINapp0F8 0xa /* Application Buffer 0, Fractional 8-8-8 */
366 #define BINattr 0xd /* Attribute Bitmap */
367 #define RopSrc 0x3
368 #define BitmapExtent08 3 /* Each write hits ( 8) bits in depth */
369 #define BitmapExtent32 5 /* Each write hits (32) bits in depth */
370 #define DataDynamic 0 /* Data register reloaded by direct access */
371 #define MaskDynamic 1 /* Mask register reloaded by direct access */
372 #define MaskOtc 0 /* Mask contains Object Count valid bits */
373 
374 #define MaskAddrOffset(offset) (offset)
375 #define StaticReg(en) (en)
376 #define BGx(en) (en)
377 #define FGx(en) (en)
378 
379 #define BAJustPoint(offset) (offset)
380 #define BAIndexBase(base) (base)
381 #define BA(F,C,S,A,J,B,I) \
382  (((F)<<31)|((C)<<27)|((S)<<24)|((A)<<21)|((J)<<16)|((B)<<12)|(I))
383 
384 #define IBOvals(R,M,X,S,D,L,B,F) \
385  (((R)<<8)|((M)<<16)|((X)<<24)|((S)<<29)|((D)<<28)|((L)<<31)|((B)<<1)|(F))
386 
387 #define NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb, val) \
388  WRITE_WORD(val, fb, REG_14)
389 
390 #define NGLE_QUICK_SET_DST_BM_ACCESS(fb, val) \
391  WRITE_WORD(val, fb, REG_11)
392 
393 #define NGLE_QUICK_SET_CTL_PLN_REG(fb, val) \
394  WRITE_WORD(val, fb, REG_12)
395 
396 #define NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, plnmsk32) \
397  WRITE_WORD(plnmsk32, fb, REG_13)
398 
399 #define NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, fg32) \
400  WRITE_WORD(fg32, fb, REG_35)
401 
402 #define NGLE_SET_TRANSFERDATA(fb, val) \
403  WRITE_WORD(val, fb, REG_8)
404 
405 #define NGLE_SET_DSTXY(fb, val) \
406  WRITE_WORD(val, fb, REG_6)
407 
408 #define NGLE_LONG_FB_ADDRESS(fbaddrbase, x, y) ( \
409  (u32) (fbaddrbase) + \
410  ( (unsigned int) ( (y) << 13 ) | \
411  (unsigned int) ( (x) << 2 ) ) \
412  )
413 
414 #define NGLE_BINC_SET_DSTADDR(fb, addr) \
415  WRITE_WORD(addr, fb, REG_3)
416 
417 #define NGLE_BINC_SET_SRCADDR(fb, addr) \
418  WRITE_WORD(addr, fb, REG_2)
419 
420 #define NGLE_BINC_SET_DSTMASK(fb, mask) \
421  WRITE_WORD(mask, fb, REG_22)
422 
423 #define NGLE_BINC_WRITE32(fb, data32) \
424  WRITE_WORD(data32, fb, REG_23)
425 
426 #define START_COLORMAPLOAD(fb, cmapBltCtlData32) \
427  WRITE_WORD((cmapBltCtlData32), fb, REG_38)
428 
429 #define SET_LENXY_START_RECFILL(fb, lenxy) \
430  WRITE_WORD(lenxy, fb, REG_9)
431 
432 static void
433 HYPER_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
434 {
435  u32 DregsHypMiscVideo = REG_33;
436  unsigned int value;
437  SETUP_HW(fb);
438  value = READ_WORD(fb, DregsHypMiscVideo);
439  if (enable)
440  value |= 0x0A000000;
441  else
442  value &= ~0x0A000000;
443  WRITE_WORD(value, fb, DregsHypMiscVideo);
444 }
445 
446 
447 /* BufferNumbers used by SETUP_ATTR_ACCESS() */
448 #define BUFF0_CMAP0 0x00001e02
449 #define BUFF1_CMAP0 0x02001e02
450 #define BUFF1_CMAP3 0x0c001e02
451 #define ARTIST_CMAP0 0x00000102
452 #define HYPER_CMAP8 0x00000100
453 #define HYPER_CMAP24 0x00000800
454 
455 static void
456 SETUP_ATTR_ACCESS(struct stifb_info *fb, unsigned BufferNumber)
457 {
458  SETUP_HW(fb);
459  WRITE_WORD(0x2EA0D000, fb, REG_11);
460  WRITE_WORD(0x23000302, fb, REG_14);
461  WRITE_WORD(BufferNumber, fb, REG_12);
462  WRITE_WORD(0xffffffff, fb, REG_8);
463 }
464 
465 static void
466 SET_ATTR_SIZE(struct stifb_info *fb, int width, int height)
467 {
468  /* REG_6 seems to have special values when run on a
469  RDI precisionbook parisc laptop (INTERNAL_EG_DX1024 or
470  INTERNAL_EG_X1024). The values are:
471  0x2f0: internal (LCD) & external display enabled
472  0x2a0: external display only
473  0x000: zero on standard artist graphic cards
474  */
475  WRITE_WORD(0x00000000, fb, REG_6);
476  WRITE_WORD((width<<16) | height, fb, REG_9);
477  WRITE_WORD(0x05000000, fb, REG_6);
478  WRITE_WORD(0x00040001, fb, REG_9);
479 }
480 
481 static void
482 FINISH_ATTR_ACCESS(struct stifb_info *fb)
483 {
484  SETUP_HW(fb);
485  WRITE_WORD(0x00000000, fb, REG_12);
486 }
487 
488 static void
489 elkSetupPlanes(struct stifb_info *fb)
490 {
491  SETUP_RAMDAC(fb);
492  SETUP_FB(fb);
493 }
494 
495 static void
496 ngleSetupAttrPlanes(struct stifb_info *fb, int BufferNumber)
497 {
498  SETUP_ATTR_ACCESS(fb, BufferNumber);
499  SET_ATTR_SIZE(fb, fb->info.var.xres, fb->info.var.yres);
500  FINISH_ATTR_ACCESS(fb);
501  SETUP_FB(fb);
502 }
503 
504 
505 static void
506 rattlerSetupPlanes(struct stifb_info *fb)
507 {
508  int saved_id, y;
509 
510  /* Write RAMDAC pixel read mask register so all overlay
511  * planes are display-enabled. (CRX24 uses Bt462 pixel
512  * read mask register for overlay planes, not image planes).
513  */
514  CRX24_SETUP_RAMDAC(fb);
515 
516  /* change fb->id temporarily to fool SETUP_FB() */
517  saved_id = fb->id;
518  fb->id = CRX24_OVERLAY_PLANES;
519  SETUP_FB(fb);
520  fb->id = saved_id;
521 
522  for (y = 0; y < fb->info.var.yres; ++y)
523  memset(fb->info.screen_base + y * fb->info.fix.line_length,
524  0xff, fb->info.var.xres * fb->info.var.bits_per_pixel/8);
525 
526  CRX24_SET_OVLY_MASK(fb);
527  SETUP_FB(fb);
528 }
529 
530 
531 #define HYPER_CMAP_TYPE 0
532 #define NGLE_CMAP_INDEXED0_TYPE 0
533 #define NGLE_CMAP_OVERLAY_TYPE 3
534 
535 /* typedef of LUT (Colormap) BLT Control Register */
536 typedef union /* Note assumption that fields are packed left-to-right */
538  struct
539  {
540  unsigned enable : 1;
541  unsigned waitBlank : 1;
542  unsigned reserved1 : 4;
543  unsigned lutOffset : 10; /* Within destination LUT */
544  unsigned lutType : 2; /* Cursor, image, overlay */
545  unsigned reserved2 : 4;
546  unsigned length : 10;
547  } fields;
548 } NgleLutBltCtl;
549 
550 
551 #if 0
552 static NgleLutBltCtl
553 setNgleLutBltCtl(struct stifb_info *fb, int offsetWithinLut, int length)
554 {
555  NgleLutBltCtl lutBltCtl;
556 
557  /* set enable, zero reserved fields */
558  lutBltCtl.all = 0x80000000;
559  lutBltCtl.fields.length = length;
560 
561  switch (fb->id)
562  {
563  case S9000_ID_A1439A: /* CRX24 */
564  if (fb->var.bits_per_pixel == 8) {
565  lutBltCtl.fields.lutType = NGLE_CMAP_OVERLAY_TYPE;
566  lutBltCtl.fields.lutOffset = 0;
567  } else {
568  lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;
569  lutBltCtl.fields.lutOffset = 0 * 256;
570  }
571  break;
572 
573  case S9000_ID_ARTIST:
574  lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;
575  lutBltCtl.fields.lutOffset = 0 * 256;
576  break;
577 
578  default:
579  lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;
580  lutBltCtl.fields.lutOffset = 0;
581  break;
582  }
583 
584  /* Offset points to start of LUT. Adjust for within LUT */
585  lutBltCtl.fields.lutOffset += offsetWithinLut;
586 
587  return lutBltCtl;
588 }
589 #endif
590 
591 static NgleLutBltCtl
592 setHyperLutBltCtl(struct stifb_info *fb, int offsetWithinLut, int length)
593 {
594  NgleLutBltCtl lutBltCtl;
595 
596  /* set enable, zero reserved fields */
597  lutBltCtl.all = 0x80000000;
598 
599  lutBltCtl.fields.length = length;
600  lutBltCtl.fields.lutType = HYPER_CMAP_TYPE;
601 
602  /* Expect lutIndex to be 0 or 1 for image cmaps, 2 or 3 for overlay cmaps */
603  if (fb->info.var.bits_per_pixel == 8)
604  lutBltCtl.fields.lutOffset = 2 * 256;
605  else
606  lutBltCtl.fields.lutOffset = 0 * 256;
607 
608  /* Offset points to start of LUT. Adjust for within LUT */
609  lutBltCtl.fields.lutOffset += offsetWithinLut;
610 
611  return lutBltCtl;
612 }
613 
614 
615 static void hyperUndoITE(struct stifb_info *fb)
616 {
617  int nFreeFifoSlots = 0;
618  u32 fbAddr;
619 
620  NGLE_LOCK(fb);
621 
622  GET_FIFO_SLOTS(fb, nFreeFifoSlots, 1);
623  WRITE_WORD(0xffffffff, fb, REG_32);
624 
625  /* Write overlay transparency mask so only entry 255 is transparent */
626 
627  /* Hardware setup for full-depth write to "magic" location */
628  GET_FIFO_SLOTS(fb, nFreeFifoSlots, 7);
631  BAJustPoint(0), BINovly, BAIndexBase(0)));
635  DataDynamic, MaskOtc, BGx(0), FGx(0)));
636 
637  /* Now prepare to write to the "magic" location */
638  fbAddr = NGLE_LONG_FB_ADDRESS(0, 1532, 0);
639  NGLE_BINC_SET_DSTADDR(fb, fbAddr);
640  NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xffffff);
641  NGLE_BINC_SET_DSTMASK(fb, 0xffffffff);
642 
643  /* Finally, write a zero to clear the mask */
644  NGLE_BINC_WRITE32(fb, 0);
645 
646  NGLE_UNLOCK(fb);
647 }
648 
649 static void
650 ngleDepth8_ClearImagePlanes(struct stifb_info *fb)
651 {
652  /* FIXME! */
653 }
654 
655 static void
656 ngleDepth24_ClearImagePlanes(struct stifb_info *fb)
657 {
658  /* FIXME! */
659 }
660 
661 static void
662 ngleResetAttrPlanes(struct stifb_info *fb, unsigned int ctlPlaneReg)
663 {
664  int nFreeFifoSlots = 0;
665  u32 packed_dst;
666  u32 packed_len;
667 
668  NGLE_LOCK(fb);
669 
670  GET_FIFO_SLOTS(fb, nFreeFifoSlots, 4);
673  AddrLong, BAJustPoint(0),
674  BINattr, BAIndexBase(0)));
675  NGLE_QUICK_SET_CTL_PLN_REG(fb, ctlPlaneReg);
676  NGLE_SET_TRANSFERDATA(fb, 0xffffffff);
677 
682  BGx(0), FGx(0)));
683  packed_dst = 0;
684  packed_len = (fb->info.var.xres << 16) | fb->info.var.yres;
685  GET_FIFO_SLOTS(fb, nFreeFifoSlots, 2);
686  NGLE_SET_DSTXY(fb, packed_dst);
687  SET_LENXY_START_RECFILL(fb, packed_len);
688 
689  /*
690  * In order to work around an ELK hardware problem (Buffy doesn't
691  * always flush it's buffers when writing to the attribute
692  * planes), at least 4 pixels must be written to the attribute
693  * planes starting at (X == 1280) and (Y != to the last Y written
694  * by BIF):
695  */
696 
697  if (fb->id == S9000_ID_A1659A) { /* ELK_DEVICE_ID */
698  /* It's safe to use scanline zero: */
699  packed_dst = (1280 << 16);
700  GET_FIFO_SLOTS(fb, nFreeFifoSlots, 2);
701  NGLE_SET_DSTXY(fb, packed_dst);
702  packed_len = (4 << 16) | 1;
703  SET_LENXY_START_RECFILL(fb, packed_len);
704  } /* ELK Hardware Kludge */
705 
706  /**** Finally, set the Control Plane Register back to zero: ****/
707  GET_FIFO_SLOTS(fb, nFreeFifoSlots, 1);
709 
710  NGLE_UNLOCK(fb);
711 }
712 
713 static void
714 ngleClearOverlayPlanes(struct stifb_info *fb, int mask, int data)
715 {
716  int nFreeFifoSlots = 0;
717  u32 packed_dst;
718  u32 packed_len;
719 
720  NGLE_LOCK(fb);
721 
722  /* Hardware setup */
723  GET_FIFO_SLOTS(fb, nFreeFifoSlots, 8);
726  BAJustPoint(0), BINovly, BAIndexBase(0)));
727 
728  NGLE_SET_TRANSFERDATA(fb, 0xffffffff); /* Write foreground color */
729 
732 
733  packed_dst = 0;
734  packed_len = (fb->info.var.xres << 16) | fb->info.var.yres;
735  NGLE_SET_DSTXY(fb, packed_dst);
736 
737  /* Write zeroes to overlay planes */
741  DataDynamic, MaskOtc, BGx(0), FGx(0)));
742 
743  SET_LENXY_START_RECFILL(fb, packed_len);
744 
745  NGLE_UNLOCK(fb);
746 }
747 
748 static void
749 hyperResetPlanes(struct stifb_info *fb, int enable)
750 {
751  unsigned int controlPlaneReg;
752 
753  NGLE_LOCK(fb);
754 
755  if (IS_24_DEVICE(fb))
756  if (fb->info.var.bits_per_pixel == 32)
757  controlPlaneReg = 0x04000F00;
758  else
759  controlPlaneReg = 0x00000F00; /* 0x00000800 should be enough, but lets clear all 4 bits */
760  else
761  controlPlaneReg = 0x00000F00; /* 0x00000100 should be enough, but lets clear all 4 bits */
762 
763  switch (enable) {
764  case ENABLE:
765  /* clear screen */
766  if (IS_24_DEVICE(fb))
767  ngleDepth24_ClearImagePlanes(fb);
768  else
769  ngleDepth8_ClearImagePlanes(fb);
770 
771  /* Paint attribute planes for default case.
772  * On Hyperdrive, this means all windows using overlay cmap 0. */
773  ngleResetAttrPlanes(fb, controlPlaneReg);
774 
775  /* clear overlay planes */
776  ngleClearOverlayPlanes(fb, 0xff, 255);
777 
778  /**************************************************
779  ** Also need to counteract ITE settings
780  **************************************************/
781  hyperUndoITE(fb);
782  break;
783 
784  case DISABLE:
785  /* clear screen */
786  if (IS_24_DEVICE(fb))
787  ngleDepth24_ClearImagePlanes(fb);
788  else
789  ngleDepth8_ClearImagePlanes(fb);
790  ngleResetAttrPlanes(fb, controlPlaneReg);
791  ngleClearOverlayPlanes(fb, 0xff, 0);
792  break;
793 
794  case -1: /* RESET */
795  hyperUndoITE(fb);
796  ngleResetAttrPlanes(fb, controlPlaneReg);
797  break;
798  }
799 
800  NGLE_UNLOCK(fb);
801 }
802 
803 /* Return pointer to in-memory structure holding ELK device-dependent ROM values. */
804 
805 static void
806 ngleGetDeviceRomData(struct stifb_info *fb)
807 {
808 #if 0
809 XXX: FIXME: !!!
810  int *pBytePerLongDevDepData;/* data byte == LSB */
811  int *pRomTable;
812  NgleDevRomData *pPackedDevRomData;
813  int sizePackedDevRomData = sizeof(*pPackedDevRomData);
814  char *pCard8;
815  int i;
816  char *mapOrigin = NULL;
817 
818  int romTableIdx;
819 
820  pPackedDevRomData = fb->ngle_rom;
821 
822  SETUP_HW(fb);
823  if (fb->id == S9000_ID_ARTIST) {
824  pPackedDevRomData->cursor_pipeline_delay = 4;
825  pPackedDevRomData->video_interleaves = 4;
826  } else {
827  /* Get pointer to unpacked byte/long data in ROM */
828  pBytePerLongDevDepData = fb->sti->regions[NGLEDEVDEPROM_CRT_REGION];
829 
830  /* Tomcat supports several resolutions: 1280x1024, 1024x768, 640x480 */
831  if (fb->id == S9000_ID_TOMCAT)
832  {
833  /* jump to the correct ROM table */
834  GET_ROMTABLE_INDEX(romTableIdx);
835  while (romTableIdx > 0)
836  {
837  pCard8 = (Card8 *) pPackedDevRomData;
838  pRomTable = pBytePerLongDevDepData;
839  /* Pack every fourth byte from ROM into structure */
840  for (i = 0; i < sizePackedDevRomData; i++)
841  {
842  *pCard8++ = (Card8) (*pRomTable++);
843  }
844 
845  pBytePerLongDevDepData = (Card32 *)
846  ((Card8 *) pBytePerLongDevDepData +
847  pPackedDevRomData->sizeof_ngle_data);
848 
849  romTableIdx--;
850  }
851  }
852 
853  pCard8 = (Card8 *) pPackedDevRomData;
854 
855  /* Pack every fourth byte from ROM into structure */
856  for (i = 0; i < sizePackedDevRomData; i++)
857  {
858  *pCard8++ = (Card8) (*pBytePerLongDevDepData++);
859  }
860  }
861 
862  SETUP_FB(fb);
863 #endif
864 }
865 
866 
867 #define HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES 4
868 #define HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE 8
869 #define HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE 10
870 #define HYPERBOWL_MODE2_8_24 15
871 
872 /* HCRX specific boot-time initialization */
873 static void __init
874 SETUP_HCRX(struct stifb_info *fb)
875 {
876  int hyperbowl;
877  int nFreeFifoSlots = 0;
878 
879  if (fb->id != S9000_ID_HCRX)
880  return;
881 
882  /* Initialize Hyperbowl registers */
883  GET_FIFO_SLOTS(fb, nFreeFifoSlots, 7);
884 
885  if (IS_24_DEVICE(fb)) {
886  hyperbowl = (fb->info.var.bits_per_pixel == 32) ?
889 
890  /* First write to Hyperbowl must happen twice (bug) */
891  WRITE_WORD(hyperbowl, fb, REG_40);
892  WRITE_WORD(hyperbowl, fb, REG_40);
893 
895 
896  WRITE_WORD(0x014c0148, fb, REG_42); /* Set lut 0 to be the direct color */
897  WRITE_WORD(0x404c4048, fb, REG_43);
898  WRITE_WORD(0x034c0348, fb, REG_44);
899  WRITE_WORD(0x444c4448, fb, REG_45);
900  } else {
902 
903  /* First write to Hyperbowl must happen twice (bug) */
904  WRITE_WORD(hyperbowl, fb, REG_40);
905  WRITE_WORD(hyperbowl, fb, REG_40);
906 
907  WRITE_WORD(0x00000000, fb, REG_42);
908  WRITE_WORD(0x00000000, fb, REG_43);
909  WRITE_WORD(0x00000000, fb, REG_44);
910  WRITE_WORD(0x444c4048, fb, REG_45);
911  }
912 }
913 
914 
915 /* ------------------- driver specific functions --------------------------- */
916 
917 static int
918 stifb_setcolreg(u_int regno, u_int red, u_int green,
919  u_int blue, u_int transp, struct fb_info *info)
920 {
921  struct stifb_info *fb = (struct stifb_info *) info;
922  u32 color;
923 
924  if (regno >= NR_PALETTE)
925  return 1;
926 
927  red >>= 8;
928  green >>= 8;
929  blue >>= 8;
930 
931  DEBUG_OFF();
932 
933  START_IMAGE_COLORMAP_ACCESS(fb);
934 
935  if (unlikely(fb->info.var.grayscale)) {
936  /* gray = 0.30*R + 0.59*G + 0.11*B */
937  color = ((red * 77) +
938  (green * 151) +
939  (blue * 28)) >> 8;
940  } else {
941  color = ((red << 16) |
942  (green << 8) |
943  (blue));
944  }
945 
946  if (fb->info.fix.visual == FB_VISUAL_DIRECTCOLOR) {
947  struct fb_var_screeninfo *var = &fb->info.var;
948  if (regno < 16)
949  ((u32 *)fb->info.pseudo_palette)[regno] =
950  regno << var->red.offset |
951  regno << var->green.offset |
952  regno << var->blue.offset;
953  }
954 
955  WRITE_IMAGE_COLOR(fb, regno, color);
956 
957  if (fb->id == S9000_ID_HCRX) {
958  NgleLutBltCtl lutBltCtl;
959 
960  lutBltCtl = setHyperLutBltCtl(fb,
961  0, /* Offset w/i LUT */
962  256); /* Load entire LUT */
964  NGLE_LONG_FB_ADDRESS(0, 0x100, 0));
965  /* 0x100 is same as used in WRITE_IMAGE_COLOR() */
966  START_COLORMAPLOAD(fb, lutBltCtl.all);
967  SETUP_FB(fb);
968  } else {
969  /* cleanup colormap hardware */
970  FINISH_IMAGE_COLORMAP_ACCESS(fb);
971  }
972 
973  DEBUG_ON();
974 
975  return 0;
976 }
977 
978 static int
979 stifb_blank(int blank_mode, struct fb_info *info)
980 {
981  struct stifb_info *fb = (struct stifb_info *) info;
982  int enable = (blank_mode == 0) ? ENABLE : DISABLE;
983 
984  switch (fb->id) {
985  case S9000_ID_A1439A:
986  CRX24_ENABLE_DISABLE_DISPLAY(fb, enable);
987  break;
988  case CRT_ID_VISUALIZE_EG:
989  case S9000_ID_ARTIST:
990  ARTIST_ENABLE_DISABLE_DISPLAY(fb, enable);
991  break;
992  case S9000_ID_HCRX:
993  HYPER_ENABLE_DISABLE_DISPLAY(fb, enable);
994  break;
995  case S9000_ID_A1659A: /* fall through */
996  case S9000_ID_TIMBER:
998  default:
999  ENABLE_DISABLE_DISPLAY(fb, enable);
1000  break;
1001  }
1002 
1003  SETUP_FB(fb);
1004  return 0;
1005 }
1006 
1007 static void __init
1008 stifb_init_display(struct stifb_info *fb)
1009 {
1010  int id = fb->id;
1011 
1012  SETUP_FB(fb);
1013 
1014  /* HCRX specific initialization */
1015  SETUP_HCRX(fb);
1016 
1017  /*
1018  if (id == S9000_ID_HCRX)
1019  hyperInitSprite(fb);
1020  else
1021  ngleInitSprite(fb);
1022  */
1023 
1024  /* Initialize the image planes. */
1025  switch (id) {
1026  case S9000_ID_HCRX:
1027  hyperResetPlanes(fb, ENABLE);
1028  break;
1029  case S9000_ID_A1439A:
1030  rattlerSetupPlanes(fb);
1031  break;
1032  case S9000_ID_A1659A:
1033  case S9000_ID_ARTIST:
1034  case CRT_ID_VISUALIZE_EG:
1035  elkSetupPlanes(fb);
1036  break;
1037  }
1038 
1039  /* Clear attribute planes on non HCRX devices. */
1040  switch (id) {
1041  case S9000_ID_A1659A:
1042  case S9000_ID_A1439A:
1043  if (fb->info.var.bits_per_pixel == 32)
1044  ngleSetupAttrPlanes(fb, BUFF1_CMAP3);
1045  else {
1046  ngleSetupAttrPlanes(fb, BUFF1_CMAP0);
1047  }
1048  if (id == S9000_ID_A1439A)
1049  ngleClearOverlayPlanes(fb, 0xff, 0);
1050  break;
1051  case S9000_ID_ARTIST:
1052  case CRT_ID_VISUALIZE_EG:
1053  if (fb->info.var.bits_per_pixel == 32)
1054  ngleSetupAttrPlanes(fb, BUFF1_CMAP3);
1055  else {
1056  ngleSetupAttrPlanes(fb, ARTIST_CMAP0);
1057  }
1058  break;
1059  }
1060  stifb_blank(0, (struct fb_info *)fb); /* 0=enable screen */
1061 
1062  SETUP_FB(fb);
1063 }
1064 
1065 /* ------------ Interfaces to hardware functions ------------ */
1066 
1067 static struct fb_ops stifb_ops = {
1068  .owner = THIS_MODULE,
1069  .fb_setcolreg = stifb_setcolreg,
1070  .fb_blank = stifb_blank,
1071  .fb_fillrect = cfb_fillrect,
1072  .fb_copyarea = cfb_copyarea,
1073  .fb_imageblit = cfb_imageblit,
1074 };
1075 
1076 
1077 /*
1078  * Initialization
1079  */
1080 
1081 static int __init stifb_init_fb(struct sti_struct *sti, int bpp_pref)
1082 {
1083  struct fb_fix_screeninfo *fix;
1084  struct fb_var_screeninfo *var;
1085  struct stifb_info *fb;
1086  struct fb_info *info;
1087  unsigned long sti_rom_address;
1088  char *dev_name;
1089  int bpp, xres, yres;
1090 
1091  fb = kzalloc(sizeof(*fb), GFP_ATOMIC);
1092  if (!fb) {
1093  printk(KERN_ERR "stifb: Could not allocate stifb structure\n");
1094  return -ENODEV;
1095  }
1096 
1097  info = &fb->info;
1098 
1099  /* set struct to a known state */
1100  fix = &info->fix;
1101  var = &info->var;
1102 
1103  fb->sti = sti;
1104  /* store upper 32bits of the graphics id */
1105  fb->id = fb->sti->graphics_id[0];
1106 
1107  /* only supported cards are allowed */
1108  switch (fb->id) {
1109  case CRT_ID_VISUALIZE_EG:
1110  /* Visualize cards can run either in "double buffer" or
1111  "standard" mode. Depending on the mode, the card reports
1112  a different device name, e.g. "INTERNAL_EG_DX1024" in double
1113  buffer mode and "INTERNAL_EG_X1024" in standard mode.
1114  Since this driver only supports standard mode, we check
1115  if the device name contains the string "DX" and tell the
1116  user how to reconfigure the card. */
1117  if (strstr(sti->outptr.dev_name, "DX")) {
1119 "WARNING: stifb framebuffer driver does not support '%s' in double-buffer mode.\n"
1120 "WARNING: Please disable the double-buffer mode in IPL menu (the PARISC-BIOS).\n",
1121  sti->outptr.dev_name);
1122  goto out_err0;
1123  }
1124  /* fall though */
1125  case S9000_ID_ARTIST:
1126  case S9000_ID_HCRX:
1127  case S9000_ID_TIMBER:
1128  case S9000_ID_A1659A:
1129  case S9000_ID_A1439A:
1130  break;
1131  default:
1132  printk(KERN_WARNING "stifb: '%s' (id: 0x%08x) not supported.\n",
1133  sti->outptr.dev_name, fb->id);
1134  goto out_err0;
1135  }
1136 
1137  /* default to 8 bpp on most graphic chips */
1138  bpp = 8;
1139  xres = sti_onscreen_x(fb->sti);
1140  yres = sti_onscreen_y(fb->sti);
1141 
1142  ngleGetDeviceRomData(fb);
1143 
1144  /* get (virtual) io region base addr */
1145  fix->mmio_start = REGION_BASE(fb,2);
1146  fix->mmio_len = 0x400000;
1147 
1148  /* Reject any device not in the NGLE family */
1149  switch (fb->id) {
1150  case S9000_ID_A1659A: /* CRX/A1659A */
1151  break;
1152  case S9000_ID_ELM: /* GRX, grayscale but else same as A1659A */
1153  var->grayscale = 1;
1154  fb->id = S9000_ID_A1659A;
1155  break;
1156  case S9000_ID_TIMBER: /* HP9000/710 Any (may be a grayscale device) */
1157  dev_name = fb->sti->outptr.dev_name;
1158  if (strstr(dev_name, "GRAYSCALE") ||
1159  strstr(dev_name, "Grayscale") ||
1160  strstr(dev_name, "grayscale"))
1161  var->grayscale = 1;
1162  break;
1163  case S9000_ID_TOMCAT: /* Dual CRX, behaves else like a CRX */
1164  /* FIXME: TomCat supports two heads:
1165  * fb.iobase = REGION_BASE(fb_info,3);
1166  * fb.screen_base = ioremap_nocache(REGION_BASE(fb_info,2),xxx);
1167  * for now we only support the left one ! */
1168  xres = fb->ngle_rom.x_size_visible;
1169  yres = fb->ngle_rom.y_size_visible;
1170  fb->id = S9000_ID_A1659A;
1171  break;
1172  case S9000_ID_A1439A: /* CRX24/A1439A */
1173  bpp = 32;
1174  break;
1175  case S9000_ID_HCRX: /* Hyperdrive/HCRX */
1176  memset(&fb->ngle_rom, 0, sizeof(fb->ngle_rom));
1177  if ((fb->sti->regions_phys[0] & 0xfc000000) ==
1178  (fb->sti->regions_phys[2] & 0xfc000000))
1179  sti_rom_address = F_EXTEND(fb->sti->regions_phys[0]);
1180  else
1181  sti_rom_address = F_EXTEND(fb->sti->regions_phys[1]);
1182 
1183  fb->deviceSpecificConfig = gsc_readl(sti_rom_address);
1184  if (IS_24_DEVICE(fb)) {
1185  if (bpp_pref == 8 || bpp_pref == 32)
1186  bpp = bpp_pref;
1187  else
1188  bpp = 32;
1189  } else
1190  bpp = 8;
1191  READ_WORD(fb, REG_15);
1192  SETUP_HW(fb);
1193  break;
1194  case CRT_ID_VISUALIZE_EG:
1195  case S9000_ID_ARTIST: /* Artist */
1196  break;
1197  default:
1198 #ifdef FALLBACK_TO_1BPP
1200  "stifb: Unsupported graphics card (id=0x%08x) "
1201  "- now trying 1bpp mode instead\n",
1202  fb->id);
1203  bpp = 1; /* default to 1 bpp */
1204  break;
1205 #else
1207  "stifb: Unsupported graphics card (id=0x%08x) "
1208  "- skipping.\n",
1209  fb->id);
1210  goto out_err0;
1211 #endif
1212  }
1213 
1214 
1215  /* get framebuffer physical and virtual base addr & len (64bit ready) */
1216  fix->smem_start = F_EXTEND(fb->sti->regions_phys[1]);
1217  fix->smem_len = fb->sti->regions[1].region_desc.length * 4096;
1218 
1219  fix->line_length = (fb->sti->glob_cfg->total_x * bpp) / 8;
1220  if (!fix->line_length)
1221  fix->line_length = 2048; /* default */
1222 
1223  /* limit fbsize to max visible screen size */
1224  if (fix->smem_len > yres*fix->line_length)
1225  fix->smem_len = yres*fix->line_length;
1226 
1227  fix->accel = FB_ACCEL_NONE;
1228 
1229  switch (bpp) {
1230  case 1:
1231  fix->type = FB_TYPE_PLANES; /* well, sort of */
1232  fix->visual = FB_VISUAL_MONO10;
1233  var->red.length = var->green.length = var->blue.length = 1;
1234  break;
1235  case 8:
1236  fix->type = FB_TYPE_PACKED_PIXELS;
1238  var->red.length = var->green.length = var->blue.length = 8;
1239  break;
1240  case 32:
1241  fix->type = FB_TYPE_PACKED_PIXELS;
1243  var->red.length = var->green.length = var->blue.length = var->transp.length = 8;
1244  var->blue.offset = 0;
1245  var->green.offset = 8;
1246  var->red.offset = 16;
1247  var->transp.offset = 24;
1248  break;
1249  default:
1250  break;
1251  }
1252 
1253  var->xres = var->xres_virtual = xres;
1254  var->yres = var->yres_virtual = yres;
1255  var->bits_per_pixel = bpp;
1256 
1257  strcpy(fix->id, "stifb");
1258  info->fbops = &stifb_ops;
1259  info->screen_base = ioremap_nocache(REGION_BASE(fb,1), fix->smem_len);
1260  info->screen_size = fix->smem_len;
1261  info->flags = FBINFO_DEFAULT;
1262  info->pseudo_palette = &fb->pseudo_palette;
1263 
1264  /* This has to be done !!! */
1265  if (fb_alloc_cmap(&info->cmap, NR_PALETTE, 0))
1266  goto out_err1;
1267  stifb_init_display(fb);
1268 
1269  if (!request_mem_region(fix->smem_start, fix->smem_len, "stifb fb")) {
1270  printk(KERN_ERR "stifb: cannot reserve fb region 0x%04lx-0x%04lx\n",
1271  fix->smem_start, fix->smem_start+fix->smem_len);
1272  goto out_err2;
1273  }
1274 
1275  if (!request_mem_region(fix->mmio_start, fix->mmio_len, "stifb mmio")) {
1276  printk(KERN_ERR "stifb: cannot reserve sti mmio region 0x%04lx-0x%04lx\n",
1277  fix->mmio_start, fix->mmio_start+fix->mmio_len);
1278  goto out_err3;
1279  }
1280 
1281  if (register_framebuffer(&fb->info) < 0)
1282  goto out_err4;
1283 
1284  sti->info = info; /* save for unregister_framebuffer() */
1285 
1286  printk(KERN_INFO
1287  "fb%d: %s %dx%d-%d frame buffer device, %s, id: %04x, mmio: 0x%04lx\n",
1288  fb->info.node,
1289  fix->id,
1290  var->xres,
1291  var->yres,
1292  var->bits_per_pixel,
1293  sti->outptr.dev_name,
1294  fb->id,
1295  fix->mmio_start);
1296 
1297  return 0;
1298 
1299 
1300 out_err4:
1302 out_err3:
1304 out_err2:
1305  fb_dealloc_cmap(&info->cmap);
1306 out_err1:
1307  iounmap(info->screen_base);
1308 out_err0:
1309  kfree(fb);
1310  return -ENXIO;
1311 }
1312 
1313 static int stifb_disabled __initdata;
1314 
1315 int __init
1316 stifb_setup(char *options);
1317 
1318 static int __init stifb_init(void)
1319 {
1320  struct sti_struct *sti;
1321  struct sti_struct *def_sti;
1322  int i;
1323 
1324 #ifndef MODULE
1325  char *option = NULL;
1326 
1327  if (fb_get_options("stifb", &option))
1328  return -ENODEV;
1329  stifb_setup(option);
1330 #endif
1331  if (stifb_disabled) {
1332  printk(KERN_INFO "stifb: disabled by \"stifb=off\" kernel parameter\n");
1333  return -ENXIO;
1334  }
1335 
1336  def_sti = sti_get_rom(0);
1337  if (def_sti) {
1338  for (i = 1; i <= MAX_STI_ROMS; i++) {
1339  sti = sti_get_rom(i);
1340  if (!sti)
1341  break;
1342  if (sti == def_sti) {
1343  stifb_init_fb(sti, stifb_bpp_pref[i - 1]);
1344  break;
1345  }
1346  }
1347  }
1348 
1349  for (i = 1; i <= MAX_STI_ROMS; i++) {
1350  sti = sti_get_rom(i);
1351  if (!sti)
1352  break;
1353  if (sti == def_sti)
1354  continue;
1355  stifb_init_fb(sti, stifb_bpp_pref[i - 1]);
1356  }
1357  return 0;
1358 }
1359 
1360 /*
1361  * Cleanup
1362  */
1363 
1364 static void __exit
1365 stifb_cleanup(void)
1366 {
1367  struct sti_struct *sti;
1368  int i;
1369 
1370  for (i = 1; i <= MAX_STI_ROMS; i++) {
1371  sti = sti_get_rom(i);
1372  if (!sti)
1373  break;
1374  if (sti->info) {
1375  struct fb_info *info = sti->info;
1377  release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
1378  release_mem_region(info->fix.smem_start, info->fix.smem_len);
1379  if (info->screen_base)
1380  iounmap(info->screen_base);
1381  fb_dealloc_cmap(&info->cmap);
1382  framebuffer_release(info);
1383  }
1384  sti->info = NULL;
1385  }
1386 }
1387 
1388 int __init
1390 {
1391  int i;
1392 
1393  if (!options || !*options)
1394  return 1;
1395 
1396  if (strncmp(options, "off", 3) == 0) {
1397  stifb_disabled = 1;
1398  options += 3;
1399  }
1400 
1401  if (strncmp(options, "bpp", 3) == 0) {
1402  options += 3;
1403  for (i = 0; i < MAX_STI_ROMS; i++) {
1404  if (*options++ != ':')
1405  break;
1406  stifb_bpp_pref[i] = simple_strtoul(options, &options, 10);
1407  }
1408  }
1409  return 1;
1410 }
1411 
1412 __setup("stifb=", stifb_setup);
1413 
1414 module_init(stifb_init);
1415 module_exit(stifb_cleanup);
1416 
1417 MODULE_AUTHOR("Helge Deller <[email protected]>, Thomas Bogendoerfer <[email protected]>");
1418 MODULE_DESCRIPTION("Framebuffer driver for HP's NGLE series graphics cards in HP PARISC machines");
1419 MODULE_LICENSE("GPL v2");