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