gma500: tidy up the opregion and lid code
[pandora-kernel.git] / drivers / staging / 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 "psb_drm.h"
24 #include "psb_drv.h"
25 #include "psb_reg.h"
26 #include "psb_intel_reg.h"
27 #include "psb_intel_bios.h"
28
29
30 static int cdv_output_init(struct drm_device *dev)
31 {
32         struct drm_psb_private *dev_priv = dev->dev_private;
33         psb_intel_lvds_init(dev, &dev_priv->mode_dev);
34         psb_intel_sdvo_init(dev, SDVOB);
35         return 0;
36 }
37
38 #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
39
40 /*
41  *      Poulsbo Backlight Interfaces
42  */
43
44 #define BLC_PWM_PRECISION_FACTOR 100    /* 10000000 */
45 #define BLC_PWM_FREQ_CALC_CONSTANT 32
46 #define MHz 1000000
47
48 #define PSB_BLC_PWM_PRECISION_FACTOR    10
49 #define PSB_BLC_MAX_PWM_REG_FREQ        0xFFFE
50 #define PSB_BLC_MIN_PWM_REG_FREQ        0x2
51
52 #define PSB_BACKLIGHT_PWM_POLARITY_BIT_CLEAR (0xFFFE)
53 #define PSB_BACKLIGHT_PWM_CTL_SHIFT     (16)
54
55 static int cdv_brightness;
56 static struct backlight_device *cdv_backlight_device;
57
58 static int cdv_get_brightness(struct backlight_device *bd)
59 {
60         /* return locally cached var instead of HW read (due to DPST etc.) */
61         /* FIXME: ideally return actual value in case firmware fiddled with
62            it */
63         return cdv_brightness;
64 }
65
66
67 static int cdv_backlight_setup(struct drm_device *dev)
68 {
69         struct drm_psb_private *dev_priv = dev->dev_private;
70         unsigned long core_clock;
71         /* u32 bl_max_freq; */
72         /* unsigned long value; */
73         u16 bl_max_freq;
74         uint32_t value;
75         uint32_t blc_pwm_precision_factor;
76
77         /* get bl_max_freq and pol from dev_priv*/
78         if (!dev_priv->lvds_bl) {
79                 dev_err(dev->dev, "Has no valid LVDS backlight info\n");
80                 return -ENOENT;
81         }
82         bl_max_freq = dev_priv->lvds_bl->freq;
83         blc_pwm_precision_factor = PSB_BLC_PWM_PRECISION_FACTOR;
84
85         core_clock = dev_priv->core_freq;
86
87         value = (core_clock * MHz) / BLC_PWM_FREQ_CALC_CONSTANT;
88         value *= blc_pwm_precision_factor;
89         value /= bl_max_freq;
90         value /= blc_pwm_precision_factor;
91
92         if (value > (unsigned long long)PSB_BLC_MAX_PWM_REG_FREQ ||
93                  value < (unsigned long long)PSB_BLC_MIN_PWM_REG_FREQ)
94                                 return -ERANGE;
95         else {
96                 /* FIXME */
97         }
98         return 0;
99 }
100
101 static int cdv_set_brightness(struct backlight_device *bd)
102 {
103         struct drm_device *dev = bl_get_data(cdv_backlight_device);
104         int level = bd->props.brightness;
105
106         /* Percentage 1-100% being valid */
107         if (level < 1)
108                 level = 1;
109
110         /*cdv_intel_lvds_set_brightness(dev, level); FIXME */
111         cdv_brightness = level;
112         return 0;
113 }
114
115 static const struct backlight_ops cdv_ops = {
116         .get_brightness = cdv_get_brightness,
117         .update_status  = cdv_set_brightness,
118 };
119
120 static int cdv_backlight_init(struct drm_device *dev)
121 {
122         struct drm_psb_private *dev_priv = dev->dev_private;
123         int ret;
124         struct backlight_properties props;
125
126         memset(&props, 0, sizeof(struct backlight_properties));
127         props.max_brightness = 100;
128         props.type = BACKLIGHT_PLATFORM;
129
130         cdv_backlight_device = backlight_device_register("psb-bl",
131                                         NULL, (void *)dev, &cdv_ops, &props);
132         if (IS_ERR(cdv_backlight_device))
133                 return PTR_ERR(cdv_backlight_device);
134
135         ret = cdv_backlight_setup(dev);
136         if (ret < 0) {
137                 backlight_device_unregister(cdv_backlight_device);
138                 cdv_backlight_device = NULL;
139                 return ret;
140         }
141         cdv_backlight_device->props.brightness = 100;
142         cdv_backlight_device->props.max_brightness = 100;
143         backlight_update_status(cdv_backlight_device);
144         dev_priv->backlight_device = cdv_backlight_device;
145         return 0;
146 }
147
148 #endif
149
150 /*
151  *      Provide the Poulsbo specific chip logic and low level methods
152  *      for power management
153  */
154
155 static void cdv_init_pm(struct drm_device *dev)
156 {
157         struct drm_psb_private *dev_priv = dev->dev_private;
158
159         u32 gating = PSB_RSGX32(PSB_CR_CLKGATECTL);
160         gating &= ~3;   /* Disable 2D clock gating */
161         gating |= 1;
162         PSB_WSGX32(gating, PSB_CR_CLKGATECTL);
163         PSB_RSGX32(PSB_CR_CLKGATECTL);
164 }
165
166 /**
167  *      cdv_save_display_registers      -       save registers lost on suspend
168  *      @dev: our DRM device
169  *
170  *      Save the state we need in order to be able to restore the interface
171  *      upon resume from suspend
172  */
173 static int cdv_save_display_registers(struct drm_device *dev)
174 {
175         struct drm_psb_private *dev_priv = dev->dev_private;
176         struct drm_crtc *crtc;
177         struct drm_connector *connector;
178
179         /* Display arbitration control + watermarks */
180         dev_priv->saveDSPARB = PSB_RVDC32(DSPARB);
181         dev_priv->saveDSPFW1 = PSB_RVDC32(DSPFW1);
182         dev_priv->saveDSPFW2 = PSB_RVDC32(DSPFW2);
183         dev_priv->saveDSPFW3 = PSB_RVDC32(DSPFW3);
184         dev_priv->saveDSPFW4 = PSB_RVDC32(DSPFW4);
185         dev_priv->saveDSPFW5 = PSB_RVDC32(DSPFW5);
186         dev_priv->saveDSPFW6 = PSB_RVDC32(DSPFW6);
187         dev_priv->saveCHICKENBIT = PSB_RVDC32(DSPCHICKENBIT);
188
189         /* Save crtc and output state */
190         mutex_lock(&dev->mode_config.mutex);
191         list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
192                 if (drm_helper_crtc_in_use(crtc))
193                         crtc->funcs->save(crtc);
194         }
195
196         list_for_each_entry(connector, &dev->mode_config.connector_list, head)
197                 connector->funcs->save(connector);
198
199         mutex_unlock(&dev->mode_config.mutex);
200         return 0;
201 }
202
203 /**
204  *      cdv_restore_display_registers   -       restore lost register state
205  *      @dev: our DRM device
206  *
207  *      Restore register state that was lost during suspend and resume.
208  */
209 static int cdv_restore_display_registers(struct drm_device *dev)
210 {
211         struct drm_psb_private *dev_priv = dev->dev_private;
212         struct drm_crtc *crtc;
213         struct drm_connector *connector;
214         int pp_stat;
215
216         /* Display arbitration + watermarks */
217         PSB_WVDC32(dev_priv->saveDSPARB, DSPARB);
218         PSB_WVDC32(dev_priv->saveDSPFW1, DSPFW1);
219         PSB_WVDC32(dev_priv->saveDSPFW2, DSPFW2);
220         PSB_WVDC32(dev_priv->saveDSPFW3, DSPFW3);
221         PSB_WVDC32(dev_priv->saveDSPFW4, DSPFW4);
222         PSB_WVDC32(dev_priv->saveDSPFW5, DSPFW5);
223         PSB_WVDC32(dev_priv->saveDSPFW6, DSPFW6);
224         PSB_WVDC32(dev_priv->saveCHICKENBIT, DSPCHICKENBIT);
225
226         /*make sure VGA plane is off. it initializes to on after reset!*/
227         PSB_WVDC32(0x80000000, VGACNTRL);
228
229         mutex_lock(&dev->mode_config.mutex);
230         list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
231                 if (drm_helper_crtc_in_use(crtc))
232                         crtc->funcs->restore(crtc);
233
234         list_for_each_entry(connector, &dev->mode_config.connector_list, head)
235                 connector->funcs->restore(connector);
236
237         mutex_unlock(&dev->mode_config.mutex);
238
239         if (dev_priv->iLVDS_enable) {
240                 /*shutdown the panel*/
241                 PSB_WVDC32(0, PP_CONTROL);
242                 do {
243                         pp_stat = PSB_RVDC32(PP_STATUS);
244                 } while (pp_stat & 0x80000000);
245
246                 /* Turn off the plane */
247                 PSB_WVDC32(0x58000000, DSPACNTR);
248                 PSB_WVDC32(0, DSPASURF);/*trigger the plane disable*/
249                 /* Wait ~4 ticks */
250                 msleep(4);
251                 /* Turn off pipe */
252                 PSB_WVDC32(0x0, PIPEACONF);
253                 /* Wait ~8 ticks */
254                 msleep(8);
255
256                 /* Turn off PLLs */
257                 PSB_WVDC32(0, MRST_DPLL_A);
258         } else {
259                 PSB_WVDC32(DPI_SHUT_DOWN, DPI_CONTROL_REG);
260                 PSB_WVDC32(0x0, PIPEACONF);
261                 PSB_WVDC32(0x2faf0000, BLC_PWM_CTL);
262                 while (REG_READ(0x70008) & 0x40000000)
263                         cpu_relax();
264                 while ((PSB_RVDC32(GEN_FIFO_STAT_REG) & DPI_FIFO_EMPTY)
265                         != DPI_FIFO_EMPTY)
266                         cpu_relax();
267                 PSB_WVDC32(0, DEVICE_READY_REG);
268         }
269         return 0;
270 }
271
272 static int cdv_power_down(struct drm_device *dev)
273 {
274         return 0;
275 }
276
277 static int cdv_power_up(struct drm_device *dev)
278 {
279         return 0;
280 }
281
282 /* FIXME ? - shared with Poulsbo */
283 static void cdv_get_core_freq(struct drm_device *dev)
284 {
285         uint32_t clock;
286         struct pci_dev *pci_root = pci_get_bus_and_slot(0, 0);
287         struct drm_psb_private *dev_priv = dev->dev_private;
288
289         /*pci_write_config_dword(pci_root, 0xD4, 0x00C32004);*/
290         /*pci_write_config_dword(pci_root, 0xD0, 0xE0033000);*/
291
292         pci_write_config_dword(pci_root, 0xD0, 0xD0050300);
293         pci_read_config_dword(pci_root, 0xD4, &clock);
294         pci_dev_put(pci_root);
295
296         switch (clock & 0x07) {
297         case 0:
298                 dev_priv->core_freq = 100;
299                 break;
300         case 1:
301                 dev_priv->core_freq = 133;
302                 break;
303         case 2:
304                 dev_priv->core_freq = 150;
305                 break;
306         case 3:
307                 dev_priv->core_freq = 178;
308                 break;
309         case 4:
310                 dev_priv->core_freq = 200;
311                 break;
312         case 5:
313         case 6:
314         case 7:
315                 dev_priv->core_freq = 266;
316         default:
317                 dev_priv->core_freq = 0;
318         }
319 }
320
321 static int cdv_chip_setup(struct drm_device *dev)
322 {
323         cdv_get_core_freq(dev);
324         intel_opregion_init(dev);
325         psb_intel_init_bios(dev);
326         return 0;
327 }
328
329 /* CDV is much like Poulsbo but has MID like SGX offsets */
330
331 const struct psb_ops cdv_chip_ops = {
332         .name = "Cedartrail",
333         .accel_2d = 0,
334         .pipes = 2,
335         .sgx_offset = MRST_SGX_OFFSET,
336         .chip_setup = cdv_chip_setup,
337
338         .crtc_helper = &psb_intel_helper_funcs,
339         .crtc_funcs = &psb_intel_crtc_funcs,
340
341         .output_init = cdv_output_init,
342
343 #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
344         .backlight_init = cdv_backlight_init,
345 #endif
346
347         .init_pm = cdv_init_pm,
348         .save_regs = cdv_save_display_registers,
349         .restore_regs = cdv_restore_display_registers,
350         .power_down = cdv_power_down,
351         .power_up = cdv_power_up,       
352 };
353