1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24#include <linux/acpi.h>
25#include <linux/acpi_io.h>
26#include "psb_drv.h"
27#include "psb_intel_reg.h"
28
29#define PCI_ASLE 0xe4
30#define PCI_ASLS 0xfc
31
32#define OPREGION_HEADER_OFFSET 0
33#define OPREGION_ACPI_OFFSET 0x100
34#define ACPI_CLID 0x01ac
35#define ACPI_CDCK 0x01b0
36#define OPREGION_SWSCI_OFFSET 0x200
37#define OPREGION_ASLE_OFFSET 0x300
38#define OPREGION_VBT_OFFSET 0x400
39
40#define OPREGION_SIGNATURE "IntelGraphicsMem"
41#define MBOX_ACPI (1<<0)
42#define MBOX_SWSCI (1<<1)
43#define MBOX_ASLE (1<<2)
44
45struct opregion_header {
46 u8 signature[16];
47 u32 size;
48 u32 opregion_ver;
49 u8 bios_ver[32];
50 u8 vbios_ver[16];
51 u8 driver_ver[16];
52 u32 mboxes;
53 u8 reserved[164];
54} __packed;
55
56
57struct opregion_acpi {
58 u32 drdy;
59 u32 csts;
60 u32 cevt;
61 u8 rsvd1[20];
62 u32 didl[8];
63 u32 cpdl[8];
64 u32 cadl[8];
65 u32 nadl[8];
66 u32 aslp;
67 u32 tidx;
68 u32 chpd;
69 u32 clid;
70 u32 cdck;
71 u32 sxsw;
72 u32 evts;
73 u32 cnot;
74 u32 nrdy;
75 u8 rsvd2[60];
76} __packed;
77
78
79struct opregion_swsci {
80
81} __packed;
82
83
84struct opregion_asle {
85 u32 ardy;
86 u32 aslc;
87 u32 tche;
88 u32 alsi;
89 u32 bclp;
90 u32 pfit;
91 u32 cblv;
92 u16 bclm[20];
93 u32 cpfm;
94 u32 epfm;
95 u8 plut[74];
96 u32 pfmb;
97 u8 rsvd[102];
98} __packed;
99
100
101#define ASLE_SET_ALS_ILLUM (1 << 0)
102#define ASLE_SET_BACKLIGHT (1 << 1)
103#define ASLE_SET_PFIT (1 << 2)
104#define ASLE_SET_PWM_FREQ (1 << 3)
105#define ASLE_REQ_MSK 0xf
106
107
108#define ASLE_ALS_ILLUM_FAILED (1<<10)
109#define ASLE_BACKLIGHT_FAILED (1<<12)
110#define ASLE_PFIT_FAILED (1<<14)
111#define ASLE_PWM_FREQ_FAILED (1<<16)
112
113
114#define ASLE_BCLP_VALID (1<<31)
115#define ASLE_BCLP_MSK (~(1<<31))
116
117
118#define ASLE_PFIT_VALID (1<<31)
119#define ASLE_PFIT_CENTER (1<<0)
120#define ASLE_PFIT_STRETCH_TEXT (1<<1)
121#define ASLE_PFIT_STRETCH_GFX (1<<2)
122
123
124#define ASLE_ALS_ILLUM_FAILED (1<<10)
125#define ASLE_BACKLIGHT_FAILED (1<<12)
126#define ASLE_PFIT_FAILED (1<<14)
127#define ASLE_PWM_FREQ_FAILED (1<<16)
128
129
130#define ASLE_BCLP_VALID (1<<31)
131#define ASLE_BCLP_MSK (~(1<<31))
132
133
134#define ASLE_PFIT_VALID (1<<31)
135#define ASLE_PFIT_CENTER (1<<0)
136#define ASLE_PFIT_STRETCH_TEXT (1<<1)
137#define ASLE_PFIT_STRETCH_GFX (1<<2)
138
139
140#define ASLE_PFMB_BRIGHTNESS_MASK (0xff)
141#define ASLE_PFMB_BRIGHTNESS_VALID (1<<8)
142#define ASLE_PFMB_PWM_MASK (0x7ffffe00)
143#define ASLE_PFMB_PWM_VALID (1<<31)
144
145#define ASLE_CBLV_VALID (1<<31)
146
147static struct psb_intel_opregion *system_opregion;
148
149static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
150{
151 struct drm_psb_private *dev_priv = dev->dev_private;
152 struct opregion_asle *asle = dev_priv->opregion.asle;
153 struct backlight_device *bd = dev_priv->backlight_device;
154
155 DRM_DEBUG_DRIVER("asle set backlight %x\n", bclp);
156
157 if (!(bclp & ASLE_BCLP_VALID))
158 return ASLE_BACKLIGHT_FAILED;
159
160 if (bd == NULL)
161 return ASLE_BACKLIGHT_FAILED;
162
163 bclp &= ASLE_BCLP_MSK;
164 if (bclp > 255)
165 return ASLE_BACKLIGHT_FAILED;
166
167 if (config_enabled(CONFIG_BACKLIGHT_CLASS_DEVICE)) {
168 int max = bd->props.max_brightness;
169 gma_backlight_set(dev, bclp * max / 255);
170 }
171
172 asle->cblv = (bclp * 0x64) / 0xff | ASLE_CBLV_VALID;
173
174 return 0;
175}
176
177void psb_intel_opregion_asle_intr(struct drm_device *dev)
178{
179 struct drm_psb_private *dev_priv = dev->dev_private;
180 struct opregion_asle *asle = dev_priv->opregion.asle;
181 u32 asle_stat = 0;
182 u32 asle_req;
183
184 if (!asle)
185 return;
186
187 asle_req = asle->aslc & ASLE_REQ_MSK;
188 if (!asle_req) {
189 DRM_DEBUG_DRIVER("non asle set request??\n");
190 return;
191 }
192
193 if (asle_req & ASLE_SET_BACKLIGHT)
194 asle_stat |= asle_set_backlight(dev, asle->bclp);
195
196 asle->aslc = asle_stat;
197}
198
199#define ASLE_ALS_EN (1<<0)
200#define ASLE_BLC_EN (1<<1)
201#define ASLE_PFIT_EN (1<<2)
202#define ASLE_PFMB_EN (1<<3)
203
204void psb_intel_opregion_enable_asle(struct drm_device *dev)
205{
206 struct drm_psb_private *dev_priv = dev->dev_private;
207 struct opregion_asle *asle = dev_priv->opregion.asle;
208
209 if (asle && system_opregion ) {
210
211
212 psb_enable_pipestat(dev_priv, 0, PIPE_LEGACY_BLC_EVENT_ENABLE);
213 psb_enable_pipestat(dev_priv, 1, PIPE_LEGACY_BLC_EVENT_ENABLE);
214
215 asle->tche = ASLE_ALS_EN | ASLE_BLC_EN | ASLE_PFIT_EN
216 | ASLE_PFMB_EN;
217 asle->ardy = 1;
218 }
219}
220
221#define ACPI_EV_DISPLAY_SWITCH (1<<0)
222#define ACPI_EV_LID (1<<1)
223#define ACPI_EV_DOCK (1<<2)
224
225
226static int psb_intel_opregion_video_event(struct notifier_block *nb,
227 unsigned long val, void *data)
228{
229
230
231
232
233
234
235
236 struct opregion_acpi *acpi;
237
238 if (!system_opregion)
239 return NOTIFY_DONE;
240
241 acpi = system_opregion->acpi;
242 acpi->csts = 0;
243
244 return NOTIFY_OK;
245}
246
247static struct notifier_block psb_intel_opregion_notifier = {
248 .notifier_call = psb_intel_opregion_video_event,
249};
250
251void psb_intel_opregion_init(struct drm_device *dev)
252{
253 struct drm_psb_private *dev_priv = dev->dev_private;
254 struct psb_intel_opregion *opregion = &dev_priv->opregion;
255
256 if (!opregion->header)
257 return;
258
259 if (opregion->acpi) {
260
261
262
263 opregion->acpi->csts = 0;
264 opregion->acpi->drdy = 1;
265
266 system_opregion = opregion;
267 register_acpi_notifier(&psb_intel_opregion_notifier);
268 }
269}
270
271void psb_intel_opregion_fini(struct drm_device *dev)
272{
273 struct drm_psb_private *dev_priv = dev->dev_private;
274 struct psb_intel_opregion *opregion = &dev_priv->opregion;
275
276 if (!opregion->header)
277 return;
278
279 if (opregion->acpi) {
280 opregion->acpi->drdy = 0;
281
282 system_opregion = NULL;
283 unregister_acpi_notifier(&psb_intel_opregion_notifier);
284 }
285
286
287 iounmap(opregion->header);
288 opregion->header = NULL;
289 opregion->acpi = NULL;
290 opregion->swsci = NULL;
291 opregion->asle = NULL;
292 opregion->vbt = NULL;
293}
294
295int psb_intel_opregion_setup(struct drm_device *dev)
296{
297 struct drm_psb_private *dev_priv = dev->dev_private;
298 struct psb_intel_opregion *opregion = &dev_priv->opregion;
299 u32 opregion_phy, mboxes;
300 void __iomem *base;
301 int err = 0;
302
303 pci_read_config_dword(dev->pdev, PCI_ASLS, &opregion_phy);
304 if (opregion_phy == 0) {
305 DRM_DEBUG_DRIVER("ACPI Opregion not supported\n");
306 return -ENOTSUPP;
307 }
308 DRM_DEBUG("OpRegion detected at 0x%8x\n", opregion_phy);
309 base = acpi_os_ioremap(opregion_phy, 8*1024);
310 if (!base)
311 return -ENOMEM;
312
313 if (memcmp(base, OPREGION_SIGNATURE, 16)) {
314 DRM_DEBUG_DRIVER("opregion signature mismatch\n");
315 err = -EINVAL;
316 goto err_out;
317 }
318
319 opregion->header = base;
320 opregion->vbt = base + OPREGION_VBT_OFFSET;
321
322 opregion->lid_state = base + ACPI_CLID;
323
324 mboxes = opregion->header->mboxes;
325 if (mboxes & MBOX_ACPI) {
326 DRM_DEBUG_DRIVER("Public ACPI methods supported\n");
327 opregion->acpi = base + OPREGION_ACPI_OFFSET;
328 }
329
330 if (mboxes & MBOX_ASLE) {
331 DRM_DEBUG_DRIVER("ASLE supported\n");
332 opregion->asle = base + OPREGION_ASLE_OFFSET;
333 }
334
335 return 0;
336
337err_out:
338 iounmap(base);
339 return err;
340}
341
342