Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
lxfb_ops.c
Go to the documentation of this file.
1 /* Geode LX framebuffer driver
2  *
3  * Copyright (C) 2006-2007, Advanced Micro Devices,Inc.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the
7  * Free Software Foundation; either version 2 of the License, or (at your
8  * option) any later version.
9  */
10 
11 #include <linux/kernel.h>
12 #include <linux/errno.h>
13 #include <linux/fb.h>
14 #include <linux/uaccess.h>
15 #include <linux/delay.h>
16 #include <linux/cs5535.h>
17 
18 #include "lxfb.h"
19 
20 /* TODO
21  * Support panel scaling
22  * Add acceleration
23  * Add support for interlacing (TV out)
24  * Support compression
25  */
26 
27 /* This is the complete list of PLL frequencies that we can set -
28  * we will choose the closest match to the incoming clock.
29  * freq is the frequency of the dotclock * 1000 (for example,
30  * 24823 = 24.983 Mhz).
31  * pllval is the corresponding PLL value
32 */
33 
34 static const struct {
35  unsigned int pllval;
36  unsigned int freq;
37 } pll_table[] = {
38  { 0x000131AC, 6231 },
39  { 0x0001215D, 6294 },
40  { 0x00011087, 6750 },
41  { 0x0001216C, 7081 },
42  { 0x0001218D, 7140 },
43  { 0x000110C9, 7800 },
44  { 0x00013147, 7875 },
45  { 0x000110A7, 8258 },
46  { 0x00012159, 8778 },
47  { 0x00014249, 8875 },
48  { 0x00010057, 9000 },
49  { 0x0001219A, 9472 },
50  { 0x00012158, 9792 },
51  { 0x00010045, 10000 },
52  { 0x00010089, 10791 },
53  { 0x000110E7, 11225 },
54  { 0x00012136, 11430 },
55  { 0x00013207, 12375 },
56  { 0x00012187, 12500 },
57  { 0x00014286, 14063 },
58  { 0x000110E5, 15016 },
59  { 0x00014214, 16250 },
60  { 0x00011105, 17045 },
61  { 0x000131E4, 18563 },
62  { 0x00013183, 18750 },
63  { 0x00014284, 19688 },
64  { 0x00011104, 20400 },
65  { 0x00016363, 23625 },
66  { 0x000031AC, 24923 },
67  { 0x0000215D, 25175 },
68  { 0x00001087, 27000 },
69  { 0x0000216C, 28322 },
70  { 0x0000218D, 28560 },
71  { 0x000010C9, 31200 },
72  { 0x00003147, 31500 },
73  { 0x000010A7, 33032 },
74  { 0x00002159, 35112 },
75  { 0x00004249, 35500 },
76  { 0x00000057, 36000 },
77  { 0x0000219A, 37889 },
78  { 0x00002158, 39168 },
79  { 0x00000045, 40000 },
80  { 0x00000089, 43163 },
81  { 0x000010E7, 44900 },
82  { 0x00002136, 45720 },
83  { 0x00003207, 49500 },
84  { 0x00002187, 50000 },
85  { 0x00004286, 56250 },
86  { 0x000010E5, 60065 },
87  { 0x00004214, 65000 },
88  { 0x00001105, 68179 },
89  { 0x000031E4, 74250 },
90  { 0x00003183, 75000 },
91  { 0x00004284, 78750 },
92  { 0x00001104, 81600 },
93  { 0x00006363, 94500 },
94  { 0x00005303, 97520 },
95  { 0x00002183, 100187 },
96  { 0x00002122, 101420 },
97  { 0x00001081, 108000 },
98  { 0x00006201, 113310 },
99  { 0x00000041, 119650 },
100  { 0x000041A1, 129600 },
101  { 0x00002182, 133500 },
102  { 0x000041B1, 135000 },
103  { 0x00000051, 144000 },
104  { 0x000041E1, 148500 },
105  { 0x000062D1, 157500 },
106  { 0x000031A1, 162000 },
107  { 0x00000061, 169203 },
108  { 0x00004231, 172800 },
109  { 0x00002151, 175500 },
110  { 0x000052E1, 189000 },
111  { 0x00000071, 192000 },
112  { 0x00003201, 198000 },
113  { 0x00004291, 202500 },
114  { 0x00001101, 204750 },
115  { 0x00007481, 218250 },
116  { 0x00004170, 229500 },
117  { 0x00006210, 234000 },
118  { 0x00003140, 251182 },
119  { 0x00006250, 261000 },
120  { 0x000041C0, 278400 },
121  { 0x00005220, 280640 },
122  { 0x00000050, 288000 },
123  { 0x000041E0, 297000 },
124  { 0x00002130, 320207 }
125 };
126 
127 
128 static void lx_set_dotpll(u32 pllval)
129 {
130  u32 dotpll_lo, dotpll_hi;
131  int i;
132 
133  rdmsr(MSR_GLCP_DOTPLL, dotpll_lo, dotpll_hi);
134 
135  if ((dotpll_lo & MSR_GLCP_DOTPLL_LOCK) && (dotpll_hi == pllval))
136  return;
137 
138  dotpll_hi = pllval;
140  dotpll_lo |= MSR_GLCP_DOTPLL_DOTRESET;
141 
142  wrmsr(MSR_GLCP_DOTPLL, dotpll_lo, dotpll_hi);
143 
144  /* Wait 100us for the PLL to lock */
145 
146  udelay(100);
147 
148  /* Now, loop for the lock bit */
149 
150  for (i = 0; i < 1000; i++) {
151  rdmsr(MSR_GLCP_DOTPLL, dotpll_lo, dotpll_hi);
152  if (dotpll_lo & MSR_GLCP_DOTPLL_LOCK)
153  break;
154  }
155 
156  /* Clear the reset bit */
157 
158  dotpll_lo &= ~MSR_GLCP_DOTPLL_DOTRESET;
159  wrmsr(MSR_GLCP_DOTPLL, dotpll_lo, dotpll_hi);
160 }
161 
162 /* Set the clock based on the frequency specified by the current mode */
163 
164 static void lx_set_clock(struct fb_info *info)
165 {
166  unsigned int diff, min, best = 0;
167  unsigned int freq, i;
168 
169  freq = (unsigned int) (1000000000 / info->var.pixclock);
170 
171  min = abs(pll_table[0].freq - freq);
172 
173  for (i = 0; i < ARRAY_SIZE(pll_table); i++) {
174  diff = abs(pll_table[i].freq - freq);
175  if (diff < min) {
176  min = diff;
177  best = i;
178  }
179  }
180 
181  lx_set_dotpll(pll_table[best].pllval & 0x00017FFF);
182 }
183 
184 static void lx_graphics_disable(struct fb_info *info)
185 {
186  struct lxfb_par *par = info->par;
187  unsigned int val, gcfg;
188 
189  /* Note: This assumes that the video is in a quitet state */
190 
191  write_vp(par, VP_A1T, 0);
192  write_vp(par, VP_A2T, 0);
193  write_vp(par, VP_A3T, 0);
194 
195  /* Turn off the VGA and video enable */
196  val = read_dc(par, DC_GENERAL_CFG) & ~(DC_GENERAL_CFG_VGAE |
198 
199  write_dc(par, DC_GENERAL_CFG, val);
200 
201  val = read_vp(par, VP_VCFG) & ~VP_VCFG_VID_EN;
202  write_vp(par, VP_VCFG, val);
203 
206 
207  val = read_dc(par, DC_GENLK_CTL) & ~DC_GENLK_CTL_GENLK_EN;
208  write_dc(par, DC_GENLK_CTL, val);
209 
210  val = read_dc(par, DC_CLR_KEY);
211  write_dc(par, DC_CLR_KEY, val & ~DC_CLR_KEY_CLR_KEY_EN);
212 
213  /* turn off the panel */
214  write_fp(par, FP_PM, read_fp(par, FP_PM) & ~FP_PM_P);
215 
216  val = read_vp(par, VP_MISC) | VP_MISC_DACPWRDN;
217  write_vp(par, VP_MISC, val);
218 
219  /* Turn off the display */
220 
221  val = read_vp(par, VP_DCFG);
222  write_vp(par, VP_DCFG, val & ~(VP_DCFG_CRT_EN | VP_DCFG_HSYNC_EN |
224 
225  gcfg = read_dc(par, DC_GENERAL_CFG);
227  write_dc(par, DC_GENERAL_CFG, gcfg);
228 
229  /* Turn off the TGEN */
230  val = read_dc(par, DC_DISPLAY_CFG);
231  val &= ~DC_DISPLAY_CFG_TGEN;
232  write_dc(par, DC_DISPLAY_CFG, val);
233 
234  /* Wait 1000 usecs to ensure that the TGEN is clear */
235  udelay(1000);
236 
237  /* Turn off the FIFO loader */
238 
239  gcfg &= ~DC_GENERAL_CFG_DFLE;
240  write_dc(par, DC_GENERAL_CFG, gcfg);
241 
242  /* Lastly, wait for the GP to go idle */
243 
244  do {
245  val = read_gp(par, GP_BLT_STATUS);
246  } while ((val & GP_BLT_STATUS_PB) || !(val & GP_BLT_STATUS_CE));
247 }
248 
249 static void lx_graphics_enable(struct fb_info *info)
250 {
251  struct lxfb_par *par = info->par;
252  u32 temp, config;
253 
254  /* Set the video request register */
255  write_vp(par, VP_VRR, 0);
256 
257  /* Set up the polarities */
258 
259  config = read_vp(par, VP_DCFG);
260 
263 
265  | VP_DCFG_GV_GAM);
266 
267  if (info->var.sync & FB_SYNC_HOR_HIGH_ACT)
268  config |= VP_DCFG_CRT_HSYNC_POL;
269 
270  if (info->var.sync & FB_SYNC_VERT_HIGH_ACT)
271  config |= VP_DCFG_CRT_VSYNC_POL;
272 
273  if (par->output & OUTPUT_PANEL) {
274  u32 msrlo, msrhi;
275 
276  write_fp(par, FP_PT1, 0);
277  temp = FP_PT2_SCRC;
278 
279  if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
280  temp |= FP_PT2_HSP;
281 
282  if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
283  temp |= FP_PT2_VSP;
284 
285  write_fp(par, FP_PT2, temp);
286  write_fp(par, FP_DFC, FP_DFC_BC);
287 
290 
291  wrmsr(MSR_LX_MSR_PADSEL, msrlo, msrhi);
292  }
293 
294  if (par->output & OUTPUT_CRT) {
295  config |= VP_DCFG_CRT_EN | VP_DCFG_HSYNC_EN |
297  }
298 
299  write_vp(par, VP_DCFG, config);
300 
301  /* Turn the CRT dacs back on */
302 
303  if (par->output & OUTPUT_CRT) {
304  temp = read_vp(par, VP_MISC);
305  temp &= ~(VP_MISC_DACPWRDN | VP_MISC_APWRDN);
306  write_vp(par, VP_MISC, temp);
307  }
308 
309  /* Turn the panel on (if it isn't already) */
310  if (par->output & OUTPUT_PANEL)
311  write_fp(par, FP_PM, read_fp(par, FP_PM) | FP_PM_P);
312 }
313 
314 unsigned int lx_framebuffer_size(void)
315 {
316  unsigned int val;
317 
318  if (!cs5535_has_vsa2()) {
319  uint32_t hi, lo;
320 
321  /* The number of pages is (PMAX - PMIN)+1 */
322  rdmsr(MSR_GLIU_P2D_RO0, lo, hi);
323 
324  /* PMAX */
325  val = ((hi & 0xff) << 12) | ((lo & 0xfff00000) >> 20);
326  /* PMIN */
327  val -= (lo & 0x000fffff);
328  val += 1;
329 
330  /* The page size is 4k */
331  return (val << 12);
332  }
333 
334  /* The frame buffer size is reported by a VSM in VSA II */
335  /* Virtual Register Class = 0x02 */
336  /* VG_MEM_SIZE (1MB units) = 0x00 */
337 
340 
341  val = (unsigned int)(inw(VSA_VRC_DATA)) & 0xFE;
342  return (val << 20);
343 }
344 
345 void lx_set_mode(struct fb_info *info)
346 {
347  struct lxfb_par *par = info->par;
348  u64 msrval;
349 
350  unsigned int max, dv, val, size;
351 
352  unsigned int gcfg, dcfg;
353  int hactive, hblankstart, hsyncstart, hsyncend, hblankend, htotal;
354  int vactive, vblankstart, vsyncstart, vsyncend, vblankend, vtotal;
355 
356  /* Unlock the DC registers */
357  write_dc(par, DC_UNLOCK, DC_UNLOCK_UNLOCK);
358 
359  lx_graphics_disable(info);
360 
361  lx_set_clock(info);
362 
363  /* Set output mode */
364 
365  rdmsrl(MSR_LX_GLD_MSR_CONFIG, msrval);
366  msrval &= ~MSR_LX_GLD_MSR_CONFIG_FMT;
367 
368  if (par->output & OUTPUT_PANEL) {
370 
371  if (par->output & OUTPUT_CRT)
372  msrval |= MSR_LX_GLD_MSR_CONFIG_FPC;
373  else
374  msrval &= ~MSR_LX_GLD_MSR_CONFIG_FPC;
375  } else
377 
378  wrmsrl(MSR_LX_GLD_MSR_CONFIG, msrval);
379 
380  /* Clear the various buffers */
381  /* FIXME: Adjust for panning here */
382 
383  write_dc(par, DC_FB_ST_OFFSET, 0);
384  write_dc(par, DC_CB_ST_OFFSET, 0);
385  write_dc(par, DC_CURS_ST_OFFSET, 0);
386 
387  /* FIXME: Add support for interlacing */
388  /* FIXME: Add support for scaling */
389 
390  val = read_dc(par, DC_GENLK_CTL);
393 
394  /* Default scaling params */
395 
396  write_dc(par, DC_GFX_SCALE, (0x4000 << 16) | 0x4000);
397  write_dc(par, DC_IRQ_FILT_CTL, 0);
398  write_dc(par, DC_GENLK_CTL, val);
399 
400  /* FIXME: Support compression */
401 
402  if (info->fix.line_length > 4096)
404  else if (info->fix.line_length > 2048)
406  else if (info->fix.line_length > 1024)
408  else
410 
411  max = info->fix.line_length * info->var.yres;
412  max = (max + 0x3FF) & 0xFFFFFC00;
413 
414  write_dc(par, DC_DV_TOP, max | DC_DV_TOP_DV_TOP_EN);
415 
416  val = read_dc(par, DC_DV_CTL) & ~DC_DV_CTL_DV_LINE_SIZE;
417  write_dc(par, DC_DV_CTL, val | dv);
418 
419  size = info->var.xres * (info->var.bits_per_pixel >> 3);
420 
421  write_dc(par, DC_GFX_PITCH, info->fix.line_length >> 3);
422  write_dc(par, DC_LINE_SIZE, (size + 7) >> 3);
423 
424  /* Set default watermark values */
425 
426  rdmsrl(MSR_LX_SPARE_MSR, msrval);
427 
432  msrval |= MSR_LX_SPARE_MSR_DIS_VIFO_WM |
434  wrmsrl(MSR_LX_SPARE_MSR, msrval);
435 
436  gcfg = DC_GENERAL_CFG_DFLE; /* Display fifo enable */
437  gcfg |= (0x6 << DC_GENERAL_CFG_DFHPSL_SHIFT) | /* default priority */
439  gcfg |= DC_GENERAL_CFG_FDTY; /* Set the frame dirty mode */
440 
441  dcfg = DC_DISPLAY_CFG_VDEN; /* Enable video data */
442  dcfg |= DC_DISPLAY_CFG_GDEN; /* Enable graphics */
443  dcfg |= DC_DISPLAY_CFG_TGEN; /* Turn on the timing generator */
444  dcfg |= DC_DISPLAY_CFG_TRUP; /* Update timings immediately */
445  dcfg |= DC_DISPLAY_CFG_PALB; /* Palette bypass in > 8 bpp modes */
446  dcfg |= DC_DISPLAY_CFG_VISL;
447  dcfg |= DC_DISPLAY_CFG_DCEN; /* Always center the display */
448 
449  /* Set the current BPP mode */
450 
451  switch (info->var.bits_per_pixel) {
452  case 8:
454  break;
455 
456  case 16:
458  break;
459 
460  case 32:
461  case 24:
463  break;
464  }
465 
466  /* Now - set up the timings */
467 
468  hactive = info->var.xres;
469  hblankstart = hactive;
470  hsyncstart = hblankstart + info->var.right_margin;
471  hsyncend = hsyncstart + info->var.hsync_len;
472  hblankend = hsyncend + info->var.left_margin;
473  htotal = hblankend;
474 
475  vactive = info->var.yres;
476  vblankstart = vactive;
477  vsyncstart = vblankstart + info->var.lower_margin;
478  vsyncend = vsyncstart + info->var.vsync_len;
479  vblankend = vsyncend + info->var.upper_margin;
480  vtotal = vblankend;
481 
482  write_dc(par, DC_H_ACTIVE_TIMING, (hactive - 1) | ((htotal - 1) << 16));
483  write_dc(par, DC_H_BLANK_TIMING,
484  (hblankstart - 1) | ((hblankend - 1) << 16));
485  write_dc(par, DC_H_SYNC_TIMING,
486  (hsyncstart - 1) | ((hsyncend - 1) << 16));
487 
488  write_dc(par, DC_V_ACTIVE_TIMING, (vactive - 1) | ((vtotal - 1) << 16));
489  write_dc(par, DC_V_BLANK_TIMING,
490  (vblankstart - 1) | ((vblankend - 1) << 16));
491  write_dc(par, DC_V_SYNC_TIMING,
492  (vsyncstart - 1) | ((vsyncend - 1) << 16));
493 
494  write_dc(par, DC_FB_ACTIVE,
495  (info->var.xres - 1) << 16 | (info->var.yres - 1));
496 
497  /* And re-enable the graphics output */
498  lx_graphics_enable(info);
499 
500  /* Write the two main configuration registers */
501  write_dc(par, DC_DISPLAY_CFG, dcfg);
502  write_dc(par, DC_ARB_CFG, 0);
503  write_dc(par, DC_GENERAL_CFG, gcfg);
504 
505  /* Lock the DC registers */
506  write_dc(par, DC_UNLOCK, DC_UNLOCK_LOCK);
507 }
508 
509 void lx_set_palette_reg(struct fb_info *info, unsigned regno,
510  unsigned red, unsigned green, unsigned blue)
511 {
512  struct lxfb_par *par = info->par;
513  int val;
514 
515  /* Hardware palette is in RGB 8-8-8 format. */
516 
517  val = (red << 8) & 0xff0000;
518  val |= (green) & 0x00ff00;
519  val |= (blue >> 8) & 0x0000ff;
520 
521  write_dc(par, DC_PAL_ADDRESS, regno);
522  write_dc(par, DC_PAL_DATA, val);
523 }
524 
525 int lx_blank_display(struct fb_info *info, int blank_mode)
526 {
527  struct lxfb_par *par = info->par;
528  u32 dcfg, misc, fp_pm;
529  int blank, hsync, vsync;
530 
531  /* CRT power saving modes. */
532  switch (blank_mode) {
533  case FB_BLANK_UNBLANK:
534  blank = 0; hsync = 1; vsync = 1;
535  break;
536  case FB_BLANK_NORMAL:
537  blank = 1; hsync = 1; vsync = 1;
538  break;
540  blank = 1; hsync = 1; vsync = 0;
541  break;
543  blank = 1; hsync = 0; vsync = 1;
544  break;
545  case FB_BLANK_POWERDOWN:
546  blank = 1; hsync = 0; vsync = 0;
547  break;
548  default:
549  return -EINVAL;
550  }
551 
552  dcfg = read_vp(par, VP_DCFG);
555  if (!blank)
557  if (hsync)
558  dcfg |= VP_DCFG_HSYNC_EN;
559  if (vsync)
560  dcfg |= VP_DCFG_VSYNC_EN;
561 
562  write_vp(par, VP_DCFG, dcfg);
563 
564  misc = read_vp(par, VP_MISC);
565 
566  if (vsync && hsync)
567  misc &= ~VP_MISC_DACPWRDN;
568  else
569  misc |= VP_MISC_DACPWRDN;
570 
571  write_vp(par, VP_MISC, misc);
572 
573  /* Power on/off flat panel */
574 
575  if (par->output & OUTPUT_PANEL) {
576  fp_pm = read_fp(par, FP_PM);
577  if (blank_mode == FB_BLANK_POWERDOWN)
578  fp_pm &= ~FP_PM_P;
579  else
580  fp_pm |= FP_PM_P;
581  write_fp(par, FP_PM, fp_pm);
582  }
583 
584  return 0;
585 }
586 
587 #ifdef CONFIG_PM
588 
589 static void lx_save_regs(struct lxfb_par *par)
590 {
591  uint32_t filt;
592  int i;
593 
594  /* wait for the BLT engine to stop being busy */
595  do {
596  i = read_gp(par, GP_BLT_STATUS);
597  } while ((i & GP_BLT_STATUS_PB) || !(i & GP_BLT_STATUS_CE));
598 
599  /* save MSRs */
600  rdmsrl(MSR_LX_MSR_PADSEL, par->msr.padsel);
601  rdmsrl(MSR_GLCP_DOTPLL, par->msr.dotpll);
602  rdmsrl(MSR_LX_GLD_MSR_CONFIG, par->msr.dfglcfg);
603  rdmsrl(MSR_LX_SPARE_MSR, par->msr.dcspare);
604 
605  write_dc(par, DC_UNLOCK, DC_UNLOCK_UNLOCK);
606 
607  /* save registers */
608  memcpy(par->gp, par->gp_regs, sizeof(par->gp));
609  memcpy(par->dc, par->dc_regs, sizeof(par->dc));
610  memcpy(par->vp, par->vp_regs, sizeof(par->vp));
611  memcpy(par->fp, par->vp_regs + VP_FP_START, sizeof(par->fp));
612 
613  /* save the display controller palette */
614  write_dc(par, DC_PAL_ADDRESS, 0);
615  for (i = 0; i < ARRAY_SIZE(par->dc_pal); i++)
616  par->dc_pal[i] = read_dc(par, DC_PAL_DATA);
617 
618  /* save the video processor palette */
619  write_vp(par, VP_PAR, 0);
620  for (i = 0; i < ARRAY_SIZE(par->vp_pal); i++)
621  par->vp_pal[i] = read_vp(par, VP_PDR);
622 
623  /* save the horizontal filter coefficients */
625  for (i = 0; i < ARRAY_SIZE(par->hcoeff); i += 2) {
626  write_dc(par, DC_IRQ_FILT_CTL, (filt & 0xffffff00) | i);
627  par->hcoeff[i] = read_dc(par, DC_FILT_COEFF1);
628  par->hcoeff[i + 1] = read_dc(par, DC_FILT_COEFF2);
629  }
630 
631  /* save the vertical filter coefficients */
633  for (i = 0; i < ARRAY_SIZE(par->vcoeff); i++) {
634  write_dc(par, DC_IRQ_FILT_CTL, (filt & 0xffffff00) | i);
635  par->vcoeff[i] = read_dc(par, DC_FILT_COEFF1);
636  }
637 
638  /* save video coeff ram */
639  memcpy(par->vp_coeff, par->vp_regs + VP_VCR, sizeof(par->vp_coeff));
640 }
641 
642 static void lx_restore_gfx_proc(struct lxfb_par *par)
643 {
644  int i;
645 
646  /* a bunch of registers require GP_RASTER_MODE to be set first */
647  write_gp(par, GP_RASTER_MODE, par->gp[GP_RASTER_MODE]);
648 
649  for (i = 0; i < ARRAY_SIZE(par->gp); i++) {
650  switch (i) {
651  case GP_RASTER_MODE:
652  case GP_VECTOR_MODE:
653  case GP_BLT_MODE:
654  case GP_BLT_STATUS:
655  case GP_HST_SRC:
656  /* FIXME: restore LUT data */
657  case GP_LUT_INDEX:
658  case GP_LUT_DATA:
659  /* don't restore these registers */
660  break;
661 
662  default:
663  write_gp(par, i, par->gp[i]);
664  }
665  }
666 }
667 
668 static void lx_restore_display_ctlr(struct lxfb_par *par)
669 {
670  uint32_t filt;
671  int i;
672 
673  wrmsrl(MSR_LX_SPARE_MSR, par->msr.dcspare);
674 
675  for (i = 0; i < ARRAY_SIZE(par->dc); i++) {
676  switch (i) {
677  case DC_UNLOCK:
678  /* unlock the DC; runs first */
679  write_dc(par, DC_UNLOCK, DC_UNLOCK_UNLOCK);
680  break;
681 
682  case DC_GENERAL_CFG:
683  case DC_DISPLAY_CFG:
684  /* disable all while restoring */
685  write_dc(par, i, 0);
686  break;
687 
688  case DC_DV_CTL:
689  /* set all ram to dirty */
690  write_dc(par, i, par->dc[i] | DC_DV_CTL_CLEAR_DV_RAM);
691 
692  case DC_RSVD_1:
693  case DC_RSVD_2:
694  case DC_RSVD_3:
695  case DC_LINE_CNT:
696  case DC_PAL_ADDRESS:
697  case DC_PAL_DATA:
698  case DC_DFIFO_DIAG:
699  case DC_CFIFO_DIAG:
700  case DC_FILT_COEFF1:
701  case DC_FILT_COEFF2:
702  case DC_RSVD_4:
703  case DC_RSVD_5:
704  /* don't restore these registers */
705  break;
706 
707  default:
708  write_dc(par, i, par->dc[i]);
709  }
710  }
711 
712  /* restore the palette */
713  write_dc(par, DC_PAL_ADDRESS, 0);
714  for (i = 0; i < ARRAY_SIZE(par->dc_pal); i++)
715  write_dc(par, DC_PAL_DATA, par->dc_pal[i]);
716 
717  /* restore the horizontal filter coefficients */
719  for (i = 0; i < ARRAY_SIZE(par->hcoeff); i += 2) {
720  write_dc(par, DC_IRQ_FILT_CTL, (filt & 0xffffff00) | i);
721  write_dc(par, DC_FILT_COEFF1, par->hcoeff[i]);
722  write_dc(par, DC_FILT_COEFF2, par->hcoeff[i + 1]);
723  }
724 
725  /* restore the vertical filter coefficients */
727  for (i = 0; i < ARRAY_SIZE(par->vcoeff); i++) {
728  write_dc(par, DC_IRQ_FILT_CTL, (filt & 0xffffff00) | i);
729  write_dc(par, DC_FILT_COEFF1, par->vcoeff[i]);
730  }
731 }
732 
733 static void lx_restore_video_proc(struct lxfb_par *par)
734 {
735  int i;
736 
737  wrmsrl(MSR_LX_GLD_MSR_CONFIG, par->msr.dfglcfg);
738  wrmsrl(MSR_LX_MSR_PADSEL, par->msr.padsel);
739 
740  for (i = 0; i < ARRAY_SIZE(par->vp); i++) {
741  switch (i) {
742  case VP_VCFG:
743  case VP_DCFG:
744  case VP_PAR:
745  case VP_PDR:
746  case VP_CCS:
747  case VP_RSVD_0:
748  /* case VP_VDC: */ /* why should this not be restored? */
749  case VP_RSVD_1:
750  case VP_CRC32:
751  /* don't restore these registers */
752  break;
753 
754  default:
755  write_vp(par, i, par->vp[i]);
756  }
757  }
758 
759  /* restore video processor palette */
760  write_vp(par, VP_PAR, 0);
761  for (i = 0; i < ARRAY_SIZE(par->vp_pal); i++)
762  write_vp(par, VP_PDR, par->vp_pal[i]);
763 
764  /* restore video coeff ram */
765  memcpy(par->vp_regs + VP_VCR, par->vp_coeff, sizeof(par->vp_coeff));
766 }
767 
768 static void lx_restore_regs(struct lxfb_par *par)
769 {
770  int i;
771 
772  lx_set_dotpll((u32) (par->msr.dotpll >> 32));
773  lx_restore_gfx_proc(par);
774  lx_restore_display_ctlr(par);
775  lx_restore_video_proc(par);
776 
777  /* Flat Panel */
778  for (i = 0; i < ARRAY_SIZE(par->fp); i++) {
779  switch (i) {
780  case FP_PM:
781  case FP_RSVD_0:
782  case FP_RSVD_1:
783  case FP_RSVD_2:
784  case FP_RSVD_3:
785  case FP_RSVD_4:
786  /* don't restore these registers */
787  break;
788 
789  default:
790  write_fp(par, i, par->fp[i]);
791  }
792  }
793 
794  /* control the panel */
795  if (par->fp[FP_PM] & FP_PM_P) {
796  /* power on the panel if not already power{ed,ing} on */
797  if (!(read_fp(par, FP_PM) &
799  write_fp(par, FP_PM, par->fp[FP_PM]);
800  } else {
801  /* power down the panel if not already power{ed,ing} down */
802  if (!(read_fp(par, FP_PM) &
804  write_fp(par, FP_PM, par->fp[FP_PM]);
805  }
806 
807  /* turn everything on */
808  write_vp(par, VP_VCFG, par->vp[VP_VCFG]);
809  write_vp(par, VP_DCFG, par->vp[VP_DCFG]);
810  write_dc(par, DC_DISPLAY_CFG, par->dc[DC_DISPLAY_CFG]);
811  /* do this last; it will enable the FIFO load */
812  write_dc(par, DC_GENERAL_CFG, par->dc[DC_GENERAL_CFG]);
813 
814  /* lock the door behind us */
815  write_dc(par, DC_UNLOCK, DC_UNLOCK_LOCK);
816 }
817 
818 int lx_powerdown(struct fb_info *info)
819 {
820  struct lxfb_par *par = info->par;
821 
822  if (par->powered_down)
823  return 0;
824 
825  lx_save_regs(par);
826  lx_graphics_disable(info);
827 
828  par->powered_down = 1;
829  return 0;
830 }
831 
832 int lx_powerup(struct fb_info *info)
833 {
834  struct lxfb_par *par = info->par;
835 
836  if (!par->powered_down)
837  return 0;
838 
839  lx_restore_regs(par);
840 
841  par->powered_down = 0;
842  return 0;
843 }
844 
845 #endif