gma500: Add support for Cedarview
[linux-2.6.git] / drivers / gpu / drm / gma500 / cdv_intel_crt.c
1 /*
2  * Copyright © 2006-2007 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  *
23  * Authors:
24  *      Eric Anholt <eric@anholt.net>
25  */
26
27 #include <linux/i2c.h>
28 #include <drm/drmP.h>
29
30 #include "intel_bios.h"
31 #include "psb_drv.h"
32 #include "psb_intel_drv.h"
33 #include "psb_intel_reg.h"
34 #include "power.h"
35 #include <linux/pm_runtime.h>
36
37
38 static void cdv_intel_crt_dpms(struct drm_encoder *encoder, int mode)
39 {
40         struct drm_device *dev = encoder->dev;
41         u32 temp, reg;
42         reg = ADPA;
43
44         temp = REG_READ(reg);
45         temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE);
46         temp &= ~ADPA_DAC_ENABLE;
47
48         switch (mode) {
49         case DRM_MODE_DPMS_ON:
50                 temp |= ADPA_DAC_ENABLE;
51                 break;
52         case DRM_MODE_DPMS_STANDBY:
53                 temp |= ADPA_DAC_ENABLE | ADPA_HSYNC_CNTL_DISABLE;
54                 break;
55         case DRM_MODE_DPMS_SUSPEND:
56                 temp |= ADPA_DAC_ENABLE | ADPA_VSYNC_CNTL_DISABLE;
57                 break;
58         case DRM_MODE_DPMS_OFF:
59                 temp |= ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE;
60                 break;
61         }
62
63         REG_WRITE(reg, temp);
64 }
65
66 static int cdv_intel_crt_mode_valid(struct drm_connector *connector,
67                                 struct drm_display_mode *mode)
68 {
69         int max_clock = 0;
70         if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
71                 return MODE_NO_DBLESCAN;
72
73         /* The lowest clock for CDV is 20000KHz */
74         if (mode->clock < 20000)
75                 return MODE_CLOCK_LOW;
76
77         /* The max clock for CDV is 355 instead of 400 */
78         max_clock = 355000;
79         if (mode->clock > max_clock)
80                 return MODE_CLOCK_HIGH;
81
82         if (mode->hdisplay > 1680 || mode->vdisplay > 1050)
83                 return MODE_PANEL;
84
85         return MODE_OK;
86 }
87
88 static bool cdv_intel_crt_mode_fixup(struct drm_encoder *encoder,
89                                  struct drm_display_mode *mode,
90                                  struct drm_display_mode *adjusted_mode)
91 {
92         return true;
93 }
94
95 static void cdv_intel_crt_mode_set(struct drm_encoder *encoder,
96                                struct drm_display_mode *mode,
97                                struct drm_display_mode *adjusted_mode)
98 {
99
100         struct drm_device *dev = encoder->dev;
101         struct drm_crtc *crtc = encoder->crtc;
102         struct psb_intel_crtc *psb_intel_crtc =
103                                         to_psb_intel_crtc(crtc);
104         int dpll_md_reg;
105         u32 adpa, dpll_md;
106         u32 adpa_reg;
107
108         if (psb_intel_crtc->pipe == 0)
109                 dpll_md_reg = DPLL_A_MD;
110         else
111                 dpll_md_reg = DPLL_B_MD;
112
113         adpa_reg = ADPA;
114
115         /*
116          * Disable separate mode multiplier used when cloning SDVO to CRT
117          * XXX this needs to be adjusted when we really are cloning
118          */
119         {
120                 dpll_md = REG_READ(dpll_md_reg);
121                 REG_WRITE(dpll_md_reg,
122                            dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK);
123         }
124
125         adpa = 0;
126         if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
127                 adpa |= ADPA_HSYNC_ACTIVE_HIGH;
128         if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
129                 adpa |= ADPA_VSYNC_ACTIVE_HIGH;
130
131         if (psb_intel_crtc->pipe == 0)
132                 adpa |= ADPA_PIPE_A_SELECT;
133         else
134                 adpa |= ADPA_PIPE_B_SELECT;
135
136         REG_WRITE(adpa_reg, adpa);
137 }
138
139
140 /**
141  * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect CRT presence.
142  *
143  * \return true if CRT is connected.
144  * \return false if CRT is disconnected.
145  */
146 static bool cdv_intel_crt_detect_hotplug(struct drm_connector *connector,
147                                                                 bool force)
148 {
149         struct drm_device *dev = connector->dev;
150         u32 hotplug_en;
151         int i, tries = 0, ret = false;
152         u32 adpa_orig;
153
154         /* disable the DAC when doing the hotplug detection */
155
156         adpa_orig = REG_READ(ADPA);
157
158         REG_WRITE(ADPA, adpa_orig & ~(ADPA_DAC_ENABLE));
159
160         /*
161          * On a CDV thep, CRT detect sequence need to be done twice
162          * to get a reliable result.
163          */
164         tries = 2;
165
166         hotplug_en = REG_READ(PORT_HOTPLUG_EN);
167         hotplug_en &= ~(CRT_HOTPLUG_DETECT_MASK);
168         hotplug_en |= CRT_HOTPLUG_FORCE_DETECT;
169
170         hotplug_en |= CRT_HOTPLUG_ACTIVATION_PERIOD_64;
171         hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50;
172
173         for (i = 0; i < tries ; i++) {
174                 unsigned long timeout;
175                 /* turn on the FORCE_DETECT */
176                 REG_WRITE(PORT_HOTPLUG_EN, hotplug_en);
177                 timeout = jiffies + msecs_to_jiffies(1000);
178                 /* wait for FORCE_DETECT to go off */
179                 do {
180                         if (!(REG_READ(PORT_HOTPLUG_EN) &
181                                         CRT_HOTPLUG_FORCE_DETECT))
182                                 break;
183                         msleep(1);
184                 } while (time_after(timeout, jiffies));
185         }
186
187         if ((REG_READ(PORT_HOTPLUG_STAT) & CRT_HOTPLUG_MONITOR_MASK) !=
188             CRT_HOTPLUG_MONITOR_NONE)
189                 ret = true;
190
191         /* Restore the saved ADPA */
192         REG_WRITE(ADPA, adpa_orig);
193         return ret;
194 }
195
196 static enum drm_connector_status cdv_intel_crt_detect(
197                                 struct drm_connector *connector, bool force)
198 {
199         if (cdv_intel_crt_detect_hotplug(connector, force))
200                 return connector_status_connected;
201         else
202                 return connector_status_disconnected;
203 }
204
205 static void cdv_intel_crt_destroy(struct drm_connector *connector)
206 {
207         struct psb_intel_output *intel_output = to_psb_intel_output(connector);
208
209         psb_intel_i2c_destroy(intel_output->ddc_bus);
210         drm_sysfs_connector_remove(connector);
211         drm_connector_cleanup(connector);
212         kfree(connector);
213 }
214
215 static int cdv_intel_crt_get_modes(struct drm_connector *connector)
216 {
217         struct psb_intel_output *intel_output =
218                                 to_psb_intel_output(connector);
219         return psb_intel_ddc_get_modes(intel_output);
220 }
221
222 static int cdv_intel_crt_set_property(struct drm_connector *connector,
223                                   struct drm_property *property,
224                                   uint64_t value)
225 {
226         return 0;
227 }
228
229 /*
230  * Routines for controlling stuff on the analog port
231  */
232
233 static const struct drm_encoder_helper_funcs cdv_intel_crt_helper_funcs = {
234         .dpms = cdv_intel_crt_dpms,
235         .mode_fixup = cdv_intel_crt_mode_fixup,
236         .prepare = psb_intel_encoder_prepare,
237         .commit = psb_intel_encoder_commit,
238         .mode_set = cdv_intel_crt_mode_set,
239 };
240
241 static const struct drm_connector_funcs cdv_intel_crt_connector_funcs = {
242         .dpms = drm_helper_connector_dpms,
243         .detect = cdv_intel_crt_detect,
244         .fill_modes = drm_helper_probe_single_connector_modes,
245         .destroy = cdv_intel_crt_destroy,
246         .set_property = cdv_intel_crt_set_property,
247 };
248
249 static const struct drm_connector_helper_funcs
250                                 cdv_intel_crt_connector_helper_funcs = {
251         .mode_valid = cdv_intel_crt_mode_valid,
252         .get_modes = cdv_intel_crt_get_modes,
253         .best_encoder = psb_intel_best_encoder,
254 };
255
256 static void cdv_intel_crt_enc_destroy(struct drm_encoder *encoder)
257 {
258         drm_encoder_cleanup(encoder);
259 }
260
261 static const struct drm_encoder_funcs cdv_intel_crt_enc_funcs = {
262         .destroy = cdv_intel_crt_enc_destroy,
263 };
264
265 void cdv_intel_crt_init(struct drm_device *dev,
266                         struct psb_intel_mode_device *mode_dev)
267 {
268
269         struct psb_intel_output *psb_intel_output;
270         struct drm_connector *connector;
271         struct drm_encoder *encoder;
272
273         u32 i2c_reg;
274
275         psb_intel_output = kzalloc(sizeof(struct psb_intel_output), GFP_KERNEL);
276         if (!psb_intel_output)
277                 return;
278
279         psb_intel_output->mode_dev = mode_dev;
280         connector = &psb_intel_output->base;
281         drm_connector_init(dev, connector,
282                 &cdv_intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA);
283
284         encoder = &psb_intel_output->enc;
285         drm_encoder_init(dev, encoder,
286                 &cdv_intel_crt_enc_funcs, DRM_MODE_ENCODER_DAC);
287
288         drm_mode_connector_attach_encoder(&psb_intel_output->base,
289                                           &psb_intel_output->enc);
290
291         /* Set up the DDC bus. */
292         i2c_reg = GPIOA;
293         /* Remove the following code for CDV */
294         /*
295         if (dev_priv->crt_ddc_bus != 0)
296                 i2c_reg = dev_priv->crt_ddc_bus;
297         }*/
298         psb_intel_output->ddc_bus = psb_intel_i2c_create(dev,
299                                                 i2c_reg, "CRTDDC_A");
300         if (!psb_intel_output->ddc_bus) {
301                 dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration "
302                            "failed.\n");
303                 goto failed_ddc;
304         }
305
306         psb_intel_output->type = INTEL_OUTPUT_ANALOG;
307         /*
308         psb_intel_output->clone_mask = (1 << INTEL_ANALOG_CLONE_BIT);
309         psb_intel_output->crtc_mask = (1 << 0) | (1 << 1);
310         */
311         connector->interlace_allowed = 0;
312         connector->doublescan_allowed = 0;
313
314         drm_encoder_helper_add(encoder, &cdv_intel_crt_helper_funcs);
315         drm_connector_helper_add(connector,
316                                         &cdv_intel_crt_connector_helper_funcs);
317
318         drm_sysfs_connector_add(connector);
319
320         return;
321 failed_ddc:
322         drm_encoder_cleanup(&psb_intel_output->enc);
323         drm_connector_cleanup(&psb_intel_output->base);
324         kfree(psb_intel_output);
325         return;
326 }