This commit was manufactured by cvs2svn to create branch 'vserver'.
[linux-2.6.git] / drivers / video / intelfb / intelfbhw.c
1 /*
2  * intelfb
3  *
4  * Linux framebuffer driver for Intel(R) 865G integrated graphics chips.
5  *
6  * Copyright © 2002, 2003 David Dawes <dawes@xfree86.org>
7  *                   2004 Sylvain Meyer
8  *
9  * This driver consists of two parts.  The first part (intelfbdrv.c) provides
10  * the basic fbdev interfaces, is derived in part from the radeonfb and
11  * vesafb drivers, and is covered by the GPL.  The second part (intelfbhw.c)
12  * provides the code to program the hardware.  Most of it is derived from
13  * the i810/i830 XFree86 driver.  The HW-specific code is covered here
14  * under a dual license (GPL and MIT/XFree86 license).
15  *
16  * Author: David Dawes
17  *
18  */
19
20 /* $DHD: intelfb/intelfbhw.c,v 1.9 2003/06/27 15:06:25 dawes Exp $ */
21
22 #include <linux/config.h>
23 #include <linux/module.h>
24 #include <linux/kernel.h>
25 #include <linux/errno.h>
26 #include <linux/string.h>
27 #include <linux/mm.h>
28 #include <linux/tty.h>
29 #include <linux/slab.h>
30 #include <linux/delay.h>
31 #include <linux/fb.h>
32 #include <linux/console.h>
33 #include <linux/selection.h>
34 #include <linux/ioport.h>
35 #include <linux/init.h>
36 #include <linux/pci.h>
37 #include <linux/vmalloc.h>
38 #include <linux/kd.h>
39 #include <linux/vt_kern.h>
40 #include <linux/pagemap.h>
41 #include <linux/version.h>
42
43 #include <asm/io.h>
44
45 #include "intelfb.h"
46 #include "intelfbhw.h"
47
48 int
49 intelfbhw_get_chipset(struct pci_dev *pdev, const char **name, int *chipset,
50                       int *mobile)
51 {
52         u32 tmp;
53
54         if (!pdev || !name || !chipset || !mobile)
55                 return 1;
56
57         switch (pdev->device) {
58         case PCI_DEVICE_ID_INTEL_830M:
59                 *name = "Intel(R) 830M";
60                 *chipset = INTEL_830M;
61                 *mobile = 1;
62                 return 0;
63         case PCI_DEVICE_ID_INTEL_845G:
64                 *name = "Intel(R) 845G";
65                 *chipset = INTEL_845G;
66                 *mobile = 0;
67                 return 0;
68         case PCI_DEVICE_ID_INTEL_85XGM:
69                 tmp = 0;
70                 *mobile = 1;
71                 pci_read_config_dword(pdev, INTEL_85X_CAPID, &tmp);
72                 switch ((tmp >> INTEL_85X_VARIANT_SHIFT) &
73                         INTEL_85X_VARIANT_MASK) {
74                 case INTEL_VAR_855GME:
75                         *name = "Intel(R) 855GME";
76                         *chipset = INTEL_855GME;
77                         return 0;
78                 case INTEL_VAR_855GM:
79                         *name = "Intel(R) 855GM";
80                         *chipset = INTEL_855GM;
81                         return 0;
82                 case INTEL_VAR_852GME:
83                         *name = "Intel(R) 852GME";
84                         *chipset = INTEL_852GME;
85                         return 0;
86                 case INTEL_VAR_852GM:
87                         *name = "Intel(R) 852GM";
88                         *chipset = INTEL_852GM;
89                         return 0;
90                 default:
91                         *name = "Intel(R) 852GM/855GM";
92                         *chipset = INTEL_85XGM;
93                         return 0;
94                 }
95                 break;
96         case PCI_DEVICE_ID_INTEL_865G:
97                 *name = "Intel(R) 865G";
98                 *chipset = INTEL_865G;
99                 *mobile = 0;
100                 return 0;
101         default:
102                 return 1;
103         }
104 }
105
106 int
107 intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size,
108                      int *stolen_size)
109 {
110         struct pci_dev *bridge_dev;
111         u16 tmp;
112
113         if (!pdev || !aperture_size || !stolen_size)
114                 return 1;
115
116         /* Find the bridge device.  It is always 0:0.0 */
117         if (!(bridge_dev = pci_find_slot(0, PCI_DEVFN(0, 0)))) {
118                 ERR_MSG("cannot find bridge device\n");
119                 return 1;
120         }
121
122         /* Get the fb aperture size and "stolen" memory amount. */
123         tmp = 0;
124         pci_read_config_word(bridge_dev, INTEL_GMCH_CTRL, &tmp);
125         switch (pdev->device) {
126         case PCI_DEVICE_ID_INTEL_830M:
127         case PCI_DEVICE_ID_INTEL_845G:
128                 if ((tmp & INTEL_GMCH_MEM_MASK) == INTEL_GMCH_MEM_64M)
129                         *aperture_size = MB(64);
130                 else
131                         *aperture_size = MB(128);
132                 switch (tmp & INTEL_830_GMCH_GMS_MASK) {
133                 case INTEL_830_GMCH_GMS_STOLEN_512:
134                         *stolen_size = KB(512) - KB(132);
135                         return 0;
136                 case INTEL_830_GMCH_GMS_STOLEN_1024:
137                         *stolen_size = MB(1) - KB(132);
138                         return 0;
139                 case INTEL_830_GMCH_GMS_STOLEN_8192:
140                         *stolen_size = MB(8) - KB(132);
141                         return 0;
142                 case INTEL_830_GMCH_GMS_LOCAL:
143                         ERR_MSG("only local memory found\n");
144                         return 1;
145                 case INTEL_830_GMCH_GMS_DISABLED:
146                         ERR_MSG("video memory is disabled\n");
147                         return 1;
148                 default:
149                         ERR_MSG("unexpected GMCH_GMS value: 0x%02x\n",
150                                 tmp & INTEL_830_GMCH_GMS_MASK);
151                         return 1;
152                 }
153                 break;
154         default:
155                 *aperture_size = MB(128);
156                 switch (tmp & INTEL_855_GMCH_GMS_MASK) {
157                 case INTEL_855_GMCH_GMS_STOLEN_1M:
158                         *stolen_size = MB(1) - KB(132);
159                         return 0;
160                 case INTEL_855_GMCH_GMS_STOLEN_4M:
161                         *stolen_size = MB(4) - KB(132);
162                         return 0;
163                 case INTEL_855_GMCH_GMS_STOLEN_8M:
164                         *stolen_size = MB(8) - KB(132);
165                         return 0;
166                 case INTEL_855_GMCH_GMS_STOLEN_16M:
167                         *stolen_size = MB(16) - KB(132);
168                         return 0;
169                 case INTEL_855_GMCH_GMS_STOLEN_32M:
170                         *stolen_size = MB(32) - KB(132);
171                         return 0;
172                 case INTEL_855_GMCH_GMS_DISABLED:
173                         ERR_MSG("video memory is disabled\n");
174                         return 0;
175                 default:
176                         ERR_MSG("unexpected GMCH_GMS value: 0x%02x\n",
177                                 tmp & INTEL_855_GMCH_GMS_MASK);
178                         return 1;
179                 }
180         }
181 }
182
183 int
184 intelfbhw_check_non_crt(struct intelfb_info *dinfo)
185 {
186         int dvo = 0;
187
188         if (INREG(LVDS) & PORT_ENABLE)
189                 dvo |= LVDS_PORT;
190         if (INREG(DVOA) & PORT_ENABLE)
191                 dvo |= DVOA_PORT;
192         if (INREG(DVOB) & PORT_ENABLE)
193                 dvo |= DVOB_PORT;
194         if (INREG(DVOC) & PORT_ENABLE)
195                 dvo |= DVOC_PORT;
196
197         return dvo;
198 }
199
200 const char *
201 intelfbhw_dvo_to_string(int dvo)
202 {
203         if (dvo & DVOA_PORT)
204                 return "DVO port A";
205         else if (dvo & DVOB_PORT)
206                 return "DVO port B";
207         else if (dvo & DVOC_PORT)
208                 return "DVO port C";
209         else if (dvo & LVDS_PORT)
210                 return "LVDS port";
211         else
212                 return NULL;
213 }
214
215
216 int
217 intelfbhw_validate_mode(struct intelfb_info *dinfo,
218                         struct fb_var_screeninfo *var)
219 {
220         int bytes_per_pixel;
221         int tmp;
222
223 #if VERBOSE > 0
224         DBG_MSG("intelfbhw_validate_mode\n");
225 #endif
226
227         bytes_per_pixel = var->bits_per_pixel / 8;
228         if (bytes_per_pixel == 3)
229                 bytes_per_pixel = 4;
230
231         /* Check if enough video memory. */
232         tmp = var->yres_virtual * var->xres_virtual * bytes_per_pixel;
233         if (tmp > dinfo->fb.size) {
234                 WRN_MSG("Not enough video ram for mode "
235                         "(%d KByte vs %d KByte).\n",
236                         BtoKB(tmp), BtoKB(dinfo->fb.size));
237                 return 1;
238         }
239
240         /* Check if x/y limits are OK. */
241         if (var->xres - 1 > HACTIVE_MASK) {
242                 WRN_MSG("X resolution too large (%d vs %d).\n",
243                         var->xres, HACTIVE_MASK + 1);
244                 return 1;
245         }
246         if (var->yres - 1 > VACTIVE_MASK) {
247                 WRN_MSG("Y resolution too large (%d vs %d).\n",
248                         var->yres, VACTIVE_MASK + 1);
249                 return 1;
250         }
251
252         /* Check for interlaced/doublescan modes. */
253         if (var->vmode & FB_VMODE_INTERLACED) {
254                 WRN_MSG("Mode is interlaced.\n");
255                 return 1;
256         }
257         if (var->vmode & FB_VMODE_DOUBLE) {
258                 WRN_MSG("Mode is double-scan.\n");
259                 return 1;
260         }
261
262         /* Check if clock is OK. */
263         tmp = 1000000000 / var->pixclock;
264         if (tmp < MIN_CLOCK) {
265                 WRN_MSG("Pixel clock is too low (%d MHz vs %d MHz).\n",
266                         (tmp + 500) / 1000, MIN_CLOCK / 1000);
267                 return 1;
268         }
269         if (tmp > MAX_CLOCK) {
270                 WRN_MSG("Pixel clock is too high (%d MHz vs %d MHz).\n",
271                         (tmp + 500) / 1000, MAX_CLOCK / 1000);
272                 return 1;
273         }
274
275         return 0;
276 }
277
278 int
279 intelfbhw_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
280 {
281         struct intelfb_info *dinfo = GET_DINFO(info);
282         u32 offset, xoffset, yoffset;
283
284 #if VERBOSE > 0
285         DBG_MSG("intelfbhw_pan_display\n");
286 #endif
287
288         xoffset = ROUND_DOWN_TO(var->xoffset, 8);
289         yoffset = var->yoffset;
290
291         if ((xoffset + var->xres > var->xres_virtual) ||
292             (yoffset + var->yres > var->yres_virtual))
293                 return -EINVAL;
294
295         offset = (yoffset * dinfo->pitch) +
296                  (xoffset * var->bits_per_pixel) / 8;
297
298         offset += dinfo->fb.offset << 12;
299
300         OUTREG(DSPABASE, offset);
301
302         return 0;
303 }
304
305 /* Blank the screen. */
306 void
307 intelfbhw_do_blank(int blank, struct fb_info *info)
308 {
309         struct intelfb_info *dinfo = GET_DINFO(info);
310         u32 tmp;
311
312 #if VERBOSE > 0
313         DBG_MSG("intelfbhw_do_blank: blank is %d\n", blank);
314 #endif
315
316         /* Turn plane A on or off */
317         tmp = INREG(DSPACNTR);
318         if (blank)
319                 tmp &= ~DISPPLANE_PLANE_ENABLE;
320         else
321                 tmp |= DISPPLANE_PLANE_ENABLE;
322         OUTREG(DSPACNTR, tmp);
323         /* Flush */
324         tmp = INREG(DSPABASE);
325         OUTREG(DSPABASE, tmp);
326
327         /* Turn off/on the HW cursor */
328 #if VERBOSE > 0
329         DBG_MSG("cursor_on is %d\n", dinfo->cursor_on);
330 #endif
331         if (dinfo->cursor_on) {
332                 if (blank) {
333                         intelfbhw_cursor_hide(dinfo);
334                 } else {
335                         intelfbhw_cursor_show(dinfo);
336                 }
337                 dinfo->cursor_on = 1;
338         }
339         dinfo->cursor_blanked = blank;
340
341         /* Set DPMS level */
342         tmp = INREG(ADPA) & ~ADPA_DPMS_CONTROL_MASK;
343         switch (blank) {
344         case FB_BLANK_UNBLANK:
345         case FB_BLANK_NORMAL:
346                 tmp |= ADPA_DPMS_D0;
347                 break;
348         case FB_BLANK_VSYNC_SUSPEND:
349                 tmp |= ADPA_DPMS_D1;
350                 break;
351         case FB_BLANK_HSYNC_SUSPEND:
352                 tmp |= ADPA_DPMS_D2;
353                 break;
354         case FB_BLANK_POWERDOWN:
355                 tmp |= ADPA_DPMS_D3;
356                 break;
357         }
358         OUTREG(ADPA, tmp);
359
360         return;
361 }
362
363
364 void
365 intelfbhw_setcolreg(struct intelfb_info *dinfo, unsigned regno,
366                     unsigned red, unsigned green, unsigned blue,
367                     unsigned transp)
368 {
369 #if VERBOSE > 0
370         DBG_MSG("intelfbhw_setcolreg: %d: (%d, %d, %d)\n",
371                 regno, red, green, blue);
372 #endif
373
374         u32 palette_reg = (dinfo->pipe == PIPE_A) ?
375                           PALETTE_A : PALETTE_B;
376
377         OUTREG(palette_reg + (regno << 2),
378                (red << PALETTE_8_RED_SHIFT) |
379                (green << PALETTE_8_GREEN_SHIFT) |
380                (blue << PALETTE_8_BLUE_SHIFT));
381 }
382
383
384 int
385 intelfbhw_read_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw,
386                         int flag)
387 {
388         int i;
389
390 #if VERBOSE > 0
391         DBG_MSG("intelfbhw_read_hw_state\n");
392 #endif
393
394         if (!hw || !dinfo)
395                 return -1;
396
397         /* Read in as much of the HW state as possible. */
398         hw->vga0_divisor = INREG(VGA0_DIVISOR);
399         hw->vga1_divisor = INREG(VGA1_DIVISOR);
400         hw->vga_pd = INREG(VGAPD);
401         hw->dpll_a = INREG(DPLL_A);
402         hw->dpll_b = INREG(DPLL_B);
403         hw->fpa0 = INREG(FPA0);
404         hw->fpa1 = INREG(FPA1);
405         hw->fpb0 = INREG(FPB0);
406         hw->fpb1 = INREG(FPB1);
407
408         if (flag == 1)
409                 return flag;
410
411 #if 0
412         /* This seems to be a problem with the 852GM/855GM */
413         for (i = 0; i < PALETTE_8_ENTRIES; i++) {
414                 hw->palette_a[i] = INREG(PALETTE_A + (i << 2));
415                 hw->palette_b[i] = INREG(PALETTE_B + (i << 2));
416         }
417 #endif
418
419         if (flag == 2)
420                 return flag;
421
422         hw->htotal_a = INREG(HTOTAL_A);
423         hw->hblank_a = INREG(HBLANK_A);
424         hw->hsync_a = INREG(HSYNC_A);
425         hw->vtotal_a = INREG(VTOTAL_A);
426         hw->vblank_a = INREG(VBLANK_A);
427         hw->vsync_a = INREG(VSYNC_A);
428         hw->src_size_a = INREG(SRC_SIZE_A);
429         hw->bclrpat_a = INREG(BCLRPAT_A);
430         hw->htotal_b = INREG(HTOTAL_B);
431         hw->hblank_b = INREG(HBLANK_B);
432         hw->hsync_b = INREG(HSYNC_B);
433         hw->vtotal_b = INREG(VTOTAL_B);
434         hw->vblank_b = INREG(VBLANK_B);
435         hw->vsync_b = INREG(VSYNC_B);
436         hw->src_size_b = INREG(SRC_SIZE_B);
437         hw->bclrpat_b = INREG(BCLRPAT_B);
438
439         if (flag == 3)
440                 return flag;
441
442         hw->adpa = INREG(ADPA);
443         hw->dvoa = INREG(DVOA);
444         hw->dvob = INREG(DVOB);
445         hw->dvoc = INREG(DVOC);
446         hw->dvoa_srcdim = INREG(DVOA_SRCDIM);
447         hw->dvob_srcdim = INREG(DVOB_SRCDIM);
448         hw->dvoc_srcdim = INREG(DVOC_SRCDIM);
449         hw->lvds = INREG(LVDS);
450
451         if (flag == 4)
452                 return flag;
453
454         hw->pipe_a_conf = INREG(PIPEACONF);
455         hw->pipe_b_conf = INREG(PIPEBCONF);
456         hw->disp_arb = INREG(DISPARB);
457
458         if (flag == 5)
459                 return flag;
460
461         hw->cursor_a_control = INREG(CURSOR_A_CONTROL);
462         hw->cursor_b_control = INREG(CURSOR_B_CONTROL);
463         hw->cursor_a_base = INREG(CURSOR_A_BASEADDR);
464         hw->cursor_b_base = INREG(CURSOR_B_BASEADDR);
465
466         if (flag == 6)
467                 return flag;
468
469         for (i = 0; i < 4; i++) {
470                 hw->cursor_a_palette[i] = INREG(CURSOR_A_PALETTE0 + (i << 2));
471                 hw->cursor_b_palette[i] = INREG(CURSOR_B_PALETTE0 + (i << 2));
472         }
473
474         if (flag == 7)
475                 return flag;
476
477         hw->cursor_size = INREG(CURSOR_SIZE);
478
479         if (flag == 8)
480                 return flag;
481
482         hw->disp_a_ctrl = INREG(DSPACNTR);
483         hw->disp_b_ctrl = INREG(DSPBCNTR);
484         hw->disp_a_base = INREG(DSPABASE);
485         hw->disp_b_base = INREG(DSPBBASE);
486         hw->disp_a_stride = INREG(DSPASTRIDE);
487         hw->disp_b_stride = INREG(DSPBSTRIDE);
488
489         if (flag == 9)
490                 return flag;
491
492         hw->vgacntrl = INREG(VGACNTRL);
493
494         if (flag == 10)
495                 return flag;
496
497         hw->add_id = INREG(ADD_ID);
498
499         if (flag == 11)
500                 return flag;
501
502         for (i = 0; i < 7; i++) {
503                 hw->swf0x[i] = INREG(SWF00 + (i << 2));
504                 hw->swf1x[i] = INREG(SWF10 + (i << 2));
505                 if (i < 3)
506                         hw->swf3x[i] = INREG(SWF30 + (i << 2));
507         }
508
509         for (i = 0; i < 8; i++)
510                 hw->fence[i] = INREG(FENCE + (i << 2));
511
512         hw->instpm = INREG(INSTPM);
513         hw->mem_mode = INREG(MEM_MODE);
514         hw->fw_blc_0 = INREG(FW_BLC_0);
515         hw->fw_blc_1 = INREG(FW_BLC_1);
516
517         return 0;
518 }
519
520
521 void
522 intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
523 {
524 #if REGDUMP
525         int i, m1, m2, n, p1, p2;
526
527         DBG_MSG("intelfbhw_print_hw_state\n");
528
529         if (!hw || !dinfo)
530                 return;
531         /* Read in as much of the HW state as possible. */
532         printk("hw state dump start\n");
533         printk("        VGA0_DIVISOR:           0x%08x\n", hw->vga0_divisor);
534         printk("        VGA1_DIVISOR:           0x%08x\n", hw->vga1_divisor);
535         printk("        VGAPD:                  0x%08x\n", hw->vga_pd);
536         n = (hw->vga0_divisor >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
537         m1 = (hw->vga0_divisor >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
538         m2 = (hw->vga0_divisor >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
539         if (hw->vga_pd & VGAPD_0_P1_FORCE_DIV2)
540                 p1 = 0;
541         else
542                 p1 = (hw->vga_pd >> VGAPD_0_P1_SHIFT) & DPLL_P1_MASK;
543         p2 = (hw->vga_pd >> VGAPD_0_P2_SHIFT) & DPLL_P2_MASK;
544         printk("        VGA0: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
545                 m1, m2, n, p1, p2);
546         printk("        VGA0: clock is %d\n", CALC_VCLOCK(m1, m2, n, p1, p2));
547
548         n = (hw->vga1_divisor >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
549         m1 = (hw->vga1_divisor >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
550         m2 = (hw->vga1_divisor >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
551         if (hw->vga_pd & VGAPD_1_P1_FORCE_DIV2)
552                 p1 = 0;
553         else
554                 p1 = (hw->vga_pd >> VGAPD_1_P1_SHIFT) & DPLL_P1_MASK;
555         p2 = (hw->vga_pd >> VGAPD_1_P2_SHIFT) & DPLL_P2_MASK;
556         printk("        VGA1: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
557                 m1, m2, n, p1, p2);
558         printk("        VGA1: clock is %d\n", CALC_VCLOCK(m1, m2, n, p1, p2));
559
560         printk("        DPLL_A:                 0x%08x\n", hw->dpll_a);
561         printk("        DPLL_B:                 0x%08x\n", hw->dpll_b);
562         printk("        FPA0:                   0x%08x\n", hw->fpa0);
563         printk("        FPA1:                   0x%08x\n", hw->fpa1);
564         printk("        FPB0:                   0x%08x\n", hw->fpb0);
565         printk("        FPB1:                   0x%08x\n", hw->fpb1);
566
567         n = (hw->fpa0 >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
568         m1 = (hw->fpa0 >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
569         m2 = (hw->fpa0 >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
570         if (hw->dpll_a & DPLL_P1_FORCE_DIV2)
571                 p1 = 0;
572         else
573                 p1 = (hw->dpll_a >> DPLL_P1_SHIFT) & DPLL_P1_MASK;
574         p2 = (hw->dpll_a >> DPLL_P2_SHIFT) & DPLL_P2_MASK;
575         printk("        PLLA0: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
576                 m1, m2, n, p1, p2);
577         printk("        PLLA0: clock is %d\n", CALC_VCLOCK(m1, m2, n, p1, p2));
578
579         n = (hw->fpa1 >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
580         m1 = (hw->fpa1 >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
581         m2 = (hw->fpa1 >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
582         if (hw->dpll_a & DPLL_P1_FORCE_DIV2)
583                 p1 = 0;
584         else
585                 p1 = (hw->dpll_a >> DPLL_P1_SHIFT) & DPLL_P1_MASK;
586         p2 = (hw->dpll_a >> DPLL_P2_SHIFT) & DPLL_P2_MASK;
587         printk("        PLLA1: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
588                 m1, m2, n, p1, p2);
589         printk("        PLLA1: clock is %d\n", CALC_VCLOCK(m1, m2, n, p1, p2));
590
591 #if 0
592         printk("        PALETTE_A:\n");
593         for (i = 0; i < PALETTE_8_ENTRIES)
594                 printk("        %3d:    0x%08x\n", i, hw->palette_a[i];
595         printk("        PALETTE_B:\n");
596         for (i = 0; i < PALETTE_8_ENTRIES)
597                 printk("        %3d:    0x%08x\n", i, hw->palette_b[i];
598 #endif
599
600         printk("        HTOTAL_A:               0x%08x\n", hw->htotal_a);
601         printk("        HBLANK_A:               0x%08x\n", hw->hblank_a);
602         printk("        HSYNC_A:                0x%08x\n", hw->hsync_a);
603         printk("        VTOTAL_A:               0x%08x\n", hw->vtotal_a);
604         printk("        VBLANK_A:               0x%08x\n", hw->vblank_a);
605         printk("        VSYNC_A:                0x%08x\n", hw->vsync_a);
606         printk("        SRC_SIZE_A:             0x%08x\n", hw->src_size_a);
607         printk("        BCLRPAT_A:              0x%08x\n", hw->bclrpat_a);
608         printk("        HTOTAL_B:               0x%08x\n", hw->htotal_b);
609         printk("        HBLANK_B:               0x%08x\n", hw->hblank_b);
610         printk("        HSYNC_B:                0x%08x\n", hw->hsync_b);
611         printk("        VTOTAL_B:               0x%08x\n", hw->vtotal_b);
612         printk("        VBLANK_B:               0x%08x\n", hw->vblank_b);
613         printk("        VSYNC_B:                0x%08x\n", hw->vsync_b);
614         printk("        SRC_SIZE_B:             0x%08x\n", hw->src_size_b);
615         printk("        BCLRPAT_B:              0x%08x\n", hw->bclrpat_b);
616
617         printk("        ADPA:                   0x%08x\n", hw->adpa);
618         printk("        DVOA:                   0x%08x\n", hw->dvoa);
619         printk("        DVOB:                   0x%08x\n", hw->dvob);
620         printk("        DVOC:                   0x%08x\n", hw->dvoc);
621         printk("        DVOA_SRCDIM:            0x%08x\n", hw->dvoa_srcdim);
622         printk("        DVOB_SRCDIM:            0x%08x\n", hw->dvob_srcdim);
623         printk("        DVOC_SRCDIM:            0x%08x\n", hw->dvoc_srcdim);
624         printk("        LVDS:                   0x%08x\n", hw->lvds);
625
626         printk("        PIPEACONF:              0x%08x\n", hw->pipe_a_conf);
627         printk("        PIPEBCONF:              0x%08x\n", hw->pipe_b_conf);
628         printk("        DISPARB:                0x%08x\n", hw->disp_arb);
629
630         printk("        CURSOR_A_CONTROL:       0x%08x\n", hw->cursor_a_control);
631         printk("        CURSOR_B_CONTROL:       0x%08x\n", hw->cursor_b_control);
632         printk("        CURSOR_A_BASEADDR:      0x%08x\n", hw->cursor_a_base);
633         printk("        CURSOR_B_BASEADDR:      0x%08x\n", hw->cursor_b_base);
634
635         printk("        CURSOR_A_PALETTE:       ");
636         for (i = 0; i < 4; i++) {
637                 printk("0x%08x", hw->cursor_a_palette[i]);
638                 if (i < 3)
639                         printk(", ");
640         }
641         printk("\n");
642         printk("        CURSOR_B_PALETTE:       ");
643         for (i = 0; i < 4; i++) {
644                 printk("0x%08x", hw->cursor_b_palette[i]);
645                 if (i < 3)
646                         printk(", ");
647         }
648         printk("\n");
649
650         printk("        CURSOR_SIZE:            0x%08x\n", hw->cursor_size);
651
652         printk("        DSPACNTR:               0x%08x\n", hw->disp_a_ctrl);
653         printk("        DSPBCNTR:               0x%08x\n", hw->disp_b_ctrl);
654         printk("        DSPABASE:               0x%08x\n", hw->disp_a_base);
655         printk("        DSPBBASE:               0x%08x\n", hw->disp_b_base);
656         printk("        DSPASTRIDE:             0x%08x\n", hw->disp_a_stride);
657         printk("        DSPBSTRIDE:             0x%08x\n", hw->disp_b_stride);
658
659         printk("        VGACNTRL:               0x%08x\n", hw->vgacntrl);
660         printk("        ADD_ID:                 0x%08x\n", hw->add_id);
661
662         for (i = 0; i < 7; i++) {
663                 printk("        SWF0%d                  0x%08x\n", i,
664                         hw->swf0x[i]);
665         }
666         for (i = 0; i < 7; i++) {
667                 printk("        SWF1%d                  0x%08x\n", i,
668                         hw->swf1x[i]);
669         }
670         for (i = 0; i < 3; i++) {
671                 printk("        SWF3%d                  0x%08x\n", i,
672                         hw->swf3x[i]);
673         }
674         for (i = 0; i < 8; i++)
675                 printk("        FENCE%d                 0x%08x\n", i,
676                         hw->fence[i]);
677
678         printk("        INSTPM                  0x%08x\n", hw->instpm);
679         printk("        MEM_MODE                0x%08x\n", hw->mem_mode);
680         printk("        FW_BLC_0                0x%08x\n", hw->fw_blc_0);
681         printk("        FW_BLC_1                0x%08x\n", hw->fw_blc_1);
682
683         printk("hw state dump end\n");
684 #endif
685 }
686
687 /* Split the M parameter into M1 and M2. */
688 static int
689 splitm(unsigned int m, unsigned int *retm1, unsigned int *retm2)
690 {
691         int m1, m2;
692
693         m1 = (m - 2 - (MIN_M2 + MAX_M2) / 2) / 5 - 2;
694         if (m1 < MIN_M1)
695                 m1 = MIN_M1;
696         if (m1 > MAX_M1)
697                 m1 = MAX_M1;
698         m2 = m - 5 * (m1 + 2) - 2;
699         if (m2 < MIN_M2 || m2 > MAX_M2 || m2 >= m1) {
700                 return 1;
701         } else {
702                 *retm1 = (unsigned int)m1;
703                 *retm2 = (unsigned int)m2;
704                 return 0;
705         }
706 }
707
708 /* Split the P parameter into P1 and P2. */
709 static int
710 splitp(unsigned int p, unsigned int *retp1, unsigned int *retp2)
711 {
712         int p1, p2;
713
714         if (p % 4 == 0)
715                 p2 = 1;
716         else
717                 p2 = 0;
718         p1 = (p / (1 << (p2 + 1))) - 2;
719         if (p % 4 == 0 && p1 < MIN_P1) {
720                 p2 = 0;
721                 p1 = (p / (1 << (p2 + 1))) - 2;
722         }
723         if (p1  < MIN_P1 || p1 > MAX_P1 || (p1 + 2) * (1 << (p2 + 1)) != p) {
724                 return 1;
725         } else {
726                 *retp1 = (unsigned int)p1;
727                 *retp2 = (unsigned int)p2;
728                 return 0;
729         }
730 }
731
732 static int
733 calc_pll_params(int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *retp1,
734                 u32 *retp2, u32 *retclock)
735 {
736         u32 m1, m2, n, p1, p2, n1;
737         u32 f_vco, p, p_best = 0, m, f_out;
738         u32 err_max, err_target, err_best = 10000000;
739         u32 n_best = 0, m_best = 0, f_best, f_err;
740         u32 p_min, p_max, p_inc, div_min, div_max;
741
742         /* Accept 0.5% difference, but aim for 0.1% */
743         err_max = 5 * clock / 1000;
744         err_target = clock / 1000;
745
746         DBG_MSG("Clock is %d\n", clock);
747
748         div_max = MAX_VCO_FREQ / clock;
749         div_min = ROUND_UP_TO(MIN_VCO_FREQ, clock) / clock;
750
751         if (clock <= P_TRANSITION_CLOCK)
752                 p_inc = 4;
753         else
754                 p_inc = 2;
755         p_min = ROUND_UP_TO(div_min, p_inc);
756         p_max = ROUND_DOWN_TO(div_max, p_inc);
757         if (p_min < MIN_P)
758                 p_min = 4;
759         if (p_max > MAX_P)
760                 p_max = 128;
761
762         DBG_MSG("p range is %d-%d (%d)\n", p_min, p_max, p_inc);
763
764         p = p_min;
765         do {
766                 if (splitp(p, &p1, &p2)) {
767                         WRN_MSG("cannot split p = %d\n", p);
768                         p += p_inc;
769                         continue;
770                 }
771                 n = MIN_N;
772                 f_vco = clock * p;
773
774                 do {
775                         m = ROUND_UP_TO(f_vco * n, PLL_REFCLK) / PLL_REFCLK;
776                         if (m < MIN_M)
777                                 m = MIN_M;
778                         if (m > MAX_M)
779                                 m = MAX_M;
780                         f_out = CALC_VCLOCK3(m, n, p);
781                         if (splitm(m, &m1, &m2)) {
782                                 WRN_MSG("cannot split m = %d\n", m);
783                                 n++;
784                                 continue;
785                         }
786                         if (clock > f_out)
787                                 f_err = clock - f_out;
788                         else
789                                 f_err = f_out - clock;
790
791                         if (f_err < err_best) {
792                                 m_best = m;
793                                 n_best = n;
794                                 p_best = p;
795                                 f_best = f_out;
796                                 err_best = f_err;
797                         }
798                         n++;
799                 } while ((n <= MAX_N) && (f_out >= clock));
800                 p += p_inc;
801         } while ((p <= p_max));
802
803         if (!m_best) {
804                 WRN_MSG("cannot find parameters for clock %d\n", clock);
805                 return 1;
806         }
807         m = m_best;
808         n = n_best;
809         p = p_best;
810         splitm(m, &m1, &m2);
811         splitp(p, &p1, &p2);
812         n1 = n - 2;
813
814         DBG_MSG("m, n, p: %d (%d,%d), %d (%d), %d (%d,%d), "
815                 "f: %d (%d), VCO: %d\n",
816                 m, m1, m2, n, n1, p, p1, p2,
817                 CALC_VCLOCK3(m, n, p), CALC_VCLOCK(m1, m2, n1, p1, p2),
818                 CALC_VCLOCK3(m, n, p) * p);
819         *retm1 = m1;
820         *retm2 = m2;
821         *retn = n1;
822         *retp1 = p1;
823         *retp2 = p2;
824         *retclock = CALC_VCLOCK(m1, m2, n1, p1, p2);
825
826         return 0;
827 }
828
829 static __inline__ int
830 check_overflow(u32 value, u32 limit, const char *description)
831 {
832         if (value > limit) {
833                 WRN_MSG("%s value %d exceeds limit %d\n",
834                         description, value, limit);
835                 return 1;
836         }
837         return 0;
838 }
839
840 /* It is assumed that hw is filled in with the initial state information. */
841 int
842 intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw,
843                      struct fb_var_screeninfo *var)
844 {
845         int pipe = PIPE_A;
846         u32 *dpll, *fp0, *fp1;
847         u32 m1, m2, n, p1, p2, clock_target, clock;
848         u32 hsync_start, hsync_end, hblank_start, hblank_end, htotal, hactive;
849         u32 vsync_start, vsync_end, vblank_start, vblank_end, vtotal, vactive;
850         u32 vsync_pol, hsync_pol;
851         u32 *vs, *vb, *vt, *hs, *hb, *ht, *ss, *pipe_conf;
852
853         DBG_MSG("intelfbhw_mode_to_hw\n");
854
855         /* Disable VGA */
856         hw->vgacntrl |= VGA_DISABLE;
857
858         /* Check whether pipe A or pipe B is enabled. */
859         if (hw->pipe_a_conf & PIPECONF_ENABLE)
860                 pipe = PIPE_A;
861         else if (hw->pipe_b_conf & PIPECONF_ENABLE)
862                 pipe = PIPE_B;
863
864         /* Set which pipe's registers will be set. */
865         if (pipe == PIPE_B) {
866                 dpll = &hw->dpll_b;
867                 fp0 = &hw->fpb0;
868                 fp1 = &hw->fpb1;
869                 hs = &hw->hsync_b;
870                 hb = &hw->hblank_b;
871                 ht = &hw->htotal_b;
872                 vs = &hw->vsync_b;
873                 vb = &hw->vblank_b;
874                 vt = &hw->vtotal_b;
875                 ss = &hw->src_size_b;
876                 pipe_conf = &hw->pipe_b_conf;
877         } else {
878                 dpll = &hw->dpll_a;
879                 fp0 = &hw->fpa0;
880                 fp1 = &hw->fpa1;
881                 hs = &hw->hsync_a;
882                 hb = &hw->hblank_a;
883                 ht = &hw->htotal_a;
884                 vs = &hw->vsync_a;
885                 vb = &hw->vblank_a;
886                 vt = &hw->vtotal_a;
887                 ss = &hw->src_size_a;
888                 pipe_conf = &hw->pipe_a_conf;
889         }
890
891         /* Use ADPA register for sync control. */
892         hw->adpa &= ~ADPA_USE_VGA_HVPOLARITY;
893
894         /* sync polarity */
895         hsync_pol = (var->sync & FB_SYNC_HOR_HIGH_ACT) ?
896                         ADPA_SYNC_ACTIVE_HIGH : ADPA_SYNC_ACTIVE_LOW;
897         vsync_pol = (var->sync & FB_SYNC_VERT_HIGH_ACT) ?
898                         ADPA_SYNC_ACTIVE_HIGH : ADPA_SYNC_ACTIVE_LOW;
899         hw->adpa &= ~((ADPA_SYNC_ACTIVE_MASK << ADPA_VSYNC_ACTIVE_SHIFT) |
900                       (ADPA_SYNC_ACTIVE_MASK << ADPA_HSYNC_ACTIVE_SHIFT));
901         hw->adpa |= (hsync_pol << ADPA_HSYNC_ACTIVE_SHIFT) |
902                     (vsync_pol << ADPA_VSYNC_ACTIVE_SHIFT);
903
904         /* Connect correct pipe to the analog port DAC */
905         hw->adpa &= ~(PIPE_MASK << ADPA_PIPE_SELECT_SHIFT);
906         hw->adpa |= (pipe << ADPA_PIPE_SELECT_SHIFT);
907
908         /* Set DPMS state to D0 (on) */
909         hw->adpa &= ~ADPA_DPMS_CONTROL_MASK;
910         hw->adpa |= ADPA_DPMS_D0;
911
912         hw->adpa |= ADPA_DAC_ENABLE;
913
914         *dpll |= (DPLL_VCO_ENABLE | DPLL_VGA_MODE_DISABLE);
915         *dpll &= ~(DPLL_RATE_SELECT_MASK | DPLL_REFERENCE_SELECT_MASK);
916         *dpll |= (DPLL_REFERENCE_DEFAULT | DPLL_RATE_SELECT_FP0);
917
918         /* Desired clock in kHz */
919         clock_target = 1000000000 / var->pixclock;
920
921         if (calc_pll_params(clock_target, &m1, &m2, &n, &p1, &p2, &clock)) {
922                 WRN_MSG("calc_pll_params failed\n");
923                 return 1;
924         }
925
926         /* Check for overflow. */
927         if (check_overflow(p1, DPLL_P1_MASK, "PLL P1 parameter"))
928                 return 1;
929         if (check_overflow(p2, DPLL_P2_MASK, "PLL P2 parameter"))
930                 return 1;
931         if (check_overflow(m1, FP_DIVISOR_MASK, "PLL M1 parameter"))
932                 return 1;
933         if (check_overflow(m2, FP_DIVISOR_MASK, "PLL M2 parameter"))
934                 return 1;
935         if (check_overflow(n, FP_DIVISOR_MASK, "PLL N parameter"))
936                 return 1;
937
938         *dpll &= ~DPLL_P1_FORCE_DIV2;
939         *dpll &= ~((DPLL_P2_MASK << DPLL_P2_SHIFT) |
940                    (DPLL_P1_MASK << DPLL_P1_SHIFT));
941         *dpll |= (p2 << DPLL_P2_SHIFT) | (p1 << DPLL_P1_SHIFT);
942         *fp0 = (n << FP_N_DIVISOR_SHIFT) |
943                (m1 << FP_M1_DIVISOR_SHIFT) |
944                (m2 << FP_M2_DIVISOR_SHIFT);
945         *fp1 = *fp0;
946
947         hw->dvob &= ~PORT_ENABLE;
948         hw->dvoc &= ~PORT_ENABLE;
949
950         /* Use display plane A. */
951         hw->disp_a_ctrl |= DISPPLANE_PLANE_ENABLE;
952         hw->disp_a_ctrl &= ~DISPPLANE_GAMMA_ENABLE;
953         hw->disp_a_ctrl &= ~DISPPLANE_PIXFORMAT_MASK;
954         switch (intelfb_var_to_depth(var)) {
955         case 8:
956                 hw->disp_a_ctrl |= DISPPLANE_8BPP | DISPPLANE_GAMMA_ENABLE;
957                 break;
958         case 15:
959                 hw->disp_a_ctrl |= DISPPLANE_15_16BPP;
960                 break;
961         case 16:
962                 hw->disp_a_ctrl |= DISPPLANE_16BPP;
963                 break;
964         case 24:
965                 hw->disp_a_ctrl |= DISPPLANE_32BPP_NO_ALPHA;
966                 break;
967         }
968         hw->disp_a_ctrl &= ~(PIPE_MASK << DISPPLANE_SEL_PIPE_SHIFT);
969         hw->disp_a_ctrl |= (pipe << DISPPLANE_SEL_PIPE_SHIFT);
970
971         /* Set CRTC registers. */
972         hactive = var->xres;
973         hsync_start = hactive + var->right_margin;
974         hsync_end = hsync_start + var->hsync_len;
975         htotal = hsync_end + var->left_margin;
976         hblank_start = hactive;
977         hblank_end = htotal;
978
979         DBG_MSG("H: act %d, ss %d, se %d, tot %d bs %d, be %d\n",
980                 hactive, hsync_start, hsync_end, htotal, hblank_start,
981                 hblank_end);
982
983         vactive = var->yres;
984         vsync_start = vactive + var->lower_margin;
985         vsync_end = vsync_start + var->vsync_len;
986         vtotal = vsync_end + var->upper_margin;
987         vblank_start = vactive;
988         vblank_end = vtotal;
989         vblank_end = vsync_end + 1;
990
991         DBG_MSG("V: act %d, ss %d, se %d, tot %d bs %d, be %d\n",
992                 vactive, vsync_start, vsync_end, vtotal, vblank_start,
993                 vblank_end);
994
995         /* Adjust for register values, and check for overflow. */
996         hactive--;
997         if (check_overflow(hactive, HACTIVE_MASK, "CRTC hactive"))
998                 return 1;
999         hsync_start--;
1000         if (check_overflow(hsync_start, HSYNCSTART_MASK, "CRTC hsync_start"))
1001                 return 1;
1002         hsync_end--;
1003         if (check_overflow(hsync_end, HSYNCEND_MASK, "CRTC hsync_end"))
1004                 return 1;
1005         htotal--;
1006         if (check_overflow(htotal, HTOTAL_MASK, "CRTC htotal"))
1007                 return 1;
1008         hblank_start--;
1009         if (check_overflow(hblank_start, HBLANKSTART_MASK, "CRTC hblank_start"))
1010                 return 1;
1011         hblank_end--;
1012         if (check_overflow(hblank_end, HBLANKEND_MASK, "CRTC hblank_end"))
1013                 return 1;
1014
1015         vactive--;
1016         if (check_overflow(vactive, VACTIVE_MASK, "CRTC vactive"))
1017                 return 1;
1018         vsync_start--;
1019         if (check_overflow(vsync_start, VSYNCSTART_MASK, "CRTC vsync_start"))
1020                 return 1;
1021         vsync_end--;
1022         if (check_overflow(vsync_end, VSYNCEND_MASK, "CRTC vsync_end"))
1023                 return 1;
1024         vtotal--;
1025         if (check_overflow(vtotal, VTOTAL_MASK, "CRTC vtotal"))
1026                 return 1;
1027         vblank_start--;
1028         if (check_overflow(vblank_start, VBLANKSTART_MASK, "CRTC vblank_start"))
1029                 return 1;
1030         vblank_end--;
1031         if (check_overflow(vblank_end, VBLANKEND_MASK, "CRTC vblank_end"))
1032                 return 1;
1033
1034         *ht = (htotal << HTOTAL_SHIFT) | (hactive << HACTIVE_SHIFT);
1035         *hb = (hblank_start << HBLANKSTART_SHIFT) |
1036               (hblank_end << HSYNCEND_SHIFT);
1037         *hs = (hsync_start << HSYNCSTART_SHIFT) | (hsync_end << HSYNCEND_SHIFT);
1038
1039         *vt = (vtotal << VTOTAL_SHIFT) | (vactive << VACTIVE_SHIFT);
1040         *vb = (vblank_start << VBLANKSTART_SHIFT) |
1041               (vblank_end << VSYNCEND_SHIFT);
1042         *vs = (vsync_start << VSYNCSTART_SHIFT) | (vsync_end << VSYNCEND_SHIFT);
1043         *ss = (hactive << SRC_SIZE_HORIZ_SHIFT) |
1044               (vactive << SRC_SIZE_VERT_SHIFT);
1045
1046         hw->disp_a_stride = var->xres_virtual * var->bits_per_pixel / 8;
1047         DBG_MSG("pitch is %d\n", hw->disp_a_stride);
1048
1049         hw->disp_a_base = hw->disp_a_stride * var->yoffset +
1050                           var->xoffset * var->bits_per_pixel / 8;
1051
1052         hw->disp_a_base += dinfo->fb.offset << 12;
1053
1054         /* Check stride alignment. */
1055         if (hw->disp_a_stride % STRIDE_ALIGNMENT != 0) {
1056                 WRN_MSG("display stride %d has bad alignment %d\n",
1057                         hw->disp_a_stride, STRIDE_ALIGNMENT);
1058                 return 1;
1059         }
1060
1061         /* Set the palette to 8-bit mode. */
1062         *pipe_conf &= ~PIPECONF_GAMMA;
1063         return 0;
1064 }
1065
1066 /* Program a (non-VGA) video mode. */
1067 int
1068 intelfbhw_program_mode(struct intelfb_info *dinfo,
1069                      const struct intelfb_hwstate *hw, int blank)
1070 {
1071         int pipe = PIPE_A;
1072         u32 tmp;
1073         const u32 *dpll, *fp0, *fp1, *pipe_conf;
1074         const u32 *hs, *ht, *hb, *vs, *vt, *vb, *ss;
1075         u32 dpll_reg, fp0_reg, fp1_reg, pipe_conf_reg;
1076         u32 hsync_reg, htotal_reg, hblank_reg;
1077         u32 vsync_reg, vtotal_reg, vblank_reg;
1078         u32 src_size_reg;
1079
1080         /* Assume single pipe, display plane A, analog CRT. */
1081
1082 #if VERBOSE > 0
1083         DBG_MSG("intelfbhw_program_mode\n");
1084 #endif
1085
1086         /* Disable VGA */
1087         tmp = INREG(VGACNTRL);
1088         tmp |= VGA_DISABLE;
1089         OUTREG(VGACNTRL, tmp);
1090
1091         /* Check whether pipe A or pipe B is enabled. */
1092         if (hw->pipe_a_conf & PIPECONF_ENABLE)
1093                 pipe = PIPE_A;
1094         else if (hw->pipe_b_conf & PIPECONF_ENABLE)
1095                 pipe = PIPE_B;
1096
1097         dinfo->pipe = pipe;
1098
1099         if (pipe == PIPE_B) {
1100                 dpll = &hw->dpll_b;
1101                 fp0 = &hw->fpb0;
1102                 fp1 = &hw->fpb1;
1103                 pipe_conf = &hw->pipe_b_conf;
1104                 hs = &hw->hsync_b;
1105                 hb = &hw->hblank_b;
1106                 ht = &hw->htotal_b;
1107                 vs = &hw->vsync_b;
1108                 vb = &hw->vblank_b;
1109                 vt = &hw->vtotal_b;
1110                 ss = &hw->src_size_b;
1111                 dpll_reg = DPLL_B;
1112                 fp0_reg = FPB0;
1113                 fp1_reg = FPB1;
1114                 pipe_conf_reg = PIPEBCONF;
1115                 hsync_reg = HSYNC_B;
1116                 htotal_reg = HTOTAL_B;
1117                 hblank_reg = HBLANK_B;
1118                 vsync_reg = VSYNC_B;
1119                 vtotal_reg = VTOTAL_B;
1120                 vblank_reg = VBLANK_B;
1121                 src_size_reg = SRC_SIZE_B;
1122         } else {
1123                 dpll = &hw->dpll_a;
1124                 fp0 = &hw->fpa0;
1125                 fp1 = &hw->fpa1;
1126                 pipe_conf = &hw->pipe_a_conf;
1127                 hs = &hw->hsync_a;
1128                 hb = &hw->hblank_a;
1129                 ht = &hw->htotal_a;
1130                 vs = &hw->vsync_a;
1131                 vb = &hw->vblank_a;
1132                 vt = &hw->vtotal_a;
1133                 ss = &hw->src_size_a;
1134                 dpll_reg = DPLL_A;
1135                 fp0_reg = FPA0;
1136                 fp1_reg = FPA1;
1137                 pipe_conf_reg = PIPEACONF;
1138                 hsync_reg = HSYNC_A;
1139                 htotal_reg = HTOTAL_A;
1140                 hblank_reg = HBLANK_A;
1141                 vsync_reg = VSYNC_A;
1142                 vtotal_reg = VTOTAL_A;
1143                 vblank_reg = VBLANK_A;
1144                 src_size_reg = SRC_SIZE_A;
1145         }
1146
1147         /* Disable planes A and B. */
1148         tmp = INREG(DSPACNTR);
1149         tmp &= ~DISPPLANE_PLANE_ENABLE;
1150         OUTREG(DSPACNTR, tmp);
1151         tmp = INREG(DSPBCNTR);
1152         tmp &= ~DISPPLANE_PLANE_ENABLE;
1153         OUTREG(DSPBCNTR, tmp);
1154
1155         /* Wait for vblank.  For now, just wait for a 50Hz cycle (20ms)) */
1156         mdelay(20);
1157
1158         /* Disable Sync */
1159         tmp = INREG(ADPA);
1160         tmp &= ~ADPA_DPMS_CONTROL_MASK;
1161         tmp |= ADPA_DPMS_D3;
1162         OUTREG(ADPA, tmp);
1163
1164         /* turn off pipe */
1165         tmp = INREG(pipe_conf_reg);
1166         tmp &= ~PIPECONF_ENABLE;
1167         OUTREG(pipe_conf_reg, tmp);
1168
1169         /* turn off PLL */
1170         tmp = INREG(dpll_reg);
1171         dpll_reg &= ~DPLL_VCO_ENABLE;
1172         OUTREG(dpll_reg, tmp);
1173
1174         /* Set PLL parameters */
1175         OUTREG(dpll_reg, *dpll & ~DPLL_VCO_ENABLE);
1176         OUTREG(fp0_reg, *fp0);
1177         OUTREG(fp1_reg, *fp1);
1178
1179         /* Set pipe parameters */
1180         OUTREG(hsync_reg, *hs);
1181         OUTREG(hblank_reg, *hb);
1182         OUTREG(htotal_reg, *ht);
1183         OUTREG(vsync_reg, *vs);
1184         OUTREG(vblank_reg, *vb);
1185         OUTREG(vtotal_reg, *vt);
1186         OUTREG(src_size_reg, *ss);
1187
1188         /* Set DVOs B/C */
1189         OUTREG(DVOB, hw->dvob);
1190         OUTREG(DVOC, hw->dvoc);
1191
1192         /* Set ADPA */
1193         OUTREG(ADPA, (hw->adpa & ~(ADPA_DPMS_CONTROL_MASK)) | ADPA_DPMS_D3);
1194
1195         /* Enable PLL */
1196         tmp = INREG(dpll_reg);
1197         tmp |= DPLL_VCO_ENABLE;
1198         OUTREG(dpll_reg, tmp);
1199
1200         /* Enable pipe */
1201         OUTREG(pipe_conf_reg, *pipe_conf | PIPECONF_ENABLE);
1202
1203         /* Enable sync */
1204         tmp = INREG(ADPA);
1205         tmp &= ~ADPA_DPMS_CONTROL_MASK;
1206         tmp |= ADPA_DPMS_D0;
1207         OUTREG(ADPA, tmp);
1208
1209         /* setup display plane */
1210         OUTREG(DSPACNTR, hw->disp_a_ctrl & ~DISPPLANE_PLANE_ENABLE);
1211         OUTREG(DSPASTRIDE, hw->disp_a_stride);
1212         OUTREG(DSPABASE, hw->disp_a_base);
1213
1214         /* Enable plane */
1215         if (!blank) {
1216                 tmp = INREG(DSPACNTR);
1217                 tmp |= DISPPLANE_PLANE_ENABLE;
1218                 OUTREG(DSPACNTR, tmp);
1219                 OUTREG(DSPABASE, hw->disp_a_base);
1220         }
1221
1222         return 0;
1223 }
1224
1225 /* forward declarations */
1226 static void refresh_ring(struct intelfb_info *dinfo);
1227 static void reset_state(struct intelfb_info *dinfo);
1228 static void do_flush(struct intelfb_info *dinfo);
1229
1230 static int
1231 wait_ring(struct intelfb_info *dinfo, int n)
1232 {
1233         int i = 0;
1234         unsigned long end;
1235         u32 last_head = INREG(PRI_RING_HEAD) & RING_HEAD_MASK;
1236
1237 #if VERBOSE > 0
1238         DBG_MSG("wait_ring: %d\n", n);
1239 #endif
1240
1241         end = jiffies + (HZ * 3);
1242         while (dinfo->ring_space < n) {
1243                 dinfo->ring_head = (u8 __iomem *)(INREG(PRI_RING_HEAD) &
1244                                                    RING_HEAD_MASK);
1245                 if (dinfo->ring_tail + RING_MIN_FREE <
1246                     (u32 __iomem) dinfo->ring_head)
1247                         dinfo->ring_space = (u32 __iomem) dinfo->ring_head
1248                                 - (dinfo->ring_tail + RING_MIN_FREE);
1249                 else
1250                         dinfo->ring_space = (dinfo->ring.size +
1251                                              (u32 __iomem) dinfo->ring_head)
1252                                 - (dinfo->ring_tail + RING_MIN_FREE);
1253                 if ((u32 __iomem) dinfo->ring_head != last_head) {
1254                         end = jiffies + (HZ * 3);
1255                         last_head = (u32 __iomem) dinfo->ring_head;
1256                 }
1257                 i++;
1258                 if (time_before(end, jiffies)) {
1259                         if (!i) {
1260                                 /* Try again */
1261                                 reset_state(dinfo);
1262                                 refresh_ring(dinfo);
1263                                 do_flush(dinfo);
1264                                 end = jiffies + (HZ * 3);
1265                                 i = 1;
1266                         } else {
1267                                 WRN_MSG("ring buffer : space: %d wanted %d\n",
1268                                         dinfo->ring_space, n);
1269                                 WRN_MSG("lockup - turning off hardware "
1270                                         "acceleration\n");
1271                                 dinfo->ring_lockup = 1;
1272                                 break;
1273                         }
1274                 }
1275                 udelay(1);
1276         }
1277         return i;
1278 }
1279
1280 static void
1281 do_flush(struct intelfb_info *dinfo) {
1282         START_RING(2);
1283         OUT_RING(MI_FLUSH | MI_WRITE_DIRTY_STATE | MI_INVALIDATE_MAP_CACHE);
1284         OUT_RING(MI_NOOP);
1285         ADVANCE_RING();
1286 }
1287
1288 void
1289 intelfbhw_do_sync(struct intelfb_info *dinfo)
1290 {
1291 #if VERBOSE > 0
1292         DBG_MSG("intelfbhw_do_sync\n");
1293 #endif
1294
1295         if (!dinfo->accel)
1296                 return;
1297
1298         /*
1299          * Send a flush, then wait until the ring is empty.  This is what
1300          * the XFree86 driver does, and actually it doesn't seem a lot worse
1301          * than the recommended method (both have problems).
1302          */
1303         do_flush(dinfo);
1304         wait_ring(dinfo, dinfo->ring.size - RING_MIN_FREE);
1305         dinfo->ring_space = dinfo->ring.size - RING_MIN_FREE;
1306 }
1307
1308 static void
1309 refresh_ring(struct intelfb_info *dinfo)
1310 {
1311 #if VERBOSE > 0
1312         DBG_MSG("refresh_ring\n");
1313 #endif
1314
1315         dinfo->ring_head = (u8 __iomem *) (INREG(PRI_RING_HEAD) &
1316                                            RING_HEAD_MASK);
1317         dinfo->ring_tail = INREG(PRI_RING_TAIL) & RING_TAIL_MASK;
1318         if (dinfo->ring_tail + RING_MIN_FREE < (u32 __iomem)dinfo->ring_head)
1319                 dinfo->ring_space = (u32 __iomem) dinfo->ring_head
1320                         - (dinfo->ring_tail + RING_MIN_FREE);
1321         else
1322                 dinfo->ring_space = (dinfo->ring.size +
1323                                      (u32 __iomem) dinfo->ring_head)
1324                         - (dinfo->ring_tail + RING_MIN_FREE);
1325 }
1326
1327 static void
1328 reset_state(struct intelfb_info *dinfo)
1329 {
1330         int i;
1331         u32 tmp;
1332
1333 #if VERBOSE > 0
1334         DBG_MSG("reset_state\n");
1335 #endif
1336
1337         for (i = 0; i < FENCE_NUM; i++)
1338                 OUTREG(FENCE + (i << 2), 0);
1339
1340         /* Flush the ring buffer if it's enabled. */
1341         tmp = INREG(PRI_RING_LENGTH);
1342         if (tmp & RING_ENABLE) {
1343 #if VERBOSE > 0
1344                 DBG_MSG("reset_state: ring was enabled\n");
1345 #endif
1346                 refresh_ring(dinfo);
1347                 intelfbhw_do_sync(dinfo);
1348                 DO_RING_IDLE();
1349         }
1350
1351         OUTREG(PRI_RING_LENGTH, 0);
1352         OUTREG(PRI_RING_HEAD, 0);
1353         OUTREG(PRI_RING_TAIL, 0);
1354         OUTREG(PRI_RING_START, 0);
1355 }
1356
1357 /* Stop the 2D engine, and turn off the ring buffer. */
1358 void
1359 intelfbhw_2d_stop(struct intelfb_info *dinfo)
1360 {
1361 #if VERBOSE > 0
1362         DBG_MSG("intelfbhw_2d_stop: accel: %d, ring_active: %d\n", dinfo->accel,
1363                 dinfo->ring_active);
1364 #endif
1365
1366         if (!dinfo->accel)
1367                 return;
1368
1369         dinfo->ring_active = 0;
1370         reset_state(dinfo);
1371 }
1372
1373 /*
1374  * Enable the ring buffer, and initialise the 2D engine.
1375  * It is assumed that the graphics engine has been stopped by previously
1376  * calling intelfb_2d_stop().
1377  */
1378 void
1379 intelfbhw_2d_start(struct intelfb_info *dinfo)
1380 {
1381 #if VERBOSE > 0
1382         DBG_MSG("intelfbhw_2d_start: accel: %d, ring_active: %d\n",
1383                 dinfo->accel, dinfo->ring_active);
1384 #endif
1385
1386         if (!dinfo->accel)
1387                 return;
1388
1389         /* Initialise the primary ring buffer. */
1390         OUTREG(PRI_RING_LENGTH, 0);
1391         OUTREG(PRI_RING_TAIL, 0);
1392         OUTREG(PRI_RING_HEAD, 0);
1393
1394         OUTREG(PRI_RING_START, dinfo->ring.physical & RING_START_MASK);
1395         OUTREG(PRI_RING_LENGTH,
1396                 ((dinfo->ring.size - GTT_PAGE_SIZE) & RING_LENGTH_MASK) |
1397                 RING_NO_REPORT | RING_ENABLE);
1398         refresh_ring(dinfo);
1399         dinfo->ring_active = 1;
1400 }
1401
1402 /* 2D fillrect (solid fill or invert) */
1403 void
1404 intelfbhw_do_fillrect(struct intelfb_info *dinfo, u32 x, u32 y, u32 w, u32 h,
1405                       u32 color, u32 pitch, u32 bpp, u32 rop)
1406 {
1407         u32 br00, br09, br13, br14, br16;
1408
1409 #if VERBOSE > 0
1410         DBG_MSG("intelfbhw_do_fillrect: (%d,%d) %dx%d, c 0x%06x, p %d bpp %d, "
1411                 "rop 0x%02x\n", x, y, w, h, color, pitch, bpp, rop);
1412 #endif
1413
1414         br00 = COLOR_BLT_CMD;
1415         br09 = dinfo->fb_start + (y * pitch + x * (bpp / 8));
1416         br13 = (rop << ROP_SHIFT) | pitch;
1417         br14 = (h << HEIGHT_SHIFT) | ((w * (bpp / 8)) << WIDTH_SHIFT);
1418         br16 = color;
1419
1420         switch (bpp) {
1421         case 8:
1422                 br13 |= COLOR_DEPTH_8;
1423                 break;
1424         case 16:
1425                 br13 |= COLOR_DEPTH_16;
1426                 break;
1427         case 32:
1428                 br13 |= COLOR_DEPTH_32;
1429                 br00 |= WRITE_ALPHA | WRITE_RGB;
1430                 break;
1431         }
1432
1433         START_RING(6);
1434         OUT_RING(br00);
1435         OUT_RING(br13);
1436         OUT_RING(br14);
1437         OUT_RING(br09);
1438         OUT_RING(br16);
1439         OUT_RING(MI_NOOP);
1440         ADVANCE_RING();
1441
1442 #if VERBOSE > 0
1443         DBG_MSG("ring = 0x%08x, 0x%08x (%d)\n", dinfo->ring_head,
1444                 dinfo->ring_tail, dinfo->ring_space);
1445 #endif
1446 }
1447
1448 void
1449 intelfbhw_do_bitblt(struct intelfb_info *dinfo, u32 curx, u32 cury,
1450                     u32 dstx, u32 dsty, u32 w, u32 h, u32 pitch, u32 bpp)
1451 {
1452         u32 br00, br09, br11, br12, br13, br22, br23, br26;
1453
1454 #if VERBOSE > 0
1455         DBG_MSG("intelfbhw_do_bitblt: (%d,%d)->(%d,%d) %dx%d, p %d bpp %d\n",
1456                 curx, cury, dstx, dsty, w, h, pitch, bpp);
1457 #endif
1458
1459         br00 = XY_SRC_COPY_BLT_CMD;
1460         br09 = dinfo->fb_start;
1461         br11 = (pitch << PITCH_SHIFT);
1462         br12 = dinfo->fb_start;
1463         br13 = (SRC_ROP_GXCOPY << ROP_SHIFT) | (pitch << PITCH_SHIFT);
1464         br22 = (dstx << WIDTH_SHIFT) | (dsty << HEIGHT_SHIFT);
1465         br23 = ((dstx + w) << WIDTH_SHIFT) |
1466                ((dsty + h) << HEIGHT_SHIFT);
1467         br26 = (curx << WIDTH_SHIFT) | (cury << HEIGHT_SHIFT);
1468
1469         switch (bpp) {
1470         case 8:
1471                 br13 |= COLOR_DEPTH_8;
1472                 break;
1473         case 16:
1474                 br13 |= COLOR_DEPTH_16;
1475                 break;
1476         case 32:
1477                 br13 |= COLOR_DEPTH_32;
1478                 br00 |= WRITE_ALPHA | WRITE_RGB;
1479                 break;
1480         }
1481
1482         START_RING(8);
1483         OUT_RING(br00);
1484         OUT_RING(br13);
1485         OUT_RING(br22);
1486         OUT_RING(br23);
1487         OUT_RING(br09);
1488         OUT_RING(br26);
1489         OUT_RING(br11);
1490         OUT_RING(br12);
1491         ADVANCE_RING();
1492 }
1493
1494 int
1495 intelfbhw_do_drawglyph(struct intelfb_info *dinfo, u32 fg, u32 bg, u32 w,
1496                        u32 h, const u8* cdat, u32 x, u32 y, u32 pitch, u32 bpp)
1497 {
1498         int nbytes, ndwords, pad, tmp;
1499         u32 br00, br09, br13, br18, br19, br22, br23;
1500         int dat, ix, iy, iw;
1501         int i, j;
1502
1503 #if VERBOSE > 0
1504         DBG_MSG("intelfbhw_do_drawglyph: (%d,%d) %dx%d\n", x, y, w, h);
1505 #endif
1506
1507         /* size in bytes of a padded scanline */
1508         nbytes = ROUND_UP_TO(w, 16) / 8;
1509
1510         /* Total bytes of padded scanline data to write out. */
1511         nbytes = nbytes * h;
1512
1513         /*
1514          * Check if the glyph data exceeds the immediate mode limit.
1515          * It would take a large font (1K pixels) to hit this limit.
1516          */
1517         if (nbytes > MAX_MONO_IMM_SIZE)
1518                 return 0;
1519
1520         /* Src data is packaged a dword (32-bit) at a time. */
1521         ndwords = ROUND_UP_TO(nbytes, 4) / 4;
1522
1523         /*
1524          * Ring has to be padded to a quad word. But because the command starts
1525            with 7 bytes, pad only if there is an even number of ndwords
1526          */
1527         pad = !(ndwords % 2);
1528
1529         tmp = (XY_MONO_SRC_IMM_BLT_CMD & DW_LENGTH_MASK) + ndwords;
1530         br00 = (XY_MONO_SRC_IMM_BLT_CMD & ~DW_LENGTH_MASK) | tmp;
1531         br09 = dinfo->fb_start;
1532         br13 = (SRC_ROP_GXCOPY << ROP_SHIFT) | (pitch << PITCH_SHIFT);
1533         br18 = bg;
1534         br19 = fg;
1535         br22 = (x << WIDTH_SHIFT) | (y << HEIGHT_SHIFT);
1536         br23 = ((x + w) << WIDTH_SHIFT) | ((y + h) << HEIGHT_SHIFT);
1537
1538         switch (bpp) {
1539         case 8:
1540                 br13 |= COLOR_DEPTH_8;
1541                 break;
1542         case 16:
1543                 br13 |= COLOR_DEPTH_16;
1544                 break;
1545         case 32:
1546                 br13 |= COLOR_DEPTH_32;
1547                 br00 |= WRITE_ALPHA | WRITE_RGB;
1548                 break;
1549         }
1550
1551         START_RING(8 + ndwords);
1552         OUT_RING(br00);
1553         OUT_RING(br13);
1554         OUT_RING(br22);
1555         OUT_RING(br23);
1556         OUT_RING(br09);
1557         OUT_RING(br18);
1558         OUT_RING(br19);
1559         ix = iy = 0;
1560         iw = ROUND_UP_TO(w, 8) / 8;
1561         while (ndwords--) {
1562                 dat = 0;
1563                 for (j = 0; j < 2; ++j) {
1564                         for (i = 0; i < 2; ++i) {
1565                                 if (ix != iw || i == 0)
1566                                         dat |= cdat[iy*iw + ix++] << (i+j*2)*8;
1567                         }
1568                         if (ix == iw && iy != (h-1)) {
1569                                 ix = 0;
1570                                 ++iy;
1571                         }
1572                 }
1573                 OUT_RING(dat);
1574         }
1575         if (pad)
1576                 OUT_RING(MI_NOOP);
1577         ADVANCE_RING();
1578
1579         return 1;
1580 }
1581
1582 /* HW cursor functions. */
1583 void
1584 intelfbhw_cursor_init(struct intelfb_info *dinfo)
1585 {
1586         u32 tmp;
1587
1588 #if VERBOSE > 0
1589         DBG_MSG("intelfbhw_cursor_init\n");
1590 #endif
1591
1592         if (dinfo->mobile) {
1593                 if (!dinfo->cursor.physical)
1594                         return;
1595                 tmp = INREG(CURSOR_A_CONTROL);
1596                 tmp &= ~(CURSOR_MODE_MASK | CURSOR_MOBILE_GAMMA_ENABLE |
1597                          CURSOR_MEM_TYPE_LOCAL |
1598                          (1 << CURSOR_PIPE_SELECT_SHIFT));
1599                 tmp |= CURSOR_MODE_DISABLE;
1600                 OUTREG(CURSOR_A_CONTROL, tmp);
1601                 OUTREG(CURSOR_A_BASEADDR, dinfo->cursor.physical);
1602         } else {
1603                 tmp = INREG(CURSOR_CONTROL);
1604                 tmp &= ~(CURSOR_FORMAT_MASK | CURSOR_GAMMA_ENABLE |
1605                          CURSOR_ENABLE | CURSOR_STRIDE_MASK);
1606                 tmp = CURSOR_FORMAT_3C;
1607                 OUTREG(CURSOR_CONTROL, tmp);
1608                 OUTREG(CURSOR_A_BASEADDR, dinfo->cursor.offset << 12);
1609                 tmp = (64 << CURSOR_SIZE_H_SHIFT) |
1610                       (64 << CURSOR_SIZE_V_SHIFT);
1611                 OUTREG(CURSOR_SIZE, tmp);
1612         }
1613 }
1614
1615 void
1616 intelfbhw_cursor_hide(struct intelfb_info *dinfo)
1617 {
1618         u32 tmp;
1619
1620 #if VERBOSE > 0
1621         DBG_MSG("intelfbhw_cursor_hide\n");
1622 #endif
1623
1624         dinfo->cursor_on = 0;
1625         if (dinfo->mobile) {
1626                 if (!dinfo->cursor.physical)
1627                         return;
1628                 tmp = INREG(CURSOR_A_CONTROL);
1629                 tmp &= ~CURSOR_MODE_MASK;
1630                 tmp |= CURSOR_MODE_DISABLE;
1631                 OUTREG(CURSOR_A_CONTROL, tmp);
1632                 /* Flush changes */
1633                 OUTREG(CURSOR_A_BASEADDR, dinfo->cursor.physical);
1634         } else {
1635                 tmp = INREG(CURSOR_CONTROL);
1636                 tmp &= ~CURSOR_ENABLE;
1637                 OUTREG(CURSOR_CONTROL, tmp);
1638         }
1639 }
1640
1641 void
1642 intelfbhw_cursor_show(struct intelfb_info *dinfo)
1643 {
1644         u32 tmp;
1645
1646 #if VERBOSE > 0
1647         DBG_MSG("intelfbhw_cursor_show\n");
1648 #endif
1649
1650         dinfo->cursor_on = 1;
1651
1652         if (dinfo->cursor_blanked)
1653                 return;
1654
1655         if (dinfo->mobile) {
1656                 if (!dinfo->cursor.physical)
1657                         return;
1658                 tmp = INREG(CURSOR_A_CONTROL);
1659                 tmp &= ~CURSOR_MODE_MASK;
1660                 tmp |= CURSOR_MODE_64_4C_AX;
1661                 OUTREG(CURSOR_A_CONTROL, tmp);
1662                 /* Flush changes */
1663                 OUTREG(CURSOR_A_BASEADDR, dinfo->cursor.physical);
1664         } else {
1665                 tmp = INREG(CURSOR_CONTROL);
1666                 tmp |= CURSOR_ENABLE;
1667                 OUTREG(CURSOR_CONTROL, tmp);
1668         }
1669 }
1670
1671 void
1672 intelfbhw_cursor_setpos(struct intelfb_info *dinfo, int x, int y)
1673 {
1674         u32 tmp;
1675
1676 #if VERBOSE > 0
1677         DBG_MSG("intelfbhw_cursor_setpos: (%d, %d)\n", x, y);
1678 #endif
1679
1680         /*
1681          * Sets the position.  The coordinates are assumed to already
1682          * have any offset adjusted.  Assume that the cursor is never
1683          * completely off-screen, and that x, y are always >= 0.
1684          */
1685
1686         tmp = ((x & CURSOR_POS_MASK) << CURSOR_X_SHIFT) |
1687               ((y & CURSOR_POS_MASK) << CURSOR_Y_SHIFT);
1688         OUTREG(CURSOR_A_POSITION, tmp);
1689 }
1690
1691 void
1692 intelfbhw_cursor_setcolor(struct intelfb_info *dinfo, u32 bg, u32 fg)
1693 {
1694 #if VERBOSE > 0
1695         DBG_MSG("intelfbhw_cursor_setcolor\n");
1696 #endif
1697
1698         OUTREG(CURSOR_A_PALETTE0, bg & CURSOR_PALETTE_MASK);
1699         OUTREG(CURSOR_A_PALETTE1, fg & CURSOR_PALETTE_MASK);
1700         OUTREG(CURSOR_A_PALETTE2, fg & CURSOR_PALETTE_MASK);
1701         OUTREG(CURSOR_A_PALETTE3, bg & CURSOR_PALETTE_MASK);
1702 }
1703
1704 void
1705 intelfbhw_cursor_load(struct intelfb_info *dinfo, int width, int height,
1706                       u8 *data)
1707 {
1708         u8 __iomem *addr = (u8 __iomem *)dinfo->cursor.virtual;
1709         int i, j, w = width / 8;
1710         int mod = width % 8, t_mask, d_mask;
1711
1712 #if VERBOSE > 0
1713         DBG_MSG("intelfbhw_cursor_load\n");
1714 #endif
1715
1716         if (!dinfo->cursor.virtual)
1717                 return;
1718
1719         t_mask = 0xff >> mod;
1720         d_mask = ~(0xff >> mod);
1721         for (i = height; i--; ) {
1722                 for (j = 0; j < w; j++) {
1723                         writeb(0x00, addr + j);
1724                         writeb(*(data++), addr + j+8);
1725                 }
1726                 if (mod) {
1727                         writeb(t_mask, addr + j);
1728                         writeb(*(data++) & d_mask, addr + j+8);
1729                 }
1730                 addr += 16;
1731         }
1732 }
1733
1734 void
1735 intelfbhw_cursor_reset(struct intelfb_info *dinfo) {
1736         u8 __iomem *addr = (u8 __iomem *)dinfo->cursor.virtual;
1737         int i, j;
1738
1739 #if VERBOSE > 0
1740         DBG_MSG("intelfbhw_cursor_reset\n");
1741 #endif
1742
1743         if (!dinfo->cursor.virtual)
1744                 return;
1745
1746         for (i = 64; i--; ) {
1747                 for (j = 0; j < 8; j++) {
1748                         writeb(0xff, addr + j+0);
1749                         writeb(0x00, addr + j+8);
1750                 }
1751                 addr += 16;
1752         }
1753 }