aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Cox <alan@linux.intel.com>2011-11-03 14:21:31 -0400
committerDave Airlie <airlied@redhat.com>2011-11-16 06:25:08 -0500
commitbbbb262d375140a27ed9fe45a13f19a04a0c51b2 (patch)
treedbd7960d612f3bbfc8ff6186be975a13159c2abe
parent4d8d096e9ae86621cc38b5417f4353305c5fd3a9 (diff)
gma500: Add device framework
The devices have various internal differences so we have some abstractions to hide the ugly differences and we then wrap them up in standard interfaces. Add these bits Signed-off-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
-rw-r--r--drivers/gpu/drm/gma500/backlight.c49
-rw-r--r--drivers/gpu/drm/gma500/power.c316
-rw-r--r--drivers/gpu/drm/gma500/power.h67
3 files changed, 432 insertions, 0 deletions
diff --git a/drivers/gpu/drm/gma500/backlight.c b/drivers/gpu/drm/gma500/backlight.c
new file mode 100644
index 000000000000..20793951fcac
--- /dev/null
+++ b/drivers/gpu/drm/gma500/backlight.c
@@ -0,0 +1,49 @@
1/*
2 * GMA500 Backlight Interface
3 *
4 * Copyright (c) 2009-2011, Intel Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Authors: Eric Knopp
20 *
21 */
22
23#include "psb_drv.h"
24#include "psb_intel_reg.h"
25#include "psb_intel_drv.h"
26#include "intel_bios.h"
27#include "power.h"
28
29int gma_backlight_init(struct drm_device *dev)
30{
31#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
32 struct drm_psb_private *dev_priv = dev->dev_private;
33 return dev_priv->ops->backlight_init(dev);
34#else
35 return 0;
36#endif
37}
38
39void gma_backlight_exit(struct drm_device *dev)
40{
41#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
42 struct drm_psb_private *dev_priv = dev->dev_private;
43 if (dev_priv->backlight_device) {
44 dev_priv->backlight_device->props.brightness = 0;
45 backlight_update_status(dev_priv->backlight_device);
46 backlight_device_unregister(dev_priv->backlight_device);
47 }
48#endif
49}
diff --git a/drivers/gpu/drm/gma500/power.c b/drivers/gpu/drm/gma500/power.c
new file mode 100644
index 000000000000..972bea7c1af2
--- /dev/null
+++ b/drivers/gpu/drm/gma500/power.c
@@ -0,0 +1,316 @@
1/**************************************************************************
2 * Copyright (c) 2009-2011, Intel Corporation.
3 * All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 *
24 * Authors:
25 * Benjamin Defnet <benjamin.r.defnet@intel.com>
26 * Rajesh Poornachandran <rajesh.poornachandran@intel.com>
27 * Massively reworked
28 * Alan Cox <alan@linux.intel.com>
29 */
30
31#include "power.h"
32#include "psb_drv.h"
33#include "psb_reg.h"
34#include "psb_intel_reg.h"
35#include <linux/mutex.h>
36#include <linux/pm_runtime.h>
37
38static struct mutex power_mutex; /* Serialize power ops */
39static spinlock_t power_ctrl_lock; /* Serialize power claim */
40
41/**
42 * gma_power_init - initialise power manager
43 * @dev: our device
44 *
45 * Set up for power management tracking of our hardware.
46 */
47void gma_power_init(struct drm_device *dev)
48{
49 struct drm_psb_private *dev_priv = dev->dev_private;
50
51 /* FIXME: Move APM/OSPM base into relevant device code */
52 dev_priv->apm_base = dev_priv->apm_reg & 0xffff;
53 dev_priv->ospm_base &= 0xffff;
54
55 dev_priv->display_power = true; /* We start active */
56 dev_priv->display_count = 0; /* Currently no users */
57 dev_priv->suspended = false; /* And not suspended */
58 spin_lock_init(&power_ctrl_lock);
59 mutex_init(&power_mutex);
60
61 dev_priv->ops->init_pm(dev);
62}
63
64/**
65 * gma_power_uninit - end power manager
66 * @dev: device to end for
67 *
68 * Undo the effects of gma_power_init
69 */
70void gma_power_uninit(struct drm_device *dev)
71{
72 pm_runtime_disable(&dev->pdev->dev);
73 pm_runtime_set_suspended(&dev->pdev->dev);
74}
75
76/**
77 * gma_suspend_display - suspend the display logic
78 * @dev: our DRM device
79 *
80 * Suspend the display logic of the graphics interface
81 */
82static void gma_suspend_display(struct drm_device *dev)
83{
84 struct drm_psb_private *dev_priv = dev->dev_private;
85
86 if (dev_priv->suspended)
87 return;
88 dev_priv->ops->save_regs(dev);
89 dev_priv->ops->power_down(dev);
90 dev_priv->display_power = false;
91}
92
93/**
94 * gma_resume_display - resume display side logic
95 *
96 * Resume the display hardware restoring state and enabling
97 * as necessary.
98 */
99static void gma_resume_display(struct pci_dev *pdev)
100{
101 struct drm_device *dev = pci_get_drvdata(pdev);
102 struct drm_psb_private *dev_priv = dev->dev_private;
103
104 if (dev_priv->suspended == false)
105 return;
106
107 /* turn on the display power island */
108 dev_priv->ops->power_up(dev);
109 dev_priv->suspended = false;
110 dev_priv->display_power = true;
111
112 PSB_WVDC32(dev_priv->pge_ctl | _PSB_PGETBL_ENABLED, PSB_PGETBL_CTL);
113 pci_write_config_word(pdev, PSB_GMCH_CTRL,
114 dev_priv->gmch_ctrl | _PSB_GMCH_ENABLED);
115 dev_priv->ops->restore_regs(dev);
116}
117
118/**
119 * gma_suspend_pci - suspend PCI side
120 * @pdev: PCI device
121 *
122 * Perform the suspend processing on our PCI device state
123 */
124static void gma_suspend_pci(struct pci_dev *pdev)
125{
126 struct drm_device *dev = pci_get_drvdata(pdev);
127 struct drm_psb_private *dev_priv = dev->dev_private;
128 int bsm, vbt;
129
130 if (dev_priv->suspended)
131 return;
132
133 pci_save_state(pdev);
134 pci_read_config_dword(pdev, 0x5C, &bsm);
135 dev_priv->saveBSM = bsm;
136 pci_read_config_dword(pdev, 0xFC, &vbt);
137 dev_priv->saveVBT = vbt;
138 pci_read_config_dword(pdev, PSB_PCIx_MSI_ADDR_LOC, &dev_priv->msi_addr);
139 pci_read_config_dword(pdev, PSB_PCIx_MSI_DATA_LOC, &dev_priv->msi_data);
140
141 pci_disable_device(pdev);
142 pci_set_power_state(pdev, PCI_D3hot);
143
144 dev_priv->suspended = true;
145}
146
147/**
148 * gma_resume_pci - resume helper
149 * @dev: our PCI device
150 *
151 * Perform the resume processing on our PCI device state - rewrite
152 * register state and re-enable the PCI device
153 */
154static bool gma_resume_pci(struct pci_dev *pdev)
155{
156 struct drm_device *dev = pci_get_drvdata(pdev);
157 struct drm_psb_private *dev_priv = dev->dev_private;
158 int ret;
159
160 if (!dev_priv->suspended)
161 return true;
162
163 pci_set_power_state(pdev, PCI_D0);
164 pci_restore_state(pdev);
165 pci_write_config_dword(pdev, 0x5c, dev_priv->saveBSM);
166 pci_write_config_dword(pdev, 0xFC, dev_priv->saveVBT);
167 /* restoring MSI address and data in PCIx space */
168 pci_write_config_dword(pdev, PSB_PCIx_MSI_ADDR_LOC, dev_priv->msi_addr);
169 pci_write_config_dword(pdev, PSB_PCIx_MSI_DATA_LOC, dev_priv->msi_data);
170 ret = pci_enable_device(pdev);
171
172 if (ret != 0)
173 dev_err(&pdev->dev, "pci_enable failed: %d\n", ret);
174 else
175 dev_priv->suspended = false;
176 return !dev_priv->suspended;
177}
178
179/**
180 * gma_power_suspend - bus callback for suspend
181 * @pdev: our PCI device
182 * @state: suspend type
183 *
184 * Called back by the PCI layer during a suspend of the system. We
185 * perform the necessary shut down steps and save enough state that
186 * we can undo this when resume is called.
187 */
188int gma_power_suspend(struct device *_dev)
189{
190 struct pci_dev *pdev = container_of(_dev, struct pci_dev, dev);
191 struct drm_device *dev = pci_get_drvdata(pdev);
192 struct drm_psb_private *dev_priv = dev->dev_private;
193
194 mutex_lock(&power_mutex);
195 if (!dev_priv->suspended) {
196 if (dev_priv->display_count) {
197 mutex_unlock(&power_mutex);
198 return -EBUSY;
199 }
200 psb_irq_uninstall(dev);
201 gma_suspend_display(dev);
202 gma_suspend_pci(pdev);
203 }
204 mutex_unlock(&power_mutex);
205 return 0;
206}
207
208/**
209 * gma_power_resume - resume power
210 * @pdev: PCI device
211 *
212 * Resume the PCI side of the graphics and then the displays
213 */
214int gma_power_resume(struct device *_dev)
215{
216 struct pci_dev *pdev = container_of(_dev, struct pci_dev, dev);
217 struct drm_device *dev = pci_get_drvdata(pdev);
218
219 mutex_lock(&power_mutex);
220 gma_resume_pci(pdev);
221 gma_resume_display(pdev);
222 psb_irq_preinstall(dev);
223 psb_irq_postinstall(dev);
224 mutex_unlock(&power_mutex);
225 return 0;
226}
227
228/**
229 * gma_power_is_on - returne true if power is on
230 * @dev: our DRM device
231 *
232 * Returns true if the display island power is on at this moment
233 */
234bool gma_power_is_on(struct drm_device *dev)
235{
236 struct drm_psb_private *dev_priv = dev->dev_private;
237 return dev_priv->display_power;
238}
239
240/**
241 * gma_power_begin - begin requiring power
242 * @dev: our DRM device
243 * @force_on: true to force power on
244 *
245 * Begin an action that requires the display power island is enabled.
246 * We refcount the islands.
247 */
248bool gma_power_begin(struct drm_device *dev, bool force_on)
249{
250 struct drm_psb_private *dev_priv = dev->dev_private;
251 int ret;
252 unsigned long flags;
253
254 spin_lock_irqsave(&power_ctrl_lock, flags);
255 /* Power already on ? */
256 if (dev_priv->display_power) {
257 dev_priv->display_count++;
258 pm_runtime_get(&dev->pdev->dev);
259 spin_unlock_irqrestore(&power_ctrl_lock, flags);
260 return true;
261 }
262 if (force_on == false)
263 goto out_false;
264
265 /* Ok power up needed */
266 ret = gma_resume_pci(dev->pdev);
267 if (ret == 0) {
268 psb_irq_preinstall(dev);
269 psb_irq_postinstall(dev);
270 pm_runtime_get(&dev->pdev->dev);
271 dev_priv->display_count++;
272 spin_unlock_irqrestore(&power_ctrl_lock, flags);
273 return true;
274 }
275out_false:
276 spin_unlock_irqrestore(&power_ctrl_lock, flags);
277 return false;
278}
279
280/**
281 * gma_power_end - end use of power
282 * @dev: Our DRM device
283 *
284 * Indicate that one of our gma_power_begin() requested periods when
285 * the diplay island power is needed has completed.
286 */
287void gma_power_end(struct drm_device *dev)
288{
289 struct drm_psb_private *dev_priv = dev->dev_private;
290 unsigned long flags;
291 spin_lock_irqsave(&power_ctrl_lock, flags);
292 dev_priv->display_count--;
293 WARN_ON(dev_priv->display_count < 0);
294 spin_unlock_irqrestore(&power_ctrl_lock, flags);
295 pm_runtime_put(&dev->pdev->dev);
296}
297
298int psb_runtime_suspend(struct device *dev)
299{
300 return gma_power_suspend(dev);
301}
302
303int psb_runtime_resume(struct device *dev)
304{
305 return 0;
306}
307
308int psb_runtime_idle(struct device *dev)
309{
310 struct drm_device *drmdev = pci_get_drvdata(to_pci_dev(dev));
311 struct drm_psb_private *dev_priv = drmdev->dev_private;
312 if (dev_priv->display_count)
313 return 0;
314 else
315 return 1;
316}
diff --git a/drivers/gpu/drm/gma500/power.h b/drivers/gpu/drm/gma500/power.h
new file mode 100644
index 000000000000..1969d2ecb328
--- /dev/null
+++ b/drivers/gpu/drm/gma500/power.h
@@ -0,0 +1,67 @@
1/**************************************************************************
2 * Copyright (c) 2009-2011, Intel Corporation.
3 * All Rights Reserved.
4
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 *
24 * Authors:
25 * Benjamin Defnet <benjamin.r.defnet@intel.com>
26 * Rajesh Poornachandran <rajesh.poornachandran@intel.com>
27 * Massively reworked
28 * Alan Cox <alan@linux.intel.com>
29 */
30#ifndef _PSB_POWERMGMT_H_
31#define _PSB_POWERMGMT_H_
32
33#include <linux/pci.h>
34#include <drm/drmP.h>
35
36void gma_power_init(struct drm_device *dev);
37void gma_power_uninit(struct drm_device *dev);
38
39/*
40 * The kernel bus power management will call these functions
41 */
42int gma_power_suspend(struct device *dev);
43int gma_power_resume(struct device *dev);
44
45/*
46 * These are the functions the driver should use to wrap all hw access
47 * (i.e. register reads and writes)
48 */
49bool gma_power_begin(struct drm_device *dev, bool force);
50void gma_power_end(struct drm_device *dev);
51
52/*
53 * Use this function to do an instantaneous check for if the hw is on.
54 * Only use this in cases where you know the mutex is already held such
55 * as in irq install/uninstall and you need to
56 * prevent a deadlock situation. Otherwise use gma_power_begin().
57 */
58bool gma_power_is_on(struct drm_device *dev);
59
60/*
61 * GFX-Runtime PM callbacks
62 */
63int psb_runtime_suspend(struct device *dev);
64int psb_runtime_resume(struct device *dev);
65int psb_runtime_idle(struct device *dev);
66
67#endif /*_PSB_POWERMGMT_H_*/