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