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