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