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