747d903fe49f33f3bb3f5c945bc48b57a4e29dbd
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / drm / gma500 / cdv_device.c
1 /**************************************************************************
2  * Copyright (c) 2011, Intel Corporation.
3  * All Rights Reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms and conditions of the GNU General Public License,
7  * version 2, as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12  * more details.
13  *
14  * You should have received a copy of the GNU General Public License along with
15  * this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
17  *
18  **************************************************************************/
19
20 #include <linux/backlight.h>
21 #include <drm/drmP.h>
22 #include <drm/drm.h>
23 #include <drm/gma_drm.h>
24 #include "psb_drv.h"
25 #include "psb_reg.h"
26 #include "psb_intel_reg.h"
27 #include "intel_bios.h"
28 #include "cdv_device.h"
29
30 #define VGA_SR_INDEX            0x3c4
31 #define VGA_SR_DATA             0x3c5
32
33 static void cdv_disable_vga(struct drm_device *dev)
34 {
35         u8 sr1;
36         u32 vga_reg;
37
38         vga_reg = VGACNTRL;
39
40         outb(1, VGA_SR_INDEX);
41         sr1 = inb(VGA_SR_DATA);
42         outb(sr1 | 1<<5, VGA_SR_DATA);
43         udelay(300);
44
45         REG_WRITE(vga_reg, VGA_DISP_DISABLE);
46         REG_READ(vga_reg);
47 }
48
49 static int cdv_output_init(struct drm_device *dev)
50 {
51         struct drm_psb_private *dev_priv = dev->dev_private;
52
53         drm_mode_create_scaling_mode_property(dev);
54
55         cdv_disable_vga(dev);
56
57         cdv_intel_crt_init(dev, &dev_priv->mode_dev);
58         cdv_intel_lvds_init(dev, &dev_priv->mode_dev);
59
60         /* These bits indicate HDMI not SDVO on CDV */
61         if (REG_READ(SDVOB) & SDVO_DETECTED) {
62                 cdv_hdmi_init(dev, &dev_priv->mode_dev, SDVOB);
63                 if (REG_READ(DP_B) & DP_DETECTED)
64                         cdv_intel_dp_init(dev, &dev_priv->mode_dev, DP_B);
65         }
66
67         if (REG_READ(SDVOC) & SDVO_DETECTED) {
68                 cdv_hdmi_init(dev, &dev_priv->mode_dev, SDVOC);
69                 if (REG_READ(DP_C) & DP_DETECTED)
70                         cdv_intel_dp_init(dev, &dev_priv->mode_dev, DP_C);
71         }
72         return 0;
73 }
74
75 #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
76
77 /*
78  *      Cedartrail Backlght Interfaces
79  */
80
81 static struct backlight_device *cdv_backlight_device;
82
83 static int cdv_backlight_combination_mode(struct drm_device *dev)
84 {
85         return REG_READ(BLC_PWM_CTL2) & PWM_LEGACY_MODE;
86 }
87
88 static u32 cdv_get_max_backlight(struct drm_device *dev)
89 {
90         u32 max = REG_READ(BLC_PWM_CTL);
91
92         if (max == 0) {
93                 DRM_DEBUG_KMS("LVDS Panel PWM value is 0!\n");
94                 /* i915 does this, I believe which means that we should not
95                  * smash PWM control as firmware will take control of it. */
96                 return 1;
97         }
98
99         max >>= 16;
100         if (cdv_backlight_combination_mode(dev))
101                 max *= 0xff;
102         return max;
103 }
104
105 static int cdv_get_brightness(struct backlight_device *bd)
106 {
107         struct drm_device *dev = bl_get_data(bd);
108         u32 val = REG_READ(BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
109
110         if (cdv_backlight_combination_mode(dev)) {
111                 u8 lbpc;
112
113                 val &= ~1;
114                 pci_read_config_byte(dev->pdev, 0xF4, &lbpc);
115                 val *= lbpc;
116         }
117         return (val * 100)/cdv_get_max_backlight(dev);
118
119 }
120
121 static int cdv_set_brightness(struct backlight_device *bd)
122 {
123         struct drm_device *dev = bl_get_data(bd);
124         int level = bd->props.brightness;
125         u32 blc_pwm_ctl;
126
127         /* Percentage 1-100% being valid */
128         if (level < 1)
129                 level = 1;
130
131         level *= cdv_get_max_backlight(dev);
132         level /= 100;
133
134         if (cdv_backlight_combination_mode(dev)) {
135                 u32 max = cdv_get_max_backlight(dev);
136                 u8 lbpc;
137
138                 lbpc = level * 0xfe / max + 1;
139                 level /= lbpc;
140
141                 pci_write_config_byte(dev->pdev, 0xF4, lbpc);
142         }
143
144         blc_pwm_ctl = REG_READ(BLC_PWM_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK;
145         REG_WRITE(BLC_PWM_CTL, (blc_pwm_ctl |
146                                 (level << BACKLIGHT_DUTY_CYCLE_SHIFT)));
147         return 0;
148 }
149
150 static const struct backlight_ops cdv_ops = {
151         .get_brightness = cdv_get_brightness,
152         .update_status  = cdv_set_brightness,
153 };
154
155 static int cdv_backlight_init(struct drm_device *dev)
156 {
157         struct drm_psb_private *dev_priv = dev->dev_private;
158         struct backlight_properties props;
159
160         memset(&props, 0, sizeof(struct backlight_properties));
161         props.max_brightness = 100;
162         props.type = BACKLIGHT_PLATFORM;
163
164         cdv_backlight_device = backlight_device_register("psb-bl",
165                                         NULL, (void *)dev, &cdv_ops, &props);
166         if (IS_ERR(cdv_backlight_device))
167                 return PTR_ERR(cdv_backlight_device);
168
169         cdv_backlight_device->props.brightness =
170                         cdv_get_brightness(cdv_backlight_device);
171         backlight_update_status(cdv_backlight_device);
172         dev_priv->backlight_device = cdv_backlight_device;
173         dev_priv->backlight_enabled = true;
174         return 0;
175 }
176
177 #endif
178
179 /*
180  *      Provide the Cedarview specific chip logic and low level methods
181  *      for power management
182  *
183  *      FIXME: we need to implement the apm/ospm base management bits
184  *      for this and the MID devices.
185  */
186
187 static inline u32 CDV_MSG_READ32(uint port, uint offset)
188 {
189         int mcr = (0x10<<24) | (port << 16) | (offset << 8);
190         uint32_t ret_val = 0;
191         struct pci_dev *pci_root = pci_get_bus_and_slot(0, 0);
192         pci_write_config_dword(pci_root, 0xD0, mcr);
193         pci_read_config_dword(pci_root, 0xD4, &ret_val);
194         pci_dev_put(pci_root);
195         return ret_val;
196 }
197
198 static inline void CDV_MSG_WRITE32(uint port, uint offset, u32 value)
199 {
200         int mcr = (0x11<<24) | (port << 16) | (offset << 8) | 0xF0;
201         struct pci_dev *pci_root = pci_get_bus_and_slot(0, 0);
202         pci_write_config_dword(pci_root, 0xD4, value);
203         pci_write_config_dword(pci_root, 0xD0, mcr);
204         pci_dev_put(pci_root);
205 }
206
207 #define PSB_PM_SSC                      0x20
208 #define PSB_PM_SSS                      0x30
209 #define PSB_PWRGT_GFX_ON                0x02
210 #define PSB_PWRGT_GFX_OFF               0x01
211 #define PSB_PWRGT_GFX_D0                0x00
212 #define PSB_PWRGT_GFX_D3                0x03
213
214 static void cdv_init_pm(struct drm_device *dev)
215 {
216         struct drm_psb_private *dev_priv = dev->dev_private;
217         u32 pwr_cnt;
218         int i;
219
220         dev_priv->apm_base = CDV_MSG_READ32(PSB_PUNIT_PORT,
221                                                         PSB_APMBA) & 0xFFFF;
222         dev_priv->ospm_base = CDV_MSG_READ32(PSB_PUNIT_PORT,
223                                                         PSB_OSPMBA) & 0xFFFF;
224
225         /* Power status */
226         pwr_cnt = inl(dev_priv->apm_base + PSB_APM_CMD);
227
228         /* Enable the GPU */
229         pwr_cnt &= ~PSB_PWRGT_GFX_MASK;
230         pwr_cnt |= PSB_PWRGT_GFX_ON;
231         outl(pwr_cnt, dev_priv->apm_base + PSB_APM_CMD);
232
233         /* Wait for the GPU power */
234         for (i = 0; i < 5; i++) {
235                 u32 pwr_sts = inl(dev_priv->apm_base + PSB_APM_STS);
236                 if ((pwr_sts & PSB_PWRGT_GFX_MASK) == 0)
237                         return;
238                 udelay(10);
239         }
240         dev_err(dev->dev, "GPU: power management timed out.\n");
241 }
242
243 static void cdv_errata(struct drm_device *dev)
244 {
245         /* Disable bonus launch.
246          *      CPU and GPU competes for memory and display misses updates and
247          *      flickers. Worst with dual core, dual displays.
248          *
249          *      Fixes were done to Win 7 gfx driver to disable a feature called
250          *      Bonus Launch to work around the issue, by degrading
251          *      performance.
252          */
253          CDV_MSG_WRITE32(3, 0x30, 0x08027108);
254 }
255
256 /**
257  *      cdv_save_display_registers      -       save registers lost on suspend
258  *      @dev: our DRM device
259  *
260  *      Save the state we need in order to be able to restore the interface
261  *      upon resume from suspend
262  */
263 static int cdv_save_display_registers(struct drm_device *dev)
264 {
265         struct drm_psb_private *dev_priv = dev->dev_private;
266         struct psb_save_area *regs = &dev_priv->regs;
267         struct drm_connector *connector;
268
269         dev_dbg(dev->dev, "Saving GPU registers.\n");
270
271         pci_read_config_byte(dev->pdev, 0xF4, &regs->cdv.saveLBB);
272
273         regs->cdv.saveDSPCLK_GATE_D = REG_READ(DSPCLK_GATE_D);
274         regs->cdv.saveRAMCLK_GATE_D = REG_READ(RAMCLK_GATE_D);
275
276         regs->cdv.saveDSPARB = REG_READ(DSPARB);
277         regs->cdv.saveDSPFW[0] = REG_READ(DSPFW1);
278         regs->cdv.saveDSPFW[1] = REG_READ(DSPFW2);
279         regs->cdv.saveDSPFW[2] = REG_READ(DSPFW3);
280         regs->cdv.saveDSPFW[3] = REG_READ(DSPFW4);
281         regs->cdv.saveDSPFW[4] = REG_READ(DSPFW5);
282         regs->cdv.saveDSPFW[5] = REG_READ(DSPFW6);
283
284         regs->cdv.saveADPA = REG_READ(ADPA);
285
286         regs->cdv.savePP_CONTROL = REG_READ(PP_CONTROL);
287         regs->cdv.savePFIT_PGM_RATIOS = REG_READ(PFIT_PGM_RATIOS);
288         regs->saveBLC_PWM_CTL = REG_READ(BLC_PWM_CTL);
289         regs->saveBLC_PWM_CTL2 = REG_READ(BLC_PWM_CTL2);
290         regs->cdv.saveLVDS = REG_READ(LVDS);
291
292         regs->cdv.savePFIT_CONTROL = REG_READ(PFIT_CONTROL);
293
294         regs->cdv.savePP_ON_DELAYS = REG_READ(PP_ON_DELAYS);
295         regs->cdv.savePP_OFF_DELAYS = REG_READ(PP_OFF_DELAYS);
296         regs->cdv.savePP_CYCLE = REG_READ(PP_CYCLE);
297
298         regs->cdv.saveVGACNTRL = REG_READ(VGACNTRL);
299
300         regs->cdv.saveIER = REG_READ(PSB_INT_ENABLE_R);
301         regs->cdv.saveIMR = REG_READ(PSB_INT_MASK_R);
302
303         list_for_each_entry(connector, &dev->mode_config.connector_list, head)
304                 connector->funcs->dpms(connector, DRM_MODE_DPMS_OFF);
305
306         return 0;
307 }
308
309 /**
310  *      cdv_restore_display_registers   -       restore lost register state
311  *      @dev: our DRM device
312  *
313  *      Restore register state that was lost during suspend and resume.
314  *
315  *      FIXME: review
316  */
317 static int cdv_restore_display_registers(struct drm_device *dev)
318 {
319         struct drm_psb_private *dev_priv = dev->dev_private;
320         struct psb_save_area *regs = &dev_priv->regs;
321         struct drm_connector *connector;
322         u32 temp;
323
324         pci_write_config_byte(dev->pdev, 0xF4, regs->cdv.saveLBB);
325
326         REG_WRITE(DSPCLK_GATE_D, regs->cdv.saveDSPCLK_GATE_D);
327         REG_WRITE(RAMCLK_GATE_D, regs->cdv.saveRAMCLK_GATE_D);
328
329         /* BIOS does below anyway */
330         REG_WRITE(DPIO_CFG, 0);
331         REG_WRITE(DPIO_CFG, DPIO_MODE_SELECT_0 | DPIO_CMN_RESET_N);
332
333         temp = REG_READ(DPLL_A);
334         if ((temp & DPLL_SYNCLOCK_ENABLE) == 0) {
335                 REG_WRITE(DPLL_A, temp | DPLL_SYNCLOCK_ENABLE);
336                 REG_READ(DPLL_A);
337         }
338
339         temp = REG_READ(DPLL_B);
340         if ((temp & DPLL_SYNCLOCK_ENABLE) == 0) {
341                 REG_WRITE(DPLL_B, temp | DPLL_SYNCLOCK_ENABLE);
342                 REG_READ(DPLL_B);
343         }
344
345         udelay(500);
346
347         REG_WRITE(DSPFW1, regs->cdv.saveDSPFW[0]);
348         REG_WRITE(DSPFW2, regs->cdv.saveDSPFW[1]);
349         REG_WRITE(DSPFW3, regs->cdv.saveDSPFW[2]);
350         REG_WRITE(DSPFW4, regs->cdv.saveDSPFW[3]);
351         REG_WRITE(DSPFW5, regs->cdv.saveDSPFW[4]);
352         REG_WRITE(DSPFW6, regs->cdv.saveDSPFW[5]);
353
354         REG_WRITE(DSPARB, regs->cdv.saveDSPARB);
355         REG_WRITE(ADPA, regs->cdv.saveADPA);
356
357         REG_WRITE(BLC_PWM_CTL2, regs->saveBLC_PWM_CTL2);
358         REG_WRITE(LVDS, regs->cdv.saveLVDS);
359         REG_WRITE(PFIT_CONTROL, regs->cdv.savePFIT_CONTROL);
360         REG_WRITE(PFIT_PGM_RATIOS, regs->cdv.savePFIT_PGM_RATIOS);
361         REG_WRITE(BLC_PWM_CTL, regs->saveBLC_PWM_CTL);
362         REG_WRITE(PP_ON_DELAYS, regs->cdv.savePP_ON_DELAYS);
363         REG_WRITE(PP_OFF_DELAYS, regs->cdv.savePP_OFF_DELAYS);
364         REG_WRITE(PP_CYCLE, regs->cdv.savePP_CYCLE);
365         REG_WRITE(PP_CONTROL, regs->cdv.savePP_CONTROL);
366
367         REG_WRITE(VGACNTRL, regs->cdv.saveVGACNTRL);
368
369         REG_WRITE(PSB_INT_ENABLE_R, regs->cdv.saveIER);
370         REG_WRITE(PSB_INT_MASK_R, regs->cdv.saveIMR);
371
372         /* Fix arbitration bug */
373         cdv_errata(dev);
374
375         drm_mode_config_reset(dev);
376
377         list_for_each_entry(connector, &dev->mode_config.connector_list, head)
378                 connector->funcs->dpms(connector, DRM_MODE_DPMS_ON);
379
380         /* Resume the modeset for every activated CRTC */
381         drm_helper_resume_force_mode(dev);
382         return 0;
383 }
384
385 static int cdv_power_down(struct drm_device *dev)
386 {
387         struct drm_psb_private *dev_priv = dev->dev_private;
388         u32 pwr_cnt, pwr_mask, pwr_sts;
389         int tries = 5;
390
391         pwr_cnt = inl(dev_priv->apm_base + PSB_APM_CMD);
392         pwr_cnt &= ~PSB_PWRGT_GFX_MASK;
393         pwr_cnt |= PSB_PWRGT_GFX_OFF;
394         pwr_mask = PSB_PWRGT_GFX_MASK;
395
396         outl(pwr_cnt, dev_priv->apm_base + PSB_APM_CMD);
397
398         while (tries--) {
399                 pwr_sts = inl(dev_priv->apm_base + PSB_APM_STS);
400                 if ((pwr_sts & pwr_mask) == PSB_PWRGT_GFX_D3)
401                         return 0;
402                 udelay(10);
403         }
404         return 0;
405 }
406
407 static int cdv_power_up(struct drm_device *dev)
408 {
409         struct drm_psb_private *dev_priv = dev->dev_private;
410         u32 pwr_cnt, pwr_mask, pwr_sts;
411         int tries = 5;
412
413         pwr_cnt = inl(dev_priv->apm_base + PSB_APM_CMD);
414         pwr_cnt &= ~PSB_PWRGT_GFX_MASK;
415         pwr_cnt |= PSB_PWRGT_GFX_ON;
416         pwr_mask = PSB_PWRGT_GFX_MASK;
417
418         outl(pwr_cnt, dev_priv->apm_base + PSB_APM_CMD);
419
420         while (tries--) {
421                 pwr_sts = inl(dev_priv->apm_base + PSB_APM_STS);
422                 if ((pwr_sts & pwr_mask) == PSB_PWRGT_GFX_D0)
423                         return 0;
424                 udelay(10);
425         }
426         return 0;
427 }
428
429 /* FIXME ? - shared with Poulsbo */
430 static void cdv_get_core_freq(struct drm_device *dev)
431 {
432         uint32_t clock;
433         struct pci_dev *pci_root = pci_get_bus_and_slot(0, 0);
434         struct drm_psb_private *dev_priv = dev->dev_private;
435
436         pci_write_config_dword(pci_root, 0xD0, 0xD0050300);
437         pci_read_config_dword(pci_root, 0xD4, &clock);
438         pci_dev_put(pci_root);
439
440         switch (clock & 0x07) {
441         case 0:
442                 dev_priv->core_freq = 100;
443                 break;
444         case 1:
445                 dev_priv->core_freq = 133;
446                 break;
447         case 2:
448                 dev_priv->core_freq = 150;
449                 break;
450         case 3:
451                 dev_priv->core_freq = 178;
452                 break;
453         case 4:
454                 dev_priv->core_freq = 200;
455                 break;
456         case 5:
457         case 6:
458         case 7:
459                 dev_priv->core_freq = 266;
460                 break;
461         default:
462                 dev_priv->core_freq = 0;
463         }
464 }
465
466 static void cdv_hotplug_work_func(struct work_struct *work)
467 {
468         struct drm_psb_private *dev_priv = container_of(work, struct drm_psb_private,
469                                                         hotplug_work);                 
470         struct drm_device *dev = dev_priv->dev;
471
472         /* Just fire off a uevent and let userspace tell us what to do */
473         drm_helper_hpd_irq_event(dev);
474 }                       
475
476 /* The core driver has received a hotplug IRQ. We are in IRQ context
477    so extract the needed information and kick off queued processing */
478    
479 static int cdv_hotplug_event(struct drm_device *dev)
480 {
481         struct drm_psb_private *dev_priv = dev->dev_private;
482         schedule_work(&dev_priv->hotplug_work);
483         REG_WRITE(PORT_HOTPLUG_STAT, REG_READ(PORT_HOTPLUG_STAT));
484         return 1;
485 }
486
487 static void cdv_hotplug_enable(struct drm_device *dev, bool on)
488 {
489         if (on) {
490                 u32 hotplug = REG_READ(PORT_HOTPLUG_EN);
491                 hotplug |= HDMIB_HOTPLUG_INT_EN | HDMIC_HOTPLUG_INT_EN |
492                            HDMID_HOTPLUG_INT_EN | CRT_HOTPLUG_INT_EN;
493                 REG_WRITE(PORT_HOTPLUG_EN, hotplug);
494         }  else {
495                 REG_WRITE(PORT_HOTPLUG_EN, 0);
496                 REG_WRITE(PORT_HOTPLUG_STAT, REG_READ(PORT_HOTPLUG_STAT));
497         }       
498 }
499
500 static const char *force_audio_names[] = {
501         "off",
502         "auto",
503         "on",
504 };
505
506 void cdv_intel_attach_force_audio_property(struct drm_connector *connector)
507 {
508         struct drm_device *dev = connector->dev;
509         struct drm_psb_private *dev_priv = dev->dev_private;
510         struct drm_property *prop;
511         int i;
512
513         prop = dev_priv->force_audio_property;
514         if (prop == NULL) {
515                 prop = drm_property_create(dev, DRM_MODE_PROP_ENUM,
516                                            "audio",
517                                            ARRAY_SIZE(force_audio_names));
518                 if (prop == NULL)
519                         return;
520
521                 for (i = 0; i < ARRAY_SIZE(force_audio_names); i++)
522                         drm_property_add_enum(prop, i, i-1, force_audio_names[i]);
523
524                 dev_priv->force_audio_property = prop;
525         }
526         drm_object_attach_property(&connector->base, prop, 0);
527 }
528
529
530 static const char *broadcast_rgb_names[] = {
531         "Full",
532         "Limited 16:235",
533 };
534
535 void cdv_intel_attach_broadcast_rgb_property(struct drm_connector *connector)
536 {
537         struct drm_device *dev = connector->dev;
538         struct drm_psb_private *dev_priv = dev->dev_private;
539         struct drm_property *prop;
540         int i;
541
542         prop = dev_priv->broadcast_rgb_property;
543         if (prop == NULL) {
544                 prop = drm_property_create(dev, DRM_MODE_PROP_ENUM,
545                                            "Broadcast RGB",
546                                            ARRAY_SIZE(broadcast_rgb_names));
547                 if (prop == NULL)
548                         return;
549
550                 for (i = 0; i < ARRAY_SIZE(broadcast_rgb_names); i++)
551                         drm_property_add_enum(prop, i, i, broadcast_rgb_names[i]);
552
553                 dev_priv->broadcast_rgb_property = prop;
554         }
555
556         drm_object_attach_property(&connector->base, prop, 0);
557 }
558
559 /* Cedarview */
560 static const struct psb_offset cdv_regmap[2] = {
561         {
562                 .fp0 = FPA0,
563                 .fp1 = FPA1,
564                 .cntr = DSPACNTR,
565                 .conf = PIPEACONF,
566                 .src = PIPEASRC,
567                 .dpll = DPLL_A,
568                 .dpll_md = DPLL_A_MD,
569                 .htotal = HTOTAL_A,
570                 .hblank = HBLANK_A,
571                 .hsync = HSYNC_A,
572                 .vtotal = VTOTAL_A,
573                 .vblank = VBLANK_A,
574                 .vsync = VSYNC_A,
575                 .stride = DSPASTRIDE,
576                 .size = DSPASIZE,
577                 .pos = DSPAPOS,
578                 .base = DSPABASE,
579                 .surf = DSPASURF,
580                 .addr = DSPABASE,
581                 .status = PIPEASTAT,
582                 .linoff = DSPALINOFF,
583                 .tileoff = DSPATILEOFF,
584                 .palette = PALETTE_A,
585         },
586         {
587                 .fp0 = FPB0,
588                 .fp1 = FPB1,
589                 .cntr = DSPBCNTR,
590                 .conf = PIPEBCONF,
591                 .src = PIPEBSRC,
592                 .dpll = DPLL_B,
593                 .dpll_md = DPLL_B_MD,
594                 .htotal = HTOTAL_B,
595                 .hblank = HBLANK_B,
596                 .hsync = HSYNC_B,
597                 .vtotal = VTOTAL_B,
598                 .vblank = VBLANK_B,
599                 .vsync = VSYNC_B,
600                 .stride = DSPBSTRIDE,
601                 .size = DSPBSIZE,
602                 .pos = DSPBPOS,
603                 .base = DSPBBASE,
604                 .surf = DSPBSURF,
605                 .addr = DSPBBASE,
606                 .status = PIPEBSTAT,
607                 .linoff = DSPBLINOFF,
608                 .tileoff = DSPBTILEOFF,
609                 .palette = PALETTE_B,
610         }
611 };
612
613 static int cdv_chip_setup(struct drm_device *dev)
614 {
615         struct drm_psb_private *dev_priv = dev->dev_private;
616         INIT_WORK(&dev_priv->hotplug_work, cdv_hotplug_work_func);
617
618         if (pci_enable_msi(dev->pdev))
619                 dev_warn(dev->dev, "Enabling MSI failed!\n");
620         dev_priv->regmap = cdv_regmap;
621         cdv_get_core_freq(dev);
622         psb_intel_opregion_init(dev);
623         psb_intel_init_bios(dev);
624         cdv_hotplug_enable(dev, false);
625         return 0;
626 }
627
628 /* CDV is much like Poulsbo but has MID like SGX offsets and PM */
629
630 const struct psb_ops cdv_chip_ops = {
631         .name = "GMA3600/3650",
632         .accel_2d = 0,
633         .pipes = 2,
634         .crtcs = 2,
635         .hdmi_mask = (1 << 0) | (1 << 1),
636         .lvds_mask = (1 << 1),
637         .cursor_needs_phys = 0,
638         .sgx_offset = MRST_SGX_OFFSET,
639         .chip_setup = cdv_chip_setup,
640         .errata = cdv_errata,
641
642         .crtc_helper = &cdv_intel_helper_funcs,
643         .crtc_funcs = &cdv_intel_crtc_funcs,
644         .clock_funcs = &cdv_clock_funcs,
645
646         .output_init = cdv_output_init,
647         .hotplug = cdv_hotplug_event,
648         .hotplug_enable = cdv_hotplug_enable,
649
650 #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
651         .backlight_init = cdv_backlight_init,
652 #endif
653
654         .init_pm = cdv_init_pm,
655         .save_regs = cdv_save_display_registers,
656         .restore_regs = cdv_restore_display_registers,
657         .power_down = cdv_power_down,
658         .power_up = cdv_power_up,
659         .update_wm = cdv_update_wm,
660 };