Initial import of modesetting for intel driver in DRM
[profile/ivi/libdrm.git] / linux-core / intel_crt.c
1 #include <linux/i2c.h>
2 #include "drmP.h"
3 #include "drm.h"
4 #include "drm_crtc.h"
5 #include "intel_drv.h"
6 #include "i915_drm.h"
7 #include "i915_drv.h"
8
9 static void intel_crt_dpms(struct drm_output *output, int mode)
10 {
11         drm_device_t *dev = output->dev;
12         drm_i915_private_t *dev_priv = dev->dev_private;
13         u32 temp;
14         
15         temp = I915_READ(ADPA);
16         temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE);
17         temp &= ~ADPA_DAC_ENABLE;
18         
19         switch(mode) {
20         case DPMSModeOn:
21                 temp |= ADPA_DAC_ENABLE;
22                 break;
23         case DPMSModeStandby:
24                 temp |= ADPA_DAC_ENABLE | ADPA_HSYNC_CNTL_DISABLE;
25                 break;
26         case DPMSModeSuspend:
27                 temp |= ADPA_DAC_ENABLE | ADPA_VSYNC_CNTL_DISABLE;
28                 break;
29         case DPMSModeOff:
30                 temp |= ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE;
31                 break;
32         }
33         
34         I915_WRITE(ADPA, temp);
35 }
36
37 static void intel_crt_save(struct drm_output *output)
38 {
39         
40 }
41
42 static void intel_crt_restore(struct drm_output *output)
43 {
44
45 }
46
47 static int intel_crt_mode_valid(struct drm_output *output,
48                                 struct drm_display_mode *mode)
49 {
50         if (mode->flags & V_DBLSCAN)
51                 return MODE_NO_DBLESCAN;
52
53         if (mode->clock > 400000 || mode->clock < 25000)
54                 return MODE_CLOCK_RANGE;
55
56         return MODE_OK;
57 }
58
59 static bool intel_crt_mode_fixup(struct drm_output *output,
60                                  struct drm_display_mode *mode,
61                                  struct drm_display_mode *adjusted_mode)
62 {
63         return true;
64 }
65
66 static void intel_crt_mode_set(struct drm_output *output,
67                                struct drm_display_mode *mode,
68                                struct drm_display_mode *adjusted_mode)
69 {
70         drm_device_t *dev = output->dev;
71         struct drm_crtc *crtc = output->crtc;
72         struct intel_crtc *intel_crtc = crtc->driver_private;
73         drm_i915_private_t *dev_priv = dev->dev_private;
74         int dpll_md_reg;
75         u32 adpa, dpll_md;
76
77         if (intel_crtc->pipe == 0) 
78                 dpll_md_reg = DPLL_A_MD;
79         else
80                 dpll_md_reg = DPLL_B_MD;
81
82         /*
83          * Disable separate mode multiplier used when cloning SDVO to CRT
84          * XXX this needs to be adjusted when we really are cloning
85          */
86         if (IS_I965G(dev))
87         {
88                 dpll_md = I915_READ(dpll_md_reg);
89                 I915_WRITE(dpll_md_reg, dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK);
90         }
91         
92         adpa = 0;
93         if (adjusted_mode->flags & V_PHSYNC)
94                 adpa |= ADPA_HSYNC_ACTIVE_HIGH;
95         if (adjusted_mode->flags & V_PVSYNC)
96                 adpa |= ADPA_VSYNC_ACTIVE_HIGH;
97         
98         if (intel_crtc->pipe == 0)
99                 adpa |= ADPA_PIPE_A_SELECT;
100         else
101                 adpa |= ADPA_PIPE_B_SELECT;
102         
103         I915_WRITE(ADPA, adpa);
104 }
105
106 /**
107  * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect CRT presence.
108  *
109  * Only for I945G/GM.
110  *
111  * \return TRUE if CRT is connected.
112  * \return FALSE if CRT is disconnected.
113  */
114 static bool intel_crt_detect_hotplug(struct drm_output *output)
115 {
116         drm_device_t *dev = output->dev;
117 //      struct intel_output *intel_output = output->driver_private;
118         drm_i915_private_t *dev_priv = dev->dev_private;
119         u32 temp;
120         const int timeout_ms = 1000;
121         int starttime, curtime;
122
123         temp = I915_READ(PORT_HOTPLUG_EN);
124
125         I915_WRITE(PORT_HOTPLUG_EN, temp | CRT_HOTPLUG_FORCE_DETECT | (1 << 5));
126 #if 0   
127         for (curtime = starttime = GetTimeInMillis();
128              (curtime - starttime) < timeout_ms; curtime = GetTimeInMillis())
129         {
130                 if ((I915_READ(PORT_HOTPLUG_EN) & CRT_HOTPLUG_FORCE_DETECT) == 0)
131                         break;
132         }
133 #endif
134         if ((I915_READ(PORT_HOTPLUG_STAT) & CRT_HOTPLUG_MONITOR_MASK) ==
135             CRT_HOTPLUG_MONITOR_COLOR)
136         {
137                 return true;
138         } else {
139                 return false;
140         }
141 }
142
143 static bool intel_crt_detect_ddc(struct drm_output *output)
144 {
145         struct intel_output *intel_output = output->driver_private;
146
147         /* CRT should always be at 0, but check anyway */
148         if (intel_output->type != INTEL_OUTPUT_ANALOG)
149                 return false;
150         
151         return intel_ddc_probe(output);
152 }
153
154 static enum drm_output_status intel_crt_detect(struct drm_output *output)
155 {
156         drm_device_t *dev = output->dev;
157         drm_i915_private_t *dev_priv = dev->dev_private;
158         
159         if (IS_I945G(dev)| IS_I945GM(dev) || IS_I965G(dev)) {
160                 if (intel_crt_detect_hotplug(output))
161                         return output_status_connected;
162                 else
163                         return output_status_disconnected;
164         }
165
166         if (intel_crt_detect_ddc(output))
167                 return output_status_connected;
168
169         /* TODO use load detect */
170         return output_status_unknown;
171 }
172
173 static void intel_crt_destroy(struct drm_output *output)
174 {
175         struct intel_output *intel_output = output->driver_private;
176
177         intel_i2c_destroy(intel_output->ddc_bus);
178
179         if (output->driver_private)
180                 kfree(output->driver_private);
181 }
182
183 /*
184  * Routines for controlling stuff on the analog port
185  */
186 static const struct drm_output_funcs intel_crt_output_funcs = {
187         .dpms = intel_crt_dpms,
188         .save = intel_crt_save,
189         .restore = intel_crt_restore,
190         .mode_valid = intel_crt_mode_valid,
191         .mode_fixup = intel_crt_mode_fixup,
192         .prepare = intel_output_prepare,
193         .mode_set = intel_crt_mode_set,
194         .commit = intel_output_commit,
195         .detect = intel_crt_detect,
196         .get_modes = intel_ddc_get_modes,
197         .cleanup = intel_crt_destroy,
198 };
199
200 void intel_crt_init(drm_device_t *dev)
201 {
202         struct drm_output *output;
203         struct intel_output *intel_output;
204         int modes;
205
206         output = drm_output_create (dev, &intel_crt_output_funcs, "VGA");
207
208         intel_output = kmalloc(sizeof(struct intel_output), GFP_KERNEL);
209         if (!intel_output) {
210                 drm_output_destroy(output);
211                 return;
212         }
213
214         intel_output->type = INTEL_OUTPUT_ANALOG;
215         output->driver_private = intel_output;
216         output->interlace_allowed = 0;
217         output->doublescan_allowed = 0;
218
219         /* Set up the DDC bus. */
220         intel_output->ddc_bus = intel_i2c_create(dev, GPIOA, "CRTDDC_A");
221         if (!intel_output->ddc_bus) {
222                 dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration "
223                            "failed.\n");
224                 return;
225         }
226 }